Write and Run

it's a simple way, but the only way.

ISUCON12予選にRubyで出場して8位で予選通過した(ソレイユ)

霧矢あおい(KOBA789)です。

タイトルのとおり、ISUCON12予選に Ruby で出場して8位で予選通過しました。最終スコアは34635(ベストと等しい)です。

本戦出場は ISUCON9 ぶり2回目です。

チーム「ソレイユ」

今年は私の多忙もあってチーム解散の危機だったんですが(チームメイトにはご迷惑をおかけしました)、無事いつものチームで出場することができました。

霧矢あおい「無事、チーム『 ソレイユ』の一員になれました。ありがとうございました!」
ひとりチームからソレイユへの移籍に際して運営さんにお手伝いいただき、無事移籍を成功させたときの様子。

というわけでメンバーは以下:

アイカツ劇場版公開おめでとうございます。忙しくてまだ観られていません。

たたかいのきろく

うちのチームは例によって Git をほぼ使っていないので正確な記録はないのですが、今回は私が ToDo リストを書きながらマネージャーっぽいことをしていたのでそれをベースに書きます。

  • 10:00 競技開始
    • KOBA789 & s4ichi: レギュレーション読み合わせ開始
    • osyoyu: 競技用サーバーに入って開発環境構築開始
  • 10:20 頃
    • KOBA789 & s4ichi: とりあえずブラウザでアプリケーションを触ってメンタルモデルを構築
  • 10:30 頃
    • KOBA789 & s4ichi: とりあえずコードを上から下まで流し読み。雰囲気を掴む
    • KOBA789: 「SQLite3 がいつもの戦い方を阻害するので MySQL への移行を視野に入れた方がいい」
  • 10:50
    • osyoyu: 開発環境構築完了
    • all: KOBA789 から osyoyu へ、課題のアプリケーションのメンタルモデルを共有
    • osyoyu: 「いつものツール使うのに Docker 邪魔なので降ろした方がいい」
    • osyoyu & s4ichi: Docker 降ろし開始
    • KOBA789: DB へのアクセスパターンの洗い出しを開始
  • 12:00
    • KOBA789: DB へのアクセスパターンの洗い出しを完了。MySQL への移行が現実的な規模であることを確信
    • osyoyu & s4ichi: Docker 降ろし完了。いつものツールで開発・分析が可能に
    • KOBA789: 「移行を見据え、すべての SQL に名前をつけてメソッドに切り出したい。移行しなくても書き換えに役立つ」
    • all: 手分けして SQL 呼び出しのメソッド切り出しを開始
  • 12:30
    • all: メソッド切り出しが完了
    • s4ichi: 切り出したメソッドを使うように変更を開始
    • KOBA789: ranking のアルゴリズムの読解を開始(味集中カウンターへ)
    • osyoyu: visit_history の Redis 化を開始
  • 12:45
    • KOBA789: ranking アルゴリズムの読解が完了。player_score はプレイヤーひとりあたり最新の1行だけを保持すればいいことに気づく
    • KOBA789: player_score のデータ構造の最適化と MySQL への移行を同時に開始(player_last_score テーブルを MySQL に作る)
  • 13:19
    • KOBA789: player_last_score 対応のアプリのコード書き換えが完了
    • KOBA789: player_last_score の初期データ作成スクリプトの開発開始
  • 13:50
    • KOBA789: player_last_score の初期データが完成
    • osyoyu: visit_history の Redis 化がバグり散らしたので断念
    • osyoyu & s4ichi: player & competition の MySQL 移行を開始
    • KOBA789: MySQL 移行完了後の一手を考えるため、プロファイリングとタスク整理の旅に出る
    • なおこのへんまでスコア変化なし
  • 15:40
    • osyoyu & s4ichi: MySQL 移行完了
    • s4ichi: 移行完了を確かめるため、SQLite 周りのメソッドを noop に書き換え開始
    • osyoyu: いつもの分析ツールが使えるようになったため、MySQL にインデックスを貼ってスロークエリを潰し始める
    • KOBA789: player_score CSV の入稿で1件も保存されずに不整合でペナルティを食らう原因を調査開始
  • 16:18
    • KOBA789: ペナルティの原因は DELETE & INSERT によるデッドロックトランザクションが ROLLBACK してるからと判明。バルクインサートにして解決を試みる
    • s4ichi: 地道に N+1 を潰し始める
    • osyoyu: 完全に MySQL に移行できたため、満を持して複数台構成へ
    • このへんでスコアが一気に跳ねて25000くらいに
  • 17:00 頃
    • s4ichi: 「player の INSERT で dispense_id が遅い」
    • KOBA789: dispense_id を Redis INCR 化
    • osyoyu & KOBA789: visit_history の効率化に再挑戦開始
  • 17:40 頃
    • osyoyu & KOBA789: visit_history がまたもやバグり散らしたため断念
    • s4ichi: デバッグログを無効化
    • デバッグログ切っただけで1割くらいスコア伸びた
  • 17:50 頃
    • s4ichi: YJIT 有効化
    • YJIT は意味なかった(MySQL がパツパツで Ruby が遊んでいたため)
  • 18:00 競技終了
    • 17:00 から本質的な改善はなく、デバッグログを切ったことによるスコア向上だけでフィニッシュ

リモートソレイユと味集中カウンター

うちのチームはいつも1つの物理空間に3人で集まって戦うスタイルだったのですが、今年は初のリモートソレイユでした。

物理空間の大きな特徴として、ブロードキャストが容易であるという点があります。たとえば同じ空間にいる場合、その場で声を出せばなんの工夫がなくても他の2人に伝わるでしょう。

一方で、互いが遠隔地にいる状況ではそうではありません。音声はなんらかの通信手段を用いて意識的にブロードキャストしなければ伝わりません。これは物理空間と比較して(直感的には)不便な点です。

しかし私はこの特性を逆手に取り、従来あったコミュニケーションの課題を解決することにしました。

物理空間では「ブロードキャストが容易である」と述べましたが、裏を返すとそれは、受け取る情報のフィルタリングが難しいということでもあります。

私達のチームでは、しばしばペアプログラミングが発生します。難しい変更でバグが出たときなど、ひとりではパニックや視野狭窄に陥ってしまいがちなシチュエーションでは、ペアプログラミングはひとりよりも冷静に問題に対処できるため、2倍の人的リソースを投入してもなお結果として効率的なことがあるためです。

ペアプログラミングをすると必然的に声によるコミュニケーションの量が増えます。そしてこの声は、物理空間では必ずブロードキャストになります。ペアでないもう一人にも声は到達します。他人が悩んでいる声というのはとても気になるものです。特に私は気になってしまうタイプです。

たいていは2人だけで解決できますし、たとえ3人の知恵を同時に投入した方が解決が多少早かったとしても、3倍の人的リソースを投入するのが合理的な課題というのはそう多くありません。多くの場合、ただの野次馬根性で首を突っ込み、貴重な時間を浪費するだけになります。それくらいなら、チームメイトを信頼して背中を任せ、もうひとりは別の問題の解決に向けて深い思考をすべきでしょう。

やや遠回りな説明になってしまいましたがまとめましょう。従来あったコミュニケーションの課題とは、物理空間ではどうしても声が気になってしまい(主に私)、ひとつの問題に余計に多くの人数で取り組むことになって効率が悪くなることがある、ということです。

今回、私達のチームではコミュニケーションツールとして Discord を選びました。そして、上述の問題を解決するため、ひとり専用のボイスチャンネル「味集中カウンター」を用意しました。

チームのDiscordサーバーには、ひとりしか入れないボイスチャンネル「味集中カウンター」がある

他のチャンネル名が意味不明なのは見なかったことにしてください。語ると長い経緯はありますが、深い意味はありません。

ひとりで集中したいとはいえ、すぐに声をかけられないのでは不便です。時間の限られた ISUCON という競技では、メンション送ったけど反応がないというようなことがあると貴重な時間を無駄にします。

さて、Discord には他のツールにない機能として、あるボイスチャンネルにいるユーザーを強制的に別のボイスチャンネルに移動させるという機能があります。味集中カウンターはこの機能を使ったアイデアです。

まず、集中したい人は味集中カウンターに入ります。そして黙々と作業をします。もし、他のメンバーが一蘭を食ってる人に用があるときは、先述のボイスチャンネル間の強制移動機能で「再起動試験(あっさり)」チャンネルに呼び戻します。するとすぐに声をかけて相談等ができます。相談が済めば、麺が伸びないうちにまたカウンターに戻ります。

こうして、「集中したいときは他人の声をシャットアウトできるが、用があるときはすぐに声をかけられる」という仕組みが完成しました。

本戦に向けて

まずは Ruby を本戦に連れて行けて嬉しいです。やはり本戦に出るからには目指すは優勝です。Ruby にもう一度てっぺんの景色を見せてあげられるまで諦められません。

おまけ

感想戦配信のアーカイブがあるのでよかったら観てってください。はじめて凸待ち配信をしたのですが、たくさんの方とお話しできて楽しかったです。

youtu.be

パスタの茹で方

この春から一人暮らしを始めたみなさんへ。

とりあえず「DJ WILDPARTY パスタ」で検索して欲しい。

検索しても見つからなかった人は下記のリンクを開いて欲しい。

note.com

以上にすべて書いてあるのでここで特段解説すべきことはない。

特段解説すべきことはないので、つまり以下は完全に蛇足なのだが、暇な人は読んでもいい。

改めて、この春から一人暮らしを始めたみなさんへ。まず火には気をつけた方がいい。火を付けている間は目を離さないほうがいい。デスクに戻って Twitter をしている間にも火は広がり、人生が終わりかけているかもしれない。

ところでパスタのゆで時間は10分弱くらいある。10分もの間キッチンに立って火を見張っているのは退屈だし、家でパスタを食べようってときはたいていそんなに元気がないときだ(私の場合)。

そこでこのテクニックだ。火をつけておかなければならないのは最初の1分だけだ。つまりそのあとは見張りは不要で、Twitter をしようがデイリーを回そうが自由だということだ。ただし油断して放置するとのびきったパスタを食べるはめになる。タイマーは忘れずに。

ちなみにオススメのパスタソースはキユーピーのこのシリーズです。ソースを温めなくていいし、1袋が1人前サイズで使いやすい。この世には1袋が2人前のパスタソースが多すぎる。

www.kewpie.co.jp

ではよき一人暮らしを。

GitHub Projects (beta)のデータをSQLでクエリ・更新できるツールを作った

これは KOBA789 日記 Advent Calendar 2021 - Adventar 21日目の記事です。

GitHub Projects (beta)

みなさん GitHub Projects (beta) は使っていますか? 私はめっちゃ使っています。

しかし beta ということもあってまだまだ使いづらかったり機能が足らなかったりすることがありますよね?

マウスでポチポチしながら、SQL で操作できたらラクなのになぁと妄想したりもします。というわけで作りました。

ghsql

GitHub Projects (beta) のデータを SQL でクエリ・更新できるツールを作りました。SELECT はもちろん、UPDATE や DELETE もできます(INSERT は未実装)。

github.com

インストール

まだ crates.io とかには公開してないので、git clone して cargo install --path . してください。

使い方

Personal Access Token や Installation Access Token などを環境変数 GITHUB_TOKEN に設定してください。

コマンドの引数は以下の通りです。

USAGE:
    ghsql <OWNER> <PROJECT_NUMBER> --github-token <github-token>

SQL の例

テーブル名は items 固定です。

とりあえず全部列挙:

SELECT * FROM items;

もちろん件数も数えられる:

SELECT count(*) FROM items;

StatusIn Progress なやつだけ列挙:

SELECT * FROM items WHERE Status = 'In Progress';

リポジトリと Issue 番号を指定して StatusDone に更新:

UPDATE items SET Status = 'Done' WHERE Repository = 'owner/repo' AND Issue = 123;

StatusDone なアイテムを全部削除:

DELETE FROM items WHERE Status = 'Done';

もちろん、Iteration にも対応しています。

イテレーション(Iteration 10)の積み残しを全部次のイテレーション(Iteration 11)に持ち越し:

UPDATE items SET Iteration = 'Iteration 11' WHERE Iteration = 'Iteration 10';

その他

思いついた勢いで一気に作ったので、気合いでごり押した設計と実装になっています。

終わりに

もうアドベントカレンダーも終盤じゃん。そろそろ書かなくていいかな。

穴を開ける、柱を立てる

これは KOBA789 日記 Advent Calendar 2021 - Adventar 18日目の記事です。

日記

今日は大学の後輩の部屋にツーバイフォー材を立てるのを手伝いました。DIY 大好きマンにはお馴染みのアレです。

ホームセンターに木材を買いに行き、軽トラを借りて持って帰ってくるという、いつものやつをやりました。

プロジェクターを設置したいということだったので、私が引っ越す前に使っていたプロジェクターとその固定金具一式を押しつけました。10年前に買った物体だし、今の部屋にはデカい有機 EL ディスプレイがあるしで、邪魔だったんですよね。

プロジェクターを適当な木ねじだけで吊るすと強度にやや不安があるので、柱に貫通穴を空けてボルトを通しました。引越し前の私が使っていた、実績のある構造です。

今持ってる電動ドリルはちょっと非力なので、マキタのやつとか欲しいですね。まぁ年に数回しか使わないんですけど。ドリルを買いにきた客が本当に欲しいのは穴ではなくマキタ。

終わりに

明日も書く。 久しぶりに暇な日曜日なので新しい DBMS でも作ろうかな。

SWDやCMSIS-DAPとにらめっこした

これは KOBA789 日記 Advent Calendar 2021 - Adventar 17日目の記事です。12月って16日がないらしいです。

日記

SWD や CMSIS-DAP とにらめっこしていました。SWD や CMSIS-DAP というのは、Arm マイコンデバッグをするときに使うやつです。にらめっこの結果として rust-dap のバグを見つけたので PR を出しました。

rust-dap は CMSIS-DAP v2 に対応してるし実装小さくて移植しやすいしで最高です。実際に手元の bluepill に移植して活用しています。

これは私がやっつけ移植した bluepill 対応版(fork): GitHub - KOBA789/rust-dap: CMSIS-DAP Rust implementation

自分が使うソフトウェアが自分の慣れた言語で書かれている安心感は何物にも代えがたいですね。多少バグってても自力で直せるので身軽です。

そうそう、CMSIS-DAP ではどうやってフラッシュへの書き込みをしているんだろうと思って調べたところ、なんとフラッシュ書き込み用の小さなファームウェアを RAM 上に展開してそれを呼び出して書き込ませるという仕組みでした。その小さなファームウェアのことを Flash Programming Algorithm と呼ぶらしいです。またひとつ賢くなりました。

終わりに

(12月に18日があれば)明日も書く。

ひさしぶりに「データ指向アプリケーションデザイン」を読んだ

これは KOBA789 日記 Advent Calendar 2021 - Adventar 14日目の記事です。

日記を書くには早すぎる時間なんだけれど、久しぶりに「データ指向アプリケーションデザイン」を読んだら気持ちが高まりすぎてしまったので、書く。

データ指向アプリケーションデザインと私

「データ指向アプリケーションデザイン」(以下、本書)は "Designing Data-Intensive Applications" の和訳であり、2019年に発行された書籍です。

原著の方は2017年には発行されていたらしいのだけれど、恥ずかしながら当時は知りませんでした。和訳が出たということで話題になっていたのを見て知り、買って読みました。

初めて読んだときの衝撃といったらすごいものでした。学術的なバックグラウンドがほぼ皆無な私が趣味・業務内の試行錯誤のみから思索してぼんやりと仮説を立てていたものについて、その答えが根拠とともに載っていたのです。

私の感覚は間違っていなかったんだという安堵感と同時に、なぜ文献にあたらずにひとりだけで問題に向き合っていたのかと後悔し、また列挙されている参考文献の多さを見て、私と興味を共有する人々が世界中にはこれほどいるのかと嬉しくなったのを覚えています。

その感動をより多くの人と分かち合いたくて、すぐにその場で追加でもう1冊追加で買い(布教用というやつです)、とりあえず当時の職場の CTO の机の上に置いたりもしました。

ペーパーバック版は大きくて持ち歩きづらいので、友人とのふとした会話の中で参照するには不便です。そのため電子版も買ってスマートフォンに入れてあります。電子版は全文検索が効くので、紙の本をシークするときの索引としても便利ですね。

ひさしぶりに読んだ

そんな本書ですが、今朝2年ぶりくらいに読み直しました。きっかけは若干仕事で必要だったからなんですが、勢いで頭から第Ⅱ部(400ページくらい)まで読みました。思い入れのある1冊の割にはレビュー(?)をしたことがなかったことに気づきました。せっかくなので書きます。

12ページ目くらいで早速 Twitter のタイムラインの話が出てくるあたりで泣きそうになりました(一度読んでるはずなんですけどね)。データシステムに興味があれば、誰しも一度はスケーラブルなタイムライン機能の設計を考えるものです。読者のハートをガッチリ掴んできます。

日常的にデータシステムと向き合っていれば、システムの信頼性を高めるにはどうすべきか、スケーラブルにするにはどうすべきか、という勘が多少なりとも育まれます。しかし、実際に信頼性の低いコードやスケーラブルでない設計を目の当たりにしたときにその問題をわかりやすく説明できるでしょうか。あるいは妥当な修正案を出せるでしょうか。必ずしもそうとは限りません。

本書ではそうした勘を言語化するための強力な武器になります。課題を分解し、概念を定義し、例を交えて読者に整理されたメンタルモデルを与えます。いずれも現場に向き合ったことがあればスッと心に染みる課題ばかりです。課題が分解され整理される様を追いながら解説にうなずき続けることになるでしょう。読者の悩みを読者より雄弁に語ります。

REST と RPC の話が個人的に好きなので一部を引用します。

RESTの魅力の一部は、それ自身がネットワークプロトコルであるという事実を隠そうとしていないことにあります データ指向アプリケーションデザイン P.145

私が今よりもさらに未熟だったころ、RPC に夢を見すぎて実際に本書で指摘されているような RPC の問題に直面したことがあります。本書では、リモートサービスの呼び出しをローカルの関数呼び出しのように見せかけるアイデアには「根本的な問題がある」とすら書かれています。私もそう思います。具体的にどういう問題があるのかは P.144 を参照してください。

関連して、8章の内容も好きです。特に8.2の、非同期パケットネットワークって不便だよね、というあたり。皆さんご存じの通り、IP ネットワークは非同期パケットネットワークの一種です。なのでいろいろ困ったことが起きます(具体的な困りは P.302 あたりを読んでください)。

でも TCP を習う時って信頼性のあるプロトコルだって説明されませんか? UDP と比較して TCP には順序保証とか到達確認とかがあるってだけなんですが、10年くらい前に勉強したときは、TCP はめっちゃ信頼性がある印象を受けました。信頼性あるなら普通に RPC 乗っければいいって発想になりますよね? 私だけ? まぁ結論としてはそれは幻想なんですが。

第3章、ストレージの話が grep や tail を用いた素朴なストレージエンジンの実装から始まっているのも感動的です。私の書いた記事ではいきなり B-Tree から始めてしまいましたが、誌面の余裕さえあればシンプルなテーブルヒープから始めた方がわかりやすいし、インデックスのありがたみや意味が実感できるよな、と思ったりします。

ストレージエンジンに(当然)魔法なんかなくて、実にエンジニアリングらしいチマチマしたトレードオフの選択でそれっぽい性能特性が得られてるだけなんですよね。その出発点として、まずは(直感的にダメそうでも)素朴な実装から始めてみるというのは理解に大いに役立ちます。ちなみに直感的にダメそうでも特定ケースでは問題なかったりしますし、現実がそのうまくいく特定ケースにハマることはよくあります。自戒を込めて。

この調子で書いていくといくらでも語れそうなのでこのへんにしておきます。あ、Avro のライターのスキーマ・リーダーのスキーマとかも地味ですがおもしろいですよね。まずい、話が終わらなくなる。

終わりに

明日も書く。

2021-12-13

これは KOBA789 日記 Advent Calendar 2021 - Adventar 13日目の記事です。

冒頭に書くこともなくなってきたし、2021年も消化試合の様相を呈して参りました。

日記

久しぶりに電磁リレー回路 CAD zuse のメンテをしました。

WebGL の足回りに golem というライブラリを使っていたのですが、メンテが止まっているっぽいので依存から外して、その下のレイヤーの glow というライブラリを直接使うように書き換えました。

経験がある人には伝わると思いますが、OpenGL ってやつは API が超 stateful です。WebGLOpenGLAPI デザインをほぼ完全に引きずっているので同様です。

あるオブジェクトを操作するにはまずそのオブジェクトを bind して、そのあとに続く関数呼び出しではその直前に bind したオブジェクトを操作する、みたいなデザインです。

golem というライブラリはこういった面倒な bind 操作をうまく隠蔽してくれていてとても便利だったんですが、作者が力尽きていそうなので仕方なしですね。

メンテのために久しぶりに電磁リレー回路 CAD に触ってみたらまだまだ遊べそうだなと思いました。年末年始の休みで時間とって拡張できたらいいなと考えてます。

終わりに

EKS めんどくさい!!!(心の叫び)

明日も書く。