HAProxyでMySQL slaveの通信を分散する
初めにだらだらと概要を書く
MySQLの負荷分散として更新系のmaster、参照系のslaveでインスタンスを複数台用意することにします。slaveについては負荷に応じて台数を増減する予定です。
アプリからみてslaveサーバが何台あるか意識しなくてもいいようにHAProxyを用意します。 HAProxyがアプリとMySQLサーバの通信の中継役を行ってくれるので、アプリからは常にHAProxyだけ見えていればOKとなります。 HAProxy側で複数のslaveサーバに接続を分散してくれます。もしslaveサーバのどれかがダウンしてるときはそのサーバには接続を振らないようにもしてくれます。
また、「負荷に備えてslaveを増設したけど暖気が終わるまで接続を振りたくない」という場合に、設定を一時的に変更することでそのサーバに接続を振らないようにもできます。 接続数の重みづけの調整もできるので、じわじわと接続数を増やしていくということもできそうです。
当初MySQLだけでなくRedisの中継も行おうと考えていたのですが、RedisはElastiCache側でうまく分散してくれるようなので、MySQLのSlaveだけに使用することにします。
インストールと設定
インストールはyumですんなり入ります。
またコマンド経由でhaproxyを制御できるようにhaproxyctlを入れます。
こちらはgemでして、$gem install haproxyctl ; rbenv rehash
でインストールします。
設定内容は以下の感じです
/etc/haproxy.cfg
global maxconn 4096 user haproxy group haproxy daemon stats socket /tmp/haproxy level admin quiet nbproc 1 log 127.0.0.1 local0 info defaults log global mode tcp retries 3 option redispatch option tcplog option dontlognull maxconn 4096 timeout connect 10s timeout client 10s timeout server 10s grace 1000 listen mysql-slave bind :3307 mode tcp balance roundrobin option mysql-check user haproxy server slave1 staging-slave-db-1.example.internal:3306 weight 50 check port 3306 inter 5s rise 2 fall 2 server slave2 staging-slave-db-2.example.internal:3306 weight 50 check port 3306 inter 5s rise 2 fall 2 server slave3 staging-slave-db-3.example.internal:3306 weight 50 check port 3306 inter 5s rise 2 fall 2 server slave4 staging-slave-db-4.example.internal:3306 weight 50 check port 3306 inter 5s rise 2 fall 2 server master1 staging-master-db-1.example.internal:3306 check port 3306 inter 5s rise 2 fall 2 backup
MySQLのヘルスチェック
option mysql-check user haproxy
という設定で、HAProxyがhaproxyユーザを使ってMySQLサーバに接続を試みてヘルスチェックを行います。
MySQLサーバ側で、haproxyユーザを作っておく必要があります。
grant usage on *.* to 'haproxy'@'%'; flush privileges;
運用中にやりそうな事
例えば、staging-slave-1を何らかの理由で使用したくないという場合は、sudo haproxyctl disable server mysql-slave/slave1
で使用されなくなります。
復活させたい場合はsudo haproxyctl enable server mysql-slave/slave1
です。
slaveを立ち上げたばかりなので少ない接続数から慣らしていきたいという場合は、他のslaveの重み(weight)より低い数値に変更します。
コマンドとしてはこんな感じです。
sudo haproxyctl set weight mysql-slave/slave1 1
weightの数値は0~256のようで、数が大きいほど接続数も多くなります。
なお、stats socket /tmp/haproxy level admin
としておかないとsetコマンドはpermission deniedで拒否されます。