トスラブ館山ルアーナで開発合宿したけど最高だった

会社の同僚と6人で開発合宿に行ってきました。場所は鮨 一新で有名なIT健保直営のトスラブ館山 ルアーナです。個人的に満足出来る開発合宿だったので、何をやったか紹介したいと思います。

宿の特徴

まず今回泊まったトスラブ館山ルアーナについては以下の様な特徴があり最高ということが分かります。

  • 最高
  • 1泊2食付き 5,000円
  • 2015年12月にオープンしたばかりなので超綺麗
  • 食事がアホみたいに美味しい
  • 最高
  • 館内全域でwifiが飛んでいる
  • プロジェクタ付き会議室が借りられる

宿の様子

宿についてテンションが上がりすぎた@do7be

企画・準備

2泊3日で行くことの合意

実は去年の夏頃にも一度開発合宿に行ったのですが、その時は1泊2日で夕飯食べて風呂入って満喫して終わり、みたいな感じになってしまいました。

その教訓を活かしこちらのエントリにもある通り、2泊3日で開発に集中出来る日を作りました。

スプレッドシートに全ての情報を集約

宿に泊まるとなると、夕食や朝食の時間、各自のコースやアレルギーなど管理しなければならない項目が多岐に渡ります。そこで合宿用のスプレッドシートを作り、合宿関連の情報は全てそこに集約させました。

Imgur

Imgur

開発テーマ

開発に入るためのオーバヘッドを減らすために予め開発テーマを決めて臨みました。これも前述のスプレッドシートで管理しています。

開発テーマをスプレッドシートなりで共有するかどうかはどちらでも良いかもしれませんが、事前にテーマを決めておくのは必ず必要でしょう。

wifi状況のヒアリング

これも前回の教訓ですが、前回はwifiが飛んでいるのがロビーだけで部屋にはWimaxすら入らないという通信状態でした。

今回は幸い館内全域でwifiが飛んでいましたが、ロビーであれば入るのか、部屋はどうなのかという点は必ず確認した方が良いと思います。

会議室の予約

前述の通りどこでもwifiが使えたので正直開発場所はどこでも良かったのですが、やはり椅子と机があった方が捗るだろうということと、最終日の発表でプロジェクタを使うために予約しました。

結果的に2日目は全員ほぼ会議室でもくもくしていました。ただこれは今回6名で2部屋に別れてしまったため、全員が満足に集まれる部屋が会議室だけになったという部分があるので必須ではないかもしれません。

Imgur

Imgur

作ったもの

Chatworkのコンタクトをメタ的に管理して、それらに対して何らかの操作が出来る、みたいなものを作ろうとしていました(出来ていない)。

実際には作業時間のほぼ半分はSlickのキャッチアップに費やしてしまっていました。触ったことが無いものを使ってイチから時間内に作り上げるのは大変だなぁと思った次第です。

https://github.com/takashabe/makimono

中にはちゃんとサービスとして公開出来るところまで持っていったメンバーもおり、その人は事前に主要な部分だけは作っておき、合宿中にブラッシュアップさせていたということです。

http://rensoul.net/

KPT

以上を踏まえて今後のために軽くKPTで分類しておきます。

  • Keep
  • Problem
    • 調べるだけで時間を使ってしまう
    • 参加者全員が同じ部屋におらず、コミュニケーションが取りづらい
  • Try
    • すぐ手を動かせるよう、事前にある程度使用技術について下調べしておく
    • 参加者全員が泊まれる部屋を予約する

おわりに

前回の合宿の教訓を活かし、より実りある合宿にすることが出来ました。開発合宿は事前準備で良し悪しがほぼ決まると思っているので、ただの旅行っぽくならないためにもしっかり準備するのがオススメです。

そしてトスラブ館山ルアーナは最高の宿だったのでなるべく流行らないことを祈っております。

Imgur

館山の海近辺でシャワーを浴びる僕

Imgur

合宿の終わりを憂う@zakiry

Imgur

Imgur

Imgur

社内ISUCONを開催した話

先日2日に渡り社内でISUCONを開催してきました。今後社内ISUCONやるぞ!という方もいらっしゃると思いますので、そこで得られた知見などを書き記しておきます。 なおリファレンス実装やベンチマーカのコードはこちらになります。

github.com

なぜ社内ISUCONをやろうと思ったか

本家ISUCONに出てメチャクチャ面白くて、社内にも広めたい!!!という思いからです。

またISUCON5本戦で「ISUCON出題すればISUCON勝てる」みたいな話が飛び交っていたので、ベンチマーカ実装にも興味があったので開催する運びとなりました。

イベントとしての工夫

今回社内ISUCONをやるにあたって懸念だったのが参加者が集まるかどうかでした。そもそも社内でのISUCON認知度が低い、平日開催なので通常業務もあるという状況でしたが、最終的には合計15チームに参加してもらってワイワイ感がありました。

2日開催

一番やって良かったな〜というのは本家ISUCONの予選同様、2日開催にしたことです。事前エントリーではそれほど参加者数が伸びなかったのですが、2日開催にして1日目競技中に参加者が2倍くらい伸びました。

ポータルサイトのゲストログインを実装しておき、1日目にエンジニア全員が入っているチャンネルでワイワイ騒いでいたので、興味はあるけど参加どうしようかな〜という勢に響いたのではないかと思っています。参加者の割合は1日目4チーム、2日目11チームと圧倒的です。

実際年末に一度開催しようとした時は4チームほどしか集まらず、この時は告知も余裕無かったし〜ということで延期した苦い過去がありました。忙しい方が多い場合や積極的な方が少ない場合は実際に盛り上がっている様子を中継出来ると参加者が伸びるかもしれません。

競技時間

本家ISUCONは8時間ですが、今回は平日開催かつ参加しやすいものを、ということで競技時間は14時〜18時の4時間としました。 合わせて参加者全員分のVMを予め用意し、アプリケーションの切り替え手順もマニュアルに載せてなるべく作業に集中出来る環境を整えました。

問題

ISUCON5をベースに作らせていただきました。TwitterベースのSNSサイトを題材にして、DBボトルネックの問題としました。index貼ってN+1クエリを潰していけば確実にスコアが上がるような問題です。 社内なので敢えて罠は設けず、普段触る設定ファイルがちゃんと設定出来て基本通りのクエリチューニングが出来るかどうかという所を焦点としました。

ベンチマーカ

これもISUCON5をベースにさせていただきました。本記事冒頭でも述べましたが、ベンチマーカの知見を得たいという目的もあったため、ISUCON5qのベンチをScalaで書き直して実装しました。なおScalaは完全に趣味です。

ベンチマーカなんてこれまで書いたことが無かったので、並列性、セッションの扱い、整合性チェックなどなど非常に参考になることばかりで書いたことない人は一度書いてみると良いと思います。 ポータルと連携させた時にどうやってベンチマーカをスケールさせるか、具体的にどう実装すれば良いかという知見も得られました。

このリポジトリを支えている先人の方々には感謝しかありません。

反省点

問題の準備がギリギリになってしまい、事前に満足なチューニングを行うことが出来ませんでした。それにより適切な難易度調節が行えず、結果的に簡単すぎる問題になってしまったかもしれません。

また今回は準備から開催まで全て1人で行いましたが、まぁ結構大変(複数言語でのリファレンス実装用意、第三者に解いてもらって調整等々)なので出来れば数人で準備出来たほうが良いでしょう。アプリケーションの性質上、相談出来る相手が準備チームに限られるので1人だと何かと不便です。

終わりに

社内ISUCON、準備は大変ですがイチから準備することによって得られることが沢山ありますし、参加してもらった人にも楽しんでもらえると思うので是非やってみると良いです。

おまけ

社内ISUCON開催後、高スコア獲得者を集めて各々何をやったか、みたいなことを喋る勉強会をやりました。以下公開されている僕と@do7beの資料です。

speakerdeck.com

github.com

エンジニアとしてこの先生きのこるために僕が考えていること

これはMynet Advent Calendar 25日目の記事です。度々このカレンダーで書いている@takashabeがお送りします。

最終日ということでエモい感じのネタで行きたいと思います。

はじめに

環境や仕事内容、才能に恵まれ、日々仕事している中で着実にスキルアップ出来ていて将来安泰という方もいらっしゃるかと思います。

しかし僕のような凡人は仕事に追われているだけでは仕事はあるかもしれませんがエンジニアとして死ぬ気がするので、エンジニアとして生き残るためにどのような事を考えているのか、つらつら書いてみたいと思います。

一般的に考える

僕が所属しているマイネットでは既にローンチされて運用フェーズにあるサービスを移管(買取)し、運用を行う仕事が主です。そのため程度はありますが、必要最低限なものは既に出来ている状態にあります。

例えばデプロイで考えてみると、引き継ぎの際に「デプロイはこのコマンドで出来るよ」と教わったとします。 運用自体はデプロイコマンドだけ覚えていればデプロイ出来るので問題ありません。しかし実はhot deployが実装されているとして、hot deployが行われていることが理解出来ているか否かは大きく違うでしょう。デプロイ自体の影響範囲を見極めることも可能ですし、hot deployという概念を知っていれば他PJでも活用出来ます。

要するに物事をどれだけ理解しているかという話でもありますが、PJ固有に抽象化された概念だけでなく、それを構成する要素を学ぶことによって他環境でも通用する力が身につくと思っています。

アウトプットする

これは様々な場面で言われており、今更感もありますね。 アウトプットすることによるメリットは様々ありますが、個人的に一番良いのは情報の質が上がる(上げようとする)ことにあると思っています。

発信先が社内/社外に限らず、何かを発信する時は「間違った情報をあげたくない」という気持ちが働くと思います。自信のない情報は上げたくないし、少なくとも間違ったことは言わないように調査検証するわけです。その過程でその情報に関する精度が上がりますし、場合によっては何かしらの技術背景に首を突っ込むことになることもあるでしょう。

そしてアウトプットすることによって間違った情報を訂正される場合もあります。自分の中で完結していたらきっと間違ったまま認識していた事柄です。

やりたいことをやる

職場環境に恵まれていて、自分の興味関心とマッチしたことが仕事でやれている場合は良いと思います。 しかし社会は厳しいので決して面白い仕事ばかりではないし、人間のやることとは思えないようなことをやらされることもしばしばあるでしょう。

定常の単純作業に追われている場合はまず自動化してしまえば良いでしょう。そして空いた時間で自分の好きなことをやります。

とはいえ全く別の言語をやりたいという場合、それをプロダクトで採用するのも厳しいので、例えばその言語で便利系スクリプトを書いてみるなどすれば良いでしょう。 もちろん小さいチームであるなど、技術の導入がある程度自由に行える場合は興味のある技術を採用してみてみるのも良いでしょう。

もしくは現状全く自由のない職場環境であればいっそ 転職 するのもひとつの手です。世の中にはそこで働いていることによって(全く勉強時間が取れないなど)、将来の可能性が狭まる職場も存在します。仕事はおそらく人生において一番長い時間を投資するものなので有意義な時間を過ごしたいものです。

おわりに

僕が普段考えていることを3つ書き出してみました。

それほど特別なことは書いていませんし、多くの方が実践している内容であるような気もします。答えがあるようなテーマでもないのでこれが正しいとも言えませんが、もし日々の仕事にただ追われてるだけだなーという方がいれば、どうすれば自分にとってプラスになるのか考えてみるのも良いのではないでしょうか。

そして偉そうなことを書いておきながら、Advent Calendar 25日目の記事を26日に書いている時点でアレな訳ですが、これを読んでいる皆様にとってこの記事あるいはMynet Advent Calendarに少しでも有益な情報があれば幸いです。

ISUCON5本戦で完敗してきました

予選に引き続き、@zakiry, nohamaと3名でISUCON本戦に出場してきました。

名札

結果は以下の通り、9位フィニッシュでした。実装しきれなかった部分や見逃しが多く、ただただ悔しい。

http://isucon.net/archives/45869121.html

以下やったこと

競技開始〜14時くらい

  • ssh, zshなどの下準備をする
  • ベンチを回してアクセスログの解析
  • DBがpostgresだったのでMySQL移行を試行する
    • pg_stat_statementsでクエリ解析するも、特にボトルネックでは無かったのでpostgresのまま行くことに
  • endpointsをコード中に移植
  • nginx, unicornのワーカー数を上げる
  • 2, 3台目のセットアップ

14時〜18時

  • APIレスポンスをRedisにキャッシュし始める
    • kenなどの不変的なものをキャッシュ対象としていた
  • nginxにAPIレスポンスをキャッシュさせる作戦を試みる
    • 実装しきれずに投入出来ず…
  • DBとKVSを1箇所にまとめて複数台構成にする

ざっくりとしたスコア推移

スコア タイミング
1,000 初期
10,000 nginx, unicornのワーカー増やした
20,000 Redisに一部APIをキャッシュ
35,000〜45,000 3台に分散

サーバ構成

サーバ 役割
A unicorn + postgres + redis
B unicorn
C nginx + unicorn

フロントはCのnginxで受け、各サーバのunicornにプロキシする構成としました。

反省

MySQL移行

  • 時間を使いすぎた。DBボトルネックではないことを早々に確認すべきだった
  • postgresでクエリの解析をしている間, @zakiryにMySQL移行準備を行ってもらっていたが、完全にリソースの無駄遣いだった

nginxキャッシュ

  • nginxキャッシュを各自ググりながら実装し、結局実装しきれずに終わってしまった
  • 実力不足だった

APIリクエストの並列化

  • 一度検討したがRubyでそれをサクッと書けるメンバーが居なかったためスルーした

APIレスポンスヘッダ読んでなかった

  • 読んでいなかったのもダメだし、仮に読んでいてもそれを活かせたとは考えづらい

最後に

悔しい。来年こそは入選するぞという思いしかない。

そして@tagomorisさん, @kamipoさん, @941さんはじめ運営に携わった皆様、最高に楽しい場をありがとうございました!!!

isucon6

追記@2015/11/04 12:30

最終的なリポジトリは以下になります

https://github.com/takashabe/isucon5-final

ISUCON 5予選を突破してきました #isucon

「ピザはバランスいい」チームでISUCON2日目に参戦し、2日目7位くらい、全体を通して15位となり本戦に進めることになりました。めでたい!! メンバーは@takashabe@zakiry、nohamaの3名。なお最終スコアは14923でした。

isucon.net

以下、準備したことや当日行ったことを書いておきます。

チームメンバーのブログは以下。@zakiryがアプリ側から見た目線で書いています。

ISUCON5に参加しました - zakiry’s diary

準備したこと

ISUCON部の設立

去年ISUCONを知ってからずっと出てみたかったので、まず社内でメンバーを集めるところからスタートした。そこで部活という体裁で毎週月木定時後に2−3時間練習を重ねることにした。 集まったメンバーは僕含めWebアプリケーションエンジニアで、過去問を題材にしてミドルウェアの設定やチューニングの勘所みたいなところを勉強していった。 初回にとりあえずやってみようということでISUCON 4予選をそれぞれ2時間チューニングしてみるということをやり、各々初期スコアから全く動かなかったのは良い思い出である。 最終的に予選は9名3チームで出場している。

秘伝のタレの準備

必ず使うであろうNginxやMySQLの設定ファイルやログ解析ツール導入をコピペで済ませられるよう、秘伝のタレを準備し、ISUCON部のgithub issuesで共有した。

役割分担、方向性の決定

チームが決定した後は、各チームでメンバーの役割分担とチューニング方向性の決定を行った。 弊チームは僕以外がRubyに詳しいこともあり、僕がインフラ、他2人がアプリという分担とした。言語、ミドルウェアについてはRuby + Nginx + MySQLという基本的な構成で行くことにした。 例年予選はクエリ改善やアプリチューニングを確実に行っていけば勝てるという見込みもあった。

時間配分の決定

以下のようにざっくりとした時間配分を決めておいた。ほぼほぼこの通りに動けたと思う。

  • 10:00〜11:00
    • 問題、アプリケーションを読む
  • 11:00〜
    • 順当にチューニングする
  • 15:00
    • 実装が困難そうな大規模な改修を行うデッドライン
  • 17:30〜18:00(終了)
    • 再起動テスト

当日やったこと(インフラ目線)

競技開始前後

  • 作業環境である弊社オフィスに集まる。口頭でコミュニケーション出来るレベルの距離にいることを意識した。
  • インスタンスを立てて、ssh鍵、zsh、解析ツール類の準備。この辺りは事前にコピペすれば整うように手順を用意していた。
  • インスタンスを立てている間に並行して当日マニュアルにチーム全員で目を通した。得点や失格条件、終了時にあるべき状態などを重点的に読み合わせた。

11時〜14時辺り

  • MySQLでslowlogが出せなくてハマる。mysql> set global slow_query_time=0; を行い、全ログが出力されるはずが、コンソールから叩いたものだけログに吐かれて、アプリケーションにアクセスした時のログが一切出ないというよく分からん状況が続いた。結局原因不明だったが、他メンバーがunicornの設定をいじった時に表示されるようになり、まぁいいかという感じだった。
  • pt-query-digestでクエリ解析出来るようになったので、ベンチを回してひたすら解析結果を共有していた
  • アプリの再起動やNginx(kataribe)、MySQL(pt-query-digest)のログ解析用に簡単なスクリプトを作る
  • 他の2人が順調にボトルネックとなっているクエリを改善し、13時半くらいでスコア10,000出て暫定1位となる。弁当食べる手が震えていた。

14時〜15時辺り

  • 順調にスコアが伸びてきたので一旦再起動テストを実施するとスコアが4,000くらいになり焦った。今回はベンチ実行時にDB初期化が無いため、innodb_buffer_poolにデータが乗ってないことを疑った。そこでウォームアップのためにinnodb_buffer_pool_dump_at_shutdown、innodb_buffer_pool_load_at_startupをmy.cnfに投入してみたが設定が反映されず焦った(後述)。
  • my.cnfの設定が反映されていない件、実は /etc/my.cnf ではなく、 /etc/mysql/my.cnf を読んでいることが分かった。そこから更に !include していたので /etc/mysql/mysql.conf.d/mysqld.cnf に諸々の設定を投入していった。
  • この段階でinnodb_buffer_pool_sizeを2Gにし、MySQL再起動もコンスタントにメモリ3G弱を使いきれるようになっていた。マシン再起動後のスコアもキープ出来ていることを確認した。
  • tcp_max_tw_buckets などのカーネルパラメータの秘伝のタレを投入
  • この時点でスコア10,000〜12,000くらい。

15時〜17時辺り

  • 引き続き他メンバーがボトルネックとなるクエリを片付けていき、僕がひたすらベンチを回しては解析するという作業を実施していた。
  • commentsentries テーブルのデータ構造を変更すれば早くなることが分かり、alter文を流してみるも全く処理が進まない事象に遭遇した。データ量が膨大で、かつディスクがHDDのために長時間かかってしまったのが原因であった。30分経っても終わらないのでalterは諦め、別のクエリを改善する方針を取った。
  • ベンチを回しながらnginxのworker数を調整し、最終的にworker_processes=4、worker_connections=10240辺りに落ち着いた。
  • 静的ファイルの数が多くはなかったが、やらないよりはマシだろうということでnginxから静的ファイルを返すようにした。
  • この時点でスコア15,000〜16,000くらい。

競技終了前後

  • MySQLのslowlogやNginxのアクセスログを外した。
  • ベンチを回しながらunicornのworker数を調整していた。10/16/32くらいで試行し、どれもそれほど大差無かったので32のままにした。今思えば、スコアが伸びないのであればもう少し下げても良かったかもしれない。
  • 再起動テストを行い、特に問題ないことを確認した。
  • 17時30分過ぎにボトルネックとなりそうなクエリを発見し、改善を試みたがFAILが取れないため17時55分時点でRevertした
  • 終了間際はとりあえずベンチキュー入れておくみたいな状態になっており、Revert時点の14923が最終スコアとなった。結果的にLatest Scoreが最終的なスコアとなったため、ここでもしFailしていたら危なかったかもしれない。

まとめ

全員初出場だったが、しっかりプロファイリングしてボトルネックを潰していたら予選通過することが出来た。 そういう意味では定期的に勉強会を行い、それなりに準備は出来たのかなと思う。

他チームの解法を見ていてより感じましたが、様々な方向性で高スコアを出すことが出来るとても素晴らしい問題であったと思います。そしていくつかトラブルも発生していたようですが、丁寧に対応されており、運営の皆様には感謝の言葉しかありません。 非常に楽しい機会を頂きありがとうございました。本戦もどうぞよろしくお願いします。

そしてひたすらボトルネックを潰してくれた優秀なチームメンバーのおかげで予選を通過出来ました。ありがとうございました。本戦も頑張りましょう!!!!

php-fpmとnginxでunix domainソケットを使う

isucon予習でやったことのメモです

  • 前提
    • isucon4予選AMIで試した
    • ソケットファイルは/home/isucon/.local/php/var/run/php.socketを想定

php-fpm側の設定

listen = /home/isucon/.local/php/var/run/php.socket
listen.mode = 0666

これでphp-fpmを再起動すれば/home/isucon/.local/php/var/run/php.socket0666で作成されるはず

nginx側の設定

fastcgi_pass unix:/home/isucon/.local/php/var/run/php.socket;

gitプロトコルをhttps proxy経由で使う

何故かオフィスとgithub.com間の通信速度が激遅だったのでproxyを介すようにした。

corkscrew を使用してgitプロトコルのままproxyを通すことも出来るらしいが、手元の環境だと上手くいかなかったので、進捗あればまた書きます(願望)。

https proxyを設定する

httpsのproxyを追加する

※ ここでproxy.localproxyサーバのアドレス、3128proxyサーバのポートを指定する

$ git config --global https.proxy http://proxy.local:3128

確認する

git config --list
===
https.proxy=https://proxy.local:3128
===

ここまででhttpsスキームでの通信はproxy経由で行われるようになる。

git@github.com:〜の通信でもproxyを通すようにする

gitconfigにurl.<foo>.insteadOf <bar>を設定することで、<foo>エイリアスとして<bar>が使えるような感じになる。 これによって既存のgitスキームで設定されているローカルリポジトリを変更せずともhttps proxyを通すことが可能となる。

insteadOfを設定する

$ git config --global url."https://github.com/".insteadof git@github.com:

確認する

git config --list
===
url.https://github.com/.insteadof=git@github.com:
===

これで普通にgit@github.com:scala/scala.gitなどとすると、実際はhttps proxyで通信が行われるようになる。

参考