VMware Workstation Playerの仮想マシンでUbuntu 22.04を起動すると、その直後にディスクアクセスが凄いことになる。
仮想ホストのWindows 11でタスクマネージャーを開いてみたところ、ディスク使用率が100%になっている。
DockerでMySQLを起動しているのだけれど、ext4のディスクとMySQLって相性が良くないようだ。
発生していたこと
仮想PCを起動すると、ディスク#2 HDDの使用率が数分間にわたって100%になる。
WindowsのタスクマネージャーでVMware Workstation VMXがずっと頑張っている。
SSHでログインするにも時間が掛かるが、どうにかログインしてiostatを確認してみた。
忙しく色々と動いているが、jdb2というのが時々上に上がってくる。
Total DISK READ: 6.63 M/s | Total DISK WRITE: 70.36 K/s Current DISK READ: 6.63 M/s | Current DISK WRITE: 125.90 K/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 434 be/3 root 0.00 B/s 3.70 K/s ?unavailable? [jbd2/sda2-8] 2671 be/4 lxd 74.06 K/s 0.00 B/s ?unavailable? mariadbd --transaction-isola~COMMITTED --binlog-format=ROW 2927 be/4 git 470.27 K/s 0.00 B/s ?unavailable? gitea web 3068 be/4 git 999.79 K/s 0.00 B/s ?unavailable? gitea web 3774 be/4 git 96.28 K/s 0.00 B/s ?unavailable? gitea web 3957 be/4 git 533.22 K/s 22.22 K/s ?unavailable? gitea web 3958 be/4 git 3.70 K/s 0.00 B/s ?unavailable? gitea web 4027 be/4 lxd 0.00 B/s 29.62 K/s ?unavailable? mysqld [ib_pg_flush_co] 4033 be/4 lxd 0.00 B/s 14.81 K/s ?unavailable? mysqld [ib_log_writer] 4078 be/4 root 2.30 M/s 0.00 B/s ?unavailable? networkctl status --no-pager~-no-legend -- br-aed7481ad107 4110 be/4 lxd 1044.22 K/s 0.00 B/s ?unavailable? mysqld [connection] 4112 be/4 lxd 74.06 K/s 0.00 B/s ?unavailable? mysqld [connection] 4114 be/4 lxd 1140.50 K/s 0.00 B/s ?unavailable? mysqld [connection] 1 be/4 root 0.00 B/s 0.00 B/s ?unavailable? init 2 be/4 root 0.00 B/s 0.00 B/s ?unavailable? [kthreadd] ...
数分待つとディスクアクセスがほとんどなくなり、様々な要求への応答速度が速くなる。
根本的な原因
仮想ホストの環境がこれ。CPUとメモリーには余裕があるので、ディスクの観点で書いている。
項目 | 値 |
---|---|
OS | Windows 11 Pro |
ディスク | #1 SSD, #2 HDD |
仮想PCのディスク | HDDを使用 |
仮想PCで稼働するDockerコンテナ | Kopano+Mariadb, Gitea+MySQL, Samba ad dc, DHCP4, DHCP6 |
根本的な原因は、仮想PCのディスクをHDDに置いていること。
仮想ディスクをSSDに置けば、ディスクアクセスの速度が上がって気にならなくなるはずだ。
しかし、ホームラボでは幾つも仮想PCを作っていて、それぞれがまぁまぁ容量を食っていたりするので、仮想ディスクにはHDDを使っている。
挙げ句に、ホームラボでサービスを提供するために7つのコンテナが稼働しており、起動時には7つが一気に立ち上がるのだから、大変なことになるのは必然ではある。
とはいえ、大容量なSSDを何個もくっつける気は起きないので、設定で可能な限りの改善しようと思う。
原因
jdb2とdisk ioで探してみたところ、ext4とMySQLとの相性が良くないと書かれている。
確かに仮想PCのディスクはext4で、MariaDBとMySQLが稼働している。
Github / moby / moby / jbd2 with 100% Disk IO #35274
server fault / IO Wait causing so much slowdown (EXT4 JDB2 at 99% IO ) During Mysql Commit
何の相性が悪いのかというと、ext4のbarrier機能(停電でライトキャッシュが消えたときにも一貫性が保たれる)と、binary log(データーベースへの変更を記録しレプリケーションで使用する)の相性だそうだ。
binary logには操作用のツールも用意されていて、データーの復旧にも使えるようなのだけれども、レプリケーションはしていないし、barrierで一貫性は保たれる(?)のであれば、割り切りとしてbinary logを諦めるのが手だなと思った。
MariaDB
どこがメンテナンスしているのか、ということだけを理由にMariaDBが好み。
KopanoというグループウェアのデーターベースとしてMariaDBを使わせていただいており、このような設定で起動している。
NextCloudの設定例をマネしている。
docker-compose.yml ※抜粋
kopano_db: image: mariadb:10.8.3-jammy container_name: kopano_db restart: unless-stopped command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW volumes: - kopano_db:/var/lib/mysql networks: - kopano environment: - TZ=Asia/Tokyo - MYSQL_ROOT_PASSWORD=hogehoge - MYSQL_PASSWORD=hogehoge - MYSQL_DATABASE=kopanoserver - MYSQL_USER=kopano - SYNC_BINLOG=0
コンテナの中に入り、設定を確認してみたところ、sync_binlogに0がセットされていた。
この設定だとbinary logは吐き出されないので、barrierとの相性問題は発生しない。
$ sudo docker exec -it kopano_db bash --login # mysql -u root -p Enter password: MariaDB [(none)]> show variables like '%bin%'; +-----------------------------------------+----------------------+ | Variable_name | Value | +-----------------------------------------+----------------------+ | bind_address | | ... | sync_binlog | 0 | | wsrep_forced_binlog_format | NONE | +-----------------------------------------+----------------------+ 31 rows in set (0.001 sec) MariaDB [(none)]> quit Bye
MySQL
Giteaの構築例がMySQLだったので、MySQLも稼働している。
docker-compse.yml ※抜粋
db: image: mysql:8 container_name: gitea_db restart: always environment: - MYSQL_ROOT_PASSWORD=hogehoge - MYSQL_USER=gitea - MYSQL_PASSWORD=hogehoge - MYSQL_DATABASE=gitea networks: - gitea volumes: - mysql:/var/lib/mysql
コンテナの中に入り、設定を確認してみたところ、sync_binlogに1がセットされていた。
この設定だとbinary logが吐き出されるので、barrierとの相性問題が発生する。
$ sudo docker exec -it gitea_db bash --login [root@2e810895edc1 /]# mysql -u root -p Enter password: mysql> show variables like '%bin%'; +------------------------------------------------+-----------------------------+ | Variable_name | Value | +------------------------------------------------+-----------------------------+ | bind_address | * | ... | sync_binlog | 1 | +------------------------------------------------+-----------------------------+ 38 rows in set (0.02 sec) mysql> quit Bye
対策
対策1でも2でも、効果がある。
仮想PCの再起動では、ディスクアクセスが100%になることがない。
仮想ホストのディスクキャッシュも効いているってことなのだろう。
PCを起動してから、最初に仮想PCを立ち上げるときでも、ディスクアクセス100%の状態は45秒程度で収まる。
(ホームラボでの結果であって、もっと遅かったり早かったりするかもしれない、環境や状態による)
対策1
Binary logを止める。OSが一貫性を保つことに頑張ってくれるのだから、それに任せようという考え方。
とはいえ、データー破損が諦められないような重要な環境ならば、安全性についてもっとちゃんと調べた方が良い。
設定値について、こちらで教えてくれている。
MySQL Documentation / 17.1.6.4 Binary Logging Options and Variables
こちらで、ちょっと違うパラメーターだけれども指定方法を教えてくれたいた。
それをsync_binlogに変えて設定してみた。
stack overflow / How to disable MySQL binlog on docker-compose
MySQLのdocker-compse.yml
db:
image: mysql:8
container_name: gitea_db
restart: always
command:
- '--sync_binlog=0'
environment:
- MYSQL_ROOT_PASSWORD=hogehoge
- MYSQL_USER=gitea
- MYSQL_PASSWORD=hogehoge
- MYSQL_DATABASE=gitea
networks:
- gitea
volumes:
- mysql:/var/lib/mysql
※赤文字を追加して、起動パラメーターで指定している。
設定変更後、コンテナを止めて、改めて起動。
$ sudo docker compose stop $ sudo docker compose up -d
確認してみると、Binary logが無効化されていた。
$ sudo docker exec -it gitea_db bash --login [root@04f692ccdb10 /]# mysql -u root -p Enter password: mysql> show variables like 'sync_binlog'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | sync_binlog | 0 | +---------------+-------+ 1 row in set (0.00 sec) mysql> quit Bye
ちなみに、パラメーターはこの書き方も可能。
docker-compose.yml ※抜粋
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --sync_binlog=0
対策2
OSのbarrier機能を無効にする。
過去の経験から、仮想環境がHyper-Vならこれ一択と思う。
仮想環境がVMwareならば、対策1がおすすめ。実際、対策1でも対策2でも体感的には変わらないので、全体が保護できるbarrierは残しておいた方が良いと思う。
barrierを無効にするには、fstabに以下の設定を加える。
/etc/fstab
/dev/disk/by-uuid/060aca14-eb26-439b-813b-b7525a2fb379 / ext4 defaults,barrier=0 0 1
さいごに
仮想PCでUbuntu desktopを使って、ちょっと何か作ってみようと思っている。
このUbuntu desktopにサービスを提供するため、今回記事にした仮想PCを先に起動するのだけれど、毎回かなり待たされる。
成果をサクサク出す人は、こういうときに、どちらを選択するのだろうか。
- 成果物を作るまでの我慢だから、毎日待たされたとしても放っておいて、成果物を作る。
- 毎日やることだから、待たされる問題を解消してから、本格的に成果物を作る。
待たされる時間、問題を解消することによって得られる効果、成果物の規模のバランスではある。
自分は前者から後者への切り替えのハードルが物凄く低くて、すぐに脇道にそれてしまう。そして、その脇道もちゃんと調べると結構時間が掛かったりして。
長い目で見ればその方が良いと思ったりするけれど、実際はどうなんだろう。それぞれのやり方だし、まぁいいか。
コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他