Webアプリケーション、特にRuby等のパフォーマンスチューニングをしているときに、glibc mallocではなくjemallocを使用するとレスポンスが良くなる、という体験をしたことがある方も多いのではないでしょうか。
今回はDockerのMySQLでjemallocを使用する方法について紹介していきたいと思います。
検証環境
今回はDockerで建てたMySQLを使用します。ベースイメージとして8.
% docker run --platform linux/x86_64 -p 127.0.0.1:3307:3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw -e MYSQL_USER=kk2170 -e MYSQL_PASSWORD=my-secret-pw -d mysql:8.4.5
mysqlクライアントでアクセスが可能であることを確認しましょう。方法は以下の通りになります。
% mysql -uroot -pmy-secret-pw -h127.0.0.1 -P3307
執筆時点では、以下の通りMySQL 8.
mysql> select version(); +-----------+ | version() | +-----------+ | 8.4.5 | +-----------+ 1 row in set (0.00 sec)
jemallocとは?
jemalloc
もともとはFreeBSD向けに開発されましたが、現在ではLinuxやmacOS、Windowsなど幅広い環境で利用可能です。特徴としては、スレッドごとにメモリ領域
jemallocを使うと本当に速くなるのか?
では、MySQLにjemallocを組み込んだとして、実際にどのような効果が期待できるのでしょうか? 結論から言うと、
たとえば、複数のWebアプリケーションが同時にMySQLにアクセスするような状況や、バッチ系処理が並列に走るようなケースでは、glibcの標準mallocではロック競合による待ち時間が発生しがちです。jemallocは、スレッドごとに独立したメモリアリーナを持つ仕組みを採用しており、このようなロック競合を大幅に減らすことができます。
また、長期間稼働したサーバではメモリの断片化もパフォーマンスの低下要因になりますが、jemallocは断片化耐性が高く、ヒープの安定性を保ちやすいという特徴もあります。
…と頭では考えてみますが、実際にパフォーマンスチューニングする際には
次では、Docker環境でjemallocを有効にしたMySQLコンテナを立ち上げる方法について解説していきます。
DockerのMySQLでjemallocを有効にする
MySQLにjemallocを組み込んだ場合の効果を確認するには、まず手軽に試せる環境が欲しいところです。そんなときに便利なのがDockerを使った検証環境です。ここでは、Docker上でjemallocを有効にしたMySQLコンテナを立ち上げる手順を紹介します。
Dockerfileを作成する
MySQL の公式イメージにはjemallocは含まれていないため、jemallocをLD_
で読み込ませます。
以下のようなDockerfileを用意します。
FROM mysql:8.4
USER root
# epelを登録してjemallocをインストールする
RUN microdnf install epel-release && microdnf install -y jemalloc
ENV LD_PRELOAD=/usr/lib64/libjemalloc.so.2
USER mysql
これを起動してみましょう。まずはイメージをビルドします。
docker build -t mysql-jemalloc .
その後、以下のように指定を行い起動しましょう。
docker run -d \ --name mysql-jemalloc \ -e MYSQL_ROOT_PASSWORD=example \ -e MYSQL_DATABASE=testdb \ -p 3308:3306 \ mysql-jemalloc
起動したコンテナ内でjemallocが読み込まれているか確認してみましょう。確認にはlddコマンドが使用できます。lddはプログラムがどの共有ライブラリを使用しているかを調べるためのコマンドです。出力は長いのでgrepを使ってjemallocで引っ掛けてみましょう。
bash-5.1# ldd /usr/sbin/mysqld | grep jemalloc /usr/lib64/libjemalloc.so.2 (0x00007fbb4bd12000)
上記のようになっていればjemallocを使用しています。
また、Docker内部に入って簡単なクエリを実行して、動作しているかも確認してみましょう。
mysql> mysql> select version(); +-----------+ | version() | +-----------+ | 8.4.5 | +-----------+ 1 row in set (0.00 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0.11 sec)
簡単なクエリであれば、動いていることがわかります。
まとめ
思ったよりも簡単に試してみることができたので、拍子抜けした方もいたかもしれません。jemallocはMySQLの標準構成では使用されていないものの、高負荷な環境やメモリ断片化の影響を受けやすいシステムにおいて、効果を発揮する可能性がある選択肢です。
とはいえ、jemallocを導入することは標準的ではないため、安易な適用はおすすめできません。本番環境で利用する前には、この記事のようにDocker などで十分に検証を行い、どのようなメリットとデメリットがあるのかを見極めることが重要だと思います。
ただし、MySQLにおいてもjemallocを使用する選択肢があることを知っておくだけでも、将来のパフォーマンスチューニングの引き出しが増えるはずです。
興味がある方は、まずは開発環境からぜひ試してみてください。