# ISUCON11予選
[TOC]
## レギュレーション
https://isucon.net/archives/55854734.html
## マニュアル
当日マニュアル
https://gist.github.com/ockie1729/53589a0e8c979198b6231d8599153c70
アプリケーションマニュアル
https://gist.github.com/ockie1729/fcb41ade9cb9d2166dd3f53e5179e8a9
## スプレッドシート
https://docs.google.com/spreadsheets/d/1Gj_ul5c92KPyKWNuYqQtDKNmRPCTgzOaDp1V0nPsdEY/edit?usp=sharing
## 接続情報
### ssh
```
Host isuutil
HostName 13.230.129.93
User ubuntu
IdentityFile ~/.ssh/isucon7q-sshkey.pem
ServerAliveInterval 60
Host isucon1
HostName 54.199.41.247
User ubuntu
IdentityFile ~/.ssh/isucon7q-sshkey.pem
ServerAliveInterval 60
Host isucon2
HostName 35.75.46.176
User ubuntu
IdentityFile ~/.ssh/isucon7q-sshkey.pem
ServerAliveInterval 60
Host isucon3
HostName 52.68.31.229
User ubuntu
IdentityFile ~/.ssh/isucon7q-sshkey.pem
ServerAliveInterval 60
```
### 内部IP
- isucon1: 192.168.0.11
- isucon2: 192.168.0.12
- isucon3: 192.168.0.13
## 事前
- [ ] Elastic IPを登録しておく
- [x] AWSインスタンス作成時にダウンロードした鍵を共有しておく
- isucon-sshkey.pemで~/.sshに保存
- chmod 600 ~/.ssh/isucon-sshkey.pem
- [ ] ~/.ssh/configの設定
- [x] 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 -->
- [x] 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): インストール
競技中
- [ ] <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>
- [ ] GOMAXPROCS設定
- [ ] measure仕込む
- [ ] pprofのハンドラー準備
- [ ] mysqlの接続確立
- [ ] sqlxの差し替え
- [ ] 400/500のエラーが出た場合にログに出力するようにする
競技中
- [ ] スローログのダイジェストを見て遅い/多いクエリの分析、改善
- [ ] MySQLのパラメータチューニング
競技終了
- [ ] pprof削除
- [ ] measure削除
### ryunosuke
競技開始
- [ ] sql -> sqlx
- [ ] 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
# 必要に応じて.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の権限設定)
- sudo chmod -R 644 /var/log/nginx
- sudo chmod 757 /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に追加
- [ ] エラー出力
```
e.Use(middleware.Recover())
e.HTTPErrorHandler = func(err error, c echo.Context) {
log.Println(err)
e.DefaultHTTPErrorHandler(err, c)
}
```
- [ ] sqlをsqlxに差し替える
- sqlx.DB -> sql.DB
- sql.Open -> sqlx.Connect
- [ ] 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)
}
```
### 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