Elastic Load BalancerでMySQLサーバーを冗長化しようとするとエラーが出る

mixiアプリamazon EC2上の仮想サーバーで公開しようと目論んでいるのですが上記のところでハマりました。日本語で対策法を書いたサイトが見当たらなかったので、原因と対策法をまとめておきました!

DBサーバーの構成

・マスターサーバー1台
・スレーブサーバー2台
レプリケーション
OS/ubuntu 9.10
MySQL/5.1.37を使用
という状態で、AWSのElastic Load Balancerにスレーブサーバー2台を紐付けしてみたもののデータベースサーバーに接続出来ず。試しにマスター側サーバーから、スレーブ側に接続しようとすると下記のようなエラーメッセージが表示されました。

エラー内容

Host 'hostname' is blocked because of many connection errors. 
Unblock with 'mysqladmin flush-hosts' 

スレーブのサーバーに接続エラーが大量発生されたためにブロックしてるよー、とのこと。このエラーメッセージにある通りに

Slave# mysqladmin -p flush-hosts" 

を実行してみると、接続できるように!!なりましたが、10分くらいするとやはり同じエラーがでて接続エラーに。

原因

同じような症状が出ている人がいないか調べたところAWSのフォーラムで全く同じ症状に悩んでいる人が!
http://developer.amazonwebservices.com/connect/thread.jspa?messageID=131707𠉻
さらにリンク先には、amazonスタッフの返信もありました。一部を丸ごと引用させて頂くと

It seems as if the application being load balanced (MySQL, in this case) may have some behavior which is being triggered by the default ELB health check: The CreateLoadBalancer API will set up a default health check of type "TCP", which simply attempts to open a TCP connection to the registered instance at regular intervals.

If that is the case, you would seem to have two options:
1) Reconfigure the health check (using ConfigureHealthCheck) to something that is not interpreted as an error by your application.
2) Reconfigure your application not to interpret the ELB health check probes as errors.
You can read more about the types of ELB health checks, and the default settings, here:

どうやら、ELB側で行っているHealthCheck(インスタンスが正常に動作してるかどうかのチェック)がMySQLサーバーに接続しようとしてエラーが生じている模様。解決するためには、HealthCheck側の設定を見直すか、サーバー側の設定をいじってHealthCheckをエラーと認識させないように変更するかどっちかだよー!とのことです。

対策

HealthCheckの設定(コンソールから確認可能)をチェックしてみたところ、確かに
Ping Target:TCP:3306
となっている。これがエラーの原因だったみたいです。今回は、HealthCheckの設定の方をいじってエラーを修正することにします。そもそも、HealthCheckがMySQLに接続しない限りエラーは生じないんだからポート80経由でHealthCheckすればいいのでは!?ということで、MySQLのポートではなく80番ポートのhtmlファイルにping打つように変更してみます。CUIで設定を行う場合は以下をコピペ、コンソールで変更する場合は、HealthCheck欄の一番下に表示されているEdit Health Checkをクリックして同様の設定を行えばOKです。

elb-configure-healthcheck  ロードバランサーの名前  --headers --target "HTTP:80/index.html" --interval 30 --timeout 3 --unhealthy-threshold 5 --healthy-threshold 3

ただし、そもそも80番ポートを通すよう様にロードバランサーを作っていない場合はエラーになるので注意です。コンソールでロードバランサーのDescription→Port Configurationに80番ポートが表示されていない場合は、以下の様にロードバランサー自体作り直す必要があります。コンソールから作る場合はロードバランサー作成時の一番最初の画面に表示されるListener Configurationの項目に80番ポートと3306番ポートの両方を追加すればOKです。(作成後にコレを修正する方法、探したけど見つかりませんでした><)

elb-create-lb ロードバランサーの名前 --availability-zones us-east-1a --listener "protocol=TCP, lb-port=3306, instance-port=3306" --listener "protocol=http,lb-port=80,instance-port=80"

設定が終わったら、サーバー側でapacheを起動しておくのとpingの対象となるhtmlを設置しておくのをお忘れ無く。上記の通り設定変更した後に動作確認したところ、エラーなく無事動作していました!