---
# System prepended metadata

title: ISUCON10予選

---

# ISUCON10予選

[TOC]

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

## マニュアル
https://gist.github.com/progfay/25edb2a9ede4ca478cb3e2422f1f12f6

## スプレッドシート
https://docs.google.com/spreadsheets/d/1RCrOuT6_eLdR11_adWrWJMCm7cozexnHPEG1nUb-ElU/edit?usp=sharing

## bench
`./bench --target-url http://35.72.103.176`

## botを弾く
/ISUCONbot(-Mobile)?/
/ISUCONbot-Image\//
/Mediapartners-ISUCON/
/ISUCONCoffee/
/ISUCONFeedSeeker(Beta)?/
/crawler \(https:\/\/isucon\.invalid\/(support\/faq\/|help\/jp\/)/
/isubot/
/Isupider/
/Isupider(-image)?\+/
/(bot|crawler|spider)(?:[-_ .\/;@()]|$)/i

```
        location / {
            if ($http_user_agent ~ \ISUCONbot(-Mobile)?\) {
                return 503;
            }

            proxy_pass  http://app;
        }
```

## 接続情報
### ssh
```
Host isuutil
	HostName 13.230.129.93
	User ubuntu
	IdentityFile ~/.ssh/isucon7q-sshkey.pem
	ServerAliveInterval 60

Host isubench
	HostName 13.113.185.7
	User ubuntu
	IdentityFile ~/.ssh/isucon7q-sshkey.pem
	ServerAliveInterval 60

Host isucon1
	HostName 35.72.103.176
	User ubuntu
	IdentityFile ~/.ssh/isucon7q-sshkey.pem
	ServerAliveInterval 60
  
Host isucon2
	HostName 35.73.89.21
	User ubuntu
	IdentityFile ~/.ssh/isucon7q-sshkey.pem
	ServerAliveInterval 60

Host isucon3
	HostName 35.76.49.129
	User ubuntu
	IdentityFile ~/.ssh/isucon7q-sshkey.pem
	ServerAliveInterval 60
```

### 内部IP
- isucon1: 172.31.6.74
- isucon2: 172.31.9.97
- isucon3: 172.31.10.52

## 事前
- [ ] Elastic IPを登録しておく
- [ ] AWSインスタンス作成時にダウンロードした鍵を共有しておく
    - isucon-sshkey.pemで~/.sshに保存
    - chmod 600 ~/.ssh/isucon-sshkey.pem
- [ ] ~/.ssh/configの設定
- [ ] isucon[X]-qualifyレポジトリを空で作成しておく
    - `git@github.com:isucon-kuolc38th/isucon(X)-qualify.git`
<!--     - テンプレート準備
        - local
        - pprof
        - results
        - tools
        - .gitignore
        - docker-compose.yml
    - （各自）クローンし、ローカルで諸々のセッティングをしておく
        - VSCode
        - Github Desktop
    - (要検討)これらはサーバー内に用意されている方を踏襲したほうがよさそう?
        - mysql
        - nginx
        - env.sh -->
- [ ] isucon[X]-qualify-utilレポジトリを作成し、各自Pullして動作確認を済ませておく
    - `git@github.com:isucon-kuolc38th/isucon(X)-qualify-util.git`


## 初期構成
- isucon1
    - Nginx
    - App
- isucon2
    - 何もなし
- isucon3
    - (Redis)
    - MySQL

## AWS
- [ ] EC2でインスタンス作成→マシンイメージ選択で指定されたAMIを選択
- [ ] インスタンスタイプを選択
- [ ] ボリュームはSSDで16GB（インスタンスタイプによって変わるかも）
- [ ] セキュリティグループの設定
    - 「すべてのTCP」、ソースに「0.0.0.0/0」を指定
    - 「すべてのICMP」、ソースに「0.0.0.0/0」を指定
    - セキュリティグループはあらかじめ作成しておいたものを使うのが良い
- [ ] キーペアにisucon-sshkeyを指定
- [ ] インスタンスが起動したら、Elastic IPのページからインスタンスに事前に用意したElastic IPを紐付け
- [ ] それぞれの名前をつける

## タイムスケジュール
|timetable|all|rkoike|cojiro|ryunosuke|
|--|--|--|--|--|
|00:00 競技開始|||||
||マニュアル確認<br>初期ベンチ回す（レコード数確認）<br>アプリ触ってみる<br>レポジトリPush・各自クローン||||
|00:20 作業開始|||||
|||レポジトリPull<br>マシンセットアップ<br>Nginx（ログ含む）<br>MySQL（ログ含む）<br>App (GOインストール)<br>netdata|Appの初期設定|ALPのグルーピング<br>コードリーディング<br>仕様の整理<br>ボトルネックの洗い出し|
||（ここまでの目標）<br>スクリプトからデプロイできるようになっている<br>pprof, measure, ALPのデータが1回ずつ取れている<br>ボトルネックの洗い出し・タスク分割がある程度完了している||||
|01:30 改善開始|||||
||大幅な改修を行うかどうかの決定<br>仕様・ボトルネックの共有と把握<br>タスクの割り振り||||
|||Nginxの設定チューニング<br>Staticファイルのキャッシュ設定<br>ベンチマーク分析<br>インフラ最適化|MySQLの設定チューニング<br>インデックス作成<br>SQLクエリ改善|メインボトルネック解消<br>影響範囲の広いApp改善<br>変更のないデータのオンメモリ化|
|05:00 メインボトルネック解消|||||
|||ベンチマーク分析<br>インフラ最適化<br>時間のある時に再起動試験|影響範囲の狭いApp改善|使用頻度の高いデータのオンメモリ化|
|07:00 提出準備|||||
||再起動試験|netdata無効化<br>MySQLログ無効化<br>Nginxログ無効化|measure無効化|安全な（？）App改善<br>ボーダーが遠い場合にワンチャンかける|

- 仕様把握の上でmeasureのデータがいち早く欲しいので、GOへのアプリ切り替えとmeasureの仕込みが終わった時点ですぐベンチを回すこと
- 役割分担
    - rkoike: インフラ構成の変更に伴う実作業、netdataなどを用いたハード面の(CPU/メモリ/IO/ネットワーク)ボトムアップ分析を担当。カーネルチューニングや、余裕があればNginxのチューニングも行う
    - cojiro: SQLクエリの改善などボトムアップな改善を担当（ログの分析も含む）
    - ryunosuke: 大幅な改修を含むアプリのトップダウンな改善を担当

## チェックリスト
### 全体
競技前
- [x] ベンチ準備
- [x] 空repo作成
- [x] util環境作成
    - [x] repo
    - [x] インスタンス
    - [x] Remote Desktop
- [x] スプレッドシート作成
- [x] Elastic IP作成

競技開始
- [ ] 初期ベンチ
    - [ ] ベンチ前のレコード数を記録
    - [ ] ベンチ後のレコード数を記録

競技中
- [ ] メインベンチ
    - [ ] pprofファイル取得
    - [ ] measureのstatsをスプレッドシートに記録
    - [ ] ログ類をフェッチ

競技終了
- [ ] 再起動試験
    - ベンチ実行
    - 再起動
    - ブラウザからアクセスしてアプリが正しく動くか
    - ベンチのデータが正しく保存されているか
    - もう一度ベンチ実行して同様のスコアが出るか

### rkoike
競技開始
- [ ] <a href="#Git">レポジトリへのコードプッシュ</a>
- [ ] 初期構成のセットアップ
    - [ ] <a href="#セットアップ">nginx</a> (isucon1): インストール、ログの設定、appとの接続
    - [ ] app (isucon1): Goの最新版インストール、PATH設定、appとの接続
    - [ ] <a href="#セットアップ1">mysql</a> (isucon3): ログの設定
    - [ ] netdata (isucon1): インストール
    - [x] fixture追加

競技中
- [ ] <a href="#監視コマンド">ツールを用いたハード面のボトルネック分析</a>
    - netdata, netstat, vmstat, htop
- [ ] カーネルチューニング
    - [ ] app, nginx, mysqlのファイル上限
        - http://blog.father.gedow.net/2016/03/28/limits-of-systemd/
    - [ ] tw_reuseなどのカーネルパラメータ設定
    - [ ] (unix socket)
    - [ ] <a href="#設定のチューニング">nginxのパラメータチューニング</a>
    - [ ] 静的ファイル(キャッシュ, gzip_static)
    - [ ] proxy_cache
    - [ ] keepalive
- [ ] 再起動試験

競技終了
- [ ] ログの切り替え
    - nginx
    - mysql
- [ ] 不要なプロセス停止
    - netdata

### cojiro
競技開始
<a href="#セットアップ2">セットアップ手順</a>
- [x] GOMAXPROCS設定
- [x] measure仕込む
- [x] pprofのハンドラー準備
- [x] mysqlの接続確立
- [x] sqlxの差し替え
- [ ] 400/500のエラーが出た場合にログに出力するようにする

競技中
- [ ] スローログのダイジェストを見て遅い/多いクエリの分析、改善
- [ ] MySQLのパラメータチューニング

競技終了
- [ ] pprof削除
- [ ] measure削除

### ryunosuke
競技開始
- [ ] ALPのグルーピング
- [ ] スプレッドシートに仕様をまとめる
    - [ ] キーポイント
    - [ ] エンドポイント一覧
    - [ ] SQLスキーマ
- [ ] コードの読み込み

競技中
- [ ] 大幅なアプリの改修
- [ ] インメモリ化

競技終了
- [ ] 頑張る

## 作業マニュアル
### マニュアル確認

### ベンチマーク

### Git
#### SSH Key登録
``` bash
mkdir ~/.ssh
cd ~/.ssh && ssh-keygen
cat id_rsa.pub
```

- [ ] isucon[X]で名前をつける
- [ ] Write権限にチェックを入れること

#### 初回Push
- [ ] SSH Key登録

``` bash
cd ~/<apphome>
git config --global user.name "isucon[1-3]"
git init
git remote add origin git@github.com:isucon-kuolc38th/isucon[X]-qualify.git <appname>
# 必要に応じて.gitignoreをいい感じに編集
git add .
git commit -m "initial setup"
git push origin master
```

#### 初回Pull
- [ ] SSH Key登録
``` bash
cd ~
mv <apphome> <apphome>_backup
git clone git@github.com:isucon-kuolc38th/isucon[X]-qualify.git
git config --global user.name "isucon[1-3]"
```

フォルダをマージする場合
`rsync -av isucari_repo/ isucari/`

### Nginx
#### インストール
- [ ] `sudo apt install nginx`

#### セットアップ
- [ ] 設定をgit管理下にコピー
``` bash
cd ~/<apphome>
sudo mkdir /etc/nginx_backup
sudo cp -r /etc/nginx /etc/nginx_backup
mkdir -p ./isucon[1-3]/nginx/config
sudo cp -r /etc/nginx/* ./isucon[1-3]/nginx/config
```
- [ ] 初期実装サービスの停止
``` bash
# Apache
sudo apachectl stop
sudo service httpd stop

# h2o
sudo systemctl stop h2o
sudo systemctl disable h2o
```
- [ ] appのIPアドレス設定
```
http {
    upstream app {
        server app:8080;
    }
    
    location / {
        proxy_set_header Host $http_host;
        proxy_pass http://app;
    }
}

```

- [ ] ログの設定
    - nginx.conf
    - (/var/log/nginxの権限設定)
- [ ] Nginxサービスの`start`と`enable`

#### 設定のチューニング
http://nginx.org/en/docs/
https://qiita.com/iwai/items/1e29adbdd269380167d2#use-epoll

デフォルトで設定するもの
- worker_processes
- sendfile, tcp_nopush, tcp_nodelay
- keepalive_timeout

too many file opensが出た時
- worker_rlimit_nofile
- worker_connections

ファイルの読み書きが多い場合
- open_file_cache

接続数が多い場合
- keepalive_requests
    - 接続数が多い時はある程度大きめの値にしておいて良い？
- upstream.keepalive
    - location.proxy_http_version, location.proxy_set_headerも忘れずに設定する

静的ファイル
- gzip_static
    - 同じディレクトリにあらかじめgzipファイルを作っておく
    - gzipはCPUを使うのでonにしないほうがいい？
- クライアントキャッシュが効く場合 -> max-age
- 効かない場合 -> proxy_cache

### MySQL
#### インストール
``` bash
sudo apt install mysql-server mysql-client
```

#### セットアップ
- [ ] 設定をgit管理下にコピー
``` bash
cd ~/<apphome>
sudo mkdir /etc/mysql_backup
sudo cp -r /etc/mysql /etc/mysql_backup
mkdir -p ./isucon[1-3]/mysql/config
sudo cp -r /etc/mysql/* ./isucon[1-3]/mysql/config
```

- [ ] ログの設定
    - 設定が効いているか確認: `SHOW VARIABLES LIKE "general_log%";`
    - ログファイルの所有権変更 `sudo chown mysql:mysql /var/log/mysql`
    - ログファイルが作成された後、読み取り権を付与 `sudo chmod 777 /var/log/mysql/*`

``` my.cnf
[mysqld]
log_output=FILE
general_log=1
general_log_file=/var/log/mysql/query.log
slow_query_log=1
slow_query_log_file=/var/log/mysql/slow_query.log
log_error=/var/log/mysql/error.log
long_query_time=0.2
log_queries_not_using_indexes=1
```

- [ ] MySQLサービスの`start`と`enable`
``` bash
sudo systemctl start mysql [mariadb]
sudo systemctl enable mysql [mariadb]
```

- [ ] (要検討)初期実装がmysql以外の時のスキーマやデータのコピー方法


#### データのdump
``` bash
mysqldump -u user db > data.sql
mysqldump -u user --no-data db > schema.sql
sftp isucon[1-3] /home/isucon/data.sql ./
sftp isucon[1-3] /home/isucon/schema.sql ./
```

#### 設定のチューニング
MySQL5.6.8以降とそれまででデフォルト値が違うので注意
https://dev.mysql.com/doc/refman/5.6/ja/server-system-variables.html
https://tetsuyai.hatenablog.com/entry/20111006/1317873012
https://qiita.com/mamy1326/items/9c5eaee3c986cff65a55

##### 優先的に確認する項目
- max_connections, thread_cache_size
    - 接続数に応じてチューニング？
- query_cache_type
    - 結果が変わらないクエリを何回も実行する時は効果があるが、それ以外では無効にする
- innodb_buffer_pool_size
    - 物理メモリの8割に設定
- max_heap_table_size, key_buffer_size, innodb_log_file_size, innodb_log_buffer_size
    - メモリに合わせて設定？
- innodb_buffer_pool_dump_at_shutdown, innodb_buffer_pool_load_at_startup
    - 設定しておくことで起動を速くできる

##### 設定項目一覧

### Redis
https://github.com/shirokanezoo/isucon4-qualifier-sorah/blob/master/redis.conf

#### インデックス最適化
- WHERE ORはUNIONにする
```sql
SELECT * FROM items WHERE seller_id = ? OR buyer_id = ?
--------------------------------------------------
SELECT * FROM items WHERE seller_id = ?
UNION
SELECT * FROM items WHERE buyer_id = ?
```

### systemd
`/etc/systemd/*`を編集し，appで`<appdir>/isucon[1-3]/env.sh`を読むようにする

### App
#### セットアップ
- [ ] Go最新版に入れ替え
``` bash
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
rm go1.16.5.linux-amd64.tar.gz 
```

- [ ] PATHを通す
    - `export PATH=$PATH:$HOME/local/go/bin`
    - `vim ~/.bashrc`をして`PATH=`に`$HOME/local/go/bin`を追記

- [ ] `<apphome>/isucon[1-3]/env.sh`を読むように設定
``` bash
cd ~/<apphome>
touch ./isucon[1-3]/env.sh
sudo vim /etc/systemd/system/<service_name>
# [Service]
# EnvironmentFile=<apphome>/isucon[1-3]/env.sh
```
- [ ] 実装切り替え
    - 他の言語実装を`stop`と`disable`
    - Golang実装を`start`と`enable`

- [ ] GOMAXPROCS
    - `runtime.GOMAXPROCS(runtime.NumCPU())`をinitに追加
### netdata
``` bash
bash <(curl -Ss https://my-netdata.io/kickstart.sh) all --dont-wait
```

### measure
https://github.com/najeira/measure

インストール
```
go get github.com/najeira/measure
```

使い方
```go
import "github.com/najeira/measure"

// 測定
func hoge() {
    defer measure.Start("hoge").Stop()
}

// リセット (initializeに書く)
measure.Reset()

// 結果取得用ハンドラ (echoの場合)
e.GET("/stats", echo.WrapHandler(http.HandlerFunc(measure.HandleStats)))
```

`/stats`にアクセスし、結果を右クリック>stats.csvで保存

### pprof
使い方
https://christina04.hatenablog.com/entry/golang-pprof-basic

```go
import "net/http/pprof"

// echo
e.Group("/debug/pprof").Any("/cmdline", echo.WrapHandler(http.HandlerFunc(pprof.Cmdline)))
e.Group("/debug/pprof").Any("/profile", echo.WrapHandler(http.HandlerFunc(pprof.Profile)))
e.Group("/debug/pprof").Any("/symbol", echo.WrapHandler(http.HandlerFunc(pprof.Symbol)))
e.Group("/debug/pprof").Any("/trace", echo.WrapHandler(http.HandlerFunc(pprof.Trace)))
e.Group("/debug/pprof").Any("/*", echo.WrapHandler(http.HandlerFunc(pprof.Index)))

// goji
mux.HandleFunc(pat.Get("/debug/pprof/cmdline"), pprof.Cmdline)
mux.HandleFunc(pat.Get("/debug/pprof/profile"), pprof.Profile)
mux.HandleFunc(pat.Get("/debug/pprof/symbol"), pprof.Symbol)
mux.HandleFunc(pat.Get("/debug/pprof/trace"), pprof.Trace)
mux.HandleFunc(pat.Get("/debug/pprof/*"), pprof.Index)
```

ベンチマーク中に、稼働しているサーバーに対してローカルで次を実行
``` bash
// CPU
curl -s http://<ip>/debug/pprof/profile?seconds=60 > cpu.pprof

// メモリ
curl -s http://<ip>/debug/pprof/heap?seconds=60 > memory.pprof
```

ローカルで結果表示
``` bash
go tool pprof -http=localhost:8080 *.pprof 
```

Webでの閲覧にはgraphvizのインストールが必要
``` bash
brew install graphviz
```

<!-- ### ローカル環境
#### セットアップ
- [ ] isucon-templateのdocker-compose.ymlのコメントアウトを編集
    - [ ] appのフォルダ
    - [ ] DBの環境変数
    - [ ] MySQLの変数
- [ ] local/publicにpublicをコピー
- [ ] local/nginx/config/nginx.confを編集
    - [ ] appのupstream
    - [ ] staticファイル
- [ ] local/mysql/initの各SQLファイルを編集
    - [ ] 00_setup.sqlにユーザー作成処理を書く
    - [ ] 01_schema.sqlにスキーマを書く
 --> 

### キャッシュ

### ベンチマーク分析
#### pt-query-digest
`pt-query-digest slow_query.log`

```
# 290ms user time, 20ms system time, 30.93M rss, 4.13G vsz
# Current date: Sun Aug  8 13:38:02 2021
# Hostname: iwairyuunosukenoMacBook-Pro.local
# Files: slow_query3.log
# Overall: 749 total, 5 unique, 11.70 QPS, 1.77x concurrency _____________
# Time range: 2021-07-18 11:46:31 to 11:47:35
# Attribute          total     min     max     avg     95%  stddev  median
# ============     ======= ======= ======= ======= ======= ======= =======
# Exec time           113s    63us      3s   151ms   672ms   310ms   119us
# Lock time             4s     5us      2s     5ms    63us    82ms    23us
# Rows sent          2.21M       0 187.74k   3.02k   28.75  22.97k   21.45
# Rows examine      51.66M      18 563.26k  70.62k 182.98k 105.89k   26.08
# Query size        53.27k      36     191   72.83  183.58   53.37   34.95

# Profile
# Rank Query ID                            Response time Calls R/Call V/M 
# ==== =================================== ============= ===== ====== ====
#    1 0xC622688A0CBAF834501E39FDEB19B588  39.9824 35.2%    82 0.4876  0.06 SELECT reservations
#    2 0x2B1DC7423E71BCFAC6BE997CA53B4627  39.3838 34.7%    82 0.4803  0.06 SELECT reservations sheets events
#    3 0x6DDCECAE12499086677CFFB2A33F9691  22.7544 20.1%    12 1.8962  0.19 SELECT reservations events
#    4 0xCB340AA6D46DFD09CF116CE1265D110C  11.1799  9.9%    82 0.1363  0.02 SELECT reservations
# MISC 0xMISC                               0.1547  0.1%   491 0.0003   0.0 <1 ITEMS>

# Query 1: 1.39 QPS, 0.68x concurrency, ID 0xC622688A0CBAF834501E39FDEB19B588 at byte 31538
# This item is included in the report because it matches --limit.
# Scores: V/M = 0.06
# Time range: 2021-07-18 11:46:32 to 11:47:31
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count         10      82
# Exec time     35     40s   187ms   877ms   488ms   740ms   171ms   501ms
# Lock time      0     1ms     6us    42us    13us    27us     7us    11us
# Rows sent      0     400       0       5    4.88    4.96    0.77    4.96
# Rows examine  29  15.02M 187.33k 187.75k 187.53k 182.98k       0 182.98k
# Query size    19  10.56k     130     132  131.84  130.47    0.68  130.47
# String:
# Databases    torb
# Hosts        ip-172-31-16-197.ap-northeast-1.compute.inte...
# Users        isucon
# Query_time distribution
#   1us
#  10us
# 100us
#   1ms
#  10ms
# 100ms  ################################################################
#    1s
#  10s+
# Tables
#    SHOW TABLE STATUS FROM `torb` LIKE 'reservations'\G
#    SHOW CREATE TABLE `torb`.`reservations`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT event_id FROM reservations WHERE user_id = 2209 GROUP BY event_id ORDER BY MAX(IFNULL(canceled_at, reserved_at)) DESC LIMIT 5\G
```

#### 監視コマンド
https://qiita.com/aosho235/items/c4d6995743dd1dac16e1

|コマンド|用途|収録パッケージ|
|--|--|--|
|vmstat 2|システム全体の負荷を見るならこれ。2で2秒ごと|procps|
|top|CPUやメモリを食っているプロセスを特定したいならこれ|procps|
|sar|過去の負荷の履歴をみたいならこれ|sysstat|
|mpstat -P ALL 1|CPUコアごとの負荷を見るならこれ|sysstat|
|dstat -taf|標準ではインストールされていないが、一番便利なコマン|dstat|
|free -m|メモリ。-mでメガバイト単位|procps|
|iostat -dmxt 1|IO状況|sysstat|

##### sar
https://qiita.com/muijp/items/956ac41c4cf6cf85ae12

sar -u CPU使用率
sar -q ロードアベレージ
sar -r メモリ利用状況
sar -W スワップ発生状況
sar -n ネットワークトラフィック
sar 1 1000 で1秒毎に1000回レポートする。

##### htop


### 再起動試験対策
#### AppのDB接続
``` go
for {
    var err error
    db, err = sqlx.Connect("mysql", dsn)
    if err == nil && db.Ping() == nil {
        break
    }

    log.Println(err)
    time.Sleep(time.Second * 3)
}
```

#### initialize
``` go
func initialize() {
    ClearCache()
    
    // DBロード処理
}

func getInitialize() {
    ...
    initialize()
}

func main() {
    ...
    initialize()
}
```

### 掃除
- [ ] MySQLログ無効化
- [ ] Nginxログ無効化
- [ ] Appログ無効化
- [ ] Redisログ無効化
- [ ] netdata無効化
    - `systemctl stop & disble`
- [ ] measure削除
    - `github.com/najeira/measure`をインポートから外して関連コードを削除
- [ ] pprof削除

<!-- ## 以下未整理（項目ごとに上の作業マニュアルに入れていく）
- [ ] 与えられたディレクトリ構成に合わせてこの資料を編集
    - (要検討)3台で別々のamiインスタンスが渡された場合のテンプレ

## 当日やること(ツール類の整備)
### 計測ツール検討中
- [ ] AWS X-Ray


## その他のツールやコマンド
### alp
``` bash
wget https://github.com/tkuchiki/alp/releases/download/v1.0.3/alp_linux_amd64.zip
apt install unzip
unzip alp_linux_amd64.zip
sudo mv alp /usr/local/bin/
rm alp_linux_amd64.zip
```

### 初期実装切り替え
#### init.d
``` bash
sudo chkconfig <service> on/off
sudo service <service> start/stop
```

#### systemd
``` bash
sudo systemctl enable/disable <service>
sudo systemctl start/stop <service>
```

#### supervisord
vim /etc/supervisord.conf 
```
[<service>]
...
autostart: true/false
```

```
supervisorctl restart
```

### 更新 & ベンチ
``` bash
cd <apphome>
git pull origin master

ps -aux | grep app
sudo kill <pid>

cd app && make build
make run &

cd ~/webapp && ./tools/benchmark.sh
# Running benchmark...

vim results/initial_score # TODO: 自動化

git add *
git commit -m "initial_score"
git push origin master
```
 -->
 
## Trouble Shooting
### Nginxで権限問題
- 迷ったら`nginx.conf`にはrootユーザーを書くのが無難
- 「13: Permission denied」[参考リンク](https://itips.krsw.biz/nginx-fail-port-forward-13-permission-denied/)

``` bash
sudo setsebool httpd_can_network_connect on -P
sudo chmod 701 /home/isucon
sudo systemctl restart nginx
```

- 「SELinuxの無効化」[参考リンク](https://qiita.com/hanaita0102/items/5d3675e4dc1530b255ba)
``` bash
# 一時的に無効化
setenforce 0

# 永続的に無効化(要サーバー再起動)
# vi /etc/selinux/config
SELINUX=enforcing
```

### MySQLで権限問題
``` bash
sudo chmod 755 -R /var/log/mysql

# git add できない
sudo chmod 755 -R isucon3/mysql/config
```

### MySQLで外部サーバーから接続できない
#### ERROR 2003 (HY000): Can't connect to MySQL server on 'x.x.x.x' (111)
https://ameblo.jp/mojeld/entry-12645669164.html
```my.cnf
# bind-address		= 127.0.0.1
bind-address		= 0.0.0.0
```

#### ERROR 1130 (HY000): Host x.x.x.x is not allowed to connect to this MySQL server
https://fantasiabaetica.hatenablog.com/entry/2019/07/12/081848
```
GRANT ALL PRIVILEGES ON *.* TO 'isucon'@'%' WITH GRANT OPTION;
```


### Redisで権限問題
```
sudo chown redis:adm -R /var/log/redis
sudo chmod 755 /var/log/redis
```

### サーバー間通信でno route to host
- pingは通るがcurlは通らない
```
sudo systemctl stop firewalld
sudo systemctl disable firewalld
```

### worker_rlimit_nofileをあげてもtoo many open filesが解決しない
``` bash
ulimit -Sn 4096

ps aux | grep nginx
cat /proc/<pid>/limits
```

/etc/systemd/system/multi.target/nginx.service
```
[Service]
LimitNOFILE=65536
```

### deploy.shでPermission Denied
- `go build isucon-kuolc38th/isucon4-qualify: copying /tmp/go-build3899013241/b001/exe/a.out: open golang-webapp: permission denied`

実行ファイルに777
```bash
chmod 777 ./golang-webapp
```

- restart.shが実行できない

restart.shに777
```bash
chmod 777 <apphome>/isucon[1-3]/restart.sh
```

### Can't assign request address
sudo sysctl -w net.ipv4.ip_local_port_range="10240 61000" # 32768 61000
sudo sysctl -w net.ipv4.tcp_tw_reuse="1"

netstat -an |grep TIME_WAIT |wc

### unix socket
https://kaneshin.hateblo.jp/entry/2016/05/29/020302

### 書き込みのバックグラウンド実行
https://github.com/methane/isucon4q-go/blob/b09d45adb0c08616fe14d02acd801496befa3bd6/db.go#L89-L110

## やる必要があるかもしれないこと
- [ ] my.cnfの読み込み優先度が高いものが入ってないか確認
    - [ ] ` mysql --help | grep .cnf`の場所にファイル実体があればそれも読み込まれることを意識
    - mysqlコマンドで`defaults-extra-file`オプションがあればそれも入る
    - 候補は以下の通り
        1. `/etc/my.cnf` (git管理済み)
        1. `/etc/mysql/my.cnf` (git管理済み)
        1. `SYSCONFDIR/my.cnf`
        1. `$MYSQL_HOME/my.cnf`
        1. `--defaults-extra-file=path`
        1. `~/.my.cnf`
        1. `~/.mylogin.cnf`

## Reference
- Nginx+MySQL+カーネルチューニングレシピ
https://kazeburo.hatenablog.com/entry/2014/10/14/170129