MySQLクライアントからRDSへ大量データをインポートしようとしたら処理が途中で終了した

# はじめに

MySQLクライアントからRDSへ大量データをインポートしようとしたところ異常終了しました。この記事はその時の対応メモです。

# 注意
この記事では、RDSのサーバーシステム変数の調整を行なっています。サーバーシステム変数はRDSの挙動に大きな影響を与えるので、それぞれの環境において、その影響を検討の上、適用するようにしてください。

# 状況

- MySQLクライアントから大量データをインポートしていたら処理が途中で終了した
- データは途中までしか入っていなかった
- クライアントには何のエラー表示もされずにスッと終わっていた
- データベースサーバーのログを探すと次のようなエラーが見つかった


```text:エラーメッセージ
Aborted connection XXXXX to db: 'データベース名' user: 'ユーザー名' host: 'IPアドレス'
 (Got an error reading communication packets). (sql_connect.cc:828)
```


```bash:インポート処理
mysql -h ホスト名 -u ユーザー名 --password=パスワード データベース名 < インポート.sql
```

インポートしようとしたSQLファイルのサイズは数GB
エラー発生後、再度インポート処理すると問題なく終了することがあったりして、必ず再現するわけではなかった。


# 環境

### AWS RDS

データ検証のために用意したRDS
エンジンバージョン：8.0.mysql_aurora.3.05.2

### MySQLクライアント

AWS EC2上のシェルで実行

mysql --version
mysql  Ver 15.1 Distrib 10.5.23-MariaDB, for Linux (x86_64) using  EditLine wrapper


**【補足】公式ページでAurora MySQLへの接続にMariaDBクライアントが指定されている。**

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/CHAP_GettingStartedAurora.CreatingConnecting.Aurora.html

# 対応


## 1. RDSのサーバーシステム変数の変更

|  | 初期値 | 変更値 |
| --- | --- | --- |
| connect_timeout | 10 | 600 |
| net_read_timeout | 30 | 600 |
| net_write_timeout | 60 | 600 |
| max_allowed_packet | 67108864（64MB） | 1073741824（1GB） |

AWS RDSはパラメータグループによってシステム変数を指定することができる。

パラメータグループを直接変更するのではなく、

- パラメータグループの複製
- 値の変更
- RDSへ適用

といったステップを踏んだ。

## 2. インポート処理時のオプション変更

:::note
「max_allowed_packet」の指定はサーバーだけでなくクライアント側にも必要
:::

https://dev.mysql.com/doc/refman/8.0/ja/packet-too-large.html

```bash:インポート処理
mysql -h ホスト名 -u ユーザー名 --password=パスワード --max_allowed_packet=1G データベース名 < インポート.sql
```

これらの対応を行うことでエラーなくインポートできるようになった。

# 原因

エラーメッセージを元に検索してみると次の記事が見つかった。

https://repost.aws/ja/knowledge-center/rds-mysql-communication-packet-error

記事では次の要因が挙げられていた。

1. クライアントまたはドライバーの非互換性
2. アイドル状態の接続を閉じたり、接続をブロックしたりできるファイアウォールまたはプロキシ
3. クライアント/サーバー接続が不適切に閉じられると、RDS for MySQL 内のスリープ接続の数が増えます
4. 接続を不適切に終了するクライアントアプリケーション。接続が一定時間アイドル状態になると、MySQL はこれらの接続を強制的に閉じます。次に、「接続が中止されました」というメッセージが表示されます
5. wait\ _timeout または interactive_timeout のしきい値を超えるアイドル接続
6. 接続パケットの取得時に connect_timeout 秒のしきい値を超えるクライアント接続
7. net_write_timeout や net_read_timeout などのパラメータの不十分な値
8. max_allowed_packet パラメータ値を超過している。値が小さすぎる場合、またはクエリがRDS for MySQL に割り当てられているメモリよりも多くのメモリを必要とする場合、接続の中断警告がトリガーされます

今回の状況では、途中までインポートが進んでいることから1〜4は考え難く
可能性がないわけではないが、他の項目に比べて優先度は低いと判断した。

5〜8について確認した。

## サーバーシステム変数の確認

mysqlクライアントから以下を実行
```sql:サーバーシステム変数の確認
show variables 
where false
or variable_name = 'connect_timeout'
or variable_name = 'wait_timeout'
or variable_name = 'interactive_timeout'
or variable_name = 'net_read_timeout'
or variable_name = 'net_write_timeout' 
or variable_name = 'max_allowed_packet'
```

|  | 設定されていた値 |
| --- | --- |
| connect_timeout | 10 |
| wait_timeout | 28800 |
| interactive_timeout | 28800 |
| net_read_timeout | 30 |
| net_write_timeout | 60 |
| max_allowed_packet | 134217728（128MB） |

max_allowed_packetだけ64MBの初期値から128MBに変更している状況だった。

wait_timeoutとinteractive_timeoutに指定されている時間を超えてエラー発生している状況ではなかったので、connect_timeout、net_read_timeout、net_write_timeout、max_allowed_packet に絞って設定値を増やすことにした。


### MySQLサーバーシステム変数のリファレンス

https://dev.mysql.com/doc/refman/8.0/ja/server-system-variables.html

# 余談

データ検証を行うためにエクスポート、インポート、スナップショットの保管・復元を何度も行なっている時に、冒頭で書いたエラーに遭遇しました。とりあえず処理をやり直すことでエラーが解消したのですが、そこでエラーが再発せずに解消したことによって根本解決に取り組むのが遅れました。

その後、エラーの頻度が増えたため、ようやく調査を始めました。再現性の乏しいエラーはいつ対応すべきか判断が難しいですが、サクッと調査・解決できるようになりたいなと思いました。