初福岡ですが前日は熊本に泊まって馬刺しを食べました。今まで食べてきた馬刺しとはなんだったのか。
合法レバ刺しです 🐴なので pic.twitter.com/v2t7y6pI01
— fujiwara (@fujiwara) 2017年6月30日
発表資料はこちらです。
開発してから2年、本番で使いまくっていますが大変安定してますし、いろいろ面白い使い方ができる特性を持っているので、是非お試しください。(rausサポートした版はまだ本番に入れてないですが、今後数ヶ月のうちに入れる予定です)
初福岡ですが前日は熊本に泊まって馬刺しを食べました。今まで食べてきた馬刺しとはなんだったのか。
合法レバ刺しです 🐴なので pic.twitter.com/v2t7y6pI01
— fujiwara (@fujiwara) 2017年6月30日
発表資料はこちらです。
開発してから2年、本番で使いまくっていますが大変安定してますし、いろいろ面白い使い方ができる特性を持っているので、是非お試しください。(rausサポートした版はまだ本番に入れてないですが、今後数ヶ月のうちに入れる予定です)
HTTPを使って、ファイルを Consul クラスタ内で分散配布する daemon です。Go で書かれています。読みかたは「たぐる」です。
拙作の Stretcher というデプロイツールがあります。嬉しいことに、自分が勤務しているカヤックだけではなく、他社さんでも使われているようです。 先日、某社の Stretcher をお使いのかたに話を伺う機会があり、デプロイアーカイブの取得時のネットワーク負荷が問題になっているということを聞きました。
カヤックではサーバは基本 AWS にあり、S3 からデプロイアーカイブ(200〜300MB程度)を取得しています。S3はちょっと意味が分からないぐらい堅牢で、stretcherの -random-delay 5
(開始を平均2.5秒、最大5秒ずらす) を設定した状態で100台程度から一斉に200MBを取得しに行っても、平然と各ホストに対して 60〜80MB/sec ぐらいの転送速度でファイルを配ってきますし、エラーになることもほぼありません。(毎日10回deployしていて S3 からの取得が失敗するのは数ヶ月に一度とか)
ところがAWS外部から取得する場合、AWSまでの回線の問題もありますし、delayを大きく取っても結構な確率で失敗するので困っている、という話でした。
ということで、Consul クラスタ内部でファイルを分散配布し、HTTP で取得できる仕組みを作ってみました。
README に書いてあるとおりですが、HTTP の PUT, GET, HEAD, DELETE に対応しています。
Consul クラスタ内で各 node に tuggle を起動します。(デフォルトではTCP 8900番ポートを listen します)
[node{1,2,3}]$ mkdir /tmp/tuggle [node{1,2,3}]$ tuggle -data-dir /tmp/tuggle
どこか1台の node で PUT することでファイルを登録できます。
[node1]$ curl -XPUT -H"Content-Type: application/gzip" --data-binary @test.gz localhost:8900/test.gz
登録されたファイルは GET / することで一覧を参照できます。
[node1]$ curl -s localhost:8900 | jq . [ { "id": "6524a9d7b3bde0f3543f1ead0ae8604f", "name": "test.gz", "content_type": "application/gzip", "size": 8764510, "created_at": "2017-02-13T07:46:18.809409122Z" } ]
その後、他の node で動いている tuggle から GET することで、ファイルを取得できます。
[node2]$ curl localhost:8900/test.gz > test.gz [node2]$ ls -l test.gz -rw-rw-r-- 1 foo bar 8764510 Feb 13 07:55 test.gz
ファイルの上書きは未対応です。同一ファイル名へは一旦 DELETE で消してから PUT しなおしてください。どこの node からでも DELETE 可能です。
[node1]$ curl -X DELETE localhost:8900/test.gz
tuggle の動作原理を簡単に説明します。
tuggle は PUT を受け付けると、以下の動作をします。
tuggle
tag=ファイル名のMD5
として自分の node を登録sync
がついている場合、Consul Event を発行して他の node の tuggle に取得を促す)つまり、どの node がどのファイルを保持しているのかを Consul Service のタグで管理しています。
tuggleはGETを受け付けると、Consul KVのメタデータを参照した上で
tuggle
tag=ファイル名のMD5
で検索し、ファイルを持っているnodeにHTTPで取得しに行きます
という動作をします。これによって、自分が持っていないファイルはその時点で持っている node を検索して取得し、その後自分自身も配布 node として動作することになります。
DELETEでは、受け付けた node は以下の動作をします。
Stretcher と組み合わせて使う場合はデプロイアーカイブを tuggle に PUT してから、manifest で src: http://localhost:8900/foo.tar.gz
などと指定する想定です。
最初にファイルを持っているのは 1 node なので、デプロイ時のように一斉に各 node で取得しようとすると、結局最初の1台に負荷が集中してしまいます。 そこで tuggle は Consul のセマフォの仕組みを利用して、1 nodeに対する取得の並列数を 3 に制限しています。
セマフォが取得できなかった node は、しばらく待ったあとに Consul Service の検索からリトライします。その時点で取得が終わった node は配布 node となっているため、増えた配布 node の中からランダムに選択することで負荷を分散します。
また、Consul 0.6 以降では Consul Agent 間でネットワーク的な距離を測定しています。Serviceを検索するときに near=_agent
というクエリをすることで、自分と近い node を優先的に選択することができます。
これによって、AWSの AZ (Availiability Zone)間のようにネットワーク間に距離がある場合でも、自分と近いところから取得することで効率を上げることができます。
また、取得によって帯域を使い尽くさないように -fetch-rate
というオプションで、取得に使用する帯域を制限することができます。これは拙作の shapeio というライブラリで実現しています。
https://github.com/fujiwara/shapeio
ファイルがどのように node 間で伝達していったのをかを Consul KV に保管しておいて、graphviz の dot 形式で出力する機能があります。
$ curl "http://localhost:8900/test.gz?graph" > graph.dot $ curl "http://localhost:8900/test.gz?graph&format=svg" > graph.svg
node に graphviz (dot
コマンド) がインストールされていれば、format=(svg|png)
などと指定することで変換後の画像を取得することもできます。
実際に 135MB のファイルを AWS 上で c4.large インスタンス 50台、multi-az 構成で配布 (sync引数付き) してみたグラフは以下のようになりました。
全 node にファイルが配布完了するまでに約18秒でした。c4.large インスタンスではおおよそ 70MB/sec 程度のネットワーク速度しか出ないため、1台に対して全台が取得すると100秒近くかかるはずのところが分散配布によって高速化しているのが分かります。
(手動で) AZ ごとに色を付けてみると以下のように、いいかんじに AZ 内を優先してファイルが流れていってるようです。最初に同 AZ のが集中しているのは、ネットワーク的に近いため Consul Event の伝達が早いものから先にセマフォを取得したためかと思われます。この辺は工夫の余地がありそうです。
ということで、まだ動き始めたばかりで本番投入もしていませんが、興味のあるかたはお試しいただけると幸いです。
リポジトリの docker ディレクトリ以下で make up
とすると、docker-compose で 8 node のクラスタが起動するので、試すのはこちらがお手軽です。
ISUCON 6 にチーム「morimoto組」で参加して、最終スコア 36,067 で準優勝しました。
morimoto組は自分と、会社の新卒1,2年目( kasari , id:moshisora ) という歳の差チームです。
今年も作りました #isucon pic.twitter.com/y2fX4HiJys
— fujiwara (@fujiwara) October 22, 2016
やー、盛りだくさんでしたね…
11:02:53 PASS 942 11:21:28 PASS 1159 11:58:31 PASS 1364 12:31:15 FAIL 253 12:36:34 PASS 1616 12:39:18 PASS 2051 nginxをいれて /api 以下を直接 Perl に (fujiwara) 12:43:40 PASS 3175 並列度が高いのでPerlを200プロセスに (fujiwara) 12:46:41 PASS 3543 12:49:26 FAIL 12 12:53:18 PASS 2816 13:03:36 PASS 3314 13:35:14 FAIL 251 13:47:46 FAIL 251 14:07:14 PASS 3211 pointsをstrokesのカラムにJSONで保持 (kasari, moshisora) 14:09:41 FAIL 0 壊れたSVGを返してベンチマーカーがクラッシュしたらしい 14:10:56 FAIL 0 14:11:25 FAIL 0 14:14:25 PASS 3470 14:15:21 FAIL 0 14:16:38 FAIL 0 14:20:25 FAIL 0 14:24:03 PASS 4697 /img/* で返すSVGをPerlでレンダリング (fujiwara) 14:27:05 FAIL 252 14:29:53 PASS 4781 15:17:25 FAIL 106 15:21:32 PASS 7412 /img/* をRedisにCache(Perlで処理) (kasari) 15:31:52 PASS 6040 16:09:04 FAIL 253 16:10:24 FAIL 253 16:12:32 PASS 8020 16:54:56 FAIL 253 16:58:52 FAIL 253 17:10:31 PASS 9339 /api/stream/rooms SSEをGo + Redis PubSub実装に置き換え (fujiwara) 17:41:33 PASS 15241 React, Perl, Goをisu02で動かして2台構成 17:43:36 PASS 30714 React, Perl, Goを全台で動かす5台構成 17:45:12 PASS 29301 17:48:35 PASS 36067 React, Perl, Goを isu02〜05、isu01にnginx, MySQL, Redisの5台構成
全体の方針としては、以下のようなざっくりとしたスケジュールを組みました。
チームメイト的には Perl のほうが書きやすい、ということでまず Perl 実装を選択。Perlの初期実装は各言語の中でもだいぶスコアが出にくかったようで、ベンチを回して1000前後。
なかなか立ち上がりが早くできず、スコアをあまり上げられずにお昼へ。
1 Strokeに対して複数保存されるPointsが1点毎に1レコードになっていたので、これはそのままJSONでシリアライズしてStorkeのカラムに保存してしまう(kasari)。既存データもマイグレーションするスクリプトで処理(moshisora)。この時点ではスコアはほとんど変わらないが、その後の改善をしたら効いてくるはず。
/img/
でSVGを返している部分は、初期実装が
という作りになっていたので、ここを直接 Perl で SVG を吐き出すように修正(fujiwara)。
my $svg = qq{<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full" width="${width}" height="${height}" style="width:${width}px;height:${height}px;background-color:white;" viewBox="0 0 ${width} ${height}">}; for my $s (@{ $room->{strokes} }) { my ($r, $g, $b, $a) = ($s->{red}, $s->{green}, $s->{blue}, $s->{alpha}); my ($id, $w) = ($s->{id}, $s->{width}); $svg .= qq{<polyline id="$id" stroke="rgba($r,$g,$b,$a)" stroke-width="$w" stroke-linecap="round" stroke-linejoin="round" fill="none" points="}; $svg .= join(" ", map { $_->{x} . "," . $_->{y} } @{$s->{points}}); $svg .= qq{"></polyline>}; } $svg .= "</svg>";
ひどいコードだが、動く (4697)。そのあと SVG を Redis に cache するようにして 7412。ここは nginx (OpenResty) から直接 Redis を参照するようにすればもっと伸びたはず、だけど手が回らず未着手。
SSEを処理している部分は初期実装が 500ms sleep してDBに新しいStrokeがあるかどうかをポーリングをくりかえす、という作りで、これは Perl の Prefork server (Starlet) ではプロセスが専有されてしまうので並列度が上がらず不利。
既に15:30なので、手を打つとしたらここが最後の判断ポイント。Goを混ぜることを決断。
/api/stream/rooms
の SSE だけ Go 実装にする
実装としては、以下のようなコード。
case <-time.After(500 * time.Millisecond):
のところ// func getAPIStreamRoomsID(ctx context.Context, w http.ResponseWriter, r *http.Request) { // ... ch := make(chan *redis.Message, 10) nctx, cancel := context.WithTimeout(ctx, 3*time.Second) defer cancel() go func(ctx context.Context) { redisClient := redis.NewClient(&redis.Options{ Addr: os.Getenv("REDIS_HOST") + ":6379", DB: 0, // use default DB }) defer redisClient.Close() log.Println("starting psubscribe") pubsub, err := redisClient.PSubscribe(fmt.Sprintf("%d", room.ID)) defer pubsub.Close() if err != nil { log.Println("psubscrie err", err) return } for { msg, err := pubsub.ReceiveMessage() if err != nil { log.Println("recv err", err) return } select { case <-ctx.Done(): return default: ch <- msg } } }(nctx) for { select { case <-nctx.Done(): return case msg := <-ch: var s Stroke err := json.Unmarshal([]byte(msg.Payload), &s) if err != nil { log.Println(err) return } d, _ := json.Marshal(s) printAndFlush(w, "id:"+strconv.FormatInt(s.ID, 10)+"\n\n"+"event:stroke\n"+"data:"+string(d)+"\n\n") case <-time.After(500 * time.Millisecond): } // ...
たいした変更でもないし1時間あればいけるだろう、と思って一人で書いたものの(fujiwara) 、やはり焦りからかなかなかベンチを通過できず。
17時をまわってしまったので、これで通らなければ Perl のまま複数台構成にするしかないか…というところで最後、kasari に「イベントがなくても 500ms ごとに watcherを送る必要があるのでは?」という指摘をもらってなんとか 17:10 にベンチを通すことに成功!(9339)。
ここまでチューニングしてきたホストには netdata をいれていたので、ベンチを回しつつまだまだアプリケーション (React, Perl, Go) がCPUを使っていることは確認済み。
そこで、Dockerで動いていて分散が容易な React, Perl, Go を 2〜5台目のホストで動作させ、1台目は nginx, Redis, MySQL という構成へ。1台目のnetwork転送量がちょっと心配だったけど、そこを詰めている時間的余裕がなかった…
5台構成にしたところ、MySQL が too many connections のエラーを吐いて接続できない現象を確認。
max-connections = 10000
になっている214
...??? と一瞬パニクりかけたが、あこれは systemd から起動して limit が掛かってるな、という見当が付いたので /etc/systemd/system/mysql.service.d/limits.conf
を適当に設定して再起動で解決。
[Service] LimitNOFILE=1000000 LimitNPROC=1000000
1台ずつ再起動テストをして、02〜05 は 01 にあった docker-compose でのOS起動時のアプリケーション起動設定がない、というのも発見したので /etc/systemd/system/multi-user.target.wants/isu.service
/etc/systemd/system/isu.service
を01からコピーして反映。
最終的には 17:48:35 に記録した 36,067 が提出スコアとなり、運営の再起動テストも通過。2位で準優勝しました。
他チームにスコアが見られる17時までは1万も行かない状態だったので、最後の1時間でだいぶ跳ねた感じでしたが、ここまで書いたとおり決して余裕があって潜行してたわけではありません…
予選も本選も、素晴らしい問題とイベントを提供していただいた出題者の皆様、運営の皆様に感謝します。ありがとうございました!
ISUCON6裏話Nightに酒を贈りたい方はこちら→ https://t.co/2mxdarwDKf
— edvakf (@edvakf) October 23, 2016
おや…? #isucon pic.twitter.com/PF2DpxwJ9n
— ISUCON公式 (@isucon_official) October 22, 2016
タイトル長い。 LambdaでGoが正式サポートされるのを首を長くして待ちつつ、Apex で Go を実行しています。
先日、API Gatewayで受けたすべてのリクエストをLambdaに丸投げすることができるようになりました。
これまではAPI Gatewayでいちいちマッピング定義を作るのが面倒で、いまいち普通のWebAPI的なものをLambdaで作る気がしなかったわけですが、これで行けるのでは…? と思って、catch all されたリクエストとレスポンスを net/http.Request と net/http.ResponseWriter で扱えるようにする ridge というライブラリを書いてみました。
Readmeそのままですが、以下のような Go のコードが API Gateway (プロキシ統合)+ Lambda + Apex で動きます。
package main import ( "encoding/json" "fmt" "log" "net/http" "os" "github.com/apex/go-apex" "github.com/fujiwara/ridge" ) var mux = http.NewServeMux() func init() { mux.HandleFunc("/", handleRoot) mux.HandleFunc("/hello", handleHello) } func main() { if os.Getenv("APEX") == "" { // ローカルで動かしたい場合はこっち log.Println("starting up with local httpd") log.Fatal(http.ListenAndServe(":8080", mux)) } // Lambdaで動く場合はこっち apex.HandleFunc(func(event json.RawMessage, ctx *apex.Context) (interface{}, error) { r, err := ridge.NewRequest(event) if err != nil { log.Println(err) return nil, err } w := ridge.NewResponseWriter() mux.ServeHTTP(w, r) return w.Response(), nil }) } func handleHello(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") fmt.Fprintf(w, "Hello %s\n", r.FormValue("name")) } func handleRoot(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") fmt.Fprintln(w, "Hello World") fmt.Fprintln(w, r.URL) }
*net/http.Request
に変換してアプリケーションに渡すridge.ResponseWriter
は net/http.ResponseWriter
interfaceを持っているのでそれに対してレスポンスを書き込むとすると、普通に Lambda で Go の webapp らしきものが動きます。
ユーザの書くコードは普通の Go の webapp と同様 func(http.ResponseWriter, *http.Request)
で行けるので、ローカルでは http を直接 listen するサーバとして動かしつつ、API Gateway + Lambda でも同じコードを動かせる……これはもしかして凄く便利なのでは!
制限とか
foo=1&foo=2
みたいなの) があると、入力Eventの時点でひとつになってしまうという現時点の制約があります。ちゃんとバイナリが扱えれば、画像変換サーバみたいなものにも使えて夢が広がる感じなのですが…
ISUCON 6 にチーム「morimoto組」で参加して、予選を通過して決勝進出することになりました。
ISUCONは過去5回のうち優勝3回、3位1回、出題1回、ということでもう引退(勝ち逃げ)しようかな…とも思ったのですが、今年は出題にも関わっていないので参加しないと完全に縁が切れてしまうし、それも寂しい。ということで。
チームメンバーは直前まで決まらなかったのですが、結局会社の新卒1,2年目( id:amusan , id:moshisora ) と組むことにしました。若いとはいえ去年と今年の社内ISUCON優勝メンバーです。(歳の差何歳だろう)
設営完了 #isucon pic.twitter.com/Beu4lLiYnC
— fujiwara (@fujiwara) 2016年9月18日
天気は悪いが見晴らしはいい会議室を確保して万全の体制 (まぶしいのですぐブラインドは下ろされました)。
言語は Perl です。
nginx.confはこんなかんじ。
http { upstream app { server unix:/var/tmp/app.sock; } upstream app_post { server unix:/var/tmp/app_post.sock; } include /etc/nginx/mime.types; server { location ~ ^/(css|img|js|favicon\.ico) { gzip_static on; expires max; access_log off; root /home/isucon/webapp/public; } location /initialize { proxy_pass http://app_post; } location /keyword { set $app "app"; if ($request_method = "POST") { set $app "app_post"; } proxy_pass http://$app; } location / { proxy_pass http://app; } } }
ここまでやった状態で14:40すぎに8万点ほどでトップに躍り出る。
やる気出てきた #isucon
— fujiwara (@fujiwara) 2016年9月18日
ここで、アプリケーションのプロセスを再起動せずにベンチを回していくと、どんどんスコアが上がっていくという現象を確認。2回目だと12万点ぐらい。 特にメモリ内に cache は作っていない (つもりだった) ので、何が原因なのかさっぱり分からず。
ここから、他のチームがスコアを上げてきたのになかなか上げられず苦しむ時間帯。
/
でoffsetが大きいクエリをentry using(id) の自己結合にこれでだいたい9万ぐらいだったので、このままだと予選通過はボーダー付近だった模様。
17:30ごろから2度目のベンチでスコアが上がる現象を解明するべく、個別にプロセスを再起動して切り分けしたところ、POSTを担当するプロセスを再起動しなければ速度が出る、ということを確認。こいつは Regexp::Trie のオブジェクトを永続化して持っているので、二回目は既に初回のベンチでキーワードが追加済みの状態になっていた (ので速かった)。
つまりこの状態では本来リンクになってはいないはずのキーワードがリンクになる状態。アプリケーションとしてはまずいんだけども、ベンチマーカーがそれを検出しても結果がPASSとされていればスコアも有効である、ということを運営とのやりとりで確認していたので、(多少良心が痛むものの) 突っ込むことに。
1回ベンチが走って追加された状態のキーワードをテキストファイルに書き出しておいて、initialize でそれを Regexp::Trie にaddしておくというコードを追加して、終了1分前にベンチqueue投入。18時の終了3秒前ぐらいにベンチが始まり、その状態で dstat をみていた限りでは14万点だしたときとおなじぐらい捌けてそう、というところで(最終的にスコアは知れずに) 競技終了。
結果、143,366で通過できました。
チームメイト二人ともなぜか Perl-5.24 を手元で動かせずに、手元でコードの確認ができない状態だったのが完全に想定外 (環境構築で30分ぐらいハマってたので「もうそれは諦めて、こっちで動かすので」という判断を早めにできたのがよかった…)。それ以外は、結構ちゃんと戦えたのかな、という感想です。
聞くところによると、htmlfy()の結果cacheは結構雑でも (リンク関係を検出はされるものの) スコアが出せたようなので、ここがもっと厳密だったら展開も変わってきたのかなあ、という印象はあります。(とはいえ、一発アウトにするのは出題側も誤検知が怖いんですよね…)
幸いにも、これで ISUCON 本選は6年連続で出場できるので、精一杯戦いたいと思います。運営の皆様、楽しいイベントを本当にありがとうございます!
「なんだかすごいことになっちゃったぞ」 pic.twitter.com/nv3IH5KwyY
— fujiwara (@fujiwara) 2016年9月18日
技術評論社から発行される「みんなのGo言語」という書籍の執筆に参加しました。本日、9月9日発売です!
Goは2009年に一番最初にリリースされたときにちょっと触っていて、このblogにもいくつかエントリを書いていました。 golang カテゴリーの記事一覧 - 酒日記 はてな支店
その後、実際にプロダクションで使うことがなかったのでしばらく離れていたのですが、 2013年頃からGoが盛り上がってるなという雰囲気もあり、
で、ここ数年はもっぱら Go をメインで書くようになっていました。公開している OSS としては
をはじめ、いろいろあります。Perlをメインで書いていたときも CPANに上げていたもの があるのですが、ほとんどがライブラリで、いわゆるアプリケーションは少数でした。
Goではライブラリよりもアプリケーションを多く公開するようになったのが面白いなと、今振り返って思います。これはGoが、デプロイのしやすいシングルバイナリで動作するアプリケーションを書くのに向いている、ということ無関係ではないでしょう。
Go製の OSS をいくつか公開していたことからか suzuken (id:suzu_v) さん、id:mattn さん経由で声を掛けていただいて、共著で執筆することになりました。雑誌記事は WEB+DB PRESS に書いたことがあるのですが、書籍は初めての経験です。
自分がどういうことについて書けるかを考えた結果 (言語自体には特に詳しくもないですし)、Goでこれまで書いて、本番で運用してきた実用アプリケーションを作り上げることについてのTips的なことならば書けそう。ということで、本書では第3章の「実用的なアプリケーションを作るために」という内容で執筆させていただきました。
内容は本当にTips的で、最初に一通り書いたところではあまりに断片的すぎた感があったのですが、編集のかたや共著者のレビューでお力添えをいただいて、なんとかまとめることができました。
本書は、最初からGo自体の入門書ではなく応用のための実用書、という位置づけで書かれていて、どの章も現場でGoをつかって仕事をする人に役に立つ内容になっていると思います。A Tour of Go や プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES) で言語自体を学んだ上で、実際になにかまとまったものを書き始める時に、よいお供になると思います。144ページと気軽に読める分量で、お値段も1980円(本体)と比較的安価ですので、是非お手にとっていただければと思います。
リリースパーティーを開いていただけるそうで、自分もビールを美味しく飲みにお邪魔する予定です。まだ定員に余裕があるようなので、こちらも是非よろしくお願いします。
機会をいただいて、技術評論社 WEB+DB PRESS vol.94 の特集1「実践スケーラブルAWS」を同僚の id:tkuchiki と執筆しました。本日8/24発売です。
どなたかが編集のかたに自分を推薦していただいたようで、インフラの特集で、というお話をいただいて、ここ数年はほぼAWSをメインで使っているのでAWS前提の内容でよければ…ということで寄稿することになりました。
[鍵は監視にあり!]実践スケーラブルAWS
1,2,6章を自分が、3,4,5章を id:tkuchiki で分担しています。
内容は、1台からはじめた小規模なサービスを AWS で100台規模までスケールさせて行くにはどうすればいいのか、という想定で、それに必要な要素や構築の際に注意すべき事をまとめてあります。
最近はクラウドで「スケーラブル」というとコンテナやサーバーレスやら、というかっこいい話になりそうなものですがそうではなく(そもそもそこまで仕事で突っ込んでないので)、普通にEC2上にアプリケーションサーバを立てるような構成でどう徐々に拡張していけばいいのか、という、どちらかというと泥臭い話です。
全体を貫く軸としては「監視」をメインにしていて、どのような項目をモニタリングして判断すればいいのか、という指針で各章に記述があるのと、監視だけで独立して章を設けてZabbixとMackerel、ログ集約(分量は少ないですが…)には Fluentd と Norikra などを取り上げています。
また、AWSらしいところということでオートスケールについても章を設けました。これは先日 YAP(achimon)C::Asia Hachioji 2016 mid in Shinagawa で発表した内容がベースになっていたりします。
他の特集も Kotlin、Electron と今話題の技術が取り上げられていて大変面白いと思いますので、是非お買い求めください!