MaxScaleをDatabase Proxyとしてデプロイ:MySQLの参照・更新(Read/Write)を自動分離

MySQL tutorial - IT technology blog
MySQL tutorial - IT technology blog

クイックスタート:Dockerを使って5分でMaxScaleを試す

効果をすぐに確認するために、Docker Composeを使用します。この方法では、1台のMaster、1台 celestial Slave、そして1台のMaxScaleからなるテスト環境を素早く構築し、Read/Write Splitting(参照・更新分離)機能をテストできます。

以下の内容でdocker-compose.ymlファイルを作成します:

version: '3.8'
services:
  mysql-master:
    image: mariadb:10.6
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: testdb
    ports:
      - "3306:3306"

  mysql-slave:
    image: mariadb:10.6
    environment:
      MYSQL_ROOT_PASSWORD: root_password
    depends_on:
      - mysql-master

  maxscale:
    image: mariadb/maxscale:latest
    volumes:
      - ./maxscale.cnf:/etc/maxscale.cnf
    ports:
      - "6033:6033" # アプリケーション接続用ポート
      - "8989:8989" # ダッシュボードGUI
    depends_on:
      - mysql-master
      - mysql-slave

docker-compose up -dコマンドでシステムを起動します。これで、データベースの前面にインテリジェントなプロキシが配置されました。ポート6033に送信されるすべてのクエリは、MaxScaleによって適切なノードへ自動的にルーティングされます。

なぜProxySQLではなくMaxScaleを選ぶのか?

データベースクラスターの管理において、「アプリケーション側でどのIPがMaster(書き込み用)で、どのIPがSlave(読み取り用)かを意識したくない」という課題がよくあります。

MaxScaleはMariaDBチームによるその解決策です。ProxySQLと同じ目的を持ちますが、MaxScaleは.cnfファイルによる明快な設定が可能で、複雑なSQLiteインターフェースを介した操作が不要な点がメリットです。

実際に私が運用した50GBのデータを持つEコマースプロジェクトでは、Read/Writeを分離することでMasterの負荷を最大70%削減できました。重いレポート用のSELECTクエリを処理する代わりに、Masterはトランザクション処理のみに集中できるようになります。すべての読み取り負荷はSlaveに分散されます。

MySQLシステム向けMaxScaleの詳細設定

まず最初に、MySQL Masterでユーザーを作成します。このユーザーは、MaxScaleが各ノードのヘルスステータスを監視(モニタリング)するために使用されます。

-- MySQL Masterでこのコマンドを実行
CREATE USER 'maxuser'@'%' IDENTIFIED BY 'password123';
GRANT SELECT ON mysql.user TO 'maxuser'@'%';
GRANT SELECT ON mysql.db TO 'maxuser'@'%';
GRANT SELECT ON mysql.tables_priv TO 'maxuser'@'%';
GRANT SHOW DATABASES ON *.* TO 'maxuser'@'%';
GRANT REPLICATION CLIENT ON *.* TO 'maxuser'@'%';
FLUSH PRIVILEGES;

次に、ルーティングの「頭脳」を有効にするためにmaxscale.cnfファイルを構成します:

[maxscale]
threads=auto

# 1. データベースノードの定義
[server1]
type=server
address=mysql-master
port=3306
protocol=MariaDBBackend

[server2]
type=server
address=mysql-slave
port=3306
protocol=MariaDBBackend

# 2. モニター:2秒ごとにノードの状態を確認
[MariaDB-Monitor]
type=monitor
module=mariadbmon
servers=server1,server2
user=maxuser
password=password123
monitor_interval=2s

# 3. サービス:参照・更新(Read/Write)の自動分離
[Read-Write-Service]
type=service
router=readwritesplit
servers=server1,server2
user=maxuser
password=password123

# 4. リスナー:アプリからの受付ポート
[Read-Write-Listener]
type=listener
service=Read-Write-Service
protocol=MariaDBClient
port=6033

内部動作の仕組み:

  • Monitor: ノードを継続的にチェックします。Masterに障害が発生した場合、MaxScaleはそれを検知し、データを保護するために書き込みフローを遮断します。
  • Router (readwritesplit): SQL構文をリアルタイムで解析します。INSERT/UPDATE/DELETEコマンドはMasterへ、SELECTは優先的にSlaveへ送信されます。
  • Listener: 単一のエンドポイント(Endpoint)を提供します。アプリ側はポート6033を指す接続文字列(Connection String)を1つ用意するだけです。

同期遅延(Slave Lag)への根本的な対策

最も頭を悩ませるのは、MasterにデータをINSERTした直後にSlaveでSELECTしても, 同期遅延のためにデータが反映されていないという問題です。

MaxScaleは、[Read-Write-Service]内のパラメータでこの問題を非常にスマートに解決します:

[Read-Write-Service]
type=service
router=readwritesplit
max_slave_replication_lag=5
...

max_slave_replication_lag=5を設定すると、Slaveの遅延が5秒を超えた場合、MaxScaleは自動的に読み取りクエリをMasterへ送り返します。これにより、システムが同期負荷で遅延している時でも、ユーザーは常に最新のデータを確認できます。

運用における実戦的なアドバイス

プロキシを導入した多くのプロジェクトを経て、3つの重要な注意点をまとめました:

  1. ダッシュボードのセキュリティ: Webインターフェース(ポート 8989)のデフォルト設定はadmin/mariadbです。すぐにパスワードを変更するか、ファイアウォールでインターネットからのアクセスを遮断してください。
  2. Masterでのクエリ実行を強制する: ウォレットの残高確認など、精度の高いデータが必要な処理では、SQLヒント(/* maxscale route to master */ SELECT ...)を使用して100%正確なデータを取得してください。
  3. デバッグログの活用: クエリが意図しない方向にルーティングされている場合は、log_debug=1を有効にしてください。MaxScaleがなぜそのノードを選択したのか、ログファイルに詳細な理由が出力されます。

MaxScaleを導入することで、システムの負荷耐性が向上し、開発者は手動の接続管理から解放されます。設定過程で困ったことがあれば、お気軽に下のコメント欄で質問してください!

Share: