MySQLのmax_allowed_packetについて

先日、カイシャのギョームでこんなことがあった。

「なんか、普通に投稿はできるんだけど、下書きが保存できないんだよね。ちょっと原因わからない?」

Railsで書かれている対象のコードを読んだのだが、全く問題がなさそうだ。普通に ActiveRecord のメソッドを読んでテキスト情報を保存しているだけだからだ。

今扱っているプロジェクトは負債が多くてどこが本当に原因なのかはわからなかったので途方に暮れていたら、カイシャの凄腕の人が「 max_allowed_packet だったかな」と言い、サクッと直してしまった。

こういうのが技術力なんだなぁとしみじみ思ったので、どういうことが起こっていたのかちゃんと復習して次同じようなことが合った時に後輩にドヤ顔できるようにする。(間違いがあるかもなので指摘してもらえると幸い)


まず、対象の tableshow create table するとこんな感じだった。(一部抜粋)

CREATE TABLE `drafts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `dump_obj_encode_in_base64` longtext NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=145 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC

引き継いだプログラムなのでなぜこうなっていたのか全くわからないが、dump_obj_encode_in_base64 の型が longtext で保存されていた。

longtext最長4,294,967,295、または4GB (232 - 1) バイト と非常にsizeが大きい。

参考: BLOB型とTEXT型(DB Online)

mysqlのclientがserver投げられる最大のデータ量はどのくらいだろうか。

それを定義しているのが max_allowed_packet だ。

現在このブログを書いているPCのMySQL(Server version: 5.7.25-0ubuntu0.18.04.2 (Ubuntu))はどうだろうか。

mysql> show variables like 'max_allowed_packet';
+--------------------+----------+
| Variable_name      | Value    |
+--------------------+----------+
| max_allowed_packet | 16777216 |
+--------------------+----------+
1 row in set (0.06 sec)

約16MBだった。 longtext では全然足りないサイズだ。

RDSはAWS Consoleで変更できたので、ユーザーの少ない時間に再起動をして問題なく動き始めた。


gem: mysql2 では 今のエラーを以下のように表現している。

https://github.com/brianmario/mysql2/blob/master/lib/mysql2/error.rb#L18

1153 => ConnectionError, # ER_NET_PACKET_TOO_LARGE

packet too largeconnection error

これはわからない...


カイシャの凄腕の人が言ってたことを忘れないようにメモをしておく(無断掲載サーセン)

ピンポイントで下書きでエラーが出てる
↓
下書きテーブルに何かあるのでは&接続が切れるといえばタイムアウト・コネクション数・パケット長のどれか
↓
テーブルを見るとlongtextがある

ちなみにmax_allowed_packetを上げると、MySQLにデータ(SQL文)を流し込む時間も当然長くなるので
今度はそこでタイムアウトする懸念があります

net_write_timeout/net_read_timeoutね