kasei_sanのブログ

かせいさんのIT系のおぼえがきです。胡乱の方はnoteとtwitterへ

MHA for MySQLのデフォルトのヘルスチェックでは、DBの書き込み障害ではフェイルオーバーしないよというお話

先に結論

MHA for MySQLのデフォルトのヘルスチェックでは、DBの書き込み障害ではフェイルオーバーしない

なんで?

  • MHAはヘルスチェックをバラメータ ping_type で設定された方法で行う
  • ping_type のデフォルトは SELECT
  • ping_type : SELECT の場合、ヘルスチェックは SELECT 1 As Value で行うので、書き込み障害には気づけない

どうすればよいの?

ping_type : INSERT の場合の注意事項

感想

書き込み障害が発生したのに、フェイルオーバーが行われず、めちゃくちゃ焦った

ツールが想定通りの挙動をしなかった場合、公式ドキュメントとコードをじっくり読もう

SRE本読書メモ エラーバシェットの話しを読んで、明確な数値目標は意思決定コストを下げると思った

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

なぜ数値目標を決めるのが大事か?

明確な数値目標は、意思決定コストを下げる

数値を決めることで意思決定コストが下がる例

  • エラーバシェット

エラーバシェットとは?

チーム内で合意が取れた、一定期間内に許容できる予定外のシステムダウン時間の合計

なぜエラーバシェットがあるのか

機能追加と信頼性向上どちらに注力するか悩むことが無くなる

  • エラーバシェットに余裕がある間は、機能追加にリソースを割く
  • 逆に、いまのままだとエラーバシェットが無くなりそうならば、信頼性向上にリソースを割く

信頼性向上の施策の優先順位に悩むことが無くなる

たとえば、ある障害のリカバリに掛かる時間が、どれだけエラーバシェットにインパクトを与えるか? で判断できるようになる

  • エラーバシェットが15分なのに、リカバリに30分掛かるならば、それは必ず自動化すべきと判断できる

過剰な信頼性向上をしなくなる

  • SLA 100%は実現不可能
  • 一定以上信頼性を上げるのには、指数関数的に開発コストが上昇する

感想

  • スプリント計画時にエラーバシェットをチェックすると、次やるべきことが明確になりそう

SRE本読書メモ 15章: ポストモーテム文化。非難のない振り返りが改善を生む

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

非難のない振り返り

googleでは、インシデントから学びを得るために ポストモーテム (検死) と呼ばれる振り返りを行う文化がある

なんで非難しない振り返りが重要なの?

  • 非難は人が変わることを強要することだが、人は人を変えることはとても難しい
  • 人を変えることは出来ないが、その人が正しい判断をすることを助ける仕組みを作ることはできる
  • 非難を避けようと、インシデントや問題を隠蔽するようになる

ヘスルスケアや航空業界など、些細なミスが大事故に繋がる業界で生まれた文化

ポストモーテムの意義

  • 再発の可能性を削減するための効果的な予防策が確実に導入されること
  • 記録することで、他のチームもそれを参照して、問題を予防できるようになる

ポストモーテムのゴール

ポストモーテムのゴールは事前にチームメンバーに共有されていることがだいじ

  • 後々の分析のために必要なデータは収集されていること
  • サービスへの影響(インパクト)の分析が完全に行われていること
  • 根本原因がしっかり分析されていること
  • アクションプランの内容と優先度は適切であること
  • 結果をステークホルダーに共有できていること

ゴールの条件を満たしているか、かならず上級エンジニアからのレビューを受けること

ポストモーテムのテンプレ

* 作成日:
* 作者:
* ステータス: (現在のステータスを書く
* サマリ: (概要を書く
* 根本原因:  (発生要因に書かれた現象が発生した根本的な原因を書く
* 発生要因: (例: トラフィック突然の増加で表面化した潜在的なバグ
* 対応: 
* 検出: (なにを検出した事でインシデントに気づいたか?
* アクションアイテム: (改善、再発防止の為に取る/取ったアクションの一覧

# 教訓
## うまくいったこと
## うまくいかなかったこと
## 幸運だったこと

# タイムライン

(発生から改善までの時系列を書く

# 参考情報

感想

  • 「人を変えることは出来ないが、その人が正しい判断をすることを助ける仕組みを作ることはできる」だいじ
  • 他チームへの共有を意識したポストモーテムだいじ

[SRE本読書メモ] 13章: 障害対応。ストレスの無い障害対応が少ないダウンタイムを生み出す

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

言いたいこと

障害対応時のストレスを減らすことで、(人を含めたシステムの)信頼度を上げることができる

なので、ストレスを減らす施策を積極的に打ちましょう

なんでストレスの無い障害対応がだいじなの?

  • ストレスホルモンが生じると、人間は、認知機能が下がり、直感・反射で動くようになる
  • 障害対応は、実測→仮説→検証の繰り返しなので、感や経験で動いても良い結果を生み出さない
  • そのため、理性的な障害対応を行えるようにするためには、担当者にいかにストレスを生じさせないかがキモになる

どうすれば、ストレスを感じずに障害対応ができるようになるの?

以下のようなことを予め準備/共有することで、担当者の負担感を下げ、心理的安全性が確保できる

  • 明確なインシデント管理の手順
  • インシデント発生時の役割分担
  • 振り返りでは避難されないことを明示(後述

インシデント発生時の役割分担

役割分担を明確にすることで、メンバーの負担感を下げ、それぞれが正しい目的に注力できるようになる

  • 責任者: 他メンバーへの責任の割当、作業効率の障害を取り除く、ライブインシデント対応ドキュメントの作成
  • 実行担当: インシデントに直接対応するメンバー
  • コミュニケーション: 公の顔。チームとステークホルダーに状況を共有し続ける役割
  • 計画: 長期的な課題を扱う。引き継ぎの調整、夕食の発注、最終的に通常の状態に戻す準備など

ストレスを減らすために個人的にできること

  • 「障害が発生したからといって世界が終わるわけではない」ということを意識する
  • 自分の感情に注意を払う。パニックや圧倒されているという感覚が生じたら、メンバーに支援を求める

感想など

  • 障害対応のストレスから人間の認知機能の話が出たのが興味深かった
  • 振り返りときに対応者が「どこにストレスを感じたか?」を記録すると、仕組みの改善の余地が見えそう
  • 自分も障害対応時には、視点が狭くなったり、ステークホルダーとの共有がおろそかになる。それを減らすためなに、役割の分担を次回の障害対応時にやってみたい

RubyでGCしても直ちにRSSが減るわけではないというお話

先に結論

  • GCをしても、RSSが直ちに減るわけではない
  • C言語のレイヤーで、free しても次の malloc に割り当てるためにメモリを手放さない実装があるのが原因らしい

計測してみた

適当な長さのStringを10000回作って、RSSと、ObjectSpace.memsize_of_all を計測する

require 'objspace'

puts ",ObjectSpace.memsize_of_all,RSS"
1.upto(10000) do |i|
  a = "10"*10000
  a += '123'
  rss = `ps -o rss= -p #{Process.pid}`.to_i * 0.001
  memsize_of_all = ObjectSpace.memsize_of_all * 0.001 * 0.001
  puts "#{i},#{rss},#{memsize_of_all}"
end

結果

以下のグラフの通り

memsize_of_all は数ループに1回GCされているが、実際にプロセスがメモリを手放すタイミングはもっとゆっくりしている

f:id:kasei_san:20180517221213p:plain

単位はMB

なんでGCしても、RSSはすぐに減らないの?

stackoverflowだけれど納得感のある解説を見つけた

Cレベルの話をすると、free を呼んでもOSにメモリを返さず、次に malloc した際に再割当するような実装も多く存在します。 ということで、一般的にはメモリの解放によっても占有メモリが減らない前提でプログラミングすることになろうかと思います。

2018/05/18 追記

会社のひとから、上記のコメントは Conservative GC と混同しているのではないか? とご意見頂いた

参考リンク

スレーブのレプリケーションが遅延している時に SHOW SLAVE STATUS でチェックするべき値

前提知識

MySQLのスレーブでは、以下の2つのスレッドを使って、レプリケーションを行っている

  • I/Oスレッド : マスタからバイナリログの差分を取得する
  • SQLスレッド : IOスレッドから取得したバイナリログを元にDBを更新する

SHOW SLAVE STATUS で見るべき値

そもそも起動しているか

  • Slave_IO_Running : IOスレッドの動作有無 Yes なら起動中
  • Slave_SQL_Running : SQLスレッドの動作有無 Yes なら起動中

IOスレッド-SQLスレッド間が遅延しているか

Seconds_Behind_Master を見る

  • Relay_Master_Log_File : SQLスレッドが最後に実行したバイナリログのファイル名
  • Exec_Master_Log_Pos : SQLスレッドが最後に実行したバイナリログのファイル名
  • Seconds_Behind_Master : SQLスレッドとIOスレッドの差異

Seconds_Behind_Master が増えている場合、IOスレッドが渡すバイナリログをSQLスレッドが消化しきれていない

Seconds_Behind_Master が 0 なのに、スレーブが遅延している場合は、マスタ-IOスレッド間の遅延が疑われる

マスタ-IOスレッド間が遅延しているか

以下の値について、マスタの SHOW MASTER STATUS での File, Position と差異を確認する

  • Master_Log_File : IOスレッドが現在最新だと認識しているバイナリログのファイル名
  • Read_Master_Log_Pos : IOスレッドが現在最新だと認識しているバイナリログのポジション

大きく差異がある場合、マスタの変更にIOスレッドが追いつけていない

遅延している場合どうしたら良いの?

MySQLのバイナリログについて解説

バイナリログとは

マスタのDBの 更新命令のみ を記録したログファイル

マスタ/スレーブ間の同期(レプリケーション)で使用する

  • my.cnflog-bin オプションを設定すると、バイナリログが作成されるようになる

バイナリログの保存形式

STATEMENT, ROW, MIXED の3種類がある。binlog-format オプションで設定可能。デフォルトは、STATMENT

  • STATEMENT : SQL文をそのまま保持

    • メリット: サイズが小さい
    • デメリット: 非決定的な命令(後述) が発生すると、マスタ/スレーブ間で差異が生じる
  • ROW : DBの行をどのように更新したか? という情報を保持

    • メリット: 非決定的な命令が発生しても同期を維持できる
    • デメリット: サイズが大きい。大量に更新があるとHDDや帯域を圧迫する
  • MIXED: 非決定的な命令のみ ROW形式で保持

    • メリット: ROW形式のバイナリログより小さいサイズで、非決定的な命令が発生しても同期を維持できる
    • デメリット: STATEMENT形式のバイナリログよりはサイズが大きい 

非決定的な命令とは

ORDER BY が指定されていない INSERT」や UUID()など、結果が固定されていない命令を指す

マスタのバイナリログのステータス確認方法

SHOW MASTER STATUS で確認可能

mysql> SHOW MASTER STATUS\G
*************************** 1. row ***************************
             File: master-bin.000002
         Position: 1307
     Binlog_Do_DB: test
 Binlog_Ignore_DB: manual, mysql
Executed_Gtid_Set: 3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5
1 row in set (0.00 sec)
  • File : 現在のバイナリログの格納先
  • Position: バイナリログの座標(ポジション)
  • Binlog_Do_DB : レプリケーション対象のDB
  • Binlog_Ignore_DB : レプリケーション対象外のDB
  • Executed_Gtid_Set : GTIDの値(今回は解説しない)

参考