Upload
sugawara-genki
View
6.798
Download
0
Embed Size (px)
Citation preview
MAH on AWS+Rails2014/7/11 MySQL Casual Talks vol.6
クックパッド株式会社 菅原 元気
お前誰よ
菅原 元気
@sgwr_dts / http://so-wh.at/● Ruby / AWS● https://bitbucket.org/winebarrel● https://github.com/winebarrel● 白金台の方から来ました
最近のアクティビティ
便利スキーマ管理ツールを作りました
https://github.com/winebarrel/ridgepole
最近のアクティビティ
数日後に同僚がもっと高性能なやつを
作りましたが…
サマリ
● 弊社のMHA設定とかについて● RailsアプリにMHAを導入した話
弊社のMHAまわり
弊社のMHAまわり
弊社のMHAまわり
● 基本的にMySQL on EC2● VPC Route Tableによる仮想IP● Rails 3.2 / 4.x
弊社のMHAまわり
● フェイルオーバーまわりのツールは自作○ Route Tableの書き換えなど
● master_ip_failoverなどはPerlからポート+ VPCまわりの処理を追加
● サンプルプロジェクト:https://bitbucket.org/winebarrel/mha-example-for-aws (業務用とは若干異なります)
弊社のMHAまわり
● ManagerはUpstartでデーモン化● 複数のクラスタを監視● 冗長化はしてません
弊社のMHAまわり
● /etc/masterha_default.cnf○ サービスで共通な設定を記述○ ユーザ・ポート○ スクリプトのパス○ etc...
弊社のMHAまわり
● /usr/local/masterha/conf/service1.cnf, service2.cnf…○ サービス毎の設定○ 作業ディレクトリの設定○ セカンダリチェックの設定○ ホスト名○ etc...
弊社のMHAまわり
● /etc/sysconfig/mha.yaml○ 自作のmaster_ip_failover, master_ip_online_change
で使う情報を集約○ AWS APIのキー○ アラートメールの送信先○ サービス毎の仮想IP○ インスタンスID○ etc...
弊社のMHAまわり
ノードサーバのPuppetclass { 'mha4mysql_node': virtual_ip => $vip_xxx }
● rpmのインストール● Source/Dest Checkの無効化● loへのIPの追加● ネットワーク設定ファイルの更新● etc...
弊社のMHAまわり
マスターサーバのPuppet$mha_apps = { service1 => { hostname => 'service1-db-001', virtual_ip_address => $vip_serviec1_ipaddr, app_user => "'wriable_user'@'192.168.%'", slaves => ['service1-db-002', 'service1-db-002', 'service1-db-003'], autostart => true, }, ...
弊社のMHAまわり
● MHA用設定ファイルの作成● Upstartの各種設定● etc...
弊社のMHAまわり
MHA用のMySQLアカウント
GRANT RELOAD, PROCESS, SUPER ON *.* TO 'hoge'@'...' GRANT ALL PRIVILEGES ON `mysql`.* TO 'hoge'@'...'
導入に至るまで
導入にあたって
● 検証環境を作ってテストしました
導入にあたって
● 検証環境を作ってテストしました● 仮想IPは切り替わりました
導入にあたって
● 検証環境を作ってテストしました● 仮想IPは切り替わりました● スレーブも付け替わりました
500 Internal Server Error
500 Internal Server Error
(当たり前ですが)
Railsでエラーが出ます
Automatic Reconnectionhttp://dev.mysql.com/doc/refman/5.5/en/auto-reconnect.html
● 「reconnect: true」で自動再接続が有効に● サーバが死んでも再接続してくれる
Automatic Reconnection
● 再試行は一回だけ● 「Access denied for user…」のような
エラーでは再接続しない
activerecord-mysql-reconnect
再接続のためのライブラリを作りましたhttps://bitbucket.org/winebarrel/activerecord-mysql-reconnect
activerecord-mysql-reconnect
MyApp::Application.configure do
... config.active_record.enable_retry = true config.active_record.execution_tries = 10 config.active_record.execution_retry_wait = 1.5 config.active_record.retry_mode = :rw
...
ene
activerecord-mysql-reconnect
activerecord-mysql-reconnectStarted GET "/items" for 127.0.0.1 at 2014-07-10 13:18:08 +0000Processing by ItemsController#index as */* Rendered items/index.html.erb within layouts/application (0.3ms)Completed 200 OK in 3.2ms (Views: 1.8ms | ActiveRecord: 0.6ms)Started GET "/items" for 127.0.0.1 at 2014-07-10 13:18:08 +0000MySQL server has gone away. Trying to reconnect in 1.5 seconds. (cause: Access denied for user 'scott'@'dagon' (using password: YES) [Mysql2::Error], connection: host=192.168.100.100;database=hello;username=scott)Started GET "/items" for 127.0.0.1 at 2014-07-10 13:18:08 +0000MySQL server has gone away. Trying to reconnect in 1.5 seconds. (cause: Access denied for user 'scott'@'dagon' (using password: YES) [Mysql2::Error], connection: host=192.168.100.100;database=hello;username=scott)MySQL server has gone away. Trying to reconnect in 3.0 seconds. (cause: Access denied for user 'scott'@'dagon' (using password: YES) [Mysql2::Error], connection: host=192.168.100.100;database=hello;username=scott)MySQL server has gone away. Trying to reconnect in 3.0 seconds. (cause: Access denied for user 'scott'@'dagon' (using password: YES) [Mysql2::Error], connection: host=192.168.100.100;database=hello;username=scott)Processing by ItemsController#index as */* Rendered items/index.html.erb within layouts/application (0.4ms)Completed 200 OK in 3.5ms (Views: 1.9ms | ActiveRecord: 0.9ms)
activerecord-mysql-reconnect
実装
● フェイルオーバー時にエラーの出る下位レイヤのメソッドをフック
● エラーメッセージに応じて再試行○ 元の例外を取得できないもので、、、
参考) Rals 3.2 ActiveRecord:StatementInvalidhttps://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/errors.rb#L58
セッションを切って大丈夫か?
クエリ以外のセッションに依存している
メソッドはない?
セッションを切って大丈夫か?
last_idActiveRecord→ mysql2→ libmysql/libmysql.c
my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql){ return mysql->insert_id;}
セッションを切って大丈夫か?
affected_rowsActiveRecord→ mysql2→ libmysql/libmysql.c
my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql){ return mysql->affected_rows;}
セッションを切って大丈夫か?
quote_string / escapeActiveRecord→ mysql2→ libmysql/libmysql.c→ mysys/charset.c#escape_quotes_for_mysql→ mysys/charset.c#escape_string_for_mysql
(どちらも状態を持たない処理)
セッションを切って大丈夫か?
まあ大丈夫じゃないかな…
再接続モード
● :r (読み込み)○ SELECT / SHOW / SET をリトライ
● :rw(読み書き)
○ 「Lost connection to server during query」以外の
クエリをリトライ
● :force(全部)○ すべてのSQLをリトライします
Lost connection to server during queryhttp://dev.mysql.com/doc/refman/5.5/en/gone-away.html
CR_SERVER_LOSTThe client didn't get an error when writing to the server, but it didn't get a full answer (or any answer) to the question.
Lost connection to server during query
検証環境で発生しない…
Lost connection to server during query
mysql2をいじる…● mysql_send_queryと
mysql_read_query_resultの間にsleepを入れる● クライアントからクエリを投げる● sleepの間にMySQLを再帰起動● sleepの間にMySQLをkill● エラーにならない…
Lost connection to server during query
今のところはうまく動いてます…
その後
● いろいろと検証して本番投入● とあるサービスでオンライン切り替え● エラーなし!
Demo