Chaos Engineering やっていく宣言

技術部のヨシオリです。

Netflix が Chaos Engineering の論文を公開して 2 年ほど経ちました。
クックパッドは最近、 Chaos Engineering を導入する事を決めました。
この記事ではその背景を紹介したいと思います。

そもそも Chaos Engineering とは

Netflix では Failure Injection Testing として、営業時間中に意図的に障害を起す事をやっていました。Chaos Monkey というインスタンスとサービスを落すものから Chaos Gorilla、Kong という availability zone や region 単位で障害を発生させるものなどです。

その経験から Chaos Engineering というものが提唱されました。
Principles of Chaos Engineeringによれば

Chaos Engineering is the discipline of experimenting on a distributed system in order to build confidence in the system’s capability to withstand turbulent conditions in production.

と定義されています。
意訳すると「本番環境の分散システムが過酷な状況でも耐えれるとの確信を得るために、実験するという取り組み」とかでしょうか?

分散システムはマイクロサービスと置きかえるとイメージしやすいと思います。複数のマイクロサービスが相互に呼び出し、協調して動くシステムでは一つのサービスがクラッシュしただけでシステム全体が壊れるような事になっていてはいけません。そうなると、ユーザーに届けられる価値が減ってしまいビジネス的にも問題です。
もちろんそうならないように作るべきですが、それでも予想不可能な事は起こります。それを知るためにコントロールされた障害を投入し、知見を広げたり、確信を得たりするのです。

そのための実験は下記のステップで進めます。

  1. 正常な振る舞いをしているかどうかを測定可能な値として定義する。
  2. この正常な状態が通常時と障害エミュレート時の両方で継続することを仮定する。
  3. サーバクラッシュ、ディスク異常、ネットワークエラーなどの現実世界で起こりえる障害をエミュレートする。
  4. 1で定義した値を通常時と障害エミュレート時で比較し検証していく。

詳しくは上記論文やリンク先を見ていただくとして、凄くザックリと纏めてしまうと、
システムにコントロールされた障害をエミューレートし、それでも壊れない事を検証していく
と、思ってもらえれば良いかと思います。
元々、昔から似たような事をやっているサービスはありましたが Netflix がそこに Chaos Engineering と名前と付け原則などをわかりやすく纏めた感じですね。

必要になった背景

クックパッドでは 2014 年ころからマイクロサービスに取り組んで来ました。

そして個々の Web アプリケーションはコンテナ技術で仮想化し、コンテナオーケストレーションツールとして ECS を使い運用しています。

また、サービス間の通信に関してもサービスメッシュの導入などを行なっています。

その結果、今ではチーム数も増加し、開発規模も大きくなっています。結果として( 管理画面を提供するサービスなどを除いても) 大小 80 個近くのサービスがそれぞれお互いに緩くではありますが連携し動いています(僕も数を調べてビックリしました)。

さすがにこれだけのサービスが連携して動いているとどこかで発生した障害がどこまで影響するのか把握するのは容易ではありません。
A というモバイルアプリが叩いている B という API の裏で通信している C が必要としているデータ取得のための D のレスポンス時間が遅くなって、結果として A の応答が悪くなったのだが、原因が D だとは思っていなかった……的な事も発生します。

何故やるのか

上記ブログのマイクロサービス導入背景にもありますが、昔のようにひとつの巨大なアプリケーションを運用するようなスタイルではプロダクト開発の規模の拡大やスピードに限界があり、マイクロサービスアーキテクチャを採用するようになりました。分散システムとして Web サービスを実装する事により単一の複雑なアプリケーションからは開放されましたが個々のサービス間の連携は複雑になりました。

Chaos Engineering の導入によってサービスの耐障害性に自信を持てるようにします。日常的に障害をエミュレートする事によってサービスの耐障害性が高いことを開発者に要求します。
ソフトウェアテストなどの文脈では良く言われますが、不具合は発見が遅れれば遅れるほど、その不具合を修正するコストはかさむことになります。
可用性の高いシステムを作るために、不具合を早く発見し改善していくために Chaos Engineering を導入していきます。

付随して考えている事

人は自分が想像出来るものにしか対処出来ません。バグというのは大体が想定外の入力によって発生します。そこでもっと想像力を働かせろ的な精神論を言っていても良くはなりません。Chaos Engineering のように実際にそういった状況を作る事が大事だと思っています。
例えばクックパッドでは各サービスがどんどん AWS の Spot インスタンスで動くように移行していっています。これはサーバはいつ落ちても良いようにしておかなくてはいけないし、バックグラウンドジョブは落ちたら再実行出来るようにしておかなくてはいけない事を開発者に強制します。
でも、それらは実は Spot インスタンスで動くからやらなければいけないものではありません。耐障害性の高いシステムを作るためにはやらなければいけない事を Spot インスタンスの環境にする事によって強制するようになっただけです。
さきほども書いたように人は自分が想像出来るものにしか対処出来ません。Chad Fowler が Immutable Infrastructure を提唱したけれども、開発者がそれを真に実行出来るようになったのは Docker という環境のおかげというのと同じです。

最後に

現在、クックパッドでは Hako や ECS を使ったコンテナ環境の整備が進み、サービスメッシュの導入によりサービス間の通信を集中管理出来るようになりました。これにより、Envoy proxy を利用してサービス間通信で障害をエミュレートしたり、それらの設定を hako で行えるようになったりと環境は整いました。
まだまだクックパッドのマイクロサービス群の正常な状態( steady-state )をどう定義していくかなどやらなければいけない事は色々あります。
個人的にはこの規模のマイクロサービス群を扱っていく環境は国内ではそんなに多くはなく大変面白い環境だと思ってます。
クックパッドでは一緒に Chaos Engineering を導入していく仲間を募集しています
このエントリを読んでご興味をお持ちいただけた方は、ぜひともご応募ください。

スマートまな板による料理支援

研究開発部アルバイトの佐藤です。今日はアルバイト期間中に取り組んでいたまな板にレシピを表示する装置について紹介します。

背景

レシピ本をキッチンに持ち込む以外にも、キッチンでスマホ上から検索することによってレシピを見る機会が増えています。しかし、キッチン内でタブレット端末やスマホでレシピを見る問題点として以下が挙げられます。

  • デバイスが水や油で汚れず、レシピが見やすい位置に置きたいが、スペースの都合上難しい
  • 汚れた手で端末の画面を料理中に触って操作しなくてはならない

また、最近ではAmazon EchoやGoogle HomeなどのスマートスピーカーでCookpadのレシピを検索し、タブレット端末やスマホでレシピを保存することができます。その発展として、レシピの読み上げやEcho Showなどの端末を用いたレシピ表示なども考えられますが、端末と同様に映像などの表示位置が固定されてしまうという問題が挙げられます。また、音声での入力の他にジェスチャなどもとりいれることができればより視覚的な操作も可能ではないかと考えられます。

このような問題に対して取り組んでいるプロジェクトはいくつかあります。例として2つのプロジェクトを紹介します。

こちらのプロジェクトではユーザーの動作やキッチン台の上のものを認識して、端末に現在の動作に合わせた作業内容を表示します。切り方の動画の再生なども端末上で行っていますが、再生するには端末を操作する必要があります。また、この装置では切っている食材を認識するためにまな板自身にセンサなどを取り付ける必要があります。

こちらの論文ではカメラ・プロジェクタ・対話ロボットを連携させた調理支援システムが提案されていますが、対話ロボット1台、カメラ2台、プロジェクタ3台とかなり大掛かりなシステムとなっています。

スマートまな板

f:id:sss3p:20180720111838p:plain

そこで図のように天井に装置を設置することによりキッチン用品には非接触のスマートまな板を開発しました。このまな板の特徴はまな板には何も手を加えないことです(つまり、正確にはスマートまな板でなく、レシピプロジェクターです)。具体的には次のことを目標に開発しました。

  • プロジェクターでレシピや操作画面をまな板に投影し、視線の移動の少ない情報提供
  • 作業台の上に装置を置かないことによる広い作業スペースの提供
  • webカメラとRaspberry Piによる画像処理で人の手を検知し、画面に触らない操作

今回の対象者

以下のような問題に困っている料理初心者を対象ユーザとしました。

  • にんじん、たまねぎ、じゃがいもの剥き方・切り方がわからない
  • だしのとり方がわからない
  • ケーキをどのようにデコレーションすれば良いかわからない

今回実装した機能

上記の様な料理初心者に対して、にんじん、たまねぎ、じゃがいも、だしが材料にすべて入っている肉じゃがの調理とケーキのデコレーションを支援するような機能を実装しました。 料理初心者への支援としてまな板に映像の投影を行い、次のようなものを視覚的に提供しました。

  • にんじん、たまねぎ、じゃがいもの剥き方・切り方の手順動画:文字だけでは中々習得の難しい包丁の具体的な使い方を、まな板の左上に動画を流すことで視覚的に伝える
  • 材料と調味料のチェックボックス:何が準備できていて次に何を準備すべきか判断しやすいようにする
  • 手順表示:一文ずつ手順を表示していく。また、時間が手順に書いてあった場合はタイマーを起動する
  • デコレーションケーキの下書き:デコレーションケーキの下書きを投影し、デコレーションの位置ガイドとして使えるようにする

実装方法

webカメラ・小型プロジェクター・Raspberry Piを用いて実装を行いました。 開発言語はPython3、使用ライブラリはtkinter、opencv2です。 詳細は以下のようになっています。

使用物名 型名など
webカメラ Logicool HD720p
小型プロジェクター iOCHOW iO4 ミニ プロジェクター
Raspberry Pi Raspberry Pi 3, raspbian gnu/linux 9
Python3 Python 3.5.3
tkinter version 8.6
opencv2 version 3.4.1

手の認識

簡易的なデモ機の実装としてカラートラッキングを用いました。具体的には手の肌色をトラッキングすることで手の位置を捉えて、画面操作ができるように実装しました。

デモ

デモ中の写真をいくつか紹介します。

  • スタート画面 f:id:sss3p:20180720111936j:plain
  • メニュー選択 f:id:sss3p:20180720112025j:plain f:id:sss3p:20180720112045j:plain
  • 材料一覧表示 f:id:sss3p:20180720112117j:plain
  • 手順表示 f:id:sss3p:20180720112244j:plain

気づき

実装したスマートまな板では視線の移動の少ない情報提供、広い作業スペースの提供、画面に触らない操作を実現することができました。 実際に実装してみて気づいたことは以下です。

  • 視線の移動の少ない情報提供:
    • 切り方動画をまな板の左上に表示することによって、動画を確認しながら作業することができた
    • 作業によってはまな板に投影するよりもキッチンの壁に投影したほうが良い場合もある(まな板に投影したほうが良い場合は食材を切るときの動画での切り方確認で、キッチンの壁に投影したほうが良い場合はレシピ表示とタイマー)
  • 広い作業スペースの提供:
    • スマホやタブレット端末を作業台の上に置く必要がないため、広い作業スペースを確保できた
  • 画面に触らない操作:
    • 今までレシピを確認するために画面操作する度に手を拭いたり洗ったりしていたことがなくなった

デモ

実際にスマートまな板を数人に体験していただきました。体験後、頂いた意見をいくつか紹介します。

  • 材料チェックリストがまな板の上で操作できるのは便利
  • まな板の上で切り方動画を見られるのは面白い
  • 実用化するんだったら、スマートスピーカーと組み合わせて提供する情報や選択肢によって音声か映像か使い分けたほうがよさそう

また、いくつかの改善点や追加機能がみつかりました。

  • ユーザーの動作によって投影位置を変える機能(ユーザーの作業している場所を検知して、作業の邪魔にならないようなスペースへ画面を移動・縮小させる)
  • まな板の上に置かれた材料を認識したレシピ検索
  • まな板の上に置かれた材料の重さを概算し、レシピで指定されている重さによって切り方を投影する機能
  • 自動でデコレーションの下書きを拡大縮小したり移動したりしてケーキに下書きを合わせてくれる機能

現在の実装では以下の問題が発生しています。

  • 肌色の位置を手の位置と認識しているため、色の似ている木のまな板などを誤認識
  • 指先や指を認識していないため手首などを誤認識するなど認識精度が低い そのため、手の認識専用デバイスを利用しない場合はニューラルネットワークを用いて手を手としてラベル付したり、手の形を認識するなどの実装に変更することが考えられます。 また、Leap Motionなどの外部デバイスを用いて手の認識を行うということも考えられます。

まとめ

キッチンでレシピを確認するときに、視線の移動の少ない情報提供、広い作業スペースの提供、画面に触らない操作を実現できるスマートまな板の開発に取り組みました。

実際に実装することによって、提案の有用性や改善点を見つけることができました。

今後の展開としてはスマートまな板を用いたアプリの開発などが考えられます。具体的には切り方動画をまな板で再生できることや材料・手順のまな板への投影を用いて、子供・初心者向け料理学習アプリなどを実装することにより、より料理初心者への支援ができると考えられます。

新規決済手段導入に際し、なるべく丁寧にテストケースを作成した話

会員事業部の日高尚美(@natan3)です。 半年前になりますが、クックパッドでは Android ユーザ向けにプレミアムサービスの決済手段の一つとして Google Play 決済を導入しました。

ユーザに新たな機能を提供する前には、何らかの形で開発者側での検証が必要です。

Google Play 決済導入バージョンのリリースは、ユーザのお金を扱うこともあり、不具合が起きた際にサービス全体の信用に関わる、非常にリスクの高いリリースでした。 それに伴い、検証もできる限り万全に行わなければなりません。

そのため、なるべく丁寧にテストケースを作成し、それをもとに検証を実施することで新機能が期待通りに実装されていることを担保しました。 丁寧にテストケースを作成したから、というだけではもちろんありませんが、リリースから半年経った今でも Google Play 決済周りの目立った不具合はまだ見つかっておりません。

今回作成したテストケースの紹介

今回作成したテストケースの一部をご紹介します。 実際に利用したものと表現を変えてはいますが、雰囲気は伝わるかなと思います。

f:id:nano-041214:20180718194510p:plain

含まれている項目は以下のとおりです。

  • 各画面で起こりうる状況の組み合わせ(上図で言うところの前提条件)
  • 前提条件を再現するシナリオ
  • シナリオを達成するための手順
  • 手順に対応した期待する振る舞い
  • 期待する振る舞いが得られたかどうかのチェック欄

これを元に動作を確認しました。

それぞれのケースにて、想定した通りの画面が表示されていれば問題ありません。 しかし、実装によっては、期待する振る舞いが得られない場合も出てきます。

テストケースにて期待する振る舞いが本来あるべき姿なので、その場合には実装に手を入れる必要があります。 すべての操作に対して期待する振る舞いが得られる状態にすることが、テストケース作成の目的であり、検証のゴールとなります。

Google Play 決済のテストケース作成までの流れ

なにもないところからいきなりテストケースを作成することは難しいため、 画面遷移図とそれらの分岐条件、各 API の返す異常系一覧をもとに、テストケースを作成しました。

テストケースを作成する流れは以下のようになります。

  1. 各画面で起こりうる状況を整理する
  2. 前提条件を再現するシナリオを作成する
  3. そのシナリオをなぞるための手順を埋める
  4. その手順を行うことで期待されるアプリの振る舞いを埋める

以降の文章で、各項目について解説します。

各画面で起こりうる状況を整理する

テストケースにおいて重要なのは 網羅性 です。

そのため、画面遷移図の各分岐である API 接続箇所や画面遷移時にて起こりうるユーザ状態など、前提条件を構成する各状況を洗い出します。

実際の遷移図ではありませんが以降の理解のために Google Play 決済導入時の画面遷移のイメージ図を添えておきます。

f:id:nano-041214:20180718194451j:plain

Google Play 決済導入プロジェクト初期リリースではクックパッドにログイン済みの無料ユーザのみを対象としていたため *1、 各分岐において以下のような状況の組み合わせを、検証すべき条件として考えました。

  • ユーザの状態がどうか
    • ログイン済みユーザ or ゲストユーザ
    • プレミアムサービス会員ユーザ or 無料ユーザ
  • Android のクックパッドアプリのバージョンが決済対応バージョン以降かどうか
  • 決済可能端末かどうか
    • クックパッドがプリインストールされているらくらくフォンなどの場合、Google Play ストアアプリがないため Google Play 決済も利用できない
  • 異常な操作をした場合でも、何らかの方法で本来あるべき状態に復帰可能かどうか
    • この画面を表示している状態で Web からクックパッドのユーザ登録を解除してみる
    • この画面を表示している状態で Web からクレジットカード決済でプレミアムサービスになってみる
    • ここでフライトモードにしてみる

もちろん全ての組み合わせが成立するわけではありません。 例えば決済可能端末かどうかについては、決済不可能端末を伝える画面にて遷移がストップするため、以降の画面については考えない、といった具合です。

前提条件を再現するシナリオを作成する

それぞれの状況が洗い出せると、それらを組み合わせることでユーザが何をしようとしたかのシナリオが書き出せます。

状況の羅列にはなりますが、シナリオを作成しておくことで見通しが良くなり、仕様の考慮漏れについて気づきやすくなります。

例えば、

「ログイン済みユーザが Google Play 決済用画面を開いた状態で Web からクレジットカード決済でプレミアムサービスになった場合、
 Google Play で決済するボタンを押すと既に課金済みであることを示すダイアログが表示される」

といったものです。

そのシナリオをなぞるための手順を埋める

シナリオまで埋め終わると安心してしまいがちですが、書き手以外が再現可能なレベルで手順を埋めるまでがテストケース作成です。

テストケースは、一度作成すると、製作者本人が望もうが望まなかろうが再利用される可能性が高いです。 現にクックパッドでは、作成されたテストケースは今後のテストケース作成の参考にできるよう、社内で共有されています。

コードや文章に限らず、テストケースも、書いた本人ですら暫く経つと書いた内容やなぜこう書いたかを忘れがちです。 テストケースが雑に書かれていた場合には、この記述が当時何のために書かれていたのかを考古学する必要が出てきます。

そのため、なるべく丁寧に書きましょう。

先程の

「ログイン済みユーザが Google Play 決済用画面を開いた状態で Web からクレジットカード決済でプレミアムサービスになった場合、
 Google Play で決済するボタンを押すと既に課金済みであることを示すダイアログが表示される」

というシナリオの例に対しての手順を具体的に書くと、

  1. 無料ユーザでログインした状態でアプリのトップページを開く
  2. サイドメニューのプレミアムサービス会員登録導線をタップする
  3. Google Play 決済を利用するボタンを押す
  4. ブラウザアプリを起動し Web からクックパッドのトップページにアクセスする
  5. Web から先ほどと同一のユーザでログインする
  6. Web のトップページのプレミアムサービス会員登録導線を開く
  7. Web の登録ページからクレジットカード決済を利用してプレミアムサービスに登録する
  8. アプリの画面に戻り、プレミアムサービスに Google Play で決済するボタンを押す

といったものになります。

その手順を行うことで期待されるアプリの振る舞いを埋める

こちらも先程の手順同様、丁寧に書く必要があります。

先程の手順の例に対応するアプリの振る舞いとしては以下のようになります。

  1. 無料ユーザ向けのトップページが表示される
  2. プレミアムサービスを訴求する画面が表示される
  3. Google Play 決済用の画面が表示される
  4. Web 版のクックパッドのゲスト向けページが表示される
  5. 先ほどと同一ユーザでログインしたトップページが表示される
  6. Web のプレミアムサービスを訴求する画面が表示される
  7. プレミアムサービス登録完了ページが表示される
  8. 既にプレミアムサービス登録済みであることを伝えるダイアログが表示される

異常系であれば、どのような操作をすれば正常系に復帰できるかを伝える画面が出ていることを期待します。 そのため、ある操作の流れで何らかの異常を伝える画面を見たユーザが、その内容を読んだ際に混乱しないかについても確認ができます。

テストケースを作成して得られた良い副作用

テストケースを作成して得られる一番の良い副作用は、仕様の考慮漏れに気づけることです。

テストケース作成前は、Google Play ストアによる決済用システムダイアログが出ているときにブラウザアプリから別な決済手段にてプレミアムサービスを登録したらどうなるのか? というケースについて考えられていませんでした。

Google Play ストアの決済用システムダイアログが出てから決済処理完了までは、クックパッドではその経過状況を知ることが不可能です。 そのため、残念ながら決済完了時に Google Play の購読情報をクックパッドに送る際に二重課金が起きていることを伝えることになります。 幸いにも既に別で考慮していたケースと同様にユーザに重複課金を伝え、問い合わせを促す画面を表示できるような実装になっておりました。

また、テストケースを作成することで、検証の手順の理解や進捗が属人化しなくなるため検証を分担したりダブルチェックしたりできます。

加えて、きちんとやったから大丈夫、という安心感がえられます。

もちろんリリースして運用に入るまで何が起こるかはわからないですが、 最大限やることはやった!という安心感を持ってリリースできるので精神衛生上良いです。

テストケース作成期間について

テストケース作成に着手してから、検証し、修正完了するまでに 1ヶ月ほどかかりました。 開発期間全体のおよそ 1/3 もかかってしまった理由は、テストケース作成と並行して API 実装を始めとした他の作業などもやっていたためです。

しかし、効率的な開発を目指す上で、必ずしもテストケース作成期間を短くする必要はないと考えています。

というのも、仕様を煮詰めながらテストケースも整理していくことで、結果的に考慮漏れによる実装の手戻りを減らすことができるからです。 仕様を煮詰めている段階でテストケースも同時に作成していくことは、回り回って効率的に開発を進めることができると感じました。

最後に

検証を怠ることは、ユーザに検証をさせることと同義です。

もちろんすべてのケースを想定したテストケースを作成するのは不可能です。 しかし、ユーザにサービスを提供する以上、リリースまでに最善をつくすことに価値があると考えております。

テストケースは技術部品質向上グループチーム(以下 QIT: Quality Improvement Team)と密に協力して作成しました。 QIT はクックパッドのアプリを利用したユーザが技術的な問題で残念な思いをする体験を減らすための専門家集団です。

このように、クックパッドでは新機能リリースプロジェクトのために様々な分野のエンジニアが一丸となって取り組みます。

そのため、クックパッドではアプリケーションの品質向上に興味のあるエンジニアや、企画から、実装、テストケース作成までを一貫して行うエンジニアリングに興味のあるエンジニアを募集中です。 興味がある方は採用ページまで!

*1:現在はクックパッドに会員登録、もしくはログインしていないユーザでも Google Play 決済を利用してプレミアムサービスを利用できます