iOSDC Japan 2017 に当日スタッフとして参加してきました
ブログを書くまでがiOSDC、ということで9/15夕方〜9/17に早稲田大学で行われたiOSDC Japan 2017(iOSとその周辺にまつわる技術カンファレンス)にスタッフとして参加したレポートです。 @moshisora990です。元々リアルなイベントが好きなので、カンファレンスの運営には少しずつ取り組んでいて、去年はYAPC::ASIA HACHIOJIに出ていたりしたのですが、今年は縁あってiOSDC Japan 2017の当日スタッフとして参加させてもらったので、スタッフ参加目線で写真を交えつつ、主に会場側の目線で書いてみようと思います。きっとトークに関してはたくさんの方がエントリー書いてくれるはず…!
スタッフMTG
iOSDC開催からひと月ほど前に、当日スタッフは初めてのMTGへ。秋葉原の会場だったのですが早速設備がすごくて圧倒されてました。内容はもちろんのこと、会場説明、スケジュール、アカウント管理、各種ドキュメント整理、おおまかな担当割り振り等、事前に準備できるものを一通り共有しました。
iOSDCスタッフ顔合わせの風景です 🤔 pic.twitter.com/57lAMn2MPI
— じん (@moshisora990) 2017年8月30日
顔見知りが何名かいらっしゃったというのもありますが、皆さん気さくな方ばかりなので特に不安事もなくこの日は終了。
準備日・前夜祭
準備日は会場設営とノベルティ等配布物の準備、前夜祭の受付をしていました。ノベルティを準備して、垂幕が広げられるとカンファレンスだなーという気持ちが一気に湧いてくるものです。
当日
当日スタッフだったので、事前に準備されたものの情報はあまりなく、当日は自分たちも新鮮な気持ちでの参加でした。実行委員長の長谷川さんに「お楽しみに!!朝からきてよ!!」とのお達しをいただいてたので何だ何だと楽しみにしていたのですが、三石琴音さんのナレーションで始まって朝から会場が湧きましたね。文化祭という表現が適切かはわからないですが、大人が本気を出した文化祭はすごい…。オープニングムービーのクオリティにも驚かされました。
当日はTrackCのルーム担当と、相変わらずカメラを提げて写真業に励んでいました。登壇者さんの写真は主に専属カメラ部隊にお任せして、自分は主に会場や受付周辺、スポンサー様ブースの周辺を走り回っていました。部屋担当に関しては、司会、タイムキーパー、マイク持ち、Twitterチェック(空調とかピックアップ)、スタッフ間の連絡、満室時の対応などなど、でしょうか。少し気を抜くとニートになってしまいそうなほどに、スタッフの皆さんが臨機応変に素早く対応してくれていて、自分は結構ついていくのに必死でした(というのは内緒話)。皆さん本当にありがとうございました!
反省点として、個人的に気になってしまったのはやはり自分達のシャッター音で、オープニングのときにも注意書きがあったと思うのですが、スタッフ側も結構な数を撮影していたので邪魔になっていないかなーと(仕方ないとは思いつつも)少々心配にはなりました。こちらは持ち帰って考えてみます。
懇親会
Twitter等を確認していると「パックマンルール(輪になって話すときに一人分のスペースを空けておく)」が大変好評だったようで、自分も乗じてたくさんの方とお話できて楽しかったです。 そしてみなさんお気付きでしたでしょうか。懇親会のビールがめちゃくちゃ豪華でした。一枚貼っておきます。まさかここで「其の十」が飲めるとは…。
写真
スタッフが撮影した写真(速報板)は少しずつGooglePhotosで公開していますので、ブログ、SNS等でご自由にご利用ください。
- 準備・前夜祭
- 一日目
- 二日目
きちんと現像したものや、プロカメラマンによる写真も後日Flickrから配信予定なので、こちらも続報をお待ち下さいませ。
また、みなさんが撮影した写真も是非、こちらからアップロードください! https://photos.google.com/share/AF1QipOcKucEn3FYE7kS4dUnxU8Dw6VuIaqikNJnpbfiVV63LmYLtSZUdVMUSM40xSgGqQ?key=aWtJQlpXQndvaUtyQnN3c3V4RGZlVlA0aGpLWkRB
おわりに
企業/個人スポンサーの皆様のご支援、スピーカーの皆様のトーク、参加された皆様の協力、そしてスタッフの尽力で、最高だったなという一言につきます。皆様本当にありがとうございました。 やはり各カンファレンスそれぞれ色はあるとは思っていますが、中でもフェス感の強いカンファレンスだなーと実感しました(自分は後から知ったのですが、テーマが「フェス」だったんですかね)。本当に楽しかったのでまたあったら是非参加したいと思います。みなさんのブログにかかっているようなので是非お願いします!
あとは個人的な話ですが、趣味で写真を良く撮るので、趣味と趣味が融合して大変楽しかったというのもありました。大きいカンファレンスに限らず、カメラマンがご入用な方、お気軽にご連絡ください。飛んでいきます。
トークの話とか、夜のiOSDCの話とか、まだまだ書きたいことはありますが、長くなってきたのでひとまずこのあたりで…。
gulp-revのリビジョン付のファイル名を任意の形式にフォーマットするgulpプラグインを書きました
はじめに
ブサウザにファイルのキャッシュを捨てさせる目的でファイル名をリビジョン付きのものにする、ということは多々あるかと思います。 gulp
でそれを行うためにgulp-revがよく使われていますね。
gulp-rev
はファイルの内容をhashにしたものをリビジョンとして [ファイル名]-[revision].[拡張子]
の形式で付与します。
今回は、やんごとなき事情により、 gulp-rev
で生成されるリビジョン付のファイル名のフォーマットを任意の形式に変更したい、という状況になったので、 gulp-rev
と連携して任意のフォーマットでリビジョンを付与できるプラグインを書きました。
使い方
npm
でインストールできます。
$ npm install --save-dev gulp-rev-format-re
以下のように、gulp-rev
の後に実行します。
const rev = require('gulp-rev'); const format = require('gulp-rev-format-re'); gulp.task('default', () => { gulp.src('./src/style.css') .pipe(rev()) .pipe(format('[% rev %].[% filename %]')) .pipe(gulp.dest('./dist')) .pipe(rev.manifest()) .pipe(gulp.dest('./dist')); });
gulp-rev-format-re
は、引数に与えた文字列の下記のパラメータを、それぞれオリジナルのファイル名とgulp-rev
の出力したリビジョンに置き換えます。拡張子は自動で最後に付与されます。
[% rev %]
:gulp-rev
で付与されたリビジョン[% filename %]
: オリジナルのファイル名
上記の例では、出力されるファイル名はxxxxxxxx.style.css
のようにフォーマットされます。
前後や間に任意の文字列を挿入することもできます。
format('head-[% filename %]-prefix-[% rev %]-suffix')
とすると、head-style-prefix-xxxxxxxx-suffix.css
のようにフォーマットされます。
おわり
中身は大したものではない&やんごとなき事情で書いたのであまり利用ケースが思いつかない気はしますが、何かお役に立てることがあれば幸いです。
類似のプラグインとして、gulp-rev-formatがあるので、[ファイル名][prefix][revision][suffix].[拡張子]
の順番を保ったまま任意のprefix
suffix
を追加したい場合はそちらを使うとよいのではないかと思います。
関連リンク
ISUCON6にmorimoto組で出場して準優勝でした
ISUCON6に出場しました
ISUCON6本戦@渋谷ヒカリエ LINE株式会社
ISUCON6に「morimoto組」で出場して、準優勝できました。メンバーは、
という布陣でした。言語は自分とボンゴレ氏がPerlの方が使い慣れている関係でPerlを選びました。
スコア推移
ラスト1時間は他のチームのスコアが非表示ですがこんな推移でした。一台でチューニングしてから最後に複数台構成になったので結果発表ではダークホース感があったかもしれません…。
Time | PASS/FAIL | Score | 変更 |
---|---|---|---|
11:02:53 | PASS | 942 | Perl初期スコア |
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導入 |
12:43:40 | PASS | 3175 | perlのプロセス数を200に(していたらしい) |
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で保存するように |
14:09:41 | FAIL | 0 | |
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でレンダリング |
14:27:05 | FAIL | 252 | |
14:29:53 | PASS | 4781 | |
15:17:25 | FAIL | 106 | |
15:21:32 | PASS | 7412 | /img/* をRedisにCache |
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 をRedis pub/subとGo実装に置き換え |
17:41:33 | PASS | 15241 | 2台構成 |
17:43:36 | PASS | 30714 | 5台構成 |
17:45:12 | PASS | 29301 | isu02再起動試験 |
17:48:35 | PASS | 36067 | isu01にnginx,MySQL,Redis、その他でPerl,Go,Reactの5台構成 |
タイムライン
10:00~12:00
開始間も無くしてAzureへのデプロイがうまくいかなかったり、アプリを読んだり触ったり、Perl実装を反映してベンチをかけるまでに1時間ほどかかりました。その後手元でperlのサーバを動かしたりと準備をしているといつの間にかお昼頃に。
12:00~15:30
pointsをstrokesのカラムにjsonで保存
points
は一点ごとにレコードになっていて、必ず strokes
と一対で、かつ更新もなさそうだったので、これは strokes
と一緒にしてしまっていいよね、ということで strokes
テーブルにカラムを追加して、そこにjsonで入れることに。同時に、初期データもjsonに変換するスクリプトを書いて strokes
のカラムに保持、としたもののこの時点ではあまり効果は無し。
/img/* で返すSVGをPerlでレンダリング
SVGの生成はReact側からperlのAPI経由で points
のjsonを取得して、React側で表示するSVGを生成していたので、これをperl側で生成するようにする実装が、残り2名で points
の変更を入れている間にfujiwaraさんにより導入。
/img/* をredisにcache
stroke
が新たに追加されるまで、 /img/*
の結果は更新する必要がないので、これをredisにcache。新たに stroke
が追加されたときにキャッシュを破棄するように。これで結構伸びて7412。
15:30~17:10
この時間が苦しかった…。
/api/stream/rooms
をRedis pub/subとGo実装に置き換え
200プロセスでゴリ押していた stream
がやはり辛いという話になり、この部分の実装をGoに置き換えることに。Perl側から新しいstrokeの投稿があったときにstrokeをpointsと一緒にpublish、Go側でsubscribeしてクライアントに配信するように変更。この変更でPerlでは500msごとに新しいstrokeをまとめて送信していたものが、新しいstrokeが来るたびに送信できるように。一旦は完成したかと思いきや、ベンチを走らせると 必要なwatch_countが送信されていません
旨のエラーメッセージでベンチが通らず、しばらくこれの解決に食われましたが、ボンゴレ氏が、「これ、publishされなくても500msしたら返さないといけなくないですか?」と閃いてなんとかベンチ通過。パフォーマンスも改善して9339。
新しいstroke投稿があったときにすぐ送信できる実装自体はあまりスコアに影響がないらしかったですが、触ってみるとレスポンス早くなっていいアプリになった感じはありました。余談です。
strokes
countもredisにcache
毎回 stroke
を全部拾ってきて scalar
で個数だけ拾っている部分があった
$room->{stroke_count} = scalar @{ get_strokes($self->dbh, $room->{id}, 0) };
ので、これもredisに
my $stroke_count = $redis->get('stroke_count'.$room->{id}); unless ( $stroke_count ) { $stroke_count = scalar @{ get_strokes($self->dbh, $room->{id}, 0) }; $redis->set('stroke_count'.$room->{id}, $stroke_count); } $room->{stroke_count} = $stroke_count;
stroke
投稿時に incr
: $redis->incr('stroke_count'.$room->{id});
というものは書いてはいたものの、時間が差し迫っていたのでmergeしないまま複数台構成作業へ。
17:10~18:00
コードはフリーズして、複数台構成と再起動試験。
fujiwaraさんにお願いしてあとは自分たちは祈るだけという状態に。
最終的には isu01
でnginx, MySQL, Redisを動かしてそれ以外でPerl, Go, Reactをのせました(競技後に教えてもらいました)。
isu02
の再起動試験をしたのち、最終的な構成にしてスコアは36067。最後に isu01
を再起動はしたものの、これ以降スコアが伸びることもなさそうだったのと、時間が終了5分前くらいだったこともあり、これでスコアfixしましょうということに。ベンチは実行しないまま、各自 isu01
につないでちゃんとレスポンスが返ってることだけ確認してそっとコンソールとブラウザを閉じました。
結果
最終スコア 36067 で準優勝でした。
反省はやはり、コードくらいは2人でがんばるぞ!!で、fujiwaraさんに下回りをお願いするのが理想形だったと思うのですが、結局結構コードも書いてもらってしまったことと、Go慣れしてなくて選択肢も最初から絞り気味だったことでしょうか。お題を聞いた時点でPerlつらいしGoよさそうという話はあったのですが。golang書こう…
結果は嬉しいものでしたが、ブログを書きながら振り返ると、肝心なところは全部先輩頼りでしたし、16時を過ぎたあたりからは何やれば良さそうかも分からなくなってきて、個人的にはやはり全然戦えてないなーという感想で、悔しくも感じた初参戦でした。悔しさ胸に勉強せねば…
出題・運営の皆様、予選も本戦も、楽しい問題と競技を本当にありがとうございました。また協賛の皆様、楽しい懇親会をありがとうございました!
そしてチームの皆様、本当にありがとうございました!すごい体験をさせていただきました。嬉しくも悔しくもありましたがこれを糧にまた頑張ります。
最後にこちらを!
ISUCON6裏話Nightに酒を贈りたい方はこちら→ https://t.co/2mxdarwDKf
— edvakf (@edvakf) 2016年10月23日
おや…? #isucon pic.twitter.com/PF2DpxwJ9n
— ISUCON公式 (@isucon_official) 2016年10月22日
ISUCON6にmorimoto組で参加してきました
ISUCON6に参加しました
ISUCON6 、日曜日に参加しました。前々から出てみたいなーと思ってはいたものの、面子をゆるぼしてみたものの集まらず…と見送りかなーと思っていたところ、社内メンバーで組めることになって自分でも驚きの布陣で参戦することに。ありがとうございました!
足回りや方針はfujiwaraさんに引っ張っていただきつつ、残る2名で実装がんばるぞい、という感じで挑みました。実装言語はPerlでやりました。
事前準備
当日タイムライン
当日のスコア遷移をメモしてなかったので朧げですが、slackとgithubのログを掘り返しつつ、こんなことをしましたメモです。アプリ側しかみてないので覚えていることをさらっと。
9:00
- 集合&作業場設営
全員起床成功。
会議室を確保してなかなかよい環境でできました。
こんな感じで頑張ります #isucon pic.twitter.com/VF2Z99wZWH
— もし (@moshisora990) 2016年9月18日
10:00〜11:00
- Azureにdeploy、chefを回して環境準備。30分くらいかかった。
- dumpとかbackupとかしておく。
- (たぶん)ミドルウェア類設定を反映。
- アプリケーションをさわってなんとなく把握。
11:00〜12:00
- ログとか計測とか。
- コード読む。
- isutarをisudaに統合。
- ローカルで動かないと辛いですねーと環境を作り始める。
12:00〜15:00
スコア伸びるまで結構つらい時間でした。
- とりあえずindex
alter table entry add index updated_at(updated_at);
- トラップを踏んだのか何なのか、新卒陣がPerlのローカル環境を動かせずに断念。以後「動け!!!🙏」と念を込めてプルリクすることに。ちょっと凹んだ。
- 明らかに
htmlify
が重いので、とりあえず Regexp::Trie を導入するもあまりスコアは伸びず。 - 毎回生成してるから重いのでは…ということで
entry
のidを覚えておいて更新があったときだけ再生成するように変更。
(この時点で最大スコア20000程度。いまいち伸びず内心結構焦ってました…。)
- 正規表現をRedisに入れるようにして、
htmlify
で正規表現を作るのはやめて、entry
がpostされる時に再生成するように変更。が、同時リクエストでRedisの値の整合性が取れずベンチがこける。 - post entry用のプロセスを立ててnginxから対象のパスは専用のそちらの1プロセスでさばくように変更。この変更で15時前頃にスコア80000くらい。一気に上位に食い込んでやる気が…!
やる気出てきた #isucon
— fujiwara (@fujiwara) 2016年9月18日
うおおおおおおおお
— もし (@moshisora990) 2016年9月18日
- この頃に
/
でSELECT COUNT(*) FROM entry
していたところもRedisにのせましたが、スコアは若干上がった程度でした。
このあたりから、プロセスを生かしたまま2度目のベンチを回すとスコア120000くらい出ることに気付きながらも原因についてはこの時点ではよくわからず。
同時に、 "上町村" に "川上町" からのリンクがありません (GET /keyword/川上町)
というメッセージが出始め、「なんでしょうねこれ」とはなりながらも、運営へ質問したところ Status: PASS
ならスコアは有効ですとの回答を得られたのでとりあえず無視。ぬか喜びしていた時間帯。
15:00〜17:30
スパムチェッカーがCPUを食っていてしばらくワード等ログに出して見てはみたものの、NG判定されているワードも規則が見えなかったのでここのテコ入れは断念。
あまり突き刺さる変更はできなかったものの地道にスコア更新。細かいものも色々。
/
のentries
のクエリを自己結合に。/stars
をRedisにキャッシュ。initialize
でstars
を全部Redisに載せてget_multi
するように変更。uri_for
が遅いらしい&絶対パスにしなくてもベンチ通る。ので全部消す。(たぶんほとんど効いてない)- user_nameもsessionにいれて
set_name
のクエリ削除 - とかとか
ここまでで初回ベンチスコア90000くらい、何度か回すと最大スコア170000くらい(まだ謎でした)。
17:30〜18:00
post entry用に立てたプロセスをrestartするとスコアが90000程度に戻ってそうだと発覚。どうやら Trie
オブジェクトが生きたままになっていて、1度目のベンチで追加したキーワードが2度目のベンチでも効いていた模様でした。ここでようやく謎が解けた。30分前。
(なので、ないはずのリンクが作られていた模様。川上町の謎が解けた…)
ならば、ということで、一度ベンチを走らせて追加されるデータをテキストに落として、 initialize
時に正規表現に追加しておくという実装がfujiwaraさんによって高速挿入されてコード変更は終了。完全に未来予知作戦なので本質的ではない&データセットが変わると全く効かないので、複雑な気持ちですねーという話をしながらではありつつも、これで140000点を突破(17:50頃)。
その後再起動してベンチキューに滑り込み、終了3秒前にベンチ実行開始。稼働状況を見る感じ大丈夫かなあ…という雰囲気でしたが、再起動後のスコアを確認できないまま競技時間終了…。
ギリギリもギリギリだった…
予選突破できた
不安な感じで競技終了時間を迎えてしまったので反省会中もdkdkしていましたが、最終スコア143,366で無事通過できました。とはいえ最後の裏技的なやつが効いてなかったら9万点いくかいかないかくらいだったので、結構やばかったんじゃないかなと…。
- Perlのコード書く以外やってない。要復習。
- htmlifyもっとなんとかできた気もする…。
- 手元でPerl動かそう…(重要)
- 普段やってないことをやると結構単純なことで詰む。全部一瞬で拾ってくれる大先輩心強すぎる…。ありがとうございました。(自分でできるようにならないと…)
- (普段仕事でJSばかりなためか、JSのコード書いてボンゴレ氏に「それJSですよ」って突っ込まれた。手が…手が…)
大会の製作・運営のみなさま、ありがとうございました!初参加でしたが楽しかったです。ベンチマークも数分で実行されて快適でした!
そしてチームの皆様、本当にありがとうございました!ものすごく連れて行ってもらった感が否めないですが、何はともあれ予選突破できました。突破されたみなさま、本戦でお会いしましょう!!本戦は勉強じゃない、戦争だぞ!!との激励もいただきまして、一ヶ月頑張ります。がんばります…
さいごは反省会の様子です。弊社golang実装組がなかなかつらそうでした。正規表現…
すごいのきた pic.twitter.com/K6WST8tWY0
— もし (@moshisora990) 2016年9月18日