クックパッド開発者ブログスマートフォン用の表示で見るクックパッド開発者ブログ2019-03-05マイクロサービス化を支える継続的切り替え術こんにちはこんにちは。技術部のクックパッドサービス基盤グループのシム(@shia)です。グループ名が大きいですね。呼びます——があります。クックパッドサービス基盤グループはこのレシピサービスの運用及び改善という責務を持つグループとして今年の2月に発足しました。わかりやすい業務の一つとしてはお台場プロジェクトが挙げられます。〜お台場プロジェクト1年半の軌跡〜という素晴らしい記事があるので紹介は省きます。フィーチャーフォン向けのサービスである「モバれぴ」を分離するという作業をしています。このサービスはコードベースが大きいので、どうやって元のコードベースから新しい方に切り替えて行くのかが非常に大事です。この記事では現在進行形である、モバれぴの切り替え戦略に関して紹介してみようと思います。始める前にこの記事でのサービス分離作業は巨大な一つのコードベースから、他に対する依存が少ない、もしくは関係のない機能・サービスなどをマイクロサービスとして分離することを意味します。方法を用いるを前提にしてお話していきます。コードベースの切り替え戦略を考えるコードベース切り替えには大きく2つの戦略があります。いわゆるビックバンデプロイと小分けにして継続的にデプロイしていく、というものですね。モバれぴは完全に作り直すことにしたため、まずビックバンデプロイは無理だと判断しました。仕様が同じとはいえ実装詳細が変わる以上、必ずなにかの問題が起こります。ロールバックが繰り返される状況になり作業は進まなくなるし、リリースのたびにユーザーに迷惑をかけることになります。あれば取れる戦略としては後者のみですね。1つのマイクロサービスとして切り出す(分離する)作業を行いました。利用し、新しいコードベースへ流すエンドポイントを指定できるようにし、これを増やしていくという方法を取りました。利用する切り替え戦略この図では赤い矢印が切り替え完了したエンドポイントに対するリクエストで、青い矢印が切り替えが終わってないエンドポイントに対するリクエストです。そこでリクエストのパスを見て切り出し元にリクエストを流すか、切り出し先のサーバに流すかを決めるわけですね。/v1/recipes)の実装を終えて、本番に投入したい状況になったとしましょう。リクエストを流せばいいわけです。利用した切り替え戦略の問題すでにお気付きの方もいると思いますが、この方法はインフラ環境を頻繁にいじる必要があるという問題があります。本番環境のインフラをいじるだけで障害が発生するリスクが生じます。特定のエンドポイントを切り替えるのにインフラ側とアプリ側のオペレーションが両方発生すること自体が不便です。20回しないといけません。気が遠くなる面倒さです。いうことで手抜きをし始めると、1回に1個以上のエンドポイントを切り替えるようになるわけですが、これはビックバンデプロイに近づく結果になります。言い換えると、ロールバックの確率が高くなるとも言えるでしょう。今考えるとエンドポイントの数が多くなかったとはいえ、よく頑張ったな〜という気持ちになります。前回はインフラの作業コストとコピペに近い移植方式を考慮した結果、コントローラー単位で切り替えるようにしていました。経由で取得するというポリシーにしたため、作業コストが跳ね上がっていました。結果、いちいち移行していたらインフラ作業コストも跳ね上がるはずなので、いつまで経っても作業が進まなくなるのは明らかでした。前回、料理きろくの分離作業から得た教訓は切り替えでインフラオペレーションを使いたくないロールバックが簡単にできるようにしたい1アクション単位で切り替えたいというものでした。切り替え作業コストを最小限に減らしたい。要求することで解決できます。実際どんな感じにリクエストが処理されるのか図を見てみましょう。赤い矢印が切り替え完了したエンドポイントに対するリクエストで、青い矢印が切り替えが終わってないエンドポイントに対するリクエストです。ステータスコードを受け取ったら切り出し元へリトライするだけです。どのリクエストを旧コードベースに流すか決めるのは切り出し先なので、こっちのコードを変更するだけで切り替え作業を完了します。設定を利用すれば実装が可能です。具体的な実装方法の前にこれらの機能に関して説明します。対して簡単に説明をしたいと思います。幾つかのサーバ群を一つのグループとして定義することができ、その内部でよしなにロードバランシングを行うことができます。グループとして定義した各サーバに対してどういうロードバランシング戦略をとるか、ラウンドロビンならどれくらいの重みでリクエストを流していくかなど、それなりに細かい設定を行うことができます。ここにはサーバの状態の扱いも含まれています。内部で定義されたサーバの状態は2つ存在します。リクエストを受けられる状態(available)、リクエストを処理できない状態(unavailable)ですね。