Ubuntu

Ubuntu22.04 起動直後にディスク使用率が高い

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とメモリーには余裕があるので、ディスクの観点で書いている。

項目
OSWindows 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を先に起動するのだけれど、毎回かなり待たされる。

成果をサクサク出す人は、こういうときに、どちらを選択するのだろうか。

  • 成果物を作るまでの我慢だから、毎日待たされたとしても放っておいて、成果物を作る。
  • 毎日やることだから、待たされる問題を解消してから、本格的に成果物を作る。

待たされる時間、問題を解消することによって得られる効果、成果物の規模のバランスではある。

自分は前者から後者への切り替えのハードルが物凄く低くて、すぐに脇道にそれてしまう。そして、その脇道もちゃんと調べると結構時間が掛かったりして。
長い目で見ればその方が良いと思ったりするけれど、実際はどうなんだろう。それぞれのやり方だし、まぁいいか。

広告

コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他