## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-SHOPIFY-TOXIPROXY
# Toxiproxy
 

Toxiproxy๋ ๋คํธ์ํฌ ์ํ๋ฅผ ์๋ฎฌ๋ ์ด์
ํ๊ธฐ ์ํ ํ๋ ์์ํฌ์
๋๋ค. ํ
์คํธ, CI ๋ฐ ๊ฐ๋ฐ ํ๊ฒฝ์์ ์๋ํ๋๋ก ํน๋ณํ ๋ง๋ค์ด์ก์ผ๋ฉฐ, ์ฐ๊ฒฐ์ ๋ํ ๊ฒฐ์ ์ ๋ณ์กฐ๋ฅผ ์ง์ํ๋ฉด์๋ ๋ฌด์์ ํผ๋๊ณผ ์ฌ์ฉ์ ์ง์ ๋ ์ง์ํฉ๋๋ค. **Toxiproxy๋ ํ
์คํธ๋ฅผ ํตํด ์ ํ๋ฆฌ์ผ์ด์
์ ๋จ์ผ ์คํจ ์ง์ ์ด ์์์ ์
์ฆํ๋ ๋ฐ ํ์ํ ๋๊ตฌ์
๋๋ค.** ์ฐ๋ฆฌ๋ 2014๋
10์๋ถํฐ Shopify์ ๋ชจ๋ ๊ฐ๋ฐ ๋ฐ ํ
์คํธ ํ๊ฒฝ์์ ์ด๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ์ฌ์ฉํด ์์ต๋๋ค. ๋ณต์๋ ฅ์ ๋ํ ์์ธํ ๋ด์ฉ์ [๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ][blog]์ ์ฐธ์กฐํ์ธ์.
Toxiproxy ์ฌ์ฉ์ ๋ ๋ถ๋ถ์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. Go๋ก ์์ฑ๋ TCP ํ๋ก์(์ด ์ ์ฅ์์ ํฌํจ๋ ๊ฒ)์ HTTP๋ฅผ ํตํด ํ๋ก์์ ํต์ ํ๋ ํด๋ผ์ด์ธํธ์
๋๋ค. ์ ํ๋ฆฌ์ผ์ด์
์ด ๋ชจ๋ ํ
์คํธ ์ฐ๊ฒฐ์ด Toxiproxy๋ฅผ ํต๊ณผํ๋๋ก ๊ตฌ์ฑํ ๋ค์ HTTP๋ฅผ ํตํด ์ฐ๊ฒฐ ์ํ๋ฅผ ์กฐ์ํ ์ ์์ต๋๋ค. ํ๋ก์ ํธ๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ ์๋ ์ฌ์ฉ๋ฒ์ ์ฐธ์กฐํ์ธ์.
์๋ฅผ ๋ค์ด, Ruby ํด๋ผ์ด์ธํธ์์ MySQL์ ์๋ต์ 1000ms์ ์ง์ฐ์ ์ถ๊ฐํ๋ ค๋ฉด:```ruby Toxiproxy[:mysql_master].downstream(:latency, latency: 1000).apply do Shop.first # this takes at least 1s end
root@kitploit:~
๋ชจ๋ Redis ์ธ์คํด์ค๋ฅผ ์ข
๋ฃํ๋ ค๋ฉด:```ruby
Toxiproxy[/redis/].down do
Shop.first # this will throw an exception
end
์ด README์ ์์ ๋ ํ์ฌ Ruby๋ก ์์ฑ๋์ด ์์ง๋ง, ๋ค๋ฅธ ์ธ์ด๋ก ํด๋ผ์ด์ธํธ๋ฅผ ๋ง๋๋ ๊ฒ์ ๋ง๋ ๊ฒ์ ์์ต๋๋ค (Clients ์ฐธ์กฐ).
## Table of Contents
* Toxiproxy
* Table of Contents
* Why yet another chaotic TCP proxy?
* Clients
* Example
* Usage
* 1\. Installing Toxiproxy
* Upgrading from Toxiproxy 1.x
* 2\. Populating Toxiproxy
* 3\. Using Toxiproxy
* 4\. Logging
* Toxics
* latency
* down
* bandwidth
* slow_close
* timeout
* reset_peer
* slicer
* limit_data
* packet_loss
* HTTP API
* Proxy fields:
* Toxic fields:
* Endpoints
* Populating Proxies
* CLI Example
* Metrics
* Frequently Asked Questions
* Development
* Release
## ์ ๋ ๋ค๋ฅธ ํผ๋(chaotic) TCP ํ๋ก์์ธ๊ฐ?
์ฐ๋ฆฌ๊ฐ ์ฐพ์ ๊ธฐ์กด ๋๊ตฌ๋ค์ ํตํฉ ํ
์คํธ์ ๋จ์ ํ
์คํธ์ ํ์ํ ๋์ API๋ฅผ ์ ๊ณตํ์ง ๋ชปํ์ต๋๋ค. Linux ๋๊ตฌ์ธ `nc` ๋ฑ์ ํฌ๋ก์ค ํ๋ซํผ์ ์ง์ํ์ง ์๊ณ root ๊ถํ์ด ํ์ํ์ฌ ํ
์คํธ, ๊ฐ๋ฐ, CI ํ๊ฒฝ์์ ๋ฌธ์ ๊ฐ ๋ฉ๋๋ค.
## Clients
* toxiproxy-ruby
* toxiproxy-go
* toxiproxy-python
* toxiproxy.net
* toxiproxy-php-client
* toxiproxy-node-client
* toxiproxy-java
* toxiproxy-haskell
* toxiproxy-rust
* toxiproxy-elixir
## Example
Rails ์ ํ๋ฆฌ์ผ์ด์
์ ์ฌ์ฉํ ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค. Toxiproxy๋ ๊ฒฐ์ฝ Ruby์ ๋ฌถ์ฌ ์์ง ์์ผ๋ฉฐ, ๋จ์ง ์ฐ๋ฆฌ์ ์ฒซ ๋ฒ์งธ ์ฌ์ฉ ์ฌ๋ก์์ ๋ฟ์
๋๋ค. ์ ์ฒด ์์ ๋ sirupsen/toxiproxy-rails-example์์ ๋ณผ ์ ์์ต๋๋ค. ๋ฐ๋ก ์์ํ๋ ค๋ฉด Usage๋ก ๋ด๋ ค๊ฐ์ธ์.
์ธ๊ธฐ ์๋ ๋ธ๋ก๊ทธ์์ ์ด๋ค ์ด์ ๋ก ๊ฒ์๋ฌผ์ ํ๊ทธ๋ฅผ Redis์ ์ ์ฅํ๊ณ ๊ฒ์๋ฌผ ์์ฒด๋ MySQL์ ์ ์ฅํ๋ค๊ณ ๊ฐ์ ํด ๋ด
์๋ค. Redis set์์ ํ๊ทธ๋ฅผ ์กฐ์ํ๋ ๋ช ๊ฐ์ง ๋ฉ์๋๋ฅผ ํฌํจํ๋ `Post` ํด๋์ค๊ฐ ์์ ์ ์์ต๋๋ค.```ruby 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
root@kitploit:~
ํ๊ทธ ๋ฐ์ดํฐ ์ ์ฅ์์ ์ฐ๋ ๋์(์ถ๊ฐ/์ ๊ฑฐ) ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ ๊ด์ฐฎ๋ค๊ณ ๊ฒฐ์ ํ์ต๋๋ค.
๊ทธ๋ฌ๋ ํ๊ทธ ๋ฐ์ดํฐ ์ ์ฅ์๊ฐ ๋ค์ด๋ ๊ฒฝ์ฐ์๋
ํ๊ทธ ์์ด ๊ฒ์๋ฌผ์ ๋ณผ ์ ์์ด์ผ ํฉ๋๋ค. ๊ฐ๋จํ
`Redis::CannotConnectError`๋ฅผ `tags` ๋ฉ์๋์ `SMEMBERS` Redis ํธ์ถ ์ฃผ๋ณ์์
rescueํ๋ฉด ๋ฉ๋๋ค. ์ด๋ฅผ ํ
์คํธํ๊ธฐ ์ํด Toxiproxy๋ฅผ ์ฌ์ฉํฉ์๋ค.
์ด๋ฏธ Toxiproxy๋ฅผ ์ค์นํ๊ณ ์ปดํจํฐ์์ ์คํ ์ค์ด๋ฏ๋ก
2๋จ๊ณ๋ก ๊ฑด๋๋ธ ์ ์์ต๋๋ค. ์ฌ๊ธฐ์์ Toxiproxy๊ฐ Redis ํ๊ทธ์ ๋ํ ๋งคํ์
๊ฐ์ง๊ณ ์๋์ง ํ์ธํด์ผ ํฉ๋๋ค. `config/boot.rb`(์ฐ๊ฒฐ์ด ์ด๋ฃจ์ด์ง๊ธฐ ์ )์ ๋ค์์ ์ถ๊ฐํฉ๋๋ค:```ruby
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 ํด๋ผ์ด์ธํธ๋ก ์ค์ ํ๊ธฐ ์ํด ๋ค์ ์ค์ ์ถ๊ฐํฉ๋๋ค:```ruby TagRedis = Redis.new(port: 22222)
root@kitploit:~
ํ
์คํธ ํ๊ฒฝ์ ๋ชจ๋ ํธ์ถ์ ์ด์ Toxiproxy๋ฅผ ๊ฑฐ์นฉ๋๋ค. ์ฆ, ์คํจ๋ฅผ ์๋ฎฌ๋ ์ด์
ํ๋ ๋จ์ ํ
์คํธ๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค:```ruby
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
The test fails with `Redis::CannotConnectError`. Perfect! Toxiproxy took down the Redis successfully for the duration of the closure. Let's fix the `tags` method to be resilient:```ruby def tags TagRedis.smembers(tag_key) rescue Redis::CannotConnectError [] end
root@kitploit:~
ํ
์คํธ๊ฐ ํต๊ณผํฉ๋๋ค! ์ด์ Redis๊ฐ ๋ค์ด๋์์ ๋ ํ๊ทธ๋ฅผ ๊ฐ์ ธ์ค๋ฉด ์์ธ๋ฅผ ๋์ง๋ ๋์ ๋น ๋ฐฐ์ด์ ๋ฐํํ๋ค๋ ๊ฒ์ ์ฆ๋ช
ํ๋ ๋จ์ ํ
์คํธ๊ฐ ์๊ฒผ์ต๋๋ค. ์ ์ฒด ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ํด์๋ Redis๊ฐ ๋ค์ด๋์์ ๋ ๋ธ๋ก๊ทธ ํฌ์คํธ ํ์ด์ง ์ ์ฒด๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ์ ํฌํจํ๋ ํตํฉ ํ
์คํธ๋ ์์ฑํด์ผ ํฉ๋๋ค.
์ ์ฒด ์์ ์ ํ๋ฆฌ์ผ์ด์
์
[sirupsen/toxiproxy-rails-example](https://github.com/sirupsen/toxiproxy-rails-example)์ ์์ต๋๋ค.
## ์ฌ์ฉ๋ฒ
Toxiproxy๋ฅผ ์ฌ์ฉํ๋๋ก ํ๋ก์ ํธ๋ฅผ ๊ตฌ์ฑํ๋ ๊ฒ์ ์ธ ๋จ๊ณ๋ก ์ด๋ฃจ์ด์ง๋๋ค:
1. Toxiproxy ์ค์น
2. Toxiproxy ์ฑ์ฐ๊ธฐ
3. Toxiproxy ์ฌ์ฉ
### 1. Toxiproxy ์ค์น
**Linux**
์ต์ ๋ฐ์ด๋๋ฆฌ์ ์์คํ
ํจํค์ง๋ [`Releases`](https://github.com/Shopify/toxiproxy/releases)๋ฅผ ์ฐธ์กฐํ์ธ์.
**Ubuntu**```bash
$ wget -O toxiproxy-2.1.4.deb https://github.com/Shopify/toxiproxy/releases/download/v2.1.4/toxiproxy_2.1.4_amd64.deb
$ sudo dpkg -i toxiproxy-2.1.4.deb
$ sudo service toxiproxy start
**OS X**
Homebrew๋ก:```bash $ brew tap shopify/shopify $ brew install toxiproxy
root@kitploit:~
๋๋ [MacPorts](https://www.macports.org/):```bash
$ port install toxiproxy
**Windows**
Toxiproxy for Windows๋ https://github.com/Shopify/toxiproxy/releases/download/v2.1.4/toxiproxy-server-windows-amd64.exe ์์ ๋ค์ด๋ก๋ํ ์ ์์ต๋๋ค.
**Docker**
Toxiproxy๋ Github ์ปจํ
์ด๋ ๋ ์ง์คํธ๋ฆฌ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด์ ๋ฒ์ `<= 2.1.4`๋ Docker Hub์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.```bash $ docker pull ghcr.io/shopify/toxiproxy $ docker run --rm -it ghcr.io/shopify/toxiproxy
root@kitploit:~
๋ค๋ฅธ ์ปจํ
์ด๋๊ฐ ์๋ ํธ์คํธ์์ Toxiproxy๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, `--net=host`๋ก ํธ์คํธ ๋คํธ์ํน์ ํ์ฑํํ์ญ์์ค.```shell
$ docker run --rm --entrypoint="/toxiproxy-cli" -it ghcr.io/shopify/toxiproxy list
Go๊ฐ ์ค์น๋์ด ์๋ค๋ฉด, make ํ์ผ์ ์ฌ์ฉํ์ฌ Toxiproxy๋ฅผ ์์ค์์ ๋น๋ํ ์ ์์ต๋๋ค:```bash $ make build $ ./toxiproxy-server
root@kitploit:~
#### Toxiproxy 1.x์์ ์
๊ทธ๋ ์ด๋
Toxiproxy 2.0์์๋ API์ ์ฌ๋ฌ ๋ณ๊ฒฝ ์ฌํญ์ด ์ ์ฉ๋์ด 1.x ๋ฒ์ ๊ณผ ํธํ๋์ง ์์ต๋๋ค.
Toxiproxy ์๋ฒ 2.x ๋ฒ์ ์ ์ฌ์ฉํ๋ ค๋ฉด ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋์ผํ ๋ฒ์ ์ ์ง์ํ๋์ง
ํ์ธํด์ผ ํฉ๋๋ค. `/version` ์๋ํฌ์ธํธ๋ฅผ ํ์ธํ๋ฉด ์คํ ์ค์ธ Toxiproxy ๋ฒ์ ์
์ ์ ์์ต๋๋ค.
ํน์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ณ๊ฒฝ ์ฌํญ์ ํด๋น ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ธ์. Toxiproxy ์๋ฒ์ ์์ธํ
๋ณ๊ฒฝ ์ฌํญ์ [CHANGELOG.md](https://github.com/shopify/toxiproxy/blob/HEAD/CHANGELOG.md)์์ ํ์ธํ ์ ์์ต๋๋ค.
### 2. Toxiproxy ์ฑ์ฐ๊ธฐ
์ ํ๋ฆฌ์ผ์ด์
์ด ๋ถํ
๋ ๋ Toxiproxy๊ฐ ์ด๋ค ์๋ํฌ์ธํธ๋ฅผ ์ด๋๋ก ํ๋ก์ํ ์ง ์ ์ ์๋๋ก
ํด์ผ ํฉ๋๋ค. ์ฃผ์ ๋งค๊ฐ๋ณ์๋ ์ด๋ฆ, Toxiproxy๊ฐ **์์ (listen)**ํ ์ฃผ์, ๊ทธ๋ฆฌ๊ณ
์
์คํธ๋ฆผ์ ์ฃผ์์
๋๋ค.
์ผ๋ถ ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์๋ ์ด ์์
์ ์ํ ํฌํผ๊ฐ ์์ผ๋ฉฐ, ์ด๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชฉ๋ก์ ๊ฐ
ํ๋ก์๊ฐ ์์ฑ๋๋๋ก ํ๋ ๊ฒ์
๋๋ค. Ruby ํด๋ผ์ด์ธํธ์ ์์:```ruby
# Make sure `shopify_test_redis_master` and `shopify_test_mysql_master` are
# present in Toxiproxy
Toxiproxy.populate([
{
name: "shopify_test_redis_master",
listen: "127.0.0.1:22220",
upstream: "127.0.0.1:6379"
},
{
name: "shopify_test_mysql_master",
listen: "127.0.0.1:24220",
upstream: "127.0.0.1:3306"
}
])
์ด ์ฝ๋๋ ๋ถํ
์ ๊ฐ๋ฅํ ํ ๋นจ๋ฆฌ, ์ด๋ค ์ฝ๋๊ฐ Toxiproxy๋ฅผ ํตํ ์ฐ๊ฒฐ์ ์ค์ ํ๊ธฐ ์ ์ ์คํ๋์ด์ผ ํฉ๋๋ค. population ํฌํผ์ ๋ํ ๋ฌธ์๋ ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ํ์ธํ์๊ธฐ ๋ฐ๋๋๋ค.
๋๋ CLI๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ก์๋ฅผ ์์ฑํ ์๋ ์์ต๋๋ค. ์:```bash toxiproxy-cli create -l localhost:26379 -u localhost:6379 shopify_test_redis_master
root@kitploit:~
๋ค์๊ณผ ๊ฐ์ ๋ช
๋ช
๊ท์น์ ๊ถ์ฅํฉ๋๋ค: `<app>_<env>_<data store>_<shard>`.
์ด๋ ๊ฒ ํ๋ฉด ๋์ผํ Toxiproxy๋ฅผ ์ฌ์ฉํ๋ ์ ํ๋ฆฌ์ผ์ด์
๊ฐ์ ์ถฉ๋์ด ๋ฐ์ํ์ง ์์ต๋๋ค.
๋๊ท๋ชจ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฒฝ์ฐ Toxiproxy ๊ตฌ์ฑ์ ๋ณ๋์ ๊ตฌ์ฑ ํ์ผ์ ์ ์ฅํ๋ ๊ฒ์ด ์ข์ต๋๋ค. `config/toxiproxy.json`์ ์ฌ์ฉํฉ๋๋ค. ์ด ํ์ผ์ `-config` ์ต์
์ผ๋ก ์๋ฒ์ ์ ๋ฌํ๊ฑฐ๋, ์ ํ๋ฆฌ์ผ์ด์
์์ ๋ก๋ํ์ฌ `populate` ํจ์์ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค.
`config/toxiproxy.json` ์์:```json
[
{
"name": "web_dev_frontend_1",
"listen": "[::]:https://raw.githubusercontent.com/shopify/toxiproxy/HEAD/18080%22,
"upstream": "webapp.domain:8080",
"enabled": true
},
{
"name": "web_dev_mysql_1",
"listen": "[::]:13306",
"upstream": "database.domain:3306",
"enabled": true
}
]
์์์ ํฌํธ ์ถฉ๋์ ํผํ๋ ค๋ฉด ์์ ํฌํธ ๋ฒ์ ๋ฐ์ ํฌํธ๋ฅผ ์ฌ์ฉํ์ธ์. Linux์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก `32,768`~`61,000`์ด๋ฉฐ, ๋ค์์ ์ฐธ์กฐํ์ธ์. `/proc/sys/net/ipv4/ip_local_port_range`.
### 3\. Toxiproxy ์ฌ์ฉํ๊ธฐ
Toxiproxy๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ด์ ์ ํ๋ฆฌ์ผ์ด์
์ด Toxiproxy๋ฅผ ํตํด ์ฐ๊ฒฐํ๋๋ก ๊ตฌ์ฑํด์ผ ํฉ๋๋ค. 2๋จ๊ณ์ ์์๋ฅผ ์ด์ด์, Redis ํด๋ผ์ด์ธํธ๊ฐ Toxiproxy๋ฅผ ํตํด ์ฐ๊ฒฐ๋๋๋ก ๊ตฌ์ฑํ ์ ์์ต๋๋ค:```ruby
# old straight to redis
redis = Redis.new(port: 6380)
# new through toxiproxy
redis = Redis.new(port: 22220)
root@kitploit:~
์ด์ Toxiproxy API๋ฅผ ํตํด ์ด๋ฅผ ๋ณ์กฐํ ์ ์์ต๋๋ค. Ruby์์:```ruby
redis = Redis.new(port: 22220)
Toxiproxy[:shopify_test_redis_master].downstream(:latency, latency: 1000).apply do
redis.get("test") # will take 1s
end
๋๋ CLI๋ฅผ ํตํด:```bash toxiproxy-cli toxic add -t latency -a latency=1000 shopify_test_redis_master
root@kitploit:~
Please consult your respective client library on usage.
### 4. Logging
There are the following log levels: panic, fatal, error, warn or warning, info, debug and trace.
The level could be updated via environment variable `LOG_LEVEL`.
### Toxics
Toxics manipulate the pipe between the client and upstream. They can be added
and removed from proxies using the [HTTP api](#http-api). Each toxic has its own parameters
to change how it affects the proxy links.
For documentation on implementing custom toxics, see [CREATING_TOXICS.md](https://github.com/shopify/toxiproxy/blob/HEAD/CREATING_TOXICS.md)
#### latency
Add a delay to all data going through the proxy. The delay is equal to `latency` +/- `jitter`.
Attributes:
- `latency`: time in milliseconds
- `jitter`: time in milliseconds
#### down
Bringing a service down is not technically a toxic in the implementation of
Toxiproxy. This is done by `POST`ing to `/proxies/{proxy}` and setting the
`enabled` field to `false`.
#### bandwidth
Limit a connection to a maximum number of kilobytes per second.
Attributes:
- `rate`: rate in KB/s
#### slow_close
Delay the TCP socket from closing until `delay` has elapsed.
Attributes:
- `delay`: time in milliseconds
#### timeout
Stops all data from getting through, and closes the connection after `timeout`. If
`timeout` is 0, the connection won't close, and data will be dropped until the
toxic is removed.
Attributes:
- `timeout`: time in milliseconds
#### reset_peer
Simulate TCP RESET (Connection reset by peer) on the connections by closing the stub Input
immediately or after a `timeout`.
Attributes:
- `timeout`: time in milliseconds
#### slicer
Slices TCP data up into small bits, optionally adding a delay between each
sliced "packet".
Attributes:
- `average_size`: size in bytes of an average packet
- `size_variation`: variation in bytes of an average packet (should be smaller than average_size)
- `delay`: time in microseconds to delay each packet by
#### limit_data
Closes connection when transmitted data exceeded limit.
- `bytes`: number of bytes it should transmit before connection is closed
#### packet_loss
Randomly drops chunks flowing through the proxy simulating
flaky Wi-Fi, mobile, or satellite network conditions.
Attributes:
- `loss_rate`: probability [0.0-1.0] that a chunk is dropped (default 0.0)
- `correlation`: extra drop probability when the previous chunk was dropped, modeling burst loss (default 0.0)
### HTTP API
All communication with the Toxiproxy daemon from the client happens through the
HTTP interface, which is described here.
Toxiproxy listens for HTTP on port **8474**.
#### Proxy fields:
- `name`: proxy name (string)
- `listen`: listen address (string)
- `upstream`: proxy upstream address (string)
- `enabled`: true/false (defaults to true on creation)
To change a proxy's name, it must be deleted and recreated.
Changing the `listen` or `upstream` fields will restart the proxy and drop any active connections.
If `listen` is specified with a port of 0, toxiproxy will pick an ephemeral port. The `listen` field
in the response will be updated with the actual port.
If you change `enabled` to `false`, it will take down the proxy. You can switch it
back to `true` to reenable it.
#### Toxic fields:
- `name`: toxic name (string, defaults to `<type>_<stream>`)
- `type`: toxic type (string)
- `stream`: link direction to affect (defaults to `downstream`)
- `toxicity`: probability of the toxic being applied to a link (defaults to 1.0, 100%)
- `attributes`: a map of toxic-specific attributes
See [Toxics](#toxics) for toxic-specific attributes.
The `stream` direction must be either `upstream` or `downstream`. `upstream` applies
the toxic on the `client -> server` connection, while `downstream` applies the toxic
on the `server -> client` connection. This can be used to modify requests and responses
separately.
#### Endpoints
All endpoints are JSON.
- **GET /proxies** - List existing proxies and their toxics
- **POST /proxies** - Create a new proxy
- **POST /populate** - Create or replace a list of proxies
- **GET /proxies/{proxy}** - Show the proxy with all its active toxics
- **POST /proxies/{proxy}** - Update a proxy's fields
- **DELETE /proxies/{proxy}** - Delete an existing proxy
- **GET /proxies/{proxy}/toxics** - List active toxics
- **POST /proxies/{proxy}/toxics** - Create a new toxic
- **GET /proxies/{proxy}/toxics/{toxic}** - Get an active toxic's fields
- **POST /proxies/{proxy}/toxics/{toxic}** - Update an active toxic
- **DELETE /proxies/{proxy}/toxics/{toxic}** - Remove an active toxic
- **POST /reset** - Enable all proxies and remove all active toxics
- **GET /version** - Returns the server version number
- **GET /metrics** - Returns Prometheus-compatible metrics
#### Populating Proxies
Proxies can be added and configured in bulk using the `/populate` endpoint. This is done by
passing a json array of proxies to toxiproxy. If a proxy with the same name already exists,
it will be compared to the new proxy and replaced if the `upstream` and `listen` address don't match.
A `/populate` call can be included for example at application start to ensure all required proxies
exist. It is safe to make this call several times, since proxies will be untouched as long as their
fields are consistent with the new data.
### CLI Example```bash
$ toxiproxy-cli create -l localhost:26379 -u localhost:6379 redis
Created new proxy redis
$ toxiproxy-cli list
Listen Upstream Name Enabled Toxics
======================================================================
127.0.0.1:26379 localhost:6379 redis true None
Hint: inspect toxics with `toxiproxy-client inspect <proxyName>`
์
๋ ฅ๋ ๋ฒ์ญํ ๋ด์ฉ(chunk 41)์ด ๋น์ด ์์ต๋๋ค. ๋ฒ์ญํ ํ
์คํธ๊ฐ ์ ๊ณต๋์ง ์์ ๋ฒ์ญ์ ์งํํ ์ ์์ต๋๋ค. ์๋ฌธ ๋ด์ฉ์ ๋ค์ ์ ๊ณตํด ์ฃผ์๋ฉด ๋ฒ์ญํด ๋๋ฆฌ๊ฒ ์ต๋๋ค.```bash $ redis-cli -p 26379 127.0.0.1:26379> SET omg pandas OK 127.0.0.1:26379> GET omg "pandas"
root@kitploit:~
์
๋ ฅ ํ
์คํธ๊ฐ ์ ๊ณต๋์ง ์์ ๋ฒ์ญํ ๋ด์ฉ์ด ์์ต๋๋ค.```bash
$ toxiproxy-cli toxic add -t latency -a latency=1000 redis
Added downstream latency toxic 'latency_downstream' on proxy 'redis'
I received no input content to translate. Please provide the chunk text.```bash $ redis-cli -p 26379 127.0.0.1:26379> GET omg "pandas" (1.00s) 127.0.0.1:26379> DEL omg (integer) 1 (1.00s)
root@kitploit:~
๋ฒ์ญํ ๋งํฌ๋ค์ด ์๋ฌธ์ ์ ๊ณตํด ์ฃผ์ธ์.```bash
$ toxiproxy-cli toxic remove -n latency_downstream redis
Removed toxic 'latency_downstream' on proxy 'redis'
The input chunk appears to be empty โ no source text was provided for chunk 49 of 55. Please supply the Markdown content to translate.```bash $ redis-cli -p 26379 127.0.0.1:26379> GET omg (nil)
root@kitploit:~
The input content for chunk 51 is missing โ the message ends with "INPUT:" but no text follows. Please resend the chunk content and I'll translate it into Korean.```bash
$ toxiproxy-cli delete redis
Deleted proxy redis
(no content provided)```bash $ redis-cli -p 26379 Could not connect to Redis at 127.0.0.1:26379: Connection refused
root@kitploit:~
### ๋ฉํธ๋ฆญ
Toxiproxy๋ HTTP API์ /metrics์์ Prometheus ํธํ ๋ฉํธ๋ฆญ์ ๋
ธ์ถํฉ๋๋ค.
์ ์ฒด ์ค๋ช
์ [METRICS.md](https://github.com/shopify/toxiproxy/blob/HEAD/METRICS.md)๋ฅผ ์ฐธ์กฐํ์ธ์.
### ์์ฃผ ๋ฌป๋ ์ง๋ฌธ
**Toxiproxy๋ ์ผ๋ง๋ ๋น ๋ฅธ๊ฐ์?** Toxiproxy์ ์๋๋ ์ฃผ๋ก ํ๋์จ์ด์ ๋ฐ๋ผ ๋ฌ๋ผ์ง์ง๋ง, ํ์ฑํ๋ toxic์ด ์์ ๋ *< 100ยตs*์ ์ง์ฐ ์๊ฐ์ ๊ธฐ๋ํ ์ ์์ต๋๋ค. Macbook Pro์์ `GOMAXPROCS=4`๋ก ์คํํ์ ๋ *~1000MB/s* ์ฒ๋ฆฌ๋์ ๋ฌ์ฑํ์ผ๋ฉฐ, ๊ณ ๊ธ ๋ฐ์คํฌํฑ์์๋ *2400MB/s*๊น์ง ๋ฌ์ฑํ์ต๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก Toxiproxy๋ ํ
์คํธ ์ค์ธ ์ฑ๋งํผ์ ๋น ๋ฅด๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ด๋ํ ์ ์์ต๋๋ค.
**Toxiproxy๋ ๋ฌด์์ ํ
์คํธ๋ฅผ ํ ์ ์๋์?** ์ฌ์ฉ ๊ฐ๋ฅํ ๋ง์ toxic์ ๋ฌด์์์ฑ์ ๊ฐ๋๋ก ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด `latency` toxic์ `jitter` ๊ฐ์ ๊ฒ์
๋๋ค. ๋ํ toxic์ด ์ํฅ์ ๋ฏธ์น ์ฐ๊ฒฐ ๋น์จ์ ์ง์ ํ๋ ์ ์ญ `toxicity` ๋งค๊ฐ๋ณ์๊ฐ ์์ต๋๋ค. ์ด๊ฒ์ ์ฐ๊ฒฐ์ X%๊ฐ ํ์์์๋๋๋ก ํ์ฉํ๋ `timeout` toxic๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ๊ฐ์ฅ ์ ์ฉํฉ๋๋ค.
**MySQL์์ Toxiproxy ์์
์ด ๋ฐ์๋์ง ์์ต๋๋ค**. ์ผ๋ถ ํด๋ผ์ด์ธํธ์ ๊ฒฝ์ฐ ํธ์คํธ๊ฐ `localhost`๋ก ์ค์ ๋์ด ์์ผ๋ฉด ํฌํธ๋ฅผ ๋ฌด์์ผ๋ก ์ ๋ฌํ๋ MySQL์ ๋ก์ปฌ Unix ๋๋ฉ์ธ ์์ผ์ ์ ํธํฉ๋๋ค. MySQL ์๋ฒ๊ฐ ์์ผ์ ์์ฑํ์ง ์๋๋ก ๊ตฌ์ฑํ๊ณ ํธ์คํธ๋ก `127.0.0.1`์ ์ฌ์ฉํ์ธ์. ์๋ฒ๋ฅผ ์ฌ์์ํ ํ์๋ ์ด์ ์์ผ์ ์ ๊ฑฐํ๋ ๊ฒ์ ์์ง ๋ง์ธ์.
**Toxiproxy๊ฐ ๊ฐํ์ ์ธ ์ฐ๊ฒฐ ์คํจ๋ฅผ ์ผ์ผํต๋๋ค**. ๋ฌด์์ ํฌํธ ์ถฉ๋์ ํผํ๋ ค๋ฉด ์์(ephemeral) ํฌํธ ๋ฒ์ ๋ฐ์ ํฌํธ๋ฅผ ์ฌ์ฉํ์ธ์. Linux์์ ๊ธฐ๋ณธ์ ์ผ๋ก `32,768`์์ `61,000`๊น์ง์ด๋ฉฐ, `/proc/sys/net/ipv4/ip_local_port_range`๋ฅผ ์ฐธ์กฐํ์ธ์.
**์ ํ๋ฆฌ์ผ์ด์
๋ง๋ค Toxiproxy๋ฅผ ์คํํด์ผ ํ๋์?** ์๋์, ๋ชจ๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๋์ผํ Toxiproxy๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. ์๋น์ค๋ฅผ ๊ตฌ๋ถํ๊ธฐ ์ํด ํ๋ก์ ์ด๋ฆ์ `<app>_<env>_<data store>_<shard>` ํจํด์ผ๋ก ์ง์ ํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. ์: `shopify_test_redis_master` ๋๋ `shopify_development_mysql_1`.
### ๊ฐ๋ฐ
* `make`. ํ์ฌ ํ๋ซํผ์ฉ toxiproxy ๊ฐ๋ฐ ๋ฐ์ด๋๋ฆฌ๋ฅผ ๋น๋ํฉ๋๋ค.
* `make all`. ๋ชจ๋ ํ๋ซํผ์ฉ Toxiproxy ๋ฐ์ด๋๋ฆฌ์ ํจํค์ง๋ฅผ ๋น๋ํฉ๋๋ค. Linux ๋ฐ Darwin(amd64)์์ ํฌ๋ก์ค ์ปดํ์ผ์ด ํ์ฑํ๋ Go์, Linux ํจํค์ง ๋ฐ์ด๋๋ฆฌ๋ฅผ ๋น๋ํ๊ธฐ ์ํด `$PATH`์ [`goreleaser`](https://goreleaser.com/)๊ฐ ํ์ํฉ๋๋ค.
* `make test`. Toxiproxy ํ
์คํธ๋ฅผ ์คํํฉ๋๋ค.
### ๋ฆด๋ฆฌ์ค
[RELEASE.md](https://github.com/shopify/toxiproxy/blob/HEAD/RELEASE.md)๋ฅผ ์ฐธ์กฐํ์ธ์.
[blog]: https://shopify.engineering/building-and-testing-resilient-ruby-on-rails-applications