三流エンジニアの落書き帳

さあ、今日も未知という扉を開けてみよう

MySQL Routerをmysqlrouter-exporterで監視する

MySQL Routerはバージョン8.0.17からREST APIをサポートするようになりました。

これにより、ルーターのヘルスチェックなどを行えるようになりました。

またこのREST APIを利用し監視するmysqlrouter-exporterというのも存在していて、それも使ってMySQL Routerの監視してみます。

今回のゴール

  • MySQL Routerを設置する

  • MySQL RouterのREST APIを使うための設定を行う

  • mysqlrouter-exporterを使ってMySQL Routerの監視を行う(主にヘルスチェック)

MySQL Router側作業

MySQL Routerのインストール

環境がCentOS8なのでrpmでサクッとインストールします。

なお、これを書いているときの最新バージョンは8.0.20です。

[root@centos8-instance3:/home/mysql/router/rpm]# rpm -ivh mysql-router-community-8.0.20-1.el8.x86_64.rpm 
Verifying...                          ################################# [100%]
準備しています...              ################################# [100%]
更新中 / インストール中...
   1:mysql-router-community-8.0.20-1.e################################# [100%]
[/usr/lib/tmpfiles.d/mdadm.conf:1] Line references path below legacy directory /var/run/, updating /var/run/mdadm → /run/mdadm; please update the tmpfiles.d/ drop-in file accordingly.
[/usr/lib/tmpfiles.d/mysql.conf:23] Line references path below legacy directory /var/run/, updating /var/run/mysqld → /run/mysqld; please update the tmpfiles.d/ drop-in file accordingly.
[/usr/lib/tmpfiles.d/mysqlrouter.conf:23] Line references path below legacy directory /var/run/, updating /var/run/mysqlrouter → /run/mysqlrouter; please update the tmpfiles.d/ drop-in file accordingly.
[/usr/lib/tmpfiles.d/radvd.conf:1] Line references path below legacy directory /var/run/, updating /var/run/radvd → /run/radvd; please update the tmpfiles.d/ drop-in file accordingly.

[root@centos8-instance3:/home/mysql/router/rpm]# mysqlrouter --version
MySQL Router  Ver 8.0.20 for Linux on x86_64 (MySQL Community - GPL)

bootstrapで設定ファイルを自動生成する

mysqlrouterはbootstrapオプションを使うことでconfファイルを自動生成することができます。

ここではあらかじめMySQL Shellのdba.deploySandboxInstanceを使って3台のサンドボックス環境を立てて、それらでGroup Replicationを構成しています。(port = 5000, 5001, 5002 versoin 8.0.20)

 MySQL  localhost:5000 ssl  JS > c.status()
{
    "clusterName": "myCluster", 
    "defaultReplicaSet": {
        "name": "default", 
        "primary": "127.0.0.1:5000", 
        "ssl": "REQUIRED", 
        "status": "OK", 
        "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.", 
        "topology": {
            "127.0.0.1:5000": {
                "address": "127.0.0.1:5000", 
                "mode": "R/W", 
                "readReplicas": {}, 
                "replicationLag": null, 
                "role": "HA", 
                "status": "ONLINE", 
                "version": "8.0.20"
            }, 
            "127.0.0.1:5001": {
                "address": "127.0.0.1:5001", 
                "mode": "R/O", 
                "readReplicas": {}, 
                "replicationLag": null, 
                "role": "HA", 
                "status": "ONLINE", 
                "version": "8.0.20"
            }, 
            "127.0.0.1:5002": {
                "address": "127.0.0.1:5002", 
                "mode": "R/O", 
                "readReplicas": {}, 
                "replicationLag": null, 
                "role": "HA", 
                "status": "ONLINE", 
                "version": "8.0.20"
            }
        }, 
        "topologyMode": "Single-Primary"
    }, 
    "groupInformationSourceMember": "127.0.0.1:5000"
}

上のクラスターに対してbootstrapしてconfファイルを作成します。

[root@centos8-instance3:/]# mysqlrouter --bootstrap=root@localhost:5000 --user=mysqlrouter
Please enter MySQL password for root: 
# Bootstrapping system MySQL Router instance...

- Creating account(s) (only those that are needed, if any)
- Verifying account (using it to run SQL queries that would be run by Router)
- Storing account in keyring
- Adjusting permissions of generated files
- Creating configuration /etc/mysqlrouter/mysqlrouter.conf

Existing configuration backed up to '/etc/mysqlrouter/mysqlrouter.conf.bak'

Existing dynamic state backed up to '/var/lib/mysqlrouter/state.json.bak'

# MySQL Router configured for the InnoDB Cluster 'myCluster'

After this MySQL Router has been started with the generated configuration

    $ /etc/init.d/mysqlrouter restart
or
    $ systemctl start mysqlrouter
or
    $ mysqlrouter -c /etc/mysqlrouter/mysqlrouter.conf

the cluster 'myCluster' can be reached by connecting to:

## MySQL Classic protocol

- Read/Write Connections: localhost:6446
- Read/Only Connections:  localhost:6447

## MySQL X protocol

- Read/Write Connections: localhost:64460
- Read/Only Connections:  localhost:64470

これで/etc/mysqlrouter/mysqlrouter.confが作られました。

REST API用の設定を追加する

REST APIを利用するためにはmysqlrouter.confに必要な項目を追加してプラグインをインストールさせる必要があります。

なお、利用できるmysqlrouter.confで利用できるプラグインは8.0.20の時点で下記のとおりです。

[root@centos8-instance3:/usr/lib64/mysqlrouter]# ls -1 *so
http_auth_backend.so
http_auth_realm.so
http_server.so
keepalive.so
metadata_cache.so
mysql_protocol.so
rest_api.so
rest_metadata_cache.so
rest_router.so
rest_routing.so
routing.so

bootstrapして作成したmysqlrouter.confに下記を追加していきます。

[http_serer]
port = 8080

[rest_api]

[rest_router]
require_realm=rlm

[rest_routing]
require_realm=rlm

[rest_metadata_cache]
require_realm=rlm

[http_auth_realm:rlm]
backend=be
method=basic
name=My Realm

[http_auth_backend:be]
backend=file
file=/etc/mysqlrouter/auth_user.passwd

http_server自体は8.0.16から導入されていてHTTPリクエストをリッスンするためのプラグインです。

rest_apiは続くrest_routerなどのプラグインをインストールするために前提となるプラグインです。

rest_router, rest_routing, rest_metadata_cacheはそれぞれMySQL Router自身のステータス、(myCluster_rwのような)各ルーターのステータス、ルーターメタデータの情報を取得するために必要なプラグインです。

これらから情報を取得するためには認証が必要となり、追加のオプションが必要です。 MySQL Routerは認証にレルムを使用するため、require_realmというオプションを指定しています。 また後述しますが、認証時に必要なユーザー名とパスワードを作成しておく必要があります。

http_auth_realmは上記オプションで指定したレルムに関する設定です。 コロンの後にはrest_routerセクションなどで指定したレルム名を記述します。 method, nameはそれぞれ認証方式、認証ユーザーに提示されるレルム名です。

http_auth_backendはhttp_auth_realmセクションで指定したバックエンド認証に関する設定です。 コロンの後には指定したバックエンド名を記述します。 backendはバックエンド実装の名前、fileはバックエンドストレージファイルの名前です。

なお、今回は触れませんが8.0.20からバックエンドの実装にmetadata_cacheがサポートされるようになりました。

認証ユーザーの作成

MySQL Rouoterの認証ユーザーを作成します。

これはmysqlrouter_passwdというユーティリティを使って作成します。

[root@centos8-instance3:/etc/mysqlrouter]# mysqlrouter_passwd set auth_user.pwd koreshiki
Please enter password: 

[root@centos8-instance3:/etc/mysqlrouter]# mysqlrouter_passwd list auth_user.pwd 
koreshiki:$5$hMJzs5osm6t63mPS$tuYG5aDwubepfa7BSwmVkJ.2xBG3q3uEJMNgDlimCb2

[root@centos8-instance3:/etc/mysqlrouter]# chown mysqlrouter auth_user.pwd 

setでユーザーの作成、listでファイルに含まれるユーザー一覧を表示することができます。

これで準備が整ったのでmysqlrouterを起動します。

[root@centos8-instance3:/etc/mysqlrouter]# systemctl status mysqlrouter
● mysqlrouter.service - MySQL Router
   Loaded: loaded (/usr/lib/systemd/system/mysqlrouter.service; disabled; vendor preset: disabled)
   Active: active (running) since Sun 2020-05-10 15:26:09 JST; 2s ago
 Main PID: 32502 (main)
    Tasks: 22 (limit: 23970)
   Memory: 10.4M
   CGroup: /system.slice/mysqlrouter.service
           └─32502 /usr/bin/mysqlrouter -c /etc/mysqlrouter/mysqlrouter.conf

 510 15:26:09 centos8-instance3 systemd[1]: Started MySQL Router.
 510 15:26:09 centos8-instance3 mysqlrouter[32502]: logging facility initialized, switching logging to loggers specified in configuration

APIを叩いてみる

MySQL RouterのAPIの準備が整ったので、さっそくAPIを使ってみます。 APIのエンドポイントは/api/20190715/xxxxxのような形式をとります。

この20190715という文字列はバージョン番号を表しており、将来的に変更される可能性があるとのことです。 Release noteは毎回チェックしておいたほうが良いでしょう。

利用可能なパスは次のようなコマンドで取得できます。

[root@centos8-instance3:/etc/mysqlrouter]# curl -s localhost:8080/api/20190715/swagger.json | jq '.paths' | grep -oP '(?<=")/[a-zA-Z\{\}/]+(?=")'
/metadata/{metadataName}/config
/metadata/{metadataName}/status
/metadata
/router/status
/routes/{routeName}/config
/routes/{routeName}/status
/routes/{routeName}/health
/routes/{routeName}/destinations
/routes/{routeName}/connections
/routes/{routeName}/blockedHosts
/routes

swagger.jsonを参照する場合はユーザー認証は必要ありません。

{}で囲まれている箇所は、環境によって変わります。

例えば/metadata/name/status, routes/myCluster_rw/healthという感じになります。 (これらはユーザー認証が必要です。)

[root@centos8-instance3:/etc/mysqlrouter]# curl -s -u koreshiki:koreshiki localhost:8080/api/20190715/metadata/myCluster/status | jq
{
  "refreshFailed": 0,
  "refreshSucceeded": 487,
  "timeLastRefreshSucceeded": "2020-05-10T06:42:33.300133Z",
  "lastRefreshHostname": "127.0.0.1",
  "lastRefreshPort": 5000
}

[root@centos8-instance3:/etc/mysqlrouter]# curl -s -u koreshiki:koreshiki localhost:8080/api/20190715/routes/myCluster_rw/health | jq
{
  "isAlive": true
}

例えば次のようなコマンドですべてのルーターのヘルスチェックを行えます。

for route_name in `curl -s -u koreshiki:koreshiki localhost:8080/api/20190715/routes | jq '.[][][]'`;do
  echo $route_name
  curl  -s -u koreshiki:koreshiki localhost:8080/api/20190715/routes/${route_name//\"/}/health | jq '.[]'
done

実行結果

"myCluster_ro"
true
"myCluster_rw"
true
"myCluster_x_ro"
true
"myCluster_x_rw"
true

特に重要そうなものは /routes/{routeName}/health, /routes/{routeName}/status とかでしょうか。

ルーターのヘルスチェック、コネクション関連の値をとれます。

これで今回の目標の上から2つを達成できました!

mysqlrouter-exporterでMySQL Routerの監視を行う

それでは、最後の目標であるmysqlrouter-exporterによる監視を行ってみましょう。

詳細は下記をご参照ください。

GitHub - rluisr/mysqlrouter_exporter: Prometheus exporter for MySQL Router.

mysqlrouter-exporterのインストール

mysqlrouter-exporterのバイナリは下記リンクから取得できます。

Releases · rluisr/mysqlrouter_exporter · GitHub

これを書いているときには、サポートバージョンに8.0.20は含まれていませんが、問題なく動作している感じがします。

8.0.20では特筆すべき新しい機能は追加されていないのでおそらく問題ないのでしょう。

[root@centos8-instance3:/home/prometheus]# wget https://github.com/rluisr/mysqlrouter_exporter/releases/download/v2.1.0/mysqlrouter_exporter_2.1.0_linux_amd64.tar.gz

[root@centos8-instance3:/home/prometheus]# ll mysqlrouter_exporter_2.1.0_linux_amd64.tar.gz 
-rw-r--r--. 1 root root 3365931  124 19:15 mysqlrouter_exporter_2.1.0_linux_amd64.tar.gz

[root@centos8-instance3:/home/prometheus]# tar xf mysqlrouter_exporter_2.1.0_linux_amd64.tar.gz 

[root@centos8-instance3:/home/prometheus]# ll mysqlrouter_exporter
-rwxr-xr-x. 1 root root 8544256  124 19:15 mysqlrouter_exporter

[root@centos8-instance3:/home/prometheus]# cp -p mysqlrouter_exporter /usr/local/bin/

Unitファイルの作成

mysqlrouter-exporter用のUnitファイルを作成します。

[Unit]
Description=mysqlrouter-exporter
Documentation=https://github.com/rluisr/mysqlrouter-exporter
After=network-online.target

[Service]
Type=simple
Environment="MYSQLROUTER_EXPORTER_URL=http://127.0.0.1:8080"
Environment="MYSQLROUTER_EXPORTER_USER=koreshiki"
Environment="MYSQLROUTER_EXPORTER_PASS=koreshiki"
Environment="MYSQLROUTER_EXPORTER_PORT=49000"
ExecStart=/usr/local/bin/mysqlrouter_exporter

[Install]
WantedBy=multi-user.target

大切なのはServiceセクションの上から3つのEnvironmentです。 mysqlrouter-exporterはこれらの変数を指定していないと起動できません。

MYSQROUTER_EXPORTER_URLには監視対象となるMySQL Routerのアドレスを指定します。

MYSQROUTER_EXPORTER_USERはAPIを叩く認証時のユーザー名(mysqlrouter_passwdで作成したユーザー)を指定します。

MYSQROUTER_EXPORTER_PASSはMYSQROUTER_EXPORTER_USERのパスワードを指定します。

なお、ポートに関してはデフォルトで49152です。 ここでは、MYSQLROUTER_EXPORTER_PORTでポート49000を指定しています。

では、起動しましょう。

[root@centos8-instance3:/home/prometheus]# systemctl start mysqlrouter-exporter

ここではPrometheusサーバはmysqlrouter-exporterがあるサーバとは異なるため、49000番ポートを開けておきます。

[root@centos8-instance3:/home/prometheus]# firewall-cmd --add-port=49000/tcp --zone=public --permanent
success
[root@centos8-instance3:/home/prometheus]# firewall-cmd --reload
success

メトリクスが取れているので大丈夫そうです。

[root@centos8-instance3:/home/prometheus]# curl -s localhost:49000/metrics | head
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
go_gc_duration_seconds{quantile="0.25"} 0
go_gc_duration_seconds{quantile="0.5"} 0
go_gc_duration_seconds{quantile="0.75"} 0
go_gc_duration_seconds{quantile="1"} 0
go_gc_duration_seconds_sum 0
go_gc_duration_seconds_count 0
# HELP go_goroutines Number of goroutines that currently exist.

これでexporterの作業は完了しました。

Prometheus側の作業

mysqlrouter-exporterを追加する

prometheus.ymlに下記を追記します。

  - job_name: 'mysqlrouter-exporter'

    static_configs:
    - targets: ['192.168.0.12:49000']

変更を反映させます。

[root@centos8-prometheus:/prometheus]# killall -SIGHUP prometheus

反映されているかブラウザから確認します。

f:id:koreshiki-nanno:20200510214657p:plain

OKですね。

Grafanaでグラフを作る

最後はGrafanaでグラフを作ってみます。

といってもこだわりすぎると時間がかかってしまうので、必要最小限をサクッと作ります。

f:id:koreshiki-nanno:20200511003505p:plain

どうでしょう。

mysqlrouter_route_healthで各ルーターのヘルスチェック、 mysqlrouter_route_active_connectionsで現在の各ルーターへの接続数、 mysqlrouter_route_total_connectionsで各ルーターのトータルの接続数

などを監視しています。

なお、上記mysqlrouter-exporterのリンクにはよくできたGrafana Dashboardの例もありImportもできるので、参考にしてみてはいかがでしょうか。

終わりに

というわけで、今回はMySQL RouterのREST APIを使ってルーターの状態を監視する方法を見てきました。

また、mysqlrouter-exporterを使ってそれらをGrafanaで監視するところまで行いました。

MySQL RouterはGroup ReplicationやInnoDB Replicaset以外にも使えます。

例えば、複数のSlaveを持つ環境でMySQL Routerを使うことでSlaveへの負荷を分散させることが可能です。

詳しいやり方は下記をご参考ください。

gihyo.jp

MySQL Routerを監視できれば本番環境への導入もやりやすくなるでしょう。

それでは、今回はこの辺で

今回参考にさせていただいたサイト等