はじめに
ユーザベースではSpeedaをはじめとするサービスを通して多くのデータを提供しており、それらを裏で支える多くのデータベースが存在しています。
パブリッククラウドのデータベースサービスを利用しているものも数多くありますが、開発環境の一部ではVM環境上で1つのサーバに複数のMySQLサーバを起動しているマニアック(?)な構成のものもあります。今回はその構成について説明したいと思います。
'docker' or 'systemd'
複数のMySQLインスタンスを同じサーバに立ち上げる手段として真っ先に思い浮かぶのはdockerという人も多いと思います。新規で何もないところから構築する場合はdockerが最適解とも思いますが、今回は既存からの移行性や必要ないサービスはなるべく起動したくないという観点からsystemdを使用して複数のインスタンスを起動することにしました。
複数のMySQLサーバの起動
古くからMySQLに携わっている方はmysqld_multiという仕組みがあったのを記憶されている方もいるかと思いますが、MySQL 5.7以降ではsystemdの機能を利用して複数のMySQLサーバを起動することができます。設定は非常に簡単で、my.cnfの内容を以下のように記載することで複数インスタンスを起動することができます。
注意点は当然のことですが、portや各種ディレクトリもしくはファイル名をinstance毎に分けるということが最低限必要です。
# 全てのインスタンスで共通の設定
[mysqld]
あれやこれや(省略)
# instance個別の設定
# instance1
[mysqld@instance1]
port = 13306
datadir=/mysql_data/instance1
socket=/mysql_data/instance1/mysql.sock
pid_file=/mysql_data/instance1/mysql.pid
log_error=/mysql_data/instance1/mysql-error.log
tmpdir=/mysql_data/instance1/tmp
log-bin=/mysql_binlog/instance1/mysql-bin
# instance2
[mysqld@instance2]
port = 23306
datadir=/mysql_data/instance2
socket=/mysql_data/instance2/mysql.sock
pid_file=/mysql_data/instance2/mysql.pid
log_error=/mysql_data/instance2/mysql-error.log
tmpdir=/mysql_data/instance2/tmp
log-bin=/mysql_binlog/instance2/mysql-bin
# instance3
[mysqld@instance3]
port = 33306
datadir=/mysql_data/instance3
socket=/mysql_data/instance3/mysql.sock
pid_file=/mysql_data/instance3/mysql.pid
log_error=/mysql_data/instance3/mysql-error.log
tmpdir=/mysql_data/instance3/tmp
log-bin=/mysql_binlog/instance3/mysql-bin
# 起動・停止
sudo systemctl [start|stop] mysqld@instance[1|2|3]
mysqld_exporterによる複数インスタンスのMySQLサーバ監視
MySQLサーバを複数インスタンス起動すること自体は公式ドキュメント通りにmy.cnfの記述を対応するだけなので簡単にできますが、これらをmysqld_exporterで監視するときは少し工夫が必要になります。
複数インスタンスを監視する2つの方法
mysqld_exporterには複数のMySQLインスタンスを監視する機能が備わっています。ただしこの設定を利用するためには、複数インスタンスの情報を出力するmysqld_exporterに対応したprometheus側の設定が必要になります。今回はprometheusの設定は既存の設定を活かして対象ノードの追加のみで済ませたかったため、mysqld_exporterをMySQLサーバのインスタンスに合わせて複数インスタンス起動するアプローチを取ることにしました。
mysqld_exporterを複数インスタンス起動する方法
mysqld_exporterにはMySQLサーバのように複数インスタンスを起動する機能はデフォルトでは備わっていないため、systemdのテンプレートユニット機能を使用して複数インスタンスを起動します。systemdのテンプレートユニットとは、systemdのserviceファイルを/etc/systemd/system/mysqld_exporter@.serviceのような形式にすることにより、service起動時に引数を渡せるようにする機能です。
mysqld_exporter@.serviceファイルを以下のように記述した場合、systemctl start mysqld_exporter@13306とコマンドを実行すると、%iに13306が引数として渡され、引数のportをLISTENするMySQLサーバを監視することができます。なお、mysqld_exporter@.service内で指定されているmy_%i.cnfファイルは事前に作成し、対応するMySQLサーバの接続情報等を記述しておく必要があります。
-
mysqld_exporter@.serviceファイル
[Unit]
Description=Prometheus MySQL Exporter on port %i
[Service]
Type=simple
User=prometheus
ExecStart=/usr/local/bin/mysqld_exporter \
--config.my-cnf=/etc/mysqld_exporter/my_%i.cnf \
--web.listen-address=:%i
[Install]
WantedBy=multi-user.target
-
my_instance1.cnfファイル
[client]
user=mysqld_exporter
password=PASSWORD
socket=/mysql_data/instance1/mysql.sock
引数にport番号ではなくinstance名を指定したい場合はもう少し工夫が必要になります。systemdにはベースのユニットファイル /etc/systemd/system/mysqld_exporter@.serviceを上書きするdrop-in機能があります。今回の場合、 /etc/systemd/system/mysqld_exporter@instance1.service.d/override.confファイルを作成して以下のような内容を記述することにより、systemctl start mysqld_exporter@instance1コマンドを実行する際にベースのユニットファイルの内容をoverride.confの内容で上書きしてmysqld_exporterが起動されます。
[Service]
# 一度クリアする
ExecStart=
# instance固有の情報を再定義
ExecStart=/usr/local/bin/mysqld_exporter \
--config.my-cnf=/etc/mysqld_exporter/my_instance1.cnf \
--web.listen-address=:9104 <= mysqld_exporterのlisten portはinstance毎に別のportを指定
さいごに
本番ではこのような構成を採用することはないと思いますが、開発環境で色々試したいときには使える構成かと思いますので、興味のある方はぜひお試しください。
参考
Managing MySQL Server with systemd
https://dev.mysql.com/doc/refman/8.4/en/using-systemd.html
mysqld_exporter
https://github.com/prometheus/mysqld_exporter
systemd.unit (5)
https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html