---
# System prepended metadata

title: ISUCON7予選
tags: [過去問]

---

# ISUCON7予選

###### tags: `過去問`

## レギュレーション
https://isucon.net/archives/50927022.html

## マニュアル
https://github.com/isucon/isucon7-qualify

isucon1(app)
public: 54.178.214.110
private: 172.31.32.90

isucon2(db)
public: 54.238.55.143
private: 172.31.34.241

isucon3(nginx)
public: 54.64.133.47
private: 172.31.40.208

ベンチ
./bin/bench -remotes=127.0.0.1 -output result.json

エラーで落ちる問題
-portalをつけるとなぜか解決する

goの最新版インストール

チャンネルが10

未読

ユーザー詳細
ユーザー名、表示名、画像



```
cd ~/local
wget https://golang.org/dl/go1.16.5.linux-amd64.tar.gz
rm -rf go
tar -xzf go1.16.5.linux-amd64.tar.gz
```

## アプリ概要

### データベーススキーマ
#### User
|field|type|desc|
|-|-|-|
|id|int|key incr|
|name|string|unique|
|salt|string|
|password|string|
|display_name|string|
|avatar_icon|string|URL?|
|created_at|time||

#### Image
|field|type|desc|
|-|-|-|
|id|int|key incr|
|name|string|unique|
|data|Blob||

#### Channel
|field|type|desc|
|-|-|-|
|id|int|key incr|
|name|string||
|description|string|MIDIUMTEXT|
|updated_at|time||
|created_at|time||

#### Message
|field|type|desc|
|-|-|-|
|id|int|key|
|channel_id|int||
|user_id|int||
|content|text||
|created_at|datetime|not null|


#### haveread
|field|type|desc|
|-|-|-|
|user_id|int|key|
|channel_id|int|key|
|message_id|int|keyいらない？|
|updated_at|time||
|created_at|time||

### エンドポイント

|resouce|method|desc|
|-|-|-|
|/initialize|GET|ベンチマークごとの初期化処理。特定のID以上のデータと既読を削除|
|/|GET|ログインしてたらチャンネル1にリダイレクト。そうじゃない場合ウェルカムページ表示|
|/register|GET|新規登録ページ|
|/register|POST|nameとpasswordで新規登録してセッションにUserIDセット。重複の場合StatusConflict|
|/login|GET|ログインページ表示|
|/login|POST|userをnameで検索。登録されていないForbidden。salt+pwをsha1してpasswordと比較。セッションにuserIDセット|
|/logout|GET|セッションのuserID.session.Save(request, response)?|
|/channel/:channel_id **ヤバイ**|GET|ensureLogin（ログインの確認），channelテーブルから**channel全体をOrderby取得して**，そこから**目的のchannel_idをfor-loopで見つける**．最後に取得したchannelを返す|
|/message|GET|channel_idのlast_message_id以降のメッセージを一覧取得。jsonifyMessageでUserを1:Nで取得しているので遅い。havereadの最新のmessage_idのupdated_atをnowにして既読判定？|
|/message|POST|ログイン確認、チャンネルにメッセージを追加|
|/fetch|GET|チャンネルごとの未読の数を一覧で取得する。謎の1秒sleep。channel一覧取得。ユーザーチャンネルのペアごとにhavereadを見て最新のmessage_idを取得して、それ以降のmessageの数をmessageにcountクエリして取得している|
|/history/:channel_id|GET|ログイン確認。1ページは20件。毎回チャンネルのメッセージ総数をクエリしてるので遅そう。OFFSE使ってるので遅い。jsonifyMessageのユーザー結合でもロス出てる。チャンネル一覧取得も（横のチャンネル一覧表示するため？）|
|/profile/:user_name|GET|ログイン確認、チャンネル一覧取得。userをnameで検索して取得。自分かどうか(self or other)で分岐処理あり|
|/profile|POST|ログイン確認、イメージがある場合はLastIndexBytesでファイルネームから拡張子取得、fileからreadしてバイナリ取得して、sha1したやつを拡張子に連結してファイル名としてimageに保存。avatarNameをavatar_iconとしてuser更新。display_nameとupdateも別クエリでやってるので改善の余地あり。nameはidでいい|
|/add_channel|GET|ログインの確認，channelテーブルから**idでソートして** channelを取得．channelからテンプレート生成して返す．|
|/add_channel|POST|ログインの確認，フォームからname,descriptionを受け取って，channelテーブルにレコードを追加．/channel/にリダイレクトする|
|/icons/:file_name|GET|imageからfile_nameで検索，name, data取得|


画像をnginxでキャッシュして返す
メッセージ:ユーザーの1:N
1. post profile
2. get icons/
3. get message


## ryunosuke
`./bin/bench --remotes=35.75.211.183,35.75.208.108 --portal=localhost -output result.json`

`
cat webapp/isucon1/nginx/log/access.log | alp ltsv -m "/history/[0-9a-zA-Z]+,/profile/[0-9a-zA-Z]+,/icons/[0-9a-zA-Z],/channel/[0-9a-zA-Z]" --sort avg -r > results/{tag}.alp`

`
cat webapp/isucon2/nginx/log/access.log | alp ltsv -m "/history/[0-9a-zA-Z]+,/profile/[0-9a-zA-Z]+,/icons/[0-9a-zA-Z],/channel/[0-9a-zA-Z]" --sort avg -r > results/{tag}.alp`

### app
git pull origin master
cd go && go build -o isuabta
sudo systemctl restart isubata.golang.service

iconをファイルで保存
5000 -> 10000

iconをnginxでキャッシュ
10000 -> 20000

unreadをキャッシュしてfetch改善
20000 -> 50000

fetchにtime sleep追加
50000 -> 90000 (ただしスコアにかなりバラつきあり)

sleepを長くしたりランダムにしたり色々試してみたけどダメ

---

ネットワーク問題解消（fetchUnreadキャッシュ済み）

isucon1: nginx, app(profileのみ)
isucon2: app
isucon3: mysql

で156712

messageの1:N解消で400000