題材を読む
読了目安 約2分
ISUCON 12 予選 ISUPORTS の構造と、データが 2 か所に分かれている事情を押さえます。
この章の目次
ISUPORTS は、大会の順位表を提供する Web サービスです。 コードは isucon/isucon12-qualify にあります。
登場人物
サービスを使う主体は 3 種類です。
| ロール | できること |
|---|---|
| SaaS 管理者 | テナントの追加、テナントごとの請求額の確認 |
| テナント管理者 | 参加者の追加、大会の作成と終了、スコアの CSV 入稿 |
| 参加者 | 大会一覧、大会ごとのランキング、自分のスコアの確認 |
テナントは、大会を主催する団体ひとつぶんの区画です。 参加者もスコアもテナントの中で完結していて、テナントをまたいで参照することはありません。
データの置き場所が 2 つある
この問題の特徴は、データベースが 2 種類あることです。
| 置き場所 | 中身 |
|---|---|
| MySQL(管理用 DB) | tenant、visit_history、id_generator |
| SQLite(テナント DB) | player、competition、player_score |
SQLite はテナントごとに 1 ファイルです。
tenant_db/1.db のように、テナント ID がそのままファイル名になっています。
// テナントDBに接続する
func connectToTenantDB(id int64) (*sqlx.DB, error) {
p := tenantDBPath(id)
db, err := sqlx.Open(sqliteDriverName, fmt.Sprintf("file:%s?mode=rw", p))
if err != nil {
return nil, fmt.Errorf("failed to open tenant DB: %w", err)
}
return db, nil
}MySQL は別プロセスなので、クエリのたびに通信の往復が起きます。 SQLite は同じプロセスの中でファイルを読むだけなので、往復がありません。 同じ「1 クエリ」でもかかる時間が違います。
スコアの決まり方
ベンチマーカーは、参加者がランキングを見るなどの操作に成功するたびに加点します。 レスポンスが速いと参加者の数を増やし、遅いと参加者が離脱します。 1 リクエストを速くすると、次はもっと多くのリクエストが飛んできます。
計測に使った環境
- アプリ・MySQL・nginx がすべて同じ 1 台に載っている(2 vCPU、メモリ 4 GB)
- ベンチマーカーの走行時間は 60 秒
- 初期実装のスコアは 6072
以降の章のスコアは、この環境で測った値です。