水深1024m

技術的なメモとか日記的なもの

AWS NLB についてあれこれ

AWS ELB (ALB, CLB) には日頃からだいぶお世話になっているわけですが、新しい Network Load Balancer (NLB) がリリースされましたね。

新しいNetwork Load Balancer – 秒間数百万リクエストに簡単にスケーリング | Amazon Web Services ブログ

雑に言えば CLB TCP モードの次世代版というとこですかね。 ざっくりドキュメントを読みつつ、いくつか気になる点があったのでまとめます。 ドキュメントに記載されていない内容は私が検証した内容です。何か間違いがあればお気軽にご指摘ください。

パケットはどのように流れるのか

一応図にしておきます。なんというか懐かしい (とか言ったら怒られそうな) 流れですね。 ALB や CLB (HTTP, TCP 両方) ではロードバランサがそれぞれの通信を終端していわゆるプロキシのような役割を果たしているのと比較すると、NLB はパケットの送信元/宛先アドレスを書き換えるのみに見えます。LVS の NAT モードと同様の挙動というところでしょうか。あくまで戻りのパケットは NLB に送出されておりいわゆる DSR ではないように見えます。

f:id:kani_b:20170920130201p:plain

internet-facing と internal の違い

基本的に ALB と変わりありません。

internet-facing

  • 起動する AZ および subnet を選ぶ
    • subnet には IGW が attach されている必要がある (いわゆる public)
  • DNS name が割り振られる
    • 返すのは各 AZ ごとに起動時に払い出された public IP もしくは起動時に追加した EIP
  • バックエンドインスタンスは private subnet に所属していても問題ないが、VPC Route Table においてデフォルトルート (0.0.0.0/0) が設定されている必要がある

internal

  • 起動する AZ および subnet を選ぶ
    • subnet に IGW, NAT Gateway などが attach されている必要はない
  • DNS name が割り振られる
    • 返すのは各 AZ ごとにランダム (DHCP?) に割り振られたプライベート IP アドレス

NLB が返す IP アドレスについて

NLB は1つの AZ につき1つのIPアドレスを持ち、それぞれの IP アドレスへのトラフィックは必ずその AZ にルーティングされます。 例えば AZ-A に 10.0.0.0/24, AZ-B に 10.0.1.0/24 の subnet を作成して設定し、A,B それぞれの AZ にまたがる NLB を作成したとすると、DNS が返す IP アドレスは以下それぞれ2つになります。

  • internet-facing
    • xxx.xxx.xxx.xxx (AZ-A 用 public IP / EIP)
    • yyy.yyy.yyy.yyy (AZ-B 用 public IP / EIP)
    • バックエンドへのヘルスチェックにはプライベート IP アドレスが適当に切り出されて使われる
  • internal
    • 10.0.0.x (AZ-A の subnet から切り出した IP)
    • 10.0.1.y (AZ-B の subnet から切り出した IP)
    • ヘルスチェック元 IP アドレスは同じ

クライアントはどちらかを選択して通信を行うことになりますが、その際選択した IP アドレスが所属している subnet と必ず通信を行うことになるわけです。例えば xxx.xxx.xxx.xxx にパケットを送出した際、それが AZ-B のバックエンドインスタンスにルーティングされることはありません。 これが NLB のリリース紹介記事にも書いてある Zonality ってことですね。

Zonality って結局どういうことなのか

先述の通り NLB から見える IP アドレスは必ず1 AZ に紐付きます。 2AZ に NLB をアタッチした状態で DNS を引いてみると必ず2つの IP アドレスが返ってきます。よって、例えば以下のように Web - App - DB のような構成にした際の接続にすべて NLB を使っている構成であれば、先頭の NLB が Zonal であっても後半の NLB で他の AZ にバランスされてしまうように見えます。

f:id:kani_b:20170920130236p:plain

これはあくまでクライアントの実装による話です。 例えば glibc の getaddrinfo(3) は RFC 3484 Rule 9 によって定義されているように、複数の IP アドレスが返された際は longest match によって IP アドレスをソートして返します。上記の図のように、それぞれのインスタンスが同じ Subnet に存在する (= NLB が同じ Subnet にある) 場合、 getaddrinfo(3) を使っているクライアントでは、同じ Subnet, 同じ AZ の NLB エンドポイントが使われるようになります。 *1

Redis や memcached をはじめとした低遅延なデータストアを利用する際には AZ またぎのレイテンシが地味に効いてくるケースがあるため、NLB と Subnet が1対1になっていることは役に立ちそうです。 NLB を利用することで、普段は同じ AZ のインスタンスに接続しつつ、AZ が全滅した際には別の AZ に接続することができます。 ただし、この挙動はあくまでクライアントに依存するものであるため、上記のような挙動をしない場合にはクライアント側での対応が必要ですし、Subnet をまたぐようなケースでもクライアント側での対応が必要です。 また、AZ 間のバランスは接続元/接続先インスタンス共に適切に保たなければ、均衡が崩れて負荷が偏ってしまうことには注意が必要ですね。

障害時に使われる IP アドレス

IP アドレスと AZ が紐付いているので、例えば AZ-B のバックエンドインスタンスが全滅したしまった際に yyy.yyy.yyy.yyy あるいは 10.0.1.y をクライアントが選択すると、どのバックエンドインスタンスにもルーティングされないことになってしまいます。 ざっと実験した感じ、NLB では以下のような挙動をするようでした。(internet-facing, internal 共通)

  • 全ての AZ に healthy なバックエンドインスタンスが存在する場合、全 AZ の IP アドレスを返す
  • healthy なバックエンドインスタンスがいない AZ が1つ以上存在する場合、その AZ を抜いた IP アドレス (上記の例だと xxx.xxx.xxx.xxx) のみを返す
  • 全ての AZ でバックエンドインスタンスが全滅した場合、全 AZ の IP アドレスを返す

よって、片方の AZ が全滅するような障害においても、DNS name をベースとして (IP アドレスを直接べた書きなどせず) クライアントが接続しようとする場合、全滅した AZ に接続しようとしてタイムアウト…といったことにはならないようです。Route53 の Alias Record にも対応しており、こちらを設定した場合でも同様の挙動をします。 NLB 自体の IP アドレスは固定ですが、複数 AZ を利用する際に複数ある IP アドレスをそのままドメインの A レコードとして設定してしまうと、AZ が全滅した際でもクライアントが接続できない AZ の IP アドレスを使ってしまうリスクが残ることになります。 そのような設定をする場合は Route53 の Healthcheck および Failover 機能 (もしくは他社 DNS における同様の機能) を一緒に使うことになるでしょう。 Active/Active な状態にしておくことで、 NLB の DNS レコードと同じような挙動を実現できそうです。

セキュリティグループについて

NLB そのものにはセキュリティグループを設定できません。バックエンドインスタンスにおいてセキュリティグループを設定する必要があります。 バックエンドインスタンスには送信元 IP アドレスがクライアントのままになっているパケットが届きますので、これをベースにして設定をする必要があります。 インターネットに公開する場合、ターゲットとなるポートは 0.0.0.0/0 からのアクセスを許可、ヘルスチェック用ポートは NLB が起動している subnet の CIDR からのアクセスを許可すれば良いでしょう。

internet-facing な NLB を使う場合、クライアントからバックエンドインスタンスへの直接アクセスを許可する必要がある?

という書き込みをちらほら見かけましたが、答えはNOです。 バックエンドインスタンスがクライアント (インターネット) からの直接アクセスを受けるためには以下の3条件が揃っている必要があります。

  • バックエンドインスタンスが所属する subnet に IGW が attach されている
  • バックエンドインスタンスに public IP もしくは EIP が割り振られている
  • バックエンドインスタンスが所属するセキュリティグループに適切な許可設定 (e.g. 80/tcp に 0.0.0.0/0 からのアクセスを許可) がされている

NLB のバックエンドインスタンスとなるためには、このうち最後の条件のみを満たしていれば良いです。 (上述の通り、 VPC Route Table においてデフォルトルート (0.0.0.0/0) が設定されている必要はあります)
よって、例えば以下のように NLB は public subnet に起動し、private subnet のインスタンストラフィックを流す (インターネットからのトラフィックは NLB のみで受ける) といった構成も問題なく行えることになります。

f:id:kani_b:20170920130251p:plain

ただし、internal においてもセキュリティグループが利用できないという制約は変わりません。つまり、バックエンドインスタンスのセキュリティグループにクライアントインスタンスのセキュリティグループを許可設定してもアクセスができません。 細かい制御を求められるところではちょっと不便ですね。

まとめ

NLB の挙動や存在する制約などについてまとめました。 アクセス制御の点で少し面倒な部分はあるものの、ALB や CLB と比較してもより普通に (X-F-F や Proxy Protocol などを考慮せず) 使え、かつ IP 固定なのは便利だなと思います。あと起動がめっちゃ早いです。 Zonality もクライアント依存な部分はありますが個人的には便利 (欲を言えばクロス AZ と選びたい) だなと思いました。 ALB で受けられない, もしくは不便なユースケースは NLB を積極的に使うと便利そう。

Simple Icons の更新もお待ちしてます!!!

*1:気になる方は glibc の getaddrinfo.c あたりを読んでみると雰囲気がわかると思います

WEB+DB PRESS Vol.100 特集「対応必須!完全HTTPS化」を執筆しました

2017年8月24日発売の WEB+DB PRESS Vol.100 に「対応必須!完全HTTPS化 - 移行手順からつまずくポイントまで」という特集記事を執筆しました。 この特集は、2017年4月に会社の技術ブログに執筆した Web サービスの完全 HTTPS 化 - クックパッド開発者ブログ という記事をベースに、中身をほぼ新規に執筆したものです。

2017年1月にクックパッドという Web サービスを完全 HTTPS 化したので、その経験を4月にブログ記事という形で公開したのですが、これをご覧になった編集部の方からご連絡をいただき今回の話に繋がりました。

WEB+DB PRESS は8年くらい前、本格的に Web 技術者を目指そうかなと思い始めた学生の頃から時折読んでおり、私にとってもかなり身近な雑誌です。しかし執筆はというとVol.92 でちょこーーっとだけ Fluentd によるログ収集話執筆のお手伝いをしたくらいで、ほぼ初執筆に近いです。

特集について

章構成はこんな感じです。全25ページ。

  • 第1章: なぜ完全 HTTPS 化が必要なのか
    • Web サービスを安心して利用してもらうために
  • 第2章: 完全 HTTPS 化はじめの一歩
    • 証明書の選び方、構成の検討、テスト環境の構築
  • 第3章: HTTP リソースの HTTPS
    • mixed content を効率的に修正するには
  • 第4章: リリース時に注意すべきこと
    • 確認すべき事項と、ミスを防ぐリリースの順序
  • 第5章: クックパッド完全 HTTPS 化の影響
    • 収益、ユーザー、パフォーマンスはどう変わったか

クックパッドにおける完全 HTTPS 化をの経験をベースに、Web サービスを完全 HTTPS 化する方法について、その前提知識などから解説しました。 主に AWS を使った環境の話をメインに書いていますが、今回pixivさんに許可をいただき、コラムという形でオンプレミス環境における完全 HTTPS 化についても執筆させていただきました。 コラムなど含め記事全体を私一人で執筆しています。

HTTPS に対して思うこと

「今の時代、新しいサービスは HTTPS であることが多いし、これから解説する必要もないのでは?」と思う方もいらっしゃる方もいるかもしれません。僕も執筆のお話をいただいた時に正直少し思いました。 が、やはりインターネット全体を見渡してみると、まだ十分とは言えない状態にあると思います。 Google が公開しているレポート でも、日本は最下位 (もちろん取り上げられている範囲でですが) です。

記事でも書いていますが、HTTPS への移行はもはや Web サービスにとって避けられないでしょう。利用者の安心や安全を守るということに加えて、これから使われるであろう新しくて面白い技術の多くは HTTPS をその前提としています。 HTTPS への移行メリットがセキュリティだけであった時代はとうに終わりました。みんながもっと楽しくて、安全な次の Web に行くためにも、HTTPS への移行は必要です。

また同時に、それはトラフィックの大小で決まるものではないと思います。「うちのサービスはトラフィックも少ないし、別に良いかな」と感じる方もいらっしゃるとは思いますが、そのサービスのユーザーも"インターネットユーザー"の一人です。 利用者が安全であることを確認しながら使うリテラシーも必要なのかもしれませんが、最低限"利用するどのサービスも HTTPS になっている"状態を作ることで、インターネットを使うために知らなければならないことをわずかでも減らせるんじゃないかなと思います。

執筆について

執筆は、編集の方と GitHub の上で行いました。既に markdown を使った快適な執筆環境ができており、執筆の上で不自由は全くありませんでした。これは本当にすごいなと思います。
進捗が悪い時期も適切にフォローいただき、その後の校正や本当に最後の最後まで修正を一緒に進めていただいた編集部の池田さんには本当に感謝しております。

また、執筆にあたり職場のみなさんや Jxck さん, catatsuy さん にもレビューをいただきました。貴重なレビューをいただき (また catatsuy さんにはブログ記事2本 前編 後編 のコラム化についても快諾いただき) 本当に助かりました。

おわりに

HTTPS というプロトコルの説明や証明書についての解説に加え、 CSP や HTTP/2, TLS1.3 など次世代の技術にも触れています。あまり下手なこと書くと槍が飛んできそうだな 😇 などと思いつつ、気をつけて書いてはいるつもりですが、なにぶん奥深い世界ですので、お気づきの点があれば温かい目でご指摘いただければなと思います。

完全 HTTPS 化について、何がボトルネックになっているかは各サービスによって当然違います。そもそも必要性が認識されていないかもしれないし、担当者は完全 HTTPS 化したいと思っていてもリソースの問題で動けないかもしれない。あるいは技術的な問題や心配で先に進めていないかもしれない。 1 しかし、かつて考慮すべきだったことの多くは現代では心配する必要がなくなっています。もちろんケースによりますが、多くの場合そんなに難しくはない、のだと思います。

本特集は、実際の構成や設定にとどまらず、同僚や上司への説明などにも利用できるよう、できる限り使いやすく書いてみたつもりです。 特集をご覧いただいて完全 HTTPS 化に進めた、なんていう声をもし聞けたなら嬉しい限りです。

記念号となる Vol.100 には、私の特集のほかにもとても面白い特集やエッセイがたくさん掲載されています。本日献本いただいた書籍を読みましたが、とてもおすすめです。 完全 HTTPS 化に興味があってもなくても、ぜひお買い求めください!


  1. このブログが HTTPS ではないのでは、というお声もあるでしょう。しかしはてなブログHTTPS 化も進んでいると伺っており、またユーザーが記事などを自由に書けるようなサービスにおける完全 HTTPS 化は難易度がかなり高いと思っていますので、気長に待つことにしています :)

MacBook (12-inch) で給電しながら 4K 60Hz 出力したい

タイトル通りの話。 仕事では持ち歩き用に MacBook (12-inch) を使っています。軽くて薄いので持ち運びには最高。

最近自宅に PS4 Pro を買ったので、思い切ってモニタを4Kに統一しました。フィリップスの31.5インチのやつ です。 で、この 4K モニタに MacBook を繋ごうとするわけです。Apple のサポートページを見てみましょう。
Mac で 4K ディスプレイ、5K ディスプレイ、Ultra HD TV を使う - Apple サポート

一見問題なく対応していそうなのですが、重要なのはリフレッシュレート。 HDMI 接続の場合ほぼ 30Hz にしか対応していない。個人的には 30Hz でモニタ使うのは無理。目が痛くなります。 というわけで、快適に 4K モニタを使うためには 60Hz で使う必要があります。 4K モニタを 60Hz で使うためには、以下の方法で出力する必要があります。

  • Displayport 1.2 (以下 DP)
  • HDMI 2.0

PC 向けでこれ以外の規格で使えるものは無いと思います。 しかし、世の中の 4K 対応製品は実際には HDMI1.4b までしか対応していないものがほとんどのため、期待して使うと 30Hz までしか出力されないことになります。 やっかいなのは、Mac 内蔵ポートはもちろんのこと、Apple から出てるいかなるアダプタでさえもまだ HDMI1.4b しか出力できないということです。

mini DP から DP への変換アダプタはサードパーティから数多くリリースされていますので、mini DP があった頃の MacBook をお使いのみなさんは 迷わずこれを使えば良いです。 問題はこのポートが全て USB-C という (現状) 地獄のポートに置き換えられてしまった新 MacBook たちです。 Apple は現状 USB-C から HDMI 出力できるアダプタをリリースしてはいますが、残念ながら前述のようにこの HDMI は HDMI1.4b なのです。よって 30Hz 止まりです。 Apple 純正, あるいは公式アナウンスしているアクセサリのみで 4K 60Hz を使いたいなら LG UltraFine 系の USB-C 対応モニタを買うしかないのです。マジか〜

さて、USB-C から DP あるいは HDMI2.0 を出力する方法について。 DP で出力するなら、USB-C から DP への変換ケーブルがありますので、これを使うと一発です。 HDMI2.0 はいくつかアダプタが出ています (必ず HDMI2.0 と明記されたアダプタを買いましょう) が、アダプタに加えて HDMI ケーブルも Premium HDMI ケーブルという 認証を通ったケーブルでないといけません。これが結構高くて、1mでも4000円くらいします。 USB-C to DP ケーブルを買うのが一番だと思います。

これでめでたしかと思いきや、 MacBook (12-inch) は最高に薄くてクールなので USB-C ポートが1つしかありません。 給電もこのポートから行うわけですので、前述のケーブルやアダプタを使うと給電できなくなってしまいます。

これを知ってから必死に探して、ついに使えるものを見つけました。それがこちら。

HyperDrive USB Type-C Hub with Mini DisplayPort (for 2016 MacBook Pro & 12" MacBook)www.hypershop.com

HyperJuice (バッテリ) とかも出してる Sanho のプロダクト。 USB-C 一つから給電可能な USB-C, miniDP, microSD, USB2.0 な USB-A を2つ出すことができます。 利用中の画像は以下です (画面きたないのは許して) 。

書いている通り、コネクタが少し浮いてたりそもそも USB-C コネクタ一つで支えるという構造がかなり不安ではありますが デスク上で固定して使う分には全く問題ないです。 使い始めてから1ヶ月くらい経ちますがまったく問題なし。 価格は送料込みで$60~70くらいだったと思います。(売り切れ中のため確認できず)

これで今のところ快適に 4K モニタを利用できています。執筆現在で売り切れ中ですが、興味のある方は登録して入荷を待ちましょう。 ただ、MacBook 自体のスペックが低い & 2015年モデルのためか、4K 出力しているとそもそも CPU を 20~30% 持っていかれてしまっているのが 結構つらいです。WWDC 2017 で新しいモデルが出たりして良い感じになるといいな。

git-secrets の Homebrew Formula 作った

最近流行りの AWS の認証情報とかを github で大公開する事故を防ぐためか AWS が作った git-secrets という git plugin があります。 インストール手順はレポジトリを clone して make install するような感じだったので、初めて Homebrew の Formula 書いて Homebrew に取り込んでもらいました。 (git-secrets 自体シンプルな git plugin なので全く大した内容ではない)
git-secrets 1.0.0 (new formula) by kanny · Pull Request #47322 · Homebrew/homebrew
というわけで Mac && Homebrew 使ってる人は

$ brew update
$ brew install git-secrets

すればインストールできます。

使い方は別の方が Qiita にまとめてくださっていますね。 クラウド破産しないように git-secrets を使う - Qiita

自分が何か作るときは認証情報はだいたい1ファイルに認証情報だけまとめて gitignore に書くようにしてるのですが、git-secrets 使うとそれでも事故るようなケースを防げてとても良いですね。 初心者向けハンズオンとかでも、

  • git init
  • git secrets —install
  • 認証情報をまとめたファイルを作る
  • .gitignore を作る

くらいまで、そんなに時間かからないと思うし紹介できると良いのかなー。

Pull Req 取り込んでもらう間に眺めてて気づいたんですが、Homebrew には毎日すさまじい量の Pull Req が来ています。 Formula 書くのも楽なので、取り込んでもらえるとみんな幸せになれそうなものは書いてみると良いかも。もちろん雑に書くのではなくちゃんとドキュメント読んで brew audit 通して、ですよ。

これを数人のメンテナで (日々寄せられる Pull Req のレビューとかも全て) 回していて、すごいなあ。

MSPJ マイグレーションコンペティション2015fall に参加してきた

MSPJマイグレーションコンペティション2015fall というイベントに出場してきました。 かなり古いシステムがオンプレっぽい環境にあるのでクラウドにいい感じに移す、というコンペティションです。 参加して敗北したのですが、初回ですし次回もぜひ開催いただければと思っているので、どういう感じだったかまとめたいと思います。

ルールやチームについて

やることは上述しましたが “古いシステムをいい感じにマイグレーションする” です。 イベントページから引用しておきます。

- お題: いま動いているふるーいシステムをバージョンアップしてね
 - できれば利用者に影響なしでやりたい
 - できれば冗長化したい
 - できればさくさく動くようになると嬉しい
 - できればプロビジョニングコードが欲しい
 - できればサーバに関する資料があると嬉しい
- 実施した内容と結果については報告してくださいね
- 背景という名の発注者の弁
 - もうすぐサポート切れるって言うし、セキュリティが心配だし、でもそんなにきちんと管理する手間もとれないし、わかるひともいないし、今のうちになんとかしておきたいんだよねー
 - あんまり何回もいじりたくないから、できるだけ長く使えるようにしてほしいなぁ

当日配布されたお題もほぼこれと同様の内容でした。 チームは当日編成されるので、あらかじめチーム組んでおいで出るみたいなことはできません。

参加者は30歳以下という縛りがあったこともあり、20代のエンジニアが幅広くという感じでした。僕のチームも社会人3年目、3年目、2年目というチームでワイワイしてました。
Slack に運営との連絡用 private chat ができ、僕らは GitHub の private repo に issue などを立ててメモを書いたりするという感じで進めました。 制限時間は10:30 過ぎから 17:00 までの6時間ちょっと。

初期環境

初期環境とさくらのクラウドのアカウント (後述) が渡されて競技開始です。お題はみんな大好き wordpress でした。
使われていたのは CentOS 5.x で、 PHP 5.1 と MySQL 5.0 の環境。PHP が古すぎるので wordpress アップデートもできないし、MySQL も特に設定はされておらず MyISAM のテーブルがあるだけという状況。
また、チームごとに teamN.example.com という単位で DNS のゾーンが分割されていて (ドメインは例です)、その NS を担う bind が立っていました。 始まって30分くらいで大体の状況は把握して新環境の設計をざっくり作り始めました。

設計

使えるサーバ台数などに特に制限もないクラウド環境だったこともあり、いわゆる普通の3層構造を当初作ろうかと話していました。
が、依頼者の背景に “趣味と実益を兼ねて作っているブログ” という話があり、お題にあるようにあまり弄りたくない、きちんと管理する手間も取れない、ということでサーバ台数とコストを抑える (ただし “できれば” の部分はできるだけ満たす) という方針で最終的には作っていました。

移行

初期環境と同時に、さくらのクラウドのアカウントを渡され (好きに使って良いとのことだった) これを使って新環境を作っていきます。 さくらのクラウドをまともに使うのははじめてだったので、とりあえずドキュメントを読みながら石狩リージョンにルータ+スイッチを作り、新環境の App サーバと DB サーバ (設計方針変更により最終的には1台に統合された) を作ります。 サポート期間が長いものを、というところと、チーム的に手に馴染んでいそうということでディストリビューションとしては CentOS7 を選びましたが、個人的には systemd や firewalld がっつり触っているわけではなかったこともあり少しもたつきました。

ディストリビューションが CentOS7 になったので、ApacheMySQL をパッケージからインストールしていけば現代で使われているバージョンになります。 CentOS7 からは MariaDB が標準採用されたという話は知っていたけどチームメイトがインストールしてくれたのは MySQL で、おや?と思ったのですが、さくらのクラウドの public image では rpmforge とか remi とか MySQL community repo とかが最初からインストールされているのですね。へーと思いました。

馴染みの道具は大体揃ったので、旧環境から新環境へのレプリを設定して (wordpress のデータベースだけ)、新環境の App を作っていきます。レプリはチームメイトがいい感じに設定してくれたので、移行先のスレーブを先にガッと InnoDB に ALTER しつつ buffer pool など基本的な設定を入れました。wordpress 本体はそのままコピーして終了。
旧環境でも新環境でも25秒くらいかかるクエリがあってこれはなんだろと思ったら、wordpress のテンプレートタグで SQL_CALC_FOUND_ROWS が使われてるみたいな話があるのですね。移行が第一目標だったので勝手にテンプレート編集するわけにもいかんよな、と思いつつクエリキャッシュが効きそうなケースだったので有効にしたら収まりました。

Web サーバはまあ無難だよねというところで Apache + mod_php になりました。APC も入れたけど先述のクエリのほうが負荷としてはとても高かったので効果は目立たなかったと思います。

新環境の準備が大体できたので、動作確認をしてとりあえず旧環境から新環境に移行していきます。さくらのクラウドでは GSLB が使えるので、そこに切り替えることにしました。

実際に気づいたのは移行よりかなり前ですが、クラウド環境への移行だし DNS サーバは立てずにさくらのクラウドに用意されてる DNS サービスに移せば自前より良いよね、という話を当初していて、いざゾーンを作ろうとしたらゾーンが登録できない旨のエラーが返ってくるというところで少しハマりました。

ドキュメント を読むと、”上位ドメインが当サービスで提供するDNSサーバにNSが向いて” いる、あるいは “上位ドメイン、および下位ドメインが当サービスで既に登録されて” いるものは使えないという記載がありました。

ハッと思い運営の方に質問したところ、予想通り移譲されているドメインの上位ドメインがそもそもさくらのクラウド DNS で既に運用されているとの回答を得た + “具体的に作業内容を伝えれば” その通りに作業をしてくださるとのことだったので、自分のチームに移譲されているドメインの NS 設定を消して自チームのサービス用ドメインへの CNAME を直接設定してもらいました。(この方法をとったのは我々だけだったらしい)

移行は無事一発で済んだので、旧環境からのレプリ設定などを消したり後始末。これで旧環境には用がなくなりました。ここまでで残り1時間30分くらいだった気がする。

冗長化

チームメイトが既に東京リージョンにもサーバを作っていてくれていたので、ネットワーク設定などをざっと入れつつアプリをコピーし、データベースは石狩リージョンに向けました。スレーブは東京リージョンのサーバにもありましたが、このフェイルオーバーまでは作りきれずドキュメントだけ書いておこうという方針になりました。
さくらのクラウドのスイッチはリージョン間接続ができるので、東京リージョンと石狩リージョンの間で L2 ネットワークを結べて便利でした。 GSLB に東京リージョンのサーバ IP を書いたので、これで「石狩が落ちると手動で切り替える必要があるけど東京が落ちても耐えられる」構成となりました。 かなり不完全ですが。。。

プロビジョニングスクリプト

当初は普段使っているItamae などでできる限りスクリプトを作るか、という話をしていたのですが、時間が足りずここは諦めることにしました。 ISUCON などで「プロビジョニングスクリプトから作っていると大抵時間がなくなって崩壊する」というのはわかっていたので、最初から手を付けず、あとから諦める判断だけしたのは良かったと思います。

終了、そして敗北

そうこうしているうちに時間は16:30と終了寸前。チームメイトがかなりきっちりしたサーバ資料を書いていてくれていたのでそちらは完全に任せきりで、こちらはざっくりと技術的な改善点や移行時の手順をメモとして残しつつ、忘れられていた運営チェック用アカウントの作成と疎通確認、再起動耐性の簡単なチェック (実際再起動している時間はなかったのですが) などをしていました。再起動耐性については特にどこにも書いてなかった項目ではありますが ISUCON のトラウマみたいなもので…

17時までに Slack 経由で資料を提出して終了となりました。 懇親会はピザや寿司やお酒などをいただきつつ、チームの構成などについて話して盛り上がっていました。

懇親会も半ばとなったところで結果発表。残念ながら我々のチームは入賞を逃しました。

講評

講評では、”MUST 要件をちゃんと考えて適切な作業やコミュニケーションをしよう” というもっともな話がまずあり、そもそも移行に失敗した (旧環境から NS を移すのを忘れていた?) チームがかなり多かったこと、移行成功したのは数チームであったものの、我々のチームは1つだけ書き込みのテストをしたテストデータが残っていたことが入賞を逃した理由として説明されました。 移行プロジェクトということで、確かに移行したアプリに勝手にテストデータ書き込まれてそれが残ってたら怒られるのはもっともだなーという感想を得ました。アプリを書き換えないという選択はしたのにテストデータはスルーしたというのも甘かったですね。。。

ただ、他チームの話を聞いている限り、ゼロダウンタイムでの移行 + 不完全とはいえ冗長化 + パフォーマンスチューニング + ドキュメントの作成、を達成したのは我々のチームだけのようでしたので、正直かなり悔しかったです。

これがなかったらおそらく優勝していたであろう内容だったので、トップスコア fail した ISUCON5 と同様、最近詰めが甘いことが多すぎるということへの反省と力不足を痛感しました。

最後に

ISUCON 同様、時間が限られた中、チームで何らかの作業をすることは、技術スキルや優先度の判断など個人の能力に加えてチームワーク(というかコミュニケーション)もかなり重要になるので、個人的にはかなり良いトレーニングになるなと感じています。チームがランダムということで若干の緊張感はありましたが、チームメイトもとても良い方々で、バランスの悪いことなどに対してお互い指摘が入れられるような形で作業が進められたのはとても良かったです。

また、さくらのクラウドをほぼ初めて使わせていただいたのですが、普段 AWS や GCE などを触っているとあまり考えることのないレイヤを触っていく必要があり、「ネットワークを作っている」感が強いなーと感じました。このあたりは、求める抽象化の度合いやコスト感 (金銭的なものだけではなく) によって他社クラウドと住み分けがされていくのだと思います。 個人的には、NIC の付け外しがオンラインでできたり、マネージドな DHCP サーバがあったりすると嬉しかったです。

長々と書いてしまいましたが、自分と同じくらいの世代のエンジニアと交流でき、かつ個人的にかなり反省するところもあり、色々と学びがありました。 運営いただいた日本MSP協会のみなさま、ありがとうございました。次回開催も楽しみにしております。

ISUCON5 本選でトップスコア fail した

ISUCON5 に .dat として @y_matsuwitter@TakatoshiMaeda で参加してきました。本選6位だった昨年に引き続き、今年で2年目です。 幸運にも予選を(2日目)1位で通過することができてたのですが、主にネットワークやミドルウェア周りを担当していた自分としては結構なニート状態だったので、本選ではもうちっとは貢献したいなーという気持ちがありました。

Go - ISUCON5予選でスコア34000を出す方法 - Qiita

で、本選ですが、アプリケーションレイヤでやったことは @y_matsuwitter の記事にほぼ全て書いてあります。 ISUCON5本選にてスコアトップの18万点でfailしました - Qiita

サーバ構成に関することも書いてあるので僕が記事書く必要もなさそうですが、せっかくなのでやったことをちょこまかと書きます。

基本的なセットアップ

@TakatoshiMaeda が完璧に仕上げたセットアップスクリプトで一撃でした。Ubuntu 15.04 + systemd だった予選と違い Ubuntu 14.04 + upstart + supervisord だったわけですが、そのへんの差異も特に気にせずドーンという感じです。 @TakatoshiMaeda++

開幕 tcpdump

改善に限られる時間が限られており、特に今回の問題では外部 API という要素が入ったこともあって、可能な限り早い段階でそれらを含めた全体像を把握する必要がありました。 アプリケーションレイヤの改善を僕以外の二人に任せていたので、アプリケーションの変更をせずある程度の分析を行っておきたいと思い、ベンチマークのパケットダンプを取っていました。 把握できたのは大体以下のようなことです。

  • ベンチマーカが送ってくるヘッダ、リクエストパターン
    • Accept-Encoding: gzip とか (最終的には忘れてたけど。。。)
  • 外部 API が返してくるヘッダ
    • リクエスト/レスポンスの仕様
    • tenki API が Last-Modified を返していたのはこの時に分かってた
  • 外部 API に接続するときに DNS リクエストをしていない
    • /etc/hosts に書いてあった
    • ハードコードしても問題ない

まあ、初手の分析としては十分なのかなーと思いました。 で、API の中にわざわざ HTTPS のエンドポイントが含まれてるのを見かけたので、おもむろに nghttp2 とリンクした curl をビルドして接続したところ HTTP/2 接続に成功しました。ベンチマーカーや外部 API に仕込まれていた要素については開始45分くらいで大体把握できていたと思います。

js の改変

一通りのチェックが終わり、大体の方針を決めて @y_matsuwitter が作業に入り、僕と @TakatoshiMaeda は airisu.js から行う XHR 先を分散できないかという検証をやっていました。結果としてそもそも js の改変そのものがどのようなレベルでも許されていなさそうなことが分かったのですが、CORS 周りの設定にハマり少し時間を無駄にしてしまったのが後悔でした。そもそも静的ファイルの変更がどのくらい許されるか自体はもっと小さな変更で確認できたはずで、検証すべきことを切り分けず最小限のことだけをやらなかったのは大きなミスでした。

ミドルウェア類の設定

正直ここについては、ざっと絵を描いた段階でチーム3人とも意見が一致していたこともあり、"あとは書くだけ"状態だったので特に考えることもハマることもなかったです。nginx, Redis, kernel 周りの設定など必要のあることをやっただけ。 @y_matsuwitter の Redis 実装をマージして1台で実行して13万点を超えたので、そこから複数台構成になるように修正。 先頭に置いた nginx (静的ファイル配信 + リバースプロキシ) で CPU affinity を固定してあげたりするとこのマシンは CPU を使い切れる状態に達しました。

終了まで

ちょうどこのタイミングで行われたベンチマーカーの修正により "ちゃんと fail するようになった" バグが最後まで取りきれずに敗北することになります。 正直この修正が発表された時はあまり真剣に考えてなかったのが痛かったです。会場内で2つだけ用意された会議室 (先着順で使える) を扉を閉めて使っていたこともあったのかもしれないけれど、アナウンスはちゃんと聞いて自分たちへの影響を確かめようというのは反省でした…

ミドルウェア側での大きな構成変更は3台構成にしてからはほぼなく、先述のバグの他にも fail がいくつかあったため他の2人にその修正をひとまず任せ、再起動耐性のチェックを行いました。バグが最後まで取りきれなかったため、再起動テストをそもそも行うことができなかったのですが、結果として再起動後もきちんと動いていたようなのでまあここはよかったのかな。。。 その後はバグ取りのサポートなどをしていましたが、結局取りきれず提出。

他にやりたかったこと

大体のことは @y_matsuwitter の記事に書いてあるのでそちらを。 他には ken API のデータを見ていて、ああこれはみんな大好きKEN_ALL.csvじゃないか、ということでこれを作りなおしてそもそも API リクエストをやめる、という案はありましたが、それ以前の問題が多すぎたので却下。

感想

Cache-Control に泣いた去年と比べ、初手でそういった目に見えないポイントを洗い出すことができていたのは進歩だったかなーと思います。スコアがどうだろうと fail というのは変わらず、”僕と @TakatoshiMaeda がこまい改善を積み上げておいて @y_matsuwitter がかめはめ波を撃つ” というのが毎回のスタイルではあるのですが、もっとやれることはあったなーと思うし実力不足を痛感しました。 あと1つのfailがなければスコア的には優勝だった、というのは事実そうなのですが、このfailを落ち着いて潰せるかどうかというところに大きな差があったわけで、そういう意味でも「次やったらきっと勝てる」というレベルの話でもないよなーという実感があります。悔しい。

とはいえチームとしての動き方も毎回良くなっていることは確かなので、来年は足回りの力をがつっと上げて優勝しに行きたいと思っています。

今回は、予選本選通して特にベンチマークがとても快適だったのが印象的でした。 本選の Microservices 問題も、自分としてはリアリティのある問題だったこともあり楽しかったです。 予選、本選、懇親会 (ハロウィンで渋谷の治安が崩壊してましたが) どれをとっても最高でした。関係者のみなさまありがとうございました!来年もぜひよろしくおねがいします。

AWS re:Invent 2015 これが見たいリストと tips とか

来週から AWS re:Invent 2015 ですね。 今年は幸運にも 無料で行ける ことになったし、日本からの参加者も多いようなので 気になってるセッションなどについて書いておきます。

選び方

セッションは カテゴリ+レベル という表記がされていて、自分の興味分野やレベルに合わせて選びやすくなっています。 まあ普段 AWS を使ってる人であれば Level 4 (Expert) を中心に3 (Advanced) のもので興味のあるやつを拾っていくと良いんじゃないかなーと思います。

Deep Dive 系セッションについて

○○ Deep Dive というタイトルの、AWS の SA や PM が担当しているセッションが多く用意されています。(だいたい Level 4)
だいたいドキュメントに書いてあることの話かと思いきや、書かれていない内部実装の話や初公開される数値 (ベンチマークなど) 、さらにはしれっと新機能がアナウンスされることがあります。VPC ClassicLink とかそうでしたね。
ただ、資料がよくできていて、知りたいことは大体書いてあったりするので、これらのセッションに行きすぎてもあんまり意味ないかなーと最近は思っています。 新サービスの Deep Dive もいきなり発表される (そしてすぐ埋まる) ので、気になる人は早めに行きましょう。

ユーザセッションについて

AWS の人ではなく、AWS を使っている人たちのセッションです。Netflix や Riot Games (LoL 作ってる会社) など日本でも知られているような規模の会社の話が聞けます。
去年行った時は Chaos Engineering でおなじみ Netflix の障害挿入に関する話とか、Adroll が100万 req/s を 5ms 以内で返す話 とか見てて面白かったです。
ただ、スポンサーセッションもあって、自社製品の紹介がメインみたいなセッションもあるので、abstract をよく読んで決めたほうが良いと思います。 ホテル内はアホかってくらい広いので、あーやっぱ違うわと思ってから移動するのに結構時間を食います。

個人的に気になってるセッション

まあだから何という話ですが、個人的に気になってるセッションについて簡単に書いておきます。選んでる時にメモつけたやつもそのまま載せているので参考までに。間違ってたこと書いてたら教えてください。
個々のセッションへのリンク貼るのはめんどうだったので、気になる人は Session Catalog をどうぞ。

  • ISM301 - Engineering Netflix Global Operations in the Cloud
    • Netflix のオペレーション全体像について聞けそう
  • STG403 - Amazon EBS: Designing for Performance
  • CMP405 - Containerizing Video: Creating the Next Generation Video Transcoding Pipeline
    • 動画変換を ECS や Lambda, S3, EFS (!!) などを使ってうまいことやってる話っぽい。SONY (グローバルのほう) の人
  • GAM402 - Turbine: A Microservice Approach to Three Billion Game Requests a Day
    • Turbine という Warner Brothers Games 傘下のゲームスタジオがゲームバックエンドを microservices で作っている話
  • CMP404 - Cloud Rendering at Walt Disney Animation Studios
    • 書いてあるのそのままだけど、Walt Disney のレンダリング環境に関する話
  • SEC302 - IAM Best Practices to Live By
  • SEC312 - Reliable Design and Deployment of Security and Compliance
  • SEC304 - Architecting for HIPAA Compliance on AWS
    • 病院の臨床情報とかを共有するサービスで AWS を使いながら HIPAA 準拠する話
  • ARC403 - From One to Many: Evolving VPC Design
    • 毎年おなじみのセッション。VPC を使うネットワークアーキテクチャについて、毎年のアップデートを盛り込みながら最新ベストプラクティスみたいなのが聞ける
  • CMP407 - Lambda as Cron: Scheduling Invocations in AWS Lambda
    • セキュリティベンダーでおなじみ Sophos のエンジニアのセッション。タイトルで吹いた
  • DAT407 - Amazon ElastiCache: Deep Dive
    • ElastiCache の Deep Dive と Riot Games の話が聞ける
  • SEC320 - AWS Security Beyond the Host: Leveraging the Power of AWS to Automate Security and Compliance
    • evident.io のスポンサーセッション。Intuit (会計ソフト) の DevSecOps の話も聞けるぽい
  • SEC402 - Enterprise Cloud Security via DevSecOps 2.0
    • 最近ちまちま聞く DevSecOps についてのセッション
  • SEC401 - Encryption Key Storage with AWS KMS at Okta
  • SEC326 - Security Science Using Big Data
    • これも IntuitAWS が吐くセキュリティ系のログをうまいこと解析する話っぽい
  • CMP403 - AWS Lambda: Simplifying Big Data Workloads
  • NET404 - Making Every Packet Count
    • 実践ハイパフォーマンスEC2ネットワーキング
  • CMP310 - Building Robust Data Processing Pipelines Using Containers and Spot Instances
  • NET402 - Consolidating DNS Data in the Cloud with Amazon Route 53
  • SEC403 - Timely Security Alerts and Analytics: Diving into AWS CloudTrail Events by Using Apache Spark on Amazon EMR

そもそも時間が重複してるとか、予定があるとか、体力的な問題 (結構体力使う) で絶対全部は回れないんですが、このへんの話を聞きたいと思っています。あとはせっかく現地行ってるので、セッション後に細かい話を直接聞きに行ったりするとよさそう。
ランチ食べながらやる BoF とか, サービスチームと話ができる Ask me about コーナーとかもありますね。コミュ力

ちなみに全セッション基本的に先着順で、人数上限が設定されてるセッションだと waitlist とか表示されてることもあるのですが、特に関係なく先着枠に入れば入場できるはず (逆に Scheduler に入れてても入場できない) です。

その他

内容が一新されて ISUCON みたいになってる GameDay とか、 ホテル中のバーが貸し切りで無限に飲んで話せる Pub Crawl とか、 Pub Crawl の腹ごしらえに便利っぽいチキン大食いイベントの Tatonka Challenge とか、 人数規模が爆発してついに会場が隣のホテルの駐車場という謎スケールになった re:Play とか、 セッション以外でも面白イベントがいろいろありますね。英語力のなさには定評があるけど勇気を出してがんばっていきたい。

はー楽しみだ。参加されるエンジニア各位ぜひ声かけてください。よろしくおねがいします。