半空洞男女関係

思ったこととかプログラミングしてるときのメモとか色々かいてます。メールはidそのままgmail

レッツプッシュ購読

#ORCΛ commit log流し読み(2019/05/19週)

葛西スペースで行われたOrcaのイベントに行ってきました。とても楽しくてOrca熱が高まってきたので、rails commit log流し読み(2019/05/25) - なるようになるブログ 的な感じでOrcaのコミットログを眺めてみるブログとか面白いかなと思ってやってみます。書くのに一時間くらいかかった気がします。

気持ちが続けば週一ペースでやってみようかなと思っています。UDP通信でOrcaを制御する周りが立地になりました。DevineさんがOrcaハードウェア作ってるみたいだったのでその周りで使えるようにいろいろ整備してるんですかね。

目玉としては指定したフレームで特定のコマンドを実行できるqueueという機能が追加されていました。


Mon May 20 06:24:07 2019 +0100 / Added links to SonicPi forum

READMEの更新。Sonic PiをOrcaの音源として使う方法を紹介するスレッドにリンクを貼っています。


Mon May 20 18:07:24 2019 +0100 / Removed extra fonts

使用されているフォントがinput_mono_regularからinput_mono_mediumになりました。不要なフォントも削除されています。

Fオペレータから不要なコードの削除も。


Mon May 20 18:12:15 2019 +0100 / Changed reset frame shortcut, to Shift+R. Fixes #114

resetFrameがCmd+Shift+NからCmd+Rに変更されています。Cmd+Nと間違えると悲惨だからかな。


Mon May 20 20:18:41 2019 +0100 / Removed capitalized operator names

一文字目が大文字になってしまっているオペレータをすべて小文字になるように修正。version 127へ。


Tue May 21 06:24:03 2019 +0100 / Fixes #115

#115 で語られていたtransposeテーブルの修正が含まれています。

b i p w のオクターブを1つ上げています。

f:id:mactkg:20190526150359p:plain

IB0ですが、半音上がる小文字のiB0#です。これは C1 になるはずなのですが、C0として定義されていました。p, wも同様の問題を抱えています。これを1オクターブ上げて修正するコミットです。

ところでbi が同じオクターブに割り当てられているのが疑問でしたが、

  • CDEFGAB(音階順)
  • CDEFGHI(アルファベット順)

の2つの表記に合わせるため、このようになっているんですね。

Issueでは A0AHで、B0BIで二重に定義されているので、IHをやめて詰めればもっとたくさんの音階が表現されるのでは?と提案していましたが、C からインクリメントしたときに挙動に問題があるため、半音問題のみ修正されたようです。基本的にCからのインクリメントが正しく動くように設計されていて、ABの定義はおまけという感じですね


チュートリアルの更新です。Pilotが手前で紹介されるようになっていますね。バージョンも128に上がりました。


Thu May 23 12:29:24 2019 +0900 / Added queue tools

新機能の搭載です。開いたファイルと同じディレクトリに queue.orca というファイルを置いておくと、指定した行数のフレームでUDPのコマンドを実行できるような機能が入っています。例えば80行目に bpm:80 と書いておくと、80フレーム目でBPMが80に変わるようなイメージです。

commanderで制御できるコマンドに eraseselect;xywh が追加されてUDPで制御できるようになりました。writeがうまく使えてなさそうなバグも修正されています。


Thu May 23 12:31:30 2019 +0900 / Move selection on write

commanderでwriteしたときにカーソルを移動する修正です。


Thu May 23 12:43:25 2019 +0900 / write block in commander

writeコマンドのリファクタリングです。ちょっとこれはどういう仕様にしたいのかわからなかった。。。READMEが間違っている気もしますね。 「write:H12;34 Writes glyph H, at 12,34.」ではなく「write:H;12;34 Writes glyph H, at 12,34.」かな。


Thu May 23 16:22:24 2019 +0900 / select written text

commanderでwriteしたときに書き込んだ領域をカーソルで選択する変更です。


Fri May 24 14:48:38 2019 +0900 / Added copy/paste

commanderでcopy,pasteができるようにしています。


Fri May 24 17:33:20 2019 +0900 / Documented queue

前途したqueueの機能がREADMEに記載されました。またqueue用のファイル名はqueue.orcaではなくファイル名.queueに変更されました。


Sun May 26 05:35:13 2019 +0900 / Changed listener port

OrcaUDPでListenしているポートが49161に変更されています。


Sun May 26 05:37:39 2019 +0900 / Added supercollider OSC port

superCollider用のOSCポートをGUIから選択出来るようになりました。

あとがき

5/23日からタイムゾーン変わってるのが面白いですね。

git log --since="1 week ago" --pretty=format:"[%ad / %s](https://github.com/hundredrabbits/Orca/commit/%H)" --reverse

ISUCON8 予選で敗退した(くやしい)

ISUCON8に id:EBAGmasaid:kwzr と私でかっぱぺんぎん㌠というチーム名で参加しました。当日はkwzrの予定が悪くなってしまって2人での参戦になったのですが、そのままやっていくことにしました。

最終的には9000点くらいで終わってしまいましたが、ざっとやってみた戦略などを紹介したいと思います。

午前中: プロファイリングと手元環境整備

プロファイリング

プロファイリングはもともと alppt-query-digest をメインに使う予定でした。Ruby実装で挑むことにしたので、 rack-lineprof なども使ったり。id:EBAGmasa が事前に alppt-query-digest の結果をGitHubにアップロードするスクリプトを書いてくれていたのですが、 pt-query-digest の結果が大きすぎてアップロードに失敗するなど事件がありました。pt-query-digest は大きなクエリは省略してくれるオプションとかあればいいんですけどね…。

当日のサーバーはh2oでalpにすぐにかけられないことがわかったため、それをnginxに置き換えるのと、MySQLのSlow Query Logがうまく出ないので苦戦して午前中をプロファイリングや実装の確認で使ってしまいました。

my.cnf 読まれない問題

当日はMySQL/etc/my.cnf/home/isucon/torb/etc/my.cnf あたりに保存し、/etc/my.cnfシンボリックリンクを貼ろうと思っていたのですが(大体の設定ファイルをそのように実装しようとしていた)、シンボリックリンクだと設定ファイルを読み込んでくれないようで、権限周りも確認したのですが結局は /etc/my.cnf に直置きすることとなりました。

環境整備

今回は始めてちゃんと手元で動作させながら確認しました。結構今まではカンでコードを書いてデプロイしてることが多かった気がするのですが、これだとなかなかサイクル回せないなということで、きちんと手元に環境を作っておきました。これは結構良かったなと思っています。DBが軽かったり、初期化スクリプトinit.sh がきちんと置いてあったのがありがたかったです。

10:30 gzip

とりあえずこれくらいはってことでgzip化とかを id:EBAGmasa がしてくれました。static fileをgzかけて置いておくだけです。

方針をたてる

3台あるけど、まず最初は今動いている1つのサーバで高速化をはかって、その上である程度まで高速化できたら3台構成にしようという作戦にしました。それまではアプリケーションの改善をメインにやっていこうということです。

12:00 reservationsのuser_idにindexを貼る

クエリの中でユーザの予約状況などを取ってくるところがあったと思うのですが、そのクエリをEXPLAINしてみると using where; using filesort あたりになっていたのでindexをはってやりました。これで数千点上がったような

13:00 sheets剥がし

あるランクの座席の総数や、値段は基本的にどれも同じという前提があったので、それをコードの中に埋め込みなおすのを id:EBAGmasa がやってくれました。1800点くらい。

14:00 3台構成化 / get_eventのN+1 queryをなおす

この辺から時間もなくなってきたので、3台構成にしようということで id:EBGAmasa が3台構成にする作業をしてくれます。 get_event の中で座席分だけSELECTしているのはヤバいなということで、先にreservationsを取ってきて使うようにしました。ついでに reservationsreserved_at にもindexを貼っています。

本当はここでもう少し、 get_event に着目すべきでした。N+1 queryは解消したものの、結局sheetsのループの中で毎回reservationsにfindをかけており、それなりにCPU時間を食っていました。実は id:EBGAmasa が最初に rack-lineprof を入れてくれていたのですが、この後くらいまで使わなかった。ちゃんとプロファイリングしていればこれに気づけたので、これが結構もったいないことをしたなあと思っています。

15:00 Redis化

コードを全体的に見ていて、トランザクション処理をかけているのが気になりました。pt-query-digest でもCOMMITに時間をかけていたし(でもこれ、処理がCOMMITのタイミングで行われるからだけなんじゃないか…)。今回のメインの処理は予約をするところかなと考えてしまったので、そこをどういうふうに処理していくかを考えました。

マニュアルには「1秒以内に反映されていれば、情報が遅延していてもOK」とのことだったので、次のような仕組みでやってみることにしました。

  1. RedisのSETをつかって、予約可能な座席を表現する。キーは "event_id:rank" といった感じ。
  2. 「event_id: 3の、S席ください」とリクエストが飛んでくる。
  3. RedisからPOPするとランダムで値が取れるので、適当に返す。取得に失敗してnilが帰ってきたら、エラー処理。
  4. 同じ席を予約する処理をすることはないので、トランザクションは特にかけずに、INSERTする。

キャンセルは同様に、DBからSELECTして正しい予約ができるかを調査して、RedisのSETに戻してやるだけです。

でもよくよく考えたら、innodbは行ロックだったと思うし、これってそんなに意味はなかったかなあ…。と思ったり。でも激しく予約リクエストが来たときは多分効きますよね。

これで、commitとか、rollbackとかは全部消しました。

ここで FOR UPDATE についてきちんと調べておけば、FOR UPDATE全部消せたんじゃないかなあ…。(それよりも get_event の重さのほうがヤバかったわけだけど。)

16:00 MySQL / Puma メモリチューニング

このあたりで id:EBAGmasaがリソースを使い切れるように、ワーカー数やメモリの割当を調整してくれた。 puma が結構メモリを食ってしまうのに苦戦していた様子。この辺で4000点とかだったかな?

16:40 get_event 再燃

ここで改めて rack-lineprof を見るとやっぱり get_event ヤバいぞ…。ということで get_event に手をいれることにしました。なるべくJOINしてDBへの問い合わせやループを削除して頑張っていく。Hashの引数にHash使ってるコード、マジで頭がヤバくなる。

17:20 再起動テスト

id: EBAGmasa が再起動テストしたりしてくれてました。

17:30 get_eventの修正入れて、デバッグ作業

ああもうこのままだと絶対勝てんぞ!ということで、出来る限り頑張ってやってみることにしました。get_eventの修正をこの時間から投入して、デバッグ作業しながら進めていき、結果9200点くらいで着地です。

実は最後にslow query logをOFFにするのを忘れていたんですよね、おつらい。

感想

運営について

今年のダッシュボードは本当によくできていて驚きました。ベンチマーカーも快適だったし(1チームに対して1ベンチマーカーいたとのこと。ネットワーク割当もすごい。)、DBのバックアップも取りやすくなっていて快適でした。前段サーバーがh2oだったりとか、mariadb使われていたりというのはちょっと驚きました。

振り返って

  • 今回は、アプリケーションの無駄を素直に取り除けば良かった問題だった。
  • slow query logやh2oからの載せ替えに手間取ってしまったのがもったいなかった
    • MySQLの設定についてはデバッグがやりにくい。
    • MySQLがどこを読みに行っているのか?などをぱっと見れなかったのが良くなかった。(普通に mysql --help | grep my.cnf とかで見れたっぽい)
  • alppt-query-digest を取ったところまでは良かった
    • もう少し良く無さそうなところを考える時間をじっくり取るべき。
    • Redis使うのはおもしろいけど、早すぎた
      • 優先順位を考えよう
      • ベンチマーカーのエラーに着目したほうがよい
  • rack-lineprof をきちんと使っていくと、安心感を持って進められそう
  • 手元ですべて動かすと楽
    • 次回は、docker-compose.yml とかでそれっぽい環境作っておきたい
  • deployはもう少しなんとかしたい
    • 今回は2人だったけど、3人いたら、1人はそのへんの自動化をやっていくと良い
  • 普段やらないことは、ISUCONだとやっぱりできない

色々後悔は残ったけど、楽しいISUCONでした!運営の皆さんありがとうございました、本線進む方がんばってください。

そういえばはてなスターの引用スターはどうしてやめてしまったのだろう。どういうところが刺さったのかとか、きちんと読んでる感が伝わってよかったのにと思う。人の引用を眺めるのも面白かった。

mediumのハイライトは結構よく使っている。