ホームページ  >  記事  >  Java  >  alibaba druid を使用して複数のデータ ソースに接続する場合の問題

alibaba druid を使用して複数のデータ ソースに接続する場合の問題

零下一度
零下一度オリジナル
2017-07-21 17:27:327334ブラウズ

alibaba druid を使用して複数のデータ ソースに接続する場合の問題

タグ (スペース区切り): druid springboot start autoconfig


  • 背景

  • 調査と分析プロセス

  • 概要

背景

最近, Alibaba druid を使用して複数のデータ ソースを接続する際に小さなバグを偶然発見しました。github の問題を提出し、正式に修正されました。問題のアドレス:

発見と分析のプロセス

私たちが使用する Java 開発フレームワークはカプセル化されています。フレームワークのデータ ソースのサポートは、マスターおよびスレーブのアーキテクチャに基づいています。つまり、複数のスレーブ データ ソースのセットにすることができ、マスター/スレーブの書き込みとクエリの切り替えが内部で自動的に実行されます。

現在、.net を Java に変換中です。特殊なシナリオでは、新しい Java システムはデフォルトで 2 つのデータ ソースに接続する必要がありますが、場合によっては sqlserver データをクエリする必要があります。ソースを使用して互換性データを取得します。

そのため、2 番目のデータ ソースを構成するときに、システム負荷によってエラーが報告されました。

springboot フレームワークを使用し、データソース構成は springboot プロパティに基づいて構成されます。次に、構成を使用して自動 druid daasource Bean を作成します。これは問題ないようです。

    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "ecommon.order.druid")
    public DataSource getOrderDataSource() {
       return new DruidDataSource();
    }
springboot でない場合は、通常、すべてのプロパティを自分で初期化します。構成ファイルから構成をロードし、DruidDataSource Bean を手動で設定します。

私は何も考えずにそのまま使ってしまいました。しかし、起動時に Bean を初期化するときにエラーが報告されました。

「maxEvictableIdleTimeMillis」がスローした例外; ネストされた例外は java.lang.IllegalArgumentException: maxEvictableIdleTimeMillis は minEvictableIdleTimeMillis より大きくなければなりません

おそらく、「maxEvictableIdleTimeMillis」の最大生存時間は「minEvictableIdle」の最小生存時間より大きくなければならないことを意味しますタイムミリス。

最初の反応は、設定が間違っている、設定を確認するということでしょう。

##一个连接在池中最小生存的时间(ms)
ecommon.order.druid.minEvictableIdleTimeMillis=300000
##一个连接在池中最大生存的时间(ms)
ecommon.order.druid.maxEvictableIdleTimeMillis=600000
それは正しいようですが、デバッグ中に同じ問題が発生します。 minEvictableIdleTimeMillis 属性と maxEvictableIdleTimeMillis 属性の順序は問題ないようです。試した後、2 つの属性の順序を入れ替えましたが、問題は引き続き発生しました。

盲目状態~_~。

この問題はちょっと変だと思うので、時間が重要なので、エラーが報告されている場所を直接見つけてソースコードをトレースします。

github 検索 alibaba druid ホームページに移動し、直接 gith clone して、エラー プロンプトの場所を見つけます。

グローバル検索中にこの例外がスローされる場所は 2 か所あります。

1: init メソッド

public void init() throws SQLException {
            if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {
                throw new SQLException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");
            }
読みやすいように、問題の分析には役に立たない init 内のコードを削除しました。

2 つ: setMaxEvictableIdleTimeMillis メソッド

    public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) {
        if (maxEvictableIdleTimeMillis < 1000 * 30) {
            LOG.error("maxEvictableIdleTimeMillis should be greater than 30000");
        }
        
        if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {
            throw new IllegalArgumentException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");
        }
        
        this.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
    }
これら 2 つのメソッドのロジックは、初期化中にこれら 2 つの Bean 属性の値がチェックされます。 setMaxEvictableIdleTimeMillis、最大生存時間を設定するときにチェックがあります。最大生存時間が最小生存時間よりも短い場合、エラーが直接報告されます。

したがって、これら 2 つの場所にブレークポイントを設定してからデバッグし、基本的に変数の値をトレースすることで問題がどこにあるのかを知ることができます。

デバッグを通じて、new DruidDataSource() でデータ ソースを直接使用すると、init メソッドに移行しないことがわかりました。エラーが発生する場所には立ち入りません。私のコードパスではこのチェックが生成されないようです。実行を続けて、setMaxEvictableIdleTimeMillis メソッドで何が起こるかを確認します。

setMaxEvictableIdleTimeMillis メソッドを実行すると、minEvictableIdleTimeMillis 属性の値が 1800000 になります。

この値がどこから来たのか見てみましょう。

protected volatile long  minEvictableIdleTimeMillis  = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
public static final long  DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 
1000L * 60L * 30L;
minEvictableIdleTimeMillis プロパティにはデフォルト値があります。単位はms(ミリ秒)なので、ここでのデフォルト値は30m(分)分です。

600000msを設定したので、1800000msよりも小さくなります。しかし、これは奇妙です。minEvictableIdleTimeMillis パラメータを明確に設定しています。なぜうまくいかなかったのでしょうか? 私はすぐにシーケンスの問題だと思いました。

その後、デバッグを続行し、最初にこのチェックをバイパスして、setMinEvictableIdleTimeMillis メソッドが setMaxEvictableIdleTimeMillis メソッドの後に実行され、このチェックが構成順序と競合するかどうかを確認します。

デバッグ後、これは実際に問題です。そこで、私たちが現在使用しているフレームワークがどのようにして druid をカプセル化するのに役立つのかに興味がありました。フレームワークのソース コードを見ると、この問題を解決するハッシュコードのソートが含まれています。 (さすがベテランドライバー、達人) ここでは詳しくは述べません。

この問題を解決すると、問題を回避する方法を知るのは非常に簡単になります。

1 つ: まず、

@Data
@EqualsAndHashCode
@ConfigurationProperties(prefix = "ecommon.order.druid")
public class SqlServerDruidConfig {
    private Long minEvictableIdleTimeMillis;
    private Long maxEvictableIdleTimeMillis;
}
で設定された minEvictableIdleTimeMillis と maxEvictableIdleTimeMillis を取得します。 2 つ: 次に、最初にこれら 2 つのプロパティを自分で設定します。そうすれば、springboot autoconfig 時にエラーは発生しません
 @Autowired
    private SqlServerDruidConfig druidConfig;

    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "ecommon.order.druid")
    public DataSource getOrderDataSource() {

        DruidDataSource dataSource = new DruidDataSource();

        /**setMinEvictableIdleTimeMillis需要先设置*/
        dataSource.setMinEvictableIdleTimeMillis(druidConfig.getMinEvictableIdleTimeMillis());
        dataSource.setMaxEvictableIdleTimeMillis(druidConfig.getMaxEvictableIdleTimeMillis());

        return dataSource;
    }

    @Bean
    public SqlServerDruidConfig getDruidConfig() {
        return new SqlServerDruidConfig();
    }

問題の分析はここで終了します。この小さなバグは alibaba druid によって修正されました。

修正方法に興味がある場合は、druid の autoconfiger 修正に関するコードを参照してください:


まとめ

突然、あなたはすでにオープンソースの恩恵を受けていることがわかります。一緒に使用したり、一緒に問題を発見したり、一緒にバグを修正したりすることに参加できます。これは、Linux や git などの優れた芸術作品の背後にある核となる技術的価値である可能性があります。

以上がalibaba druid を使用して複数のデータ ソースに接続する場合の問題の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。