たごもりすメモ

コードとかその他の話とか。

MANABIYA.tech にいってきた&しゃべってきた

manabiya.tech

こちらのMANABIYA.techというカンファレンスでインフラ方面のセッションオーナーであるさくらインターネットの田中さんから何かどう? というお誘いがあったので、最近考えてたことを話すいい機会だと思ってひと枠しゃべってきた。あと、同トラックの前佛さん、長野(kazeburo)さんといっしょにパネルディスカッション的なやつも(モデレーターは田中さん)。

会場は以前にTDの社内イベントで使ったことがある、秋葉原の3331というところで、小学校跡地をイベントスペースに改装したところ。こういうところ、いいよなー。雰囲気があって。とはいえ元の建物がモノだけにひと部屋のサイズは小さめになってて、これはカンファレンス会場としてはちょっときびしいですね。

しゃべってきた

DockerとKubernetesの名前はおそらく多くのソフトウェアエンジニアが知っていると思うけど、Kubernetesというのは実際には分散処理基盤のコントローラに他ならなくて、これらはポッと出てきたものでもなんでもなくて、過去に分散ストレージあるいは分散処理などの流れがあって発展してきたものだと思うんですよー、みたいな話。このあたりを広めに見られていない人にとって、ざっくばらんな教養めいたものになるといいなと思って話した。
これはKubernetesがGoogleにおけるBorgのOSS版であることを考えれば明らか*1とはいえ、まあ、まあ、誰にでも公開されているものをベースに明らかな歴史として組み立てるのって大事だと思うんですよね。

またタイトルやトレンドへの名前のつけかたに困って "Modern Systems" というデカい単語を使ってしまった。話したときに最初にちょっと言ったけど、誰しもがこういうツールあるいは考え方を採用すべきだと思っているわけではなくて、とはいえそれでも「全体として進んできた/これからも進んでいく方向」みたいなところに分散処理やコンテナ化みたいなものが(今のところ)あるとは思っていて、それらをひっくるめて "Modern Systems" と言ってしまった。これはここにも注記しておく。

面白かったという反応をいくつか見聞きできたので、やれてよかった。40分の制限時間のところを5分オーバーしたのは反省しております。動画は公開されるのかな?

そのほか

パネルディスカッション的なのは、そもそも現代におけるITシステムの「インフラ」ってのはなんなんですかねー、みたいな話を多くしていた気がする。まあ、もうハードウェアをがんがんいじるお仕事も少ないですからねえ。
これは自分がそこで言ったことでもあるけど、ソフトウェアの割合が大きくなってくると、昔は会社に所属して案件ベースでしか試せなかったこと(ハードウェアをあれこれいじり倒す)よりも自分のPCででも動くものが仕事の中心になってくるので、個人でやれる範囲が広くなっている、ということだ。これは歓迎すべきだと思う。面白いこといろいろやっていきましょう。

で、お昼を挟んでふたつ話したら気力も体力も尽きて、あとはだいぶダラダラしていた。おしまい。

*1:……なんだけどこのあたりは話しはじめるとGoogle内タイムラインとOSS的タイムラインで矛盾が生じるのでしなかった、しはじめたら時間がいくらあっても足りない

Golangの defer をRubyでも使いたい

前にRubyでtry-with-resourcesが使いたいという話を書いてそのときにリリースしたgemもあるが、人類の安全に・便利にリソースを解放したいという欲求には際限がない。
try-with-resources は便利なんだけど欠点がないわけではなくて、リソースの確保と解放を一ヶ所でまとめてやらないとネストが深くなる。複数箇所に分けて書くならネストも2段になってしまう。
これはこれで整理されたコードを書く圧力になるので悪くない面もあるんだけど、とはいえもうちょっと自由にやりたい、いい方法は無いもんか、という話。

defer

ある。Golangの defer が便利そう。defer foobar って書いとくと、そのスコープを外れるときに自動的に foobar の内容が実行される。あるスコープのどこに何度書いてもいい。これは便利。

# GolangのdeferのままRubyにもってきたの図(イメージ)

def my_method
  # ...
  file = File.new("filename.txt", "w")
  defer file.close
  # ...
end

ただし上記のコードはRubyでは実現できない……syntaxに本当に手を入れない限りは。defer の後が即座に評価されてしまう。

なお try-with-resource ほしいよーって話をRubyのbugsに上げたときにライブラリとして実装できるじゃんって話があったけど、これじゃダメなんですよ。なおその例はこちら(引用)。

  Deferred.new do |d|
    r0 = Resource.new
    d.defer {r0&.close}

    r1 = Resource.new
    d.defer r1

    r2 = d.defer Resource.new
    abort unless Resource === r2

    r3 = d.defer(Resource.new) {|r|r.delete}
  end

defer 使いたいときにいちいちブロックで囲わないといけないのは、元の golang の defer と較べると圧倒的に使いにくいし、見た目も理想的ではない。deferしとけば必要なときに実行されるのがいいのに、この例だとわざわざブロックの終端という deferred な処理が発動する場所を明示してやらないといけないってことじゃないですか。コレジャナイんですよ。defの内側で必ずもう1段 Deferred.new do ... end でネストするとかイヤでしょ。

deferral

というわけでgemを作った。名前は空いてたところで deferral にした。

defer に与えるのがブロックであるところが元のgolangのと少し違うが、あとは同じような挙動になるはず。スコープを外れるとdeferredな処理が自動的に実行される。複数登録する場合は登録したのの逆順で実行される。例外が発生した場合でも実行される。

require "deferral/toplevel"
using Deferral::TopLevel

def my_method_name
  # ...
  file = File.open("my_file", "r")
  defer { file.close }

  file.write "data..."
  # ...
end

ほーら便利っしょ。あと記述がシンプル。余計なネストも作らないし。

実装

TracePoint 使って実装しているので本番環境で使い倒すのはオススメできません。またRubyの最適化処理をいろいろ台無しにする可能性があります。

あとdeferredな処理内で例外が起きたときには全部握り潰すようになってます。これはイマイチ。本当は例外が起きるならそれをそのまま上げる + 複数例外が起きた場合は suppressed な形にしてひとつの例外に他のをぶら下げる、みたいにするべきなんだけど、今はやってない。
これは何故かというと、メソッド(やブロック)内から例外が上がって強制的に脱出するとき、それがTracePointで捕捉できないことによる。メソッドから出ようとしていることはわかるが、それが通常のreturnによるものなのか例外によるものなのかの区別ができない + 上がってきた例外オブジェクトもつかまえられない。
これ、どうにかなんないかなあと思っているので、そのうち bugs に報告しようと思っている。忘れなければ。

で、TracePoint使えば実装できなくはないけど、ちゃんとやるにはやっぱり言語側でサポートしてほしいなあ、と思っている。ライブラリでいいじゃんというコミッタの意見で#13923が止まっちゃったけど、いや、ここに示した通り、ライブラリじゃダメなんですよ。

ライブラリじゃ駄目なわけ (追記)

某所で指摘されたけど、ブロックが参照する変数の中身が書き変わったときもこのライブラリでは手当できません。たとえば以下のコードだと "fileB.txt" を開いた File オブジェクトが2回閉じられちゃう(いっぽう fileA.txt を開いたほうはリークする……GCの回収を待つ)。

require "deferral/toplevel"
using Deferral::TopLevel

def my_method_name
  f = File.open("fileA.txt", "w")
  defer { f.close }
  # ...

  f = File.open("fileB.txt", "w")
  defer { f.close }
  # ...

これは block で書く以上どうにもならないすね。

ライブラリじゃ駄目なわけがひとつ消滅 (追記2)

ローカル変数の中身を binding 経由で強制的に保存・再生するという悪魔的発想により上記コード例もちゃんと動く deferral v0.1.2 がリリースされました。

というわけで

興味がある人はぜひどうぞ。

Ruby誕生25周年記念イベントでしゃべった & After Partyやった

Ruby誕生から25周年を祝うイベントが開催され、そこの「Rubyの今」というセッションでデータ処理について話さないかという依頼があり、受けたので、話してきた。

Ruby25 | Top

本当にいろんな人が参加していて、みんなでわいわいとお祝いをする、という感じ。高橋会長やまつもとさんの話はあちこちのメディアに出ているから良いとして、Matzのご息女が出てきてMatzが壇上でものすごく動揺してたのがちょっと面白かった。いやあ、これこそがコンテンツだな。

他にスポンサー企業のブースがあったり、いろんなプロジェクト・コミュニティのポスター展示があったり。ポスター展示はよかったなー。あんなふうに自分のプロジェクトをアピールできるのはすごく良いと思う。見て回ったけどじつに楽しかった。

しゃべってきた

ということで、データ処理とは何を指すのか、どのようなプロダクトやサービスがあって、またその界隈を経由してどういうところでどのようにRubyが使われているかについてしゃべった。
自分が書いたコードについてではないスピーチ*1をするのはずいぶん久し振りで、また「お祝いをする」場だというのにあわせて内容もマインドセットも作ったものだから、15分弱という時間もあってだいぶ緊張した。が、まあまあうまくやれたと思う。他の人のプロダクトやプロジェクトを紹介するの、できるだけ紹介はしたいけど間違ったことを言うのは怖い、ということでけっこうキツい。今回はやれるだけのことはやった。

終わったあとで色々な人に良かったと言ってもらえたのはじつに嬉しいんだけど、ふたことめがだいたい「あんな話しかたもできたんですねえ」「酒が足りなかったのでは」などという感想で、複雑な気分というか普段のキャラクターが浸透しているというか、ううむ。

After Partyやった

Ruby25 After Party|IT勉強会ならTECH PLAY[テックプレイ]

気付いたときにはRuby25の大きいスポンサー枠は全部埋まってて、Treasure Dataとして何かできないかなーという検討の結果がこちらのイベント。180人定員のところ、最終的に170人弱は入っていたみたい。思ったよりだいぶ混雑した会場になっていたけど、やらないよりはだいぶ良かったかなという気がする。楽しんでもらえたかなあ。
技術評論社さんから最新号のWEB+DB PRESSを3冊いただいていたので、そこに著者陣のサインをいただいて会場プレゼント大会をやったりとかもしていた。わいわい。

ということで

じつにいいイベントでした。特に @_ko1 さんは本当にお疲れさまでした&ありがとうございました。
終わったあとも飲みにいってハシゴして、しかし疲れていたのか、最終的にはいっしょに飲んでいた人にちょっと迷惑をかけたかもしれぬ。君の名は。を途中まで観たところまでしか覚えてない……。おつかれさまでした。

*1:いや、幸運なことに自分が書いたコードのあるプロダクトも入ってはいるのだが

TD Tech Talk PLAZMAでBigdamについてしゃべった

今年はTreasure Dataの東京オフィスができて5年ということも兼ねてPLAZMAというイベントをやっているんだけど、その併催ということで TD Tech Talk をなんと2日間、初めて平日の午後の開催で行った。TD発のOSSが中心になるOSS Dayと、TDの内部実装についてあれこれ話すTD Internal Day。

techplay.jp
techplay.jp

あれこれ裏方もやっていたんだけど、多くの人に来ていただけたし、楽しんでもらえたような感じだった。またOSS DayとTD Internal Dayともに外部からの人にもしゃべっていただく時間を設けて*1みた。こっちも普段TDのエンジニアだけだと出てこない話がいろいろあって、本当によかったと思う。

しゃべった

ここ1年(!)やっているBigdamというプロジェクトがあるんだけど、そのプロジェクトの概要と全体の設計において重要なポイントをいくつか紹介する内容にしてみた。

これでも内容をだいぶ簡素化したんだけどそれでも30分に収まりそうにない分量になっちゃって、しょうがないからだいぶ早口でやりました。これは明らかによくないんだけど、うーん、他にどうにもならなかった。削れる場所がない。
分散システムをどういう目的で・何を達成するために設計するかという話はあまり聞いたことがない気がしたので、これはこれで新鮮な内容だったんじゃないかなという気はする。いっぽうでどうしても時間の制約から実装上のポイントとか他に検討した選択肢への言及(例えば、Kafkaを使わないの? などなど)が内容から漏れちゃうので、それは自分にとっても少し残念だった。懇親会ではけっこうそういう話をしていた。

なんにしろ疲れた、が、まあ、やっている話ができたのはよかった。

*1:これは実は昨年にあったFastly Yamagoya Meetupがすごくよかったので、これをパクらせてもらった

SENDAI IT COMMUNE #2にいってきた&しゃべってきた

こちらのイベントでしゃべらないかという依頼をいただきまして、いい機会だったのでお受けしていってきました。いやー、地方都市での登壇依頼、いつもたいへん嬉しいです。ありがとうございました。

techplay.jp

仙台市さんが仙台でITな感じを盛りあげよう、みたいな感じで行われているよう(雑な理解)で、東京でも既に一度あったようだしこの後も東京で行われるようですが、今回は仙台市内。ナイスな時に呼んでもらえました。

f:id:tagomoris:20180122132624j:plain

仙台、新幹線で早ければ東京から1時間半で着くという、とにかく圧倒的に近いのがすばらしいですね。あと酒と魚がうまい(重要)。個人的に楽しいおでかけでした。

しゃべってきた

データ分析基盤のことについて、ということだったんだけど他の方がサービス運営で使われるデータ分析の話をがっつりしてくれそうな感じだったので、自分はちょっと目先を変えてそういう基盤を作るときに必要な技術について話してた。ということはつまり、リトライと冪等性についてである。

特にTreasure Dataの主要な顧客層であるところの非IT専業企業の人が使うデータ分析基盤にはどういう特徴が必要で、それを満たすためには何について考えられていないといけないかを話したつもり。
結果としてものすごく地味な技術の話になったけど、会場で熱心に聞いてくれる人も多く、後から感想を聞くに身につまされて聞いていたという人もいたので、少なくとも全くポカーンという感じではなかったようだった、ので、それだけでも良かった。自分としても久々にこういうことをちゃんと整理して考えるいい機会になった。

聞いてきた

全体としてふたつのトピックがあって、前半がデータ分析基盤、後半はクラウドという感じ。
内容としては都内にいてもよく聞く……けど、楽天さんの話は面白かったな、具体的に発生した事件とその対処としてのデータ分析の利用の話で、やっぱり具体性のあるユースケースは常に参考になるし、面白い。しかしアホみたいにでかいHiveQLを書くよりはMapReduce書いたほうがいいと思う。w

会場が仙台市内の繁華街にあるライブハウスで、普段しゃべるよりもだいぶ高い位置にステージがあるのがちょっと面白い感じだった。面白会場での勉強会、良いと思います。

いってきた

仙台なー、最高だよな、酒も魚がうまい(重要なことなのでもう一度)。せっかくなので前日入り、翌日帰宅ということで2泊していろいろ食べてきた。

f:id:tagomoris:20180122133225j:plain
f:id:tagomoris:20180122133557j:plain

なにしろ5月末にはRubyKaigiが仙台でもあるということで、その下見も兼ねt

f:id:tagomoris:20180122134232j:plain

仕事! お仕事の一環で行ったんですよ!!!!!!

よいイベントでした。

mrbgemをビルドしてテストを手元で走らせる(2017年版)

mrubyを使っていたところ、あるmrbgemが思った通りに動かなかったとする。あなたはまず真っ先に自分のコードを疑い、次にmrbgemの挙動を疑うであろう。
しかしmrbgemにはテストが十分に書かれていないかもしれない。ので、自分でテストケースを追加して手元で走らせ、様子を見たいと思うのが人として自然な成り行きである。

ところでmrbgemのリポジトリなどを見てもどのようにビルドしテストを実行させているのかが全く不明なケースが多く、なにこれどうやるの? という疑問を当然のように持つと思うので、そのような人のためのメモがこのエントリ。

ちょっと調べると以下のようなエントリがひっかかりますが、これは2年前のもので、この通りに build_config.rb を書いて上書きして走らせてもmrbgemのテストは実行されません。注意。
mrubyのモジュールmrbgemを開発した際に簡単にTravis CIを設定する方法 - 人間とウェブの未来

どうするか

現代(2017年10月)においては mrbgem のリポジトリのクローンからテスト実行までは以下のようにします。例として mruby-foo というmrbgemをどこかからcloneしてきて、その中のテスト(おそらく test/*.rb に書いてある)を実行するものとします。

手順としてはまず対象のmrbgemのcloneから。

$ git clone https://github.com/foobar/mruby-foo.git
$ cd mruby-foo

その中でさらにmrubyをcloneする(テスト実行用のmrubyバイナリをここから作る)。

$ git clone https://github.com/mruby/mruby.git
$ cd mruby

そのmrubyのビルド設定において、テスト実行時に有効になる設定があるのでそこに1行を加える。
この "conf.gem '..'" によりmrubyの親ディレクトリ(つまりmruby-foo)が依存関係に含まれ、かつテストも実行されるようになる。

@@ -111,20 +111,21 @@ end
 
 MRuby::Build.new('test') do |conf|
   # Gets set by the VS command prompts.
   if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
     toolchain :visualcpp
   else
     toolchain :gcc
   end
 
   enable_debug
+  conf.gem '..'
   conf.enable_bintest
   conf.enable_test
 
   conf.gembox 'default'
 end

あとは rake test すればよい。末尾にテスト実行結果が出てくるはず。おしまい。

>>> Test test <<<
mrbtest - Embeddable Ruby Test

...................................................................................................?.........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................?..........................................................................................................................................................................................
Skip: Struct.new removes existing constant  redefining Struct with same name cause warnings
Skip: Module#prepend super in alias  super does not currently work in aliased methods
Total: 982
   OK: 982
   KO: 0
Crash: 0
 Time: 0.58 seconds

................
Total: 16
   OK: 16
   KO: 0
Crash: 0
 Time: 0.56 seconds

余談

ところでこの mruby のテストで使える assert がわからん。以下のように書いても OK と言われてしまう。どういうこと?

assert('Must fail') do
  1 == 0
end

追記(assertについて)

上述の余談の件、わかった。最近に mruby/test/assert.rb における assert の挙動が変更されていた。
github.com

ということで上記のような(falseを返したらfailすると期待しているような)テストケースは全部動かなくなっている。以下のように明示的に assert_* メソッドを書くべき。

assert('Must fail') do
  assert_equal 1, 0
end

これ、今までいくつかのmrbgemを見た記憶によると(特に大量にmrbgemを書いている何人かがauthorの)mrbgemのテストが軒並みぶっこわれてるんじゃないなあ。きびしい。

ISUCON7予選で敗退した

あー、負けたー。「Asakusaの方から来ました」というチーム名で、Asakusa.rbでよくいっしょする @joker1007 さん、および @yancya さんと出た。最終結果は111400くらい? ただし20時*1を過ぎても4〜6万くらいをうろうろしてて、最終的には20:10頃に入れた変更でスコアが倍になり、なんだこれー? と言ってる間にタイムアップした。
去年のISUCON6決勝はやるべきことをやれなくて負けたので素直に悔しかったけど、今年はなんか問題設定の意図がまったくわからなくてそのまま不完全燃焼で手が停まって4時間経過で死んだという感じなので、なんだかなー、という気分。あんま疲れないまま終わってしまった。

たぶん出題者にはお礼の言葉が今週のblogエントリ等では並ぶと思うので、負けた人間としてはここで一発だけdisっておきたい。結果論として、問題設定としてはISUCON4決勝の問題で Cache-Control をみんなが有効にした後の状況を作りたかったんだろうなー、という気がする。けど、ハイコンテキストすぎるだろ。あと Cache-Control: public を明示的に有効にしないとキャッシュしてくれないっていうのは明らかに特定のCDNを意識していると思うんだけど、参加者に複数ホストを最初から与えておいて、最終的にやらせたかったのは外部サービスにいかにキャッシュさせるか*2ってことですか?

いやまあ、そういう問題だったし、そこをクリアした上で勝負を争えという問題だったんでしょうね。そういう問題だと気付いた時点で残り1時間もなくて、潜在的に抱えこんでいた問題に対処しきれず負けたのは、もう普段Webサービスから遠ざかった自分の実力なんだろうと思います。
最終的にはこれCDNかということに気付いたけど、そのときに周囲のチームのようにはスコアが上がりきらなかったのは、完全に自分のオペミスのせいだった。これだけは本当に言い訳ができないミスで、チームメイトに申し訳なかったなと思う。あの1手で本選出場を逃したと言っても過言ではない(詳細は後述)。

予選環境は快適でした*3ベンチマークもエンキューした直後には始まる状態がずっと続いていて、1チームに複数サーバを与えるということも含めて、さくらインターネットさんの担当側は大変だっただろうなと思います。お疲れさまでした&ありがとうございました。
環境構築であれこれあったためかスケジュール上もあれこれあって、運営の941さんも物凄く大変だっただろうなと思います。お疲れさまでした。いつもありがとうございます。

経過

joker1007さんのエントリに細かい経過がある。

https://cdn-ak.f.st-hatena.com/images/fotolife/j/joker1007/20171023/20171023022330.jpg

SSHログイン含めてちょっと最初の環境整備でバタついて、結局この図を描いたときにはスタートから1時間半くらい経ってたと思う。負荷とトラフィックをうまく3台にバラす、ということをいつもの決勝の通りメインで考えていた。WebDAVと言ったときはまたWebDAVかと自分でも思ったけど、あとで考えたらS3的なオブジェクトストレージが欲しいときに簡単に実現するための自分の発想がWebDAVなんだなと。

メッセージまわりのコードの変更はあとの2人にお願いして、自分は画像をうまく配信するためにhttp_dav_moduleを有効にしたOpenRestyのビルドと設定、あとは手元でもちゃんと動くようにRubyのアプリケーションでもPUTを受け付けてローカルに書き出すリクエストハンドラを追加したりしてた*4

で、多少ミスったりしつつ*5もしつつ、3ノード全部で画像をnginxから直接返せるようになったのがこのcommit、17:25。けっこう時間かけちゃってるなあ。

fix to upload icons to servers · tagomoris/isucon7-elimination@b380245 · GitHub

で、ネットワークが詰まって、なんだこりゃーとなった。今にして思えば画像をDBから出して直接nginxから返すのだけを初手にやって、それを複数台構成に直す、としていればたぶん今回のミスは踏まずにすんで、普通に戦えてたんだろうなという気はする。いきなり最初からベストな最終形を描いてそこを目指して進むのは自分の仕事の進めかたのよくない所だろうかという気はちょっとする。……んだけど、うーん、普段はそっちの方が効率いいんだよなあ。

この作業のとき、以下のような手順を踏んだ。これが後にして思えば決定的なミスだった。

  1. スクリプトを書いてDBからファイルシステムに画像を書き出す (OK)
  2. 書き出した画像をgitリポジトリに突っ込む (どちらかと言えばNG、ただし決定的ではない)
  3. サーバ3台でそれぞれ git pull で画像をfetch (OK)
  4. WebDAV用の領域に画像を cp -r で移す、というコマンドを3台でそれぞれ叩く (完全NG)

最後の手順により3台のサーバでそれぞれ初期の画像セット(67ファイル)のタイムスタンプがズレて、最終的に Cache-Control: public がついた状況でCDN(と想定されるクライアント)側にうまくキャッシュが保持されなかった。
これ、単に tar.gz で画像ファイルを固めて各3台のサーバのWebDAV領域でそれぞれ展開していれば全く問題なく処理されてただろうし、あるいは cp するときに -a つけていればそれでもよかったはずで、今となってはそのあたりの手順を当然のようにとってても不思議ではなかったと思うんだけど、なんか、そうしてしまった。本当に悔やまれる。

その後、ネットワークが詰まった状態になったのはすぐに分かったので Cache-Control のことはすぐに思い付き nginx で expires の指定を入れるものの、まったく状況が改善せず、なんで? と不可解な状況に陥った。
tcpdumpをとって調べたんだけど、Last-Modified の入ったレスポンスを返していれば普通のWebブラウザ等のクライアントであれば当然入ってるはずの If-Modified-Since の指定が入っておらず、でも周囲のスコアを見てみると画像のバイナリを返していれば不可能なスコアを達成しているのは明らかで、どういうことじゃこれは、と悩み続けてた。

特に悩ましかったのがこれ*6で、同じ静的ファイルなのに違う傾向のリクエストを送ってくるCDNがあるなんて想定してなかったから、完全に思考が空転してた。ずっと「このクライアントはなんなの?」って言い続けてた気がする。

ずーっと煮詰まってたんだけど、20:10のこのcommit、半笑いで「まっさかねー」と言いつつ Cache-Control: public を入れた。ベンチ回してトイレいって、戻ってみたらスコアが倍増しててうぎゃあコイツCDNだ! とか言ったような気がする。

add Cache-Control: public explicitly · tagomoris/isucon7-elimination@079a30a · GitHub

ここで11万点まで上がったんだけど、しかしそれでもネットワーク帯域は使い切った状態で、なんで? と言い続けてた。
これは自分のミスでハマったところ。最初に撒いたファイルの Last-Modified および ETag が各サーバで異なってたため、CDNを想定したクライアントのエッジキャッシュヒット率が 1/3 に落ちていたんだと思う。んでそのたびに画像をダウンロードしに来ていたから初期データへのアクセスでネットワークをまず使い潰した。これでベンチマーカーの負荷も上がらず、結局初期データへのアクセスだけが続くようになってドツボにはまったっぽい。

その後にアップロードされてくるデータをサーバ3台に渡すのは、まあちゃんと気を使ってなかったとはいえ、1秒をまたぐこともほとんどなかったはずなので、概ね大丈夫だったはずと思っている。もちろんもっとちゃんとやりようはあったけど。
とはいえ「このクライアントなんなの?」という疑念が強過ぎて、Last-ModifiedおよびETagをちゃんと返せているかというところまで頭が回らなかった。CDNがエッジキャッシュを作るときには当然そこを厳密に見ているはず、という発想もなかったので、これは、うーん……もうちょい時間があればなあという気もするけど。うう。

他の2人がちゃんとメッセージ回りのロジック改善をやってくれていたので、あとは /icons の初期データさえどうにかなっていたらだいぶ上位のスコアが出てたんじゃないかなあという気がする。心残りは大きい。

結論

頑張って仕事しよう、と思ったものの、正直こっちの方向にISUCONが行くといくら自分の仕事してても弱くなる一方なので、引退かなあ、とか考えつつある。
去年の予選は*7はてなのサービスだ! というのがわかったので面白がれたところはあったけど、今年のはもう、なんなの、ちょっと無理、みたいな気分。

*1:今回は13時〜21時というスケジュール

*2:しかもそんなものが存在するという前提は教えない

*3:……fail2banを除いて。メンバーのひとりでもちょっとログイン試行に失敗を繰り返すと全員がbanされてたので、最初にちゃんと全員のvalidな公開鍵を入れ終わるまでちょっとトラブってたのはきつかった

*4:ISUCON3の決勝のときにもほぼ似たような構成だったけど、このときは何も考えずにWebDAVが有効なnginxが無いと動作確認もできない状態にしてしまって難儀した覚えがあったので、その教訓から

*5:OpenRestyビルド時に --with-ipv6 つけ忘れてアーッってなったり。IPv6がちゃんと最初から有効なの、さくらインターネットさすがだな! って感心しながらビルドしなおした。

*6:あとでfujiwaraさんもなんかtweetしてたので確認ミスではなかったようで、ちょっと安心している

*7:競プロ勢向きだなー! と思いはしたものの