AWSでデプロイしたアプリがMySQLが落ちた事が原因でエラーになっていた。
エラーログ
MySQLのログを見てみると
2021-06-27T22:58:07.430585Z 0 [ERROR] [MY-012681] [InnoDB] mmap(137035776 bytes) failed; errno 12
2021-06-27T22:58:07.430701Z 1 [ERROR] [MY-012956] [InnoDB] Cannot allocate memory for the buffer pool
2021-06-27T22:58:07.430767Z 1 [ERROR] [MY-012930] [InnoDB] Plugin initialization aborted with error Generic error.
2021-06-27T22:58:07.430856Z 1 [ERROR] [MY-010334] [Server] Failed to initialize DD Storage Engine
2021-06-27T22:58:07.431029Z 0 [ERROR] [MY-010020] [Server] Data Dictionary initialization failed.
2021-06-27T22:58:07.431169Z 0 [ERROR] [MY-010119] [Server] Aborting
2021-06-27T22:58:07.436718Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.25) MySQL Community Server - GPL.
というログが。
2段目に Cannot allocate memory for the buffer poolとある。
バッファプールへの割り当てが足りない。という事。
という事でググってみると、主に2つの解決策があるみたい。
対処法
- swap領域を作成する
-
innodb_buffer_pool_sizeの割り当てを増やす
というのが、主な解決策らしい。
参考サイト: https://kenzo0107.hatenablog.com/entry/2016/05/20/105756
基本的な用語の理解
初学者なので、ここでいったん整理しておく。
「そんなん知ってるわ」っていう方は見なくていいと思います。
まず、対処法1の「swap領域を作成する」ということについて。
そもそも、
swapとは
使ってないメモリの内容を一時的にしまっておくための場所。
swap領域とは
メモリの内容を一時的にしまっておく場所のこと。
ちなみに、
メモリの内容を一時的にしまっておくファイルを「スワップファイル」。
メモリの内容を一時的にしまっておくパーテーションを「スワップパーテーション」。
というらしいです。
swapに関しては下記サイトが図も交えつつ、ある程度ザックリまとまっていて分かりやすかったです。
https://wa3.i-3-i.info/word1721.html
で、対処法2の「innodb_buffer_pool_sizeの割り当てを増やす」ということについて。
innodb_buffer_pool_sizeとは
MySQLのinnodb_buffer_pool_sizeは、ディスクイメージをメモリ上にバッファさせる値をきめる設定値で、この設定が、いかにディスクIOを押さえるかに繋がったりするので、コストパフォーマンス向上を考えるうえで重要な設定のひとつだったりします。
https://corporate.inter-edu.com
MySQL、mariaDBにおけるデータベースエンジン。とのこと。
バッファとは
バッファ(Buffer)とは、一時的にデータを蓄えておく記憶装置や記憶領域のことです。 バッファは、緩衝物や緩衝装置と訳されますが、コンピュータの業界では、主にデータを一時的に蓄えておく記憶装置や記憶領域のことを指します。
https://www.secomtrust.net/secword/buffer.html
原因と対処法の整理
つまり、先ほどのエラーログで出ていた「 バッファープールへの割り当てが足りない」とログに出ていたということは、エラーは
原因: 「割り当てられているメモリの量がたりない」
↓
対処法: 使わないメモリを一時的に退避させる場所を作るか(swap領域の作成)、メモリの割り当てを増やす(innodb_buffer_pool_sizeの割り当てを増やす)
ということになる。
対処法の具体的な手順
これはググると、たくさん出てくると思うが、一応自分が実際行った手順を備忘録がてら残しておく。
swap領域を作成する
まず、ディスクの利用状況を確認
[ec2-user@ip-10-0-0-191 ~]$ df -h
ファイルシス サイズ 使用 残り 使用% マウント位置
devtmpfs 482M 0 482M 0% /dev
tmpfs 492M 0 492M 0% /dev/shm
tmpfs 492M 512K 492M 1% /run
tmpfs 492M 0 492M 0% /sys/fs/cgroup
/dev/xvda1 8.0G 6.1G 2.0G 76% /
tmpfs 99M 4.0K 99M 1% /run/user/1000
空ファイル作成
[ec2-user@ip-10-0-0-191 ~]$ sudo dd if=/dev/zero of=/swapfile bs=1M count=1024
1024+0 レコード出力
1073741824 バイト (1.1 GB) コピーされました、 15.7396 秒、 68.2 MB/秒
作成したファイルをswap領域に設定
[ec2-user@ip-10-0-0-191 ~]$ sudo mkswap /swapfile
mkswap: /swapfile: パーミッション 0644 は安全な値ではありません。 0600 をお勧めします。
スワップ空間バージョン 1 を設定します。サイズ = 1024 MiB (1073737728 バイト)
ラベルはありません, UUID=9940e6a8-3ed3-4175-8f33-8efe191aa13d
パーミションを変更
[ec2-user@ip-10-0-0-191 ~]$ sudo chmod 600 /swapfile
swap領域を有効にする
[ec2-user@ip-10-0-0-191 ~]$ sudo swapon /swapfile
メモリの利用状況を確認
[ec2-user@ip-10-0-0-191 ~]$ free
total used free shared buff/cache available
Mem: 1006896 725588 62752 524 218556 141904
Swap: 1048572 0 1048572
MySQLを再起動
[ec2-user@ip-10-0-0-191 ~]$ sudo service mysqld restart
Redirecting to /bin/systemctl restart mysqld.service
上記コマンドだけだと、再起動した際にマウントされないらしいので、 /etc/fstab に
/swapfile swap swap defaults 0 0
を追加。
innodb_buffer_pool_sizeの割り当てを増やす
MySQLに入る
[ec2-user@ip-10-0-0-191 etc]$ mysql -u root -p
(パスワードの入力)
innodb_buffer_pool_sizeを調べる
mysql> SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
+-------------------------+-----------+
| Variable_name | Value |
+-------------------------+-----------+
| innodb_buffer_pool_size | 134217728 |
+-------------------------+-----------+
1 row in set (0.00 sec)
my.cnfの場所を探す
[ec2-user@ip-10-0-0-191 etc]$ mysql --help | grep my.cnf
order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf
左から順に探していき、該当するファイルがあればそれに設定を書き込む
[ec2-user@ip-10-0-0-191 etc]$ sudo vi my.cnf
以下を追記
innodb_buffer_pool_size = 256M
MySQLを再起動
[ec2-user@ip-10-0-0-191 ~]$ sudo service mysqld restart
Redirecting to /bin/systemctl restart mysqld.service
innodb_buffer_pool_sizeを調べる
mysql> SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
+-------------------------+-----------+
| Variable_name | Value |
+-------------------------+-----------+
| innodb_buffer_pool_size | 268435456 |
+-------------------------+-----------+
1 row in set (0.00 sec)
以上。
余談ですが、過去の自分のような初学者の方は
手順が書いてある個人のブログを鵜呑みにして、それ通り行いがちですが、ブログの記事を鵜呑みにせず(この記事含め)構造的に原因と対処を捉えた方が結果的に解決が早いと思うので、
・なるべく公式サイトなどで解決できそうな文献が見つけらたら、それを参考にする。
・文献が見つけられず、個人のブログなどを参考にする場合は構造的に理解できる記事を集めて、原因を自分で理解した上で対処する
というのを意識するといいと思います。余談でした。
その他参考にしたサイト
https://yusuke.blog/2017/12/17/2029
https://qiita.com/madaran0805/items/ae0532a7436e1c684e72
https://dacelo.space/mysql/entry-1116.html
https://soudan.hatenablog.jp/entry/mysql-bufferpoolsize