
⏰ 🔥 ネットワークとシステムの状態をシミュレートしてカオスおよびレジリエンシーテストを行うためのTCPプロキシ
Toxiproxyはネットワーク条件をシミュレートするためのフレームワークです。テスト、CI、開発環境で動作するように特別に設計されており、接続に対する決定論的な改ざんをサポートしつつ、ランダムなカオスやカスタマイズもサポートしています。Toxiproxyは、あなたのアプリケーションに単一障害点がないことをテストで証明するために必要なツールです。 私たちは2014年10月からShopifyのすべての開発環境とテスト環境でこれを成功的に使用しています。詳細については、レジリエンスに関する[ブログ記事][blog]をご覧ください。
Toxiproxyの使用は2つの部分で構成されています。Goで書かれたTCPプロキシ(このリポジトリに含まれるもの)と、HTTP経由でプロキシと通信するクライアントです。アプリケーションを設定してすべてのテスト接続がToxiproxyを経由するようにし、その後HTTP経由でそれらの健全性を操作できます。プロジェクトのセットアップ方法については、以下の使用方法を参照してください。
例えば、RubyクライアントからMySQLのレスポンスに1000msのレイテンシを追加するには:
Toxiproxy[:mysql_master].downstream(:latency, latency: 1000).apply do
Shop.first # this takes at least 1s
end
すべての Redis インスタンスを停止するには:
Toxiproxy[/redis/].down do
Shop.first # this will throw an exception
end
この README の例は現在 Ruby で書かれていますが、他の言語でクライアントを作成することを妨げるものは何もありません(クライアントを参照)。
私たちが見つけた既存のものは、統合テストやユニットテストに必要な動的な API を提供していませんでした。nc などの Linux ツールはクロスプラットフォームではなく、root 権限を必要とするため、テスト、開発、CI 環境で問題を引き起こします。
Rails アプリケーションを使った例を見ていきましょう。Toxiproxy は Ruby に一切依存していないことに注意してください。単に私たちの最初のユースケースだっただけです。完全な例は sirupsen/toxiproxy-rails-example で確認できます。 すぐに始めたい場合は、使用方法まで読み進めてください。
私たちの人気ブログでは、なぜか投稿のタグを Redis に、投稿自体を MySQL に保存しています。Redis セット内のタグを操作するメソッドを含む Post クラスがあるかもしれません:
class Post < ActiveRecord::Base
# Return an Array of all the tags.
def tags
TagRedis.smembers(tag_key)
end
# Add a tag to the post.
def add_tag(tag)
TagRedis.sadd(tag_key, tag)
end
# Remove a tag from the post.
def remove_tag(tag)
TagRedis.srem(tag_key, tag)
end
# Return the key in Redis for the set of tags for the post.
def tag_key
"post:tags:#{self.id}"
end
end
タグデータストアへの書き込み(追加/削除)時にエラーが発生しても問題ないと判断しました。ただし、タグデータストアがダウンしている場合でも、タグなしで投稿を表示できるべきです。tags メソッド内の SMEMBERS Redis 呼び出しの周囲で Redis::CannotConnectError を単に rescue することができます。これをテストするために Toxiproxy を使いましょう。
Toxiproxy はすでにインストールされ、マシン上で実行されているので、ステップ2にスキップできます。ここでは、Toxiproxy に Redis タグのマッピングがあることを確認する必要があります。config/boot.rb に(接続が確立される前に)以下を追加します:
require 'toxiproxy'
Toxiproxy.populate([
{
name: "toxiproxy_test_redis_tags",
listen: "127.0.0.1:22222",
upstream: "127.0.0.1:6379"
}
])
次に、config/environments/test.rb で、次の行を追加して TagRedis を Toxiproxy 経由で Redis に接続する Redis クライアントに設定します:
TagRedis = Redis.new(port: 22222)
テスト環境内のすべての呼び出しはToxiproxyを経由するようになりました。つまり、障害をシミュレートする単体テストを追加できます:
test "should return empty array when tag redis is down when listing tags" do
@post.add_tag "mammals"
# Take down all Redises in Toxiproxy
Toxiproxy[/redis/].down do
assert_equal [], @post.tags
end
end
テストは Redis::CannotConnectError で失敗します。完璧です!Toxiproxy はクロージャの実行中、Redis を正常にダウンさせました。次に、tags メソッドを耐障害性のあるものに修正しましょう:
def tags
TagRedis.smembers(tag_key)
rescue Redis::CannotConnectError
[]
end
テストは通りました!これで、Redisがダウンしているときにタグを取得すると、例外をスローする代わりに空の配列を返すことを証明するユニットテストができました。完全なカバレッジのためには、Redisがダウンしているときにブログ記事ページ全体の取得をラップする統合テストも書くべきです。
完全なサンプルアプリケーションは sirupsen/toxiproxy-rails-example にあります。
プロジェクトでToxiproxyを使用するための設定は、3つのステップで構成されます:
Linux
お使いのアーキテクチャ向けの最新バイナリとシステムパッケージについては、Releases を参照してください。
Ubuntu
$ wget -O toxiproxy-2.13.0.deb https://github.com/Shopify/toxiproxy/releases/download/v2.13.0/toxiproxy_2.13.0_linux_amd64.deb
$ sudo dpkg -i toxiproxy-2.13.0.deb
$ sudo service toxiproxy start
OS X
Homebrew を使用する場合:
$ brew tap shopify/shopify
$ brew install toxiproxy
または MacPorts を使用する場合:
$ port install toxiproxy
Windows
Windows 版 Toxiproxy は https://github.com/Shopify/toxiproxy/releases/latest/download/toxiproxy-server-windows-amd64.exe からダウンロードでき、 対応する CLI は https://github.com/Shopify/toxiproxy/releases/latest/download/toxiproxy-cli-windows-amd64.exe にあります。
Docker
Toxiproxy は Github container registry で利用できます。
古いバージョン <= 2.1.4 は Docker Hub で利用できます。
$ docker pull ghcr.io/shopify/toxiproxy
$ docker run --rm -it ghcr.io/shopify/toxiproxy
ホストからToxiproxyを使用する場合(他のコンテナからではなく)、--net=hostでホストネットワーキングを有効にしてください。
このイメージはAPIを0.0.0.0にバインドするため、ホストネットワーキングではすべてのホストインターフェースから到達可能になります。
他のマシンがホストに到達できる場合は、-e TOXIPROXY_AUTH_TOKEN=<token>を渡してください(HTTP APIを参照)。
$ docker run --rm --entrypoint="/toxiproxy-cli" -it ghcr.io/shopify/toxiproxy list
ソース
Go がインストールされている場合、make ファイルを使用してソースから Toxiproxy をビルドできます:
$ make build
$ ./dist/toxiproxy-server
Toxiproxy 2.0 では、バージョン 1.x との互換性をなくすいくつかの API 変更が行われました。
Toxiproxy サーバーのバージョン 2.x を使用するには、お使いのクライアント
ライブラリが同じバージョンをサポートしていることを確認する必要があります。実行中の Toxiproxy のバージョンは、
/version エンドポイントを参照することで確認できます。
ライブラリ固有の変更点については、お使いのクライアントライブラリのドキュメントを参照してください。Toxiproxy サーバーの 詳細な変更点は CHANGELOG.md に記載されています。
アプリケーションの起動時に、Toxiproxy がどのエンドポイントをどこへプロキシするかを 認識していることを確認する必要があります。主なパラメータは、名前、Toxiproxy が リッスンするアドレス、そしてアップストリームのアドレスです。
一部のクライアントライブラリにはこのタスク用のヘルパーがあり、これは本質的に リスト内の各プロキシが作成されることを確認するだけのものです。Ruby クライアントの例: