5

多くの人が経験したエラーは、次のメッセージに関連しています。

[Warning] Aborted connection 38 to db: 'database_name' user: 
'root' host: 'localhost' (Got an error reading communication packets)

これは MySQL ログにあります。私の場合、データベースは、ドライバーとよく知られている C3P0 プールを使用して Java クライアントを介してローカルにアクセスされます。com.mysql.jdbc.Driver私の MySQL サーバーは非常に多くの接続を受け入れるように構成されており、max_allowed_pa​​cket の値は 64M に設定されています。my.cnf ファイル (MySQL 構成) からの抜粋を次に示します。

[mysqld]
max_allowed_packet  = 64M
thread_concurrency      = 8
thread_cache_size       = 8
thread_stack        = 192K
query_cache_size = 0
query_cache_type = 0
max_connections = 1024
back_log = 50
innodb_thread_concurrency = 6
innodb_lock_wait_timeout = 120
log_warnings

[mysqldump]
quick
quote-names
max_allowed_packet  = 64M

私のデータベースのテーブルUserには、次の単純な構造があります。

CREATE TABLE `User` (
  `uid` varchar(255) COLLATE utf8_bin NOT NULL,
  `name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `mail` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `password` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `maxParallelTasks` tinyint(4) NOT NULL DEFAULT '10',
  `maxModels` int(11) NOT NULL DEFAULT '2000',
  `maxBibTeX` int(11) NOT NULL DEFAULT '2000',
  PRIMARY KEY (`uid`) USING BTREE,
  UNIQUE KEY `mail` (`mail`) USING BTREE,
  KEY `uid` (`uid`) USING BTREE,
  KEY `index_user_name` (`name`) USING BTREE,
  KEY `index_user_mail` (`mail`) USING BTREE,
  KEY `index_user_maxModels` (`maxModels`) USING BTREE,
  KEY `index_user_maxBibTeX` (`maxBibTeX`) USING BTREE,
  KEY `index_user_maxParallelTasks` (`maxParallelTasks`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin

mysqlクライアントを使用してそのテーブルの値を取得するとINSERT(つまりmysql -u root -p)、ログに警告が表示されません。ただし、同じ Java 側を試すと、前述の警告がログに何度も表示されます。したがって、Java 側では、私の接続は次のように構成された C3P0 接続プールから引き出されます。

datasource = new ComboPooledDataSource();
datasource.setJdbcUrl(connectURI);
datasource.setMaxPoolSize(1000);
datasource.setMinPoolSize(20);
datasource.setInitialPoolSize(50);
datasource.setNumHelperThreads(6);
datasource.setTestConnectionOnCheckin(true);
datasource.setTestConnectionOnCheckout(true);

ステートメントは最初に準備されます。

PreparedStatement ps = connection.prepareStatement(getSql());

次にパラメータ化します:

ps.setString(1, user.getUid());
ps.setString(2, user.getName());
ps.setString(3, user.getMail());
ps.setString(4, user.getHashedPass());

そして実行しました:

int update = ps.executeUpdate();

次に、準備されたステートメントを閉じます。

ps.close();

SQL 接続が閉じられます。

if (connection != null) {
            try {
                if (!connection.isClosed()) {
                    connection.close();
                }
            } catch (SQLException ex) {
                throw new DbException(ex);
            }
}

全体的な手順は (私には) 合法であるように思われます。http://dev.mysql.com/doc/refman/5.0/en/communication-errors.htmlの MySQL マニュアルによると、この警告は次のことを意味している可能性があります。

クライアント プログラムは、終了する前に mysql_close() を呼び出しませんでした。

またはその:

クライアント プログラムは、データ転送の途中で突然終了しました。

私のアプリケーションの目的のために、C3P​​0 を使用して、200 以上の並列スレッドを使用してこのデータベースに書き込みおよび読み取りを行いました。データが実際にデータベースに転送され、データベースから正常に取得されることを確認している間、メモリ リークはありません。他の誰かが同様の経験をしていますか?

最後に、MySQL のバージョンと、トラブルシューティングに役立つその他の情報を含めます。

mysql> show variables like "%version%";
+-------------------------+-------------------+
| Variable_name           | Value             |
+-------------------------+-------------------+
| protocol_version        | 10                | 
| version                 | 5.1.37-1ubuntu5.5 | 
| version_comment         | (Ubuntu)          | 
| version_compile_machine | x86_64            | 
| version_compile_os      | debian-linux-gnu  | 
+-------------------------+-------------------+

Java version: 1.6.0_22, (build 1.6.0_22-b04)
4

2 に答える 2

1

この警告の原因をさらに詳しく調査しようとしています...

最初に、ログ ファイルに表示される警告メッセージの数が、で指定された最小プール サイズと等しいか、それに非常に近いことに気付きましたdatasource.setMinPoolSize(int);。テスト用の初期プール サイズは、毎回最小サイズに等しく設定されていました。

さらに、デバッガーを使用してステートメントを段階的に実行すると、単体テストが終了するとすぐに警告がログに記録されることを確認する時間がありました。これらの事実から、C3P0 によってプールされた接続は実際には破棄される前に閉じられていないという結論に達しました。必要なのは、メソッドを呼び出して使用されなくなったら、データソースを閉じることcom.​mchange.​v2.​c3p0.​impl.​AbstractPoolBackedDataSource#close()です。もちろん、単体テストの最後にのみ行うのが理にかなっているので、私の場合、修正は次のようになります。

@AfterClass
public static void tearDownClass() throws Exception {
  // Close the pool 
  DataSourceFactory.getInstance().close();
}

私のアプリケーションでは、シャットダウン フックを追加して、実行が停止する前にデータソースが閉じるようにしました。それ以前は、プールされた接続がそのまま残され、ドライバーが接続を閉じる必要があったため、MySQL ログに警告が表示されていました。これにより、すべての INSERT 操作の問題が解決されましたが、残念ながら SELECT 操作の問題は解決されませんでした。すべての結果セット、ステートメント、準備済みステートメント、および接続を閉じ、FindBugs (静的分析ツール) を使用してソース コードをチェックしたことに注意してください。回避策により、C3P0 に何か問題があるのではないかと疑うことができますが、確信は持てません。したがって、次のようにすると警告が消えます...

@AfterClass
public static void tearDownClass() throws Exception {
  Thread.sleep(100000); // wait for 100 secs
  DataSourceFactory.getInstance().close();
}

100 秒の期間が終了する (およびデータソース ファクトリが閉じる) まで、ログに警告が表示されないことに注意してください。だから、それが彼らのdatasource.close()原因です...

于 2011-02-15T15:06:04.753 に答える
1

システムで問題が発生する可能性のある場所を示唆する適切な量の情報を含む質問を見るのは良いことです。これが私がチェックするものです:

  • オブジェクトを閉じるPreparedStatement前にオブジェクトを閉じてConnectionみて、問題が解決したかどうかを確認してください。これは不要に聞こえるかもしれませんが、特定の JDBC ドライバー、特に Oracle (および MySQL の場合もあります) の場合に必要です。論理的根拠は、オブジェクトが実際には閉じられていないということです。特におよびオブジェクトConnectionのような派生オブジェクトが最初に (前述の順序で) 閉じられていない場合は特にそうです。これは、一部には、JDBC ドライバーの作成方法が原因です。ResultSetStatement
  • 関連するマシンが、必要な負荷を実際に処理できるかどうかを確認します。基礎となるネットワーク インフラストラクチャが単に指定された数の接続を処理できない場合、接続が切断される可能性は十分にあります。最初の推奨事項が役に立たない場合は、wireshark ダンプを見て、そこから推論を引き出すことができます。
  • このフラグを使用して、debugUnreturnedConnectionStackTraces接続プールのリークを検出します。これには、unreturnedConnectionTimeout が正であることも必要です。このフラグにより​​、アプリケーションが接続をプールに返さない状況に対してスタック トレースが提供されるようになります。スタック トレースは、接続が最初に予約されたコード内のポイントを示します。
于 2011-02-14T15:33:34.120 に答える