The Amazon Builder's Libraryを読む:『デプロイ時におけるロールバックの安全性の確保』

kdnakt.hatenablog.comThe Amazon Builder's Libraryオンライン輪読会の担当記事の発表資料を作るに当たって、読んだ内容をまとめておく。

 

今回の担当記事はこちら。

aws.amazon.com

 

 

[期待/予想する内容]

 この記事の目次は次のとおりである。

  • スタンドアロンソフトウェアと分散型ソフトウェアのデプロイの比較
  • プロトコルの変更による問題
  • 2 フェーズデプロイ技術
  • 2 フェーズデプロイの注意事項
  • シリアル化のベストプラクティス
  • 変更をロールバックしても問題がないことを確認する
  • まとめ

 

ここから、記事の本文を読む前に、目次から想定する内容を書き出してみる。

 

スタンドアロンはPCとかにインストールして使う、ビジネスロジック(=ユーザーにとっての価値を生むコード)がユーザーの手元にあるもの。CDやネットワークを通じて手動で、あるいはエージェントソフトウェアを介して自動的にデプロイ(=バージョンアップ)がされる。

分散型はいわゆるSaaS的な、ネットワーク越しに提供されるもの、ビジネスロジックがユーザーの手元にないもの。デプロイはユーザーが気づかないうちに行われることが多い(はず、停止する場合もなくはない)。

デプロイの行われる場所の違い、それに起因する難しさの話だろうか。

スタンドアロンはユーザーごとの環境(OS、ネットワークetc)の違いを吸収しないといけない、元のバージョンすらユーザーによって異なる場合もあるかもしれない。

分散型はデプロイ先の環境をOpsチームなどが管理するので、環境の差異はスタンドアロンと比べると少ないが、それ以外の問題がある(トイル、オンコールなど)とか?

 

デプロイのプロトコルってなんだろう。やり方、くらいの広い意味か?

変更したらいろいろ問題はありそうだけど、読まないとわからなそう。

 

  • 2 フェーズデプロイ技術

2フェーズってのはいわゆるBlue/Greenデプロイ、とかImmutableデプロイって呼ばれてるやつだろうか。あとカナリアリリース。

 

  • 2 フェーズデプロイの注意事項

注意事項……一時的に倍のコストがかかる、とか?技術的にちょっと難易度が上がるとか?

 

  • シリアル化のベストプラクティス

シリアル化ってここではどういう意味だろう?パラレルの対義語としてのシリアルっていうよりは、多分データを特定の形式に変換するっていうような意味の方か。

ロールバックとシリアル化……バックアップをとっておくことをシリアル化といっている?データを書き換える前にバックアップ=シリアル化しておけば、バージョンアップ時に書き換えたデータも元に戻せるよ、的な……違うか

 

これはバージョンアップ作業前のテスト段階で確認しようね、ってことかな。ある程度は、実践してるけどどうだろう。

 

[記事の要約]

次に、実際に記事を読んだ内容を箇条書きでまとめる。

 

前文

  • Amazonのソリューション選択指針:元に戻しにくい、拡張しにくい選択肢は選ばない
  • デプロイ:ソフトウェアのバージョンの変更。アップグレードでもダウングレードでも、始まると適切に動作しない=お客様の信頼を失う可能性
  • では、どうやったらデプロイがエラーにつながらないか
  • リリース前にテスト環境で機能、同時性、パフォーマンス、拡張性、ダウンストリームでの障害処理などをテスト、修正
  • しかし、予期せぬ障害はあるので、ロールバックで回避したい
  • 後方互換なソフトウェア=エラーなく、機能の中断なくロールバックできる
  • すべてのリビジョンが後方互換であるようにする

 

スタンドアロンソフトウェアと分散型ソフトウェアのデプロイの比較

  • スタンドアロン:1台のデバイス上で1つのプロセスとして実行、2つのバージョンは同時に実行されない
  • 古いバージョンが書き込んだ(シリアル化した)データを新バージョンが読み込む(シリアル化解除)ことができれば、安全にロールバック/ロールフォワードできる
  • 分散型:可用性は高いが、書き込み側と読み込み側のバージョンが異なることもある、エラーにつながる恐れ

 

プロトコルの変更による問題

  • プロトコル:あらかじめ決められた約束事や手順
  • ロールバックできない一般的な原因:プロトコル変更
  • 例1)データの圧縮機能が実装された場合、旧バージョンは解凍できない
  • 例2)ハートビート間隔延長
  • コードやドキュメントだけでは分析しきれない、明確に検証が必要

 

2 フェーズデプロイ技術

  • ロールバック安全性の検証方法の1つ:準備フェーズとアクティブ化フェーズ
  • 例1)XMLデータからJSONデータへの移行
    • 準備:JSONの読み取り機能だけをまずデプロイ(書き込みはXML
    • アクティブ化:JSONの書き込み機能をデプロイ(XMLの読み取りは残す)
  • 例2)ハートビート間隔延長
    • 準備:チェック間隔を10秒に延長(送信間隔は5秒のまま)
    • アクティブ化:送信間隔を10秒に延長

 

2 フェーズデプロイの注意事項

  • 準備フェーズですべてのサーバーに変更が適用されているか明確に確認すべし
  • それぞれのフェーズはロールバックできる、両方同時にロールバックはできない
  • 待機期間(bake period):準備とアクティブ化の間、通常数日間。両方同時にロールバックが必要な事態を避ける

 

シリアル化のベストプラクティス

  • ソフトウェアの進化に伴い、シリアル化ロジックは変わる
    • フィールドの追加
    • 形式の完全な変更
  • 独自のシリアル化は実装しない、JSON/XML/ProtocolBuffersなどのフレームワークが既に解決している問題を避けよう、各種安全機能も利用できる
  • 変更ごとのバージョンをシリアライザに割当て、データと共に保存、メトリクス化してトラブルシューティングに利用できる
  • 制御できないデータ構造のシリアライズを避ける(例:JavaのコレクションとJDKのアップグレード時のバグ、多分以下の記事のような事例)

stackoverflow.com

  • リアライザに不明な属性の存在を許可するよう実装する、古いバージョンで新しいデータをシリアル化しても不明な属性を削除しない 

 

変更をロールバックしても問題がないことを確認する

  • テスト環境をセットアップする時に避けるべきポイント
  • 本番と異なりテスト環境がシングルインスタンス構成(冗長化されていない)なのはよくない、倹約は重要だが品質がより重要
  • デプロイのやり方(AllAtOnce/Rolling)も本番とテストで揃える
  • MS間のデプロイ順序も揃える(バージョンアップ時は読み込みが先、書き込みが後のフェーズでデプロイする、バージョン下げる時は逆順)
  • トラフィックも本番を可能な限り厳密にシミュレート
  • 3段階のテスト
    • 半分だけデプロイしてすべての処理をテスト
    • すべてのサーバーにデプロイしてすべての処理をテスト
    • ロールバックしてすべての処理をテスト

 

まとめ

 

[予想のふりかえり]

ロールパックの話だとタイトルから分かるのに、特に最初のほうはあまりその方向性での予想ができていなかった。タイトルからできるだけ解像度あげて内容を想像できれば、インプットを効率的に進められる気がする。

 

読む前は、プロトコルと言われてパッと具体例が想像できなかったけど、事前にこういうことかな?と予想していたおかげで、差分を比較的スムーズにのみこむことができた。

シリアル化については半分想定が当たっていたが、2フェーズデプロイは事前に考えていたのとは全然違うものだった。とはいえ、これまでの自分の乏しい運用経験を振り返ってみても、そこまでレベルは高くないが2フェーズデプロイと近いことはやっていたので、やはり自分たちのやり方の方向性はこれでよかったのかな、と確認できた。

シリアル化に関連してJavaのバグ/仕様変更の話が興味深かった。ちゃんと実装まで読めていないのでこれはあとで読む。

 

ロールバックのテストについては、かなり具体的に書かれていて参考になった。自分たちがやれていないこともあったので、そこは取り組んでいきたい。

 

 

事前にちゃんと考えられていなかったけど、そもそもこうやってロールバックするとか、2フェーズデプロイで数日の期間を空けるといったプラクティスは、デプロイ対象のコンポーネントやマイクロサービスが適切な単位に小さく分割されていないと難しいと思う。この記事を読んだおかげで、そうした分割の必要性、重要性を再認識できた。

 

[まとめ]