{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell { buildInputs = with pkgs; [ gh ]; }
ghp_xxx
"isucon14"
3.114.140.17
35.74.161.58
54.95.129.135
(format "OL001-isucon/%s" repo)
cat ~/.ssh/config.d/isucon14
Host isucon-2 HostName 35.74.161.58 User isucon
Host isucon-3 HostName 54.95.129.135 User isucon
(expand-file-name "~/.ssh/isucon14")
scp "${keyfile}.pub" isucon-1:~/.ssh/id_ed25519.pub
scp "${keyfile}.pub" isucon-2:~/.ssh/id_ed25519.pub
scp "${keyfile}.pub" isucon-3:~/.ssh/id_ed25519.pub
scp "${keyfile}" isucon-1:~/.ssh/id_ed25519
scp "${keyfile}" isucon-2:~/.ssh/id_ed25519
scp "${keyfile}" isucon-3:~/.ssh/id_ed25519
ssh -T [email protected]
echo "=== System Information ==="
echo "Hostname: $(hostname)"
echo "Kernel: $(uname -r)"
echo "Uptime: $(uptime -p)"
echo "OS: $(lsb_release -d | cut -f2)"
echo "CPU: $(lscpu | grep 'Model name' | awk -F ': ' '{print $2}')"
echo "Memory: $(free -h | grep Mem | awk '{print $3 "/" $2}')"
echo "Disk Usage: $(df -h / | grep / | awk '{print $5 " (" $3 "/" $2 ")"}')"
echo "GPU: $(lspci | grep -i 'vga\|3d\|2d')"
echo "=== System Information ==="
echo "Hostname: $(hostname)"
echo "Kernel: $(uname -r)"
echo "Uptime: $(uptime -p)"
echo "OS: $(lsb_release -d | cut -f2)"
echo "CPU: $(lscpu | grep 'Model name' | awk -F ': ' '{print $2}')"
echo "Memory: $(free -h | grep Mem | awk '{print $3 "/" $2}')"
echo "Disk Usage: $(df -h / | grep / | awk '{print $5 " (" $3 "/" $2 ")"}')"
echo "GPU: $(lspci | grep -i 'vga\|3d\|2d')"
echo "=== System Information ==="
echo "Hostname: $(hostname)"
echo "Kernel: $(uname -r)"
echo "Uptime: $(uptime -p)"
echo "OS: $(lsb_release -d | cut -f2)"
echo "CPU: $(lscpu | grep 'Model name' | awk -F ': ' '{print $2}')"
echo "Memory: $(free -h | grep Mem | awk '{print $3 "/" $2}')"
echo "Disk Usage: $(df -h / | grep / | awk '{print $5 " (" $3 "/" $2 ")"}')"
echo "GPU: $(lspci | grep -i 'vga\|3d\|2d')"
sudo systemctl list-unit-files --type=service | grep -E "nginx|apache"
sudo systemctl list-unit-files --type=service | grep -E "mysql|postgresql"
sudo systemctl list-unit-files --type=service | grep -E "redis|memcached"
git config --global user.email "[email protected]"
git config --global user.name "isucon"
git init
git remote add origin [email protected]:OL001-isucon/isucon14.git
git fetch
git reset --hard remotes/origin/main
ghq get "[email protected]:${qualified_repo}.git"
cat /etc/nginx/nginx.conf
events { worker_connections 768;
}
http {
##
##
sendfile on; tcp_nopush on; types_hash_max_size 2048;
include /etc/nginx/mime.types; default_type application/octet-stream;
##
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on;
##
##
access_log /var/log/nginx/access.log;
##
##
gzip on;
##
##
include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }
#mail {
#
#
#
#}
ls -la /etc/nginx/sites-enabled
cat /etc/nginx/sites-enabled/isucon.conf
client_max_body_size 10m; root home/isucon/private_isu/webapp/public;
location / { proxy_set_header Host $host; proxy_pass http://localhost:8080; } }
- [X] ansible/roles/before_bench/nginx.yml
- [X] ansible/etc/nginx/nginx.dev.conf
- [X] ansible/etc/nginx/sites-enabled/isuride.dev.conf
- [X] ansible/etc/nginx/sites-enabled/isupipe.prod.conf
log_format json escape=json '{"time":"$time_local",'
' "host":"$remote_addr",'
' "forwardedfor":"$http_x_forwarded_for",'
' "req":"$request",'
' "status":"$status",'
' "method":"$request_method",'
' "uri":"$request_uri",'
' "body_bytes":$body_bytes_sent,'
' "referer":"$http_referer",'
' "ua":"$http_user_agent",'
' "request_time":$request_time,'
' "cache":"$upstream_http_x_cache",'
' "runtime":"$upstream_http_x_runtime",'
' "response_time":"$upstream_response_time",'
' "vhost":"$host"'
'}';
access_log /var/log/nginx/access.log json;
mysqldef -u isucon -p isucon isupipe --export > schema.sql
scp isucon@isucon-3:/home/isucon/schema.sql ./schema.sql
## DB
### 接続情報
```
host: 127.0.0.1
port: 3306
user: isucon
password: isucon
database: isuride
```
SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'isuride';
### レコード数
```sql
<結果を貼る>
```
link: https://github.com/mazrean/isucrud/
link: https://github.com/OL001-isucon/isucon9-qualify/pull/54 link: https://isucon-workshop.trap.show/text/chapter-3/3-pprof.html
diff --git a/webapp/go/main.go b/webapp/go/main.go
index 6a9f192..ee3a892 100755
--- a/webapp/go/main.go
+++ b/webapp/go/main.go
@@ -9,6 +9,8 @@ import (
"log"
"net"
"net/http"
+ _ "net/http/pprof"
+
"os"
"os/exec"
"path/filepath"
@@ -351,6 +353,12 @@ func writeQRCodeImgBinary(transactionEvidenceID int64, imgBinary []byte) error {
}
func main() {
+ runtime.SetBlockProfileRate(1)
+ runtime.SetMutexProfileFraction(1)
+ go func() {
+ log.Println(http.ListenAndServe("0.0.0.0:6060", nil))
+ }()
+
host := os.Getenv("MYSQL_HOST")
if host == "" {
host = "127.0.0.1"
link: https://github.com/goccy/go-json#how-to-use
go.mod/go.sumもpushする
db.SetMaxOpenConns(50)
db.SetMaxIdleConns(50*2)
db.SetConnMaxLifetime(5* time.Minute)
db.SetConnMaxIdleTime(2 * time.Minute)
link: https://portal.isucon.net/contestant/benchmark_jobs/3370
1. before_benchを実行
2. benchを回す前に以下を実行
```
$ go tool pprof http://localhost:6060/debug/pprof/profile?seconds=120
Saved profile in /home/isucon/pprof/pprof.isucari.samples.cpu.001.pb.gz (これを控える)
```
3. http://localhost:6070/ui/ から見れるようになる
```
$ ssh -L 6070:localhost:6070 isucon-3
# サーバ内で実行する
$ go tool pprof -http=localhost:6070 /home/isucon/pprof/pprof.isuride.samples.cpu.001.pb.gz
```
link: https://gist.github.com/wtks/0a3268de13856ed6e18c6560023ec436
link: https://github.com/OL001-isucon/isucon9-qualify/tree/main/ansible/etc/nginx
link: https://github.com/OL001-isucon/isucon14/pull/16
diff --git a/webapp/go/main.go b/webapp/go/main.go
index ec33433..f9f1ecc 100755
--- a/webapp/go/main.go
+++ b/webapp/go/main.go
@@ -6,6 +6,7 @@ import (
"fmt"
"html/template"
"io"
+ "io/ioutil"
"log"
"net"
"net/http"
@@ -334,6 +335,7 @@ func init() {
store = cs
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
+ log.SetOutput(ioutil.Discard)
templates = template.Must(template.ParseFiles(
"../public/index.html",
link: https://github.com/OL001-isucon/isucon14/pull/22
link: マニュアル#通知エンドポイント
通知エンドポイント ISURIDEではクライアントにライドの状態の変化を通知するための2つのエンドポイントが実装されています。 - ユーザー向け通知: /api/app/notification - 椅子向け通知: /api/chair/notification これらはリファレンス実装では通常のJSONレスポンスを返すエンドポイントですが、SSE(Server-Sent Events)を利用してリアルタイム通知を実装することも可能です。 どちらの実装においても、状態が変更されてから3秒以内に通知されていることが期待されます。 JSONレスポンス サーバーがJSONレスポンスを返す場合、クライアントはポーリングによってライドの状態の変化を取得します。 Content-Typeは application/json です。 クライアントはレスポンスの retry_after_ms で指定された時間(ms)が経過した後に再度リクエストを送信します。 リファレンス実装では30ms後に再度リクエストを送信するようになっています。 SSE(Server-Sent Events) サーバーがSSEを利用してリアルタイム通知を行う場合、クライアントはSSEのコネクションからライドの状態の変化を取得します。 Content-Typeは text/event-stream です。 通知メッセージは data: に続けて、webappディレクトリに存在するopenapi.yamlの components.schemas.UserNotificationData または components.schemas.ChairNotificationData のJSON文字列を返します。 これはJSONレスポンスの data に相当します。 通知メッセージは1行で記述し、最後に改行を入れる必要があります。 実際のレスポンス例は以下を参照してください。 クライアントとの間にSSEのコネクションを確立した後、即座に最新のライドの状態を送信しなければなりません その後は随時最新のライドの状態を送信します。 状態が変わった時のみ即座に送信することが望ましいです。 以下はSSEでの通知レスポンスの例です。 ユーザー向け通知 ``` data: {"ride_id":"01JEG4X2TZSE169T99XERS990M","pickup_coordinate":{"latitude":0,"longitude":0},"destination_coordinate":{"latitude":20,"longitude":20},"fare":1500,"status":"ENROUTE","chair":{"id":"01JDFEF7MGXXCJKW1MNJXPA77A","name":"QC-L13-8361","model":"クエストチェア Lite","stats":{"total_rides_count":1,"total_evaluation_avg":5}},"created_at":1733561322336,"updated_at":1733561322690} data: {"ride_id":"01JEG4X2TZSE169T99XERS990M","pickup_coordinate":{"latitude":0,"longitude":0},"destination_coordinate":{"latitude":20,"longitude":20},"fare":1500,"status":"PICKUP","chair":{"id":"01JDFEF7MGXXCJKW1MNJXPA77A","name":"QC-L13-8361","model":"クエストチェア Lite","stats":{"total_rides_count":1,"total_evaluation_avg":5}},"created_at":1733561322336,"updated_at":1733561322690} data: {"ride_id":"01JEG4X2TZSE169T99XERS990M","pickup_coordinate":{"latitude":0,"longitude":0},"destination_coordinate":{"latitude":20,"longitude":20},"fare":1500,"status":"CARRYING","chair":{"id":"01JDFEF7MGXXCJKW1MNJXPA77A","name":"QC-L13-8361","model":"クエストチェア Lite","stats":{"total_rides_count":1,"total_evaluation_avg":5}},"created_at":1733561322336,"updated_at":1733561322690} data: {"ride_id":"01JEG4X2TZSE169T99XERS990M","pickup_coordinate":{"latitude":0,"longitude":0},"destination_coordinate":{"latitude":20,"longitude":20},"fare":1500,"status":"CARRYING","chair":{"id":"01JDFEF7MGXXCJKW1MNJXPA77A","name":"QC-L13-8361","model":"クエストチェア Lite","stats":{"total_rides_count":1,"total_evaluation_avg":5}},"created_at":1733561322336,"updated_at":1733561322690} data: {"ride_id":"01JEG4X2TZSE169T99XERS990M","pickup_coordinate":{"latitude":0,"longitude":0},"destination_coordinate":{"latitude":20,"longitude":20},"fare":1500,"status":"CARRYING","chair":{"id":"01JDFEF7MGXXCJKW1MNJXPA77A","name":"QC-L13-8361","model":"クエストチェア Lite","stats":{"total_rides_count":1,"total_evaluation_avg":5}},"created_at":1733561322336,"updated_at":1733561322690} data: {"ride_id":"01JEG4X2TZSE169T99XERS990M","pickup_coordinate":{"latitude":0,"longitude":0},"destination_coordinate":{"latitude":20,"longitude":20},"fare":1500,"status":"CARRYING","chair":{"id":"01JDFEF7MGXXCJKW1MNJXPA77A","name":"QC-L13-8361","model":"クエストチェア Lite","stats":{"total_rides_count":1,"total_evaluation_avg":5}},"created_at":1733561322336,"updated_at":1733561322690} data: {"ride_id":"01JEG4X2TZSE169T99XERS990M","pickup_coordinate":{"latitude":0,"longitude":0},"destination_coordinate":{"latitude":20,"longitude":20},"fare":1500,"status":"ARRIVED","chair":{"id":"01JDFEF7MGXXCJKW1MNJXPA77A","name":"QC-L13-8361","model":"クエストチェア Lite","stats":{"total_rides_count":1,"total_evaluation_avg":5}},"created_at":1733561322336,"updated_at":1733561322690} data: {"ride_id":"01JEG4X2TZSE169T99XERS990M","pickup_coordinate":{"latitude":0,"longitude":0},"destination_coordinate":{"latitude":20,"longitude":20},"fare":1500,"status":"COMPLETED","chair":{"id":"01JDFEF7MGXXCJKW1MNJXPA77A","name":"QC-L13-8361","model":"クエストチェア Lite","stats":{"total_rides_count":2,"total_evaluation_avg":4.5}},"created_at":1733561322336,"updated_at":1733561370916} data: {"ride_id":"01JEG4X2TZSE169T99XERS990M","pickup_coordinate":{"latitude":0,"longitude":0},"destination_coordinate":{"latitude":20,"longitude":20},"fare":1500,"status":"COMPLETED","chair":{"id":"01JDFEF7MGXXCJKW1MNJXPA77A","name":"QC-L13-8361","model":"クエストチェア Lite","stats":{"total_rides_count":2,"total_evaluation_avg":4.5}},"created_at":1733561322336,"updated_at":1733561370916} data: {"ride_id":"01JEG4X2TZSE169T99XERS990M","pickup_coordinate":{"latitude":0,"longitude":0},"destination_coordinate":{"latitude":20,"longitude":20},"fare":1500,"status":"COMPLETED","chair":{"id":"01JDFEF7MGXXCJKW1MNJXPA77A","name":"QC-L13-8361","model":"クエストチェア Lite","stats":{"total_rides_count":2,"total_evaluation_avg":4.5}},"created_at":1733561322336,"updated_at":1733561370916} data: {"ride_id":"01JEG4X2TZSE169T99XERS990M","pickup_coordinate":{"latitude":0,"longitude":0},"destination_coordinate":{"latitude":20,"longitude":20},"fare":1500,"status":"COMPLETED","chair":{"id":"01JDFEF7MGXXCJKW1MNJXPA77A","name":"QC-L13-8361","model":"クエストチェア Lite","stats":{"total_rides_count":2,"total_evaluation_avg":4.5}},"created_at":1733561322336,"updated_at":1733561370916} ```
isucon@ip-172-31-22-126:/etc/systemd/system$ cat /etc/systemd/system/isuride-go.service
[Unit]
Description=isuride-go
After=syslog.target
After=mysql.service
Requires=mysql.service
[Service]
WorkingDirectory=/home/isucon/webapp/go
EnvironmentFile=/home/isucon/env.sh
User=isucon
Group=isucon
ExecStart=/home/isucon/webapp/go/isuride
ExecStop=/bin/kill -s QUIT $MAINPID
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
cat /home/isucon/env.sh
ISUCON_MATCHING_INTERVAL=0.5
cat /home/isucon/env.sh
ISUCON_MATCHING_INTERVAL=0.5
cat /home/isucon/env.sh
ISUCON_MATCHING_INTERVAL=0.5
GRANT ALL PRIVILEGES ON *.* TO `isucon`@`%` WITH GRANT OPTION;
FLUSH PRIVILEGES;
- isucon-1: nginx, app(/api/app/notification, /api/chair/notification)
- isucon-2: app(それ以外)
- isucon-3: mysql
# サーバ分割
## レイアウト
- isucon-1: nginx, app(/api/app/notification, /api/chair/notification)
- isucon-2: app(それ以外)
- isucon-3: mysql
## 作業
1. isucon-1の ~/env.sh を以下のように修正
isucon-1 before:
```
ISUCON_DB_HOST="127.0.0.1"
ISUCON_DB_PORT="3306"
ISUCON_DB_USER="isucon"
ISUCON_DB_PASSWORD="isucon"
ISUCON_DB_NAME="isuride"
# マッチング間隔(秒)
ISUCON_MATCHING_INTERVAL=0.5
```
isucon-1 after:
```
ISUCON_DB_HOST="192.168.0.13"
ISUCON_DB_PORT="3306"
ISUCON_DB_USER="isucon"
ISUCON_DB_PASSWORD="isucon"
ISUCON_DB_NAME="isuride"
# マッチング間隔(秒)
ISUCON_MATCHING_INTERVAL=0.5
```
この変更でnginxを分割してる
https://github.com/OL001-isucon/isucon14/pull/28
2. isucon-1, isucon-3にbefore_bench prodを流す
3. isucon-1に対してベンチを回す
# Ansible
## 開発者向け
### isucon-1
before_bench:
```console
$ export BRANCH_NAME=main
$ ansible-playbook -i ./ansible/hosts.yml -l isucon-1 ./ansible/playbook/before_bench.yml --extra-vars "env=dev" --extra-vars "branch=$BRANCH_NAME" --verbose
```
after_bench:
```console
$ ansible-playbook -i ./ansible/hosts.yml -l isucon-1 ./ansible/playbook/after_bench.yml --verbose
```
### isucon-2
before_bench:
```console
$ export BRANCH_NAME=main
$ ansible-playbook -i ./ansible/hosts.yml -l isucon-2 ./ansible/playbook/before_bench.yml --extra-vars "env=dev" --extra-vars "branch=$BRANCH_NAME" --verbose
```
after_bench:
```console
$ ansible-playbook -i ./ansible/hosts.yml -l isucon-2 ./ansible/playbook/after_bench.yml --verbose
```
### isucon-3
before_bench:
```console
$ export BRANCH_NAME=main
$ ansible-playbook -i ./ansible/hosts.yml -l isucon-3 ./ansible/playbook/before_bench.yml --extra-vars "env=dev" --extra-vars "branch=$BRANCH_NAME" --verbose
```
after_bench:
```console
$ ansible-playbook -i ./ansible/hosts.yml -l isucon-3 ./ansible/playbook/after_bench.yml --verbose
```
## インフラ担当者向け
## install tools
```console
$ ansible-playbook -i ./ansible/hosts.yml ./ansible/playbook/install_tools.yml --verbose
```
## before bench
for specific:
```console
$ ansible-playbook -i ./ansible/hosts.yml -l server ./ansible/playbook/before_bench.yml --extra-vars "env=dev" --extra-vars "branch=main" --verbose
$ ansible-playbook -i ./ansible/hosts.yml -l server ./ansible/playbook/before_bench.yml --extra-vars "env=prod" --extra-vars "branch=main" --verbose
```
for all:
```console
$ ansible-playbook -i ./ansible/hosts.yml ./ansible/playbook/before_bench.yml --extra-vars "env=dev" --extra-vars "branch=main" --verbose
$ ansible-playbook -i ./ansible/hosts.yml ./ansible/playbook/before_bench.yml --extra-vars "env=prod" --extra-vars "branch=main" --verbose
```
## after_bench
```console
$ ansible-playbook -i ./ansible/hosts.yml -l server ./ansible/playbook/after_bench.yml --verbose
```
## sandbox
```console
$ ansible-playbook -i ./ansible/hosts.yml -l server ./ansible/playbook/sandbox.yml --verbose
```
---
all:
hosts:
isucon-1:
ansible_host: <<isucon-server-ip-address-1>>
ansible_user: isucon
isucon-2:
ansible_host: <<isucon-server-ip-address-2>>
ansible_user: isucon
isucon-3:
ansible_host: <<isucon-server-ip-address-3>>
ansible_user: isucon
[defaults]
inventory_unparsed_warning=False
host_key_checking=False
[ssh_connection]
control_path = %(directory)s/%%h-%%r
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -F ssh_config
pipelining = True
---
reverse: true
sort: sum
matching_groups:
- /api/user/\w+/theme
output: count,method,uri,1xx,2xx,3xx,4xx,5xx,sum,avg,min,max
github.com:
user: isucon
oauth_token: <<github-token>>
[core]
quotepath = off
ignorecase = false
safecrlf = true
autocrlf = false
precomposeunicode = true
[alias]
st = status
br = branch
co = commit
ch = checkout
ad = add
fix = commit --amend --no-edit
[user]
name = isucon
email = [email protected]
[fetch]
prune = true
[pull]
rebase = false
[diff]
patience = true
[color]
ui = auto
status = auto
diff = auto
branch = auto
interactive = auto
grep = auto
[init]
defaultBranch = main
[mysqld]
#
# Basic Settings
#
user = mysql
bind-address = 0.0.0.0
mysqlx-bind-address = 0.0.0.0
#
# Basic Params
#
key_buffer_size = 4G
max_connections = 1024
#
# innodb params
#
innodb_buffer_pool_size = 1G
innodb_log_file_size = 16M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
skip_innodb_doublewrite
#
# Logging
#
log_error = /var/log/mysql/error.log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 0
log-queries-not-using-indexes
#
# binlog
#
disable-log-bin
[mysqld]
#
# Basic Settings
#
user = mysql
bind-address = 0.0.0.0
mysqlx-bind-address = 0.0.0.0
skip-name-resolve
#
# Basic Params
#
key_buffer_size = 4G
max_connections = 1024
#
# innodb params
#
innodb_buffer_pool_size = 4G
innodb_log_file_size = 1G
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
skip_innodb_doublewrite
#
# Logging
#
general_log = 0
#
# binlog
#
disable-log-bin
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
log_format json escape=json '{"time":"$time_local",'
' "host":"$remote_addr",'
' "forwardedfor":"$http_x_forwarded_for",'
' "req":"$request",'
' "status":"$status",'
' "method":"$request_method",'
' "uri":"$request_uri",'
' "body_bytes":$body_bytes_sent,'
' "referer":"$http_referer",'
' "ua":"$http_user_agent",'
' "request_time":$request_time,'
' "cache":"$upstream_http_x_cache",'
' "runtime":"$upstream_http_x_runtime",'
' "response_time":"$upstream_response_time",'
' "vhost":"$host"'
'}';
access_log /var/log/nginx/access.log json;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
include /etc/nginx/sites-available/*;
}
#mail {
# # See sample authentication script at:
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
# # auth_http localhost/auth.php;
# # pop3_capabilities "TOP" "USER";
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
# server {
# listen localhost:110;
# protocol pop3;
# proxy on;
# }
#
# server {
# listen localhost:143;
# protocol imap;
# proxy on;
# }
#}
user www-data;
worker_processes auto;
include /etc/nginx/modules-enabled/*.conf;
error_log /dev/null crit;
pid /run/nginx.pid;
worker_rlimit_nofile 65536;
events {
worker_connections 16384;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
http2_max_requests 1000000;
keepalive_requests 1000000;
keepalive_timeout 65;
access_log off;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*.conf;
include /etc/nginx/sites-available/*.conf;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
}
[Service]
LimitNOFILE=65535
set encoding=utf-8
set fileencodings=utf-8,euc-jp,cp932
set clipboard+=unnamed
set backspace=2
set tabstop=2
set shiftwidth=2
set laststatus=2
set statusline=%y
set showmatch
set wrapscan
set hlsearch
set showcmd
set title
set number relativenumber
set cursorline
set nofoldenable
set noswapfile
set expandtab
set splitbelow
set splitright
set incsearch
set ignorecase
set smartcase
nmap / /\v
nmap <Leader><Leader> V
nmap <Esc><Esc> :nohlsearch<CR><Esc>
syntax on
filetype plugin indent on
[colors]
avg_cpu_color = "Red"
border_color = "White"
graph_color = "Gray"
highlighted_border_color = "LightMagenta"
selected_bg_color = "Magenta"
selected_text_color = "Black"
table_header_color = "Blue"
text_color = "White"
widget_title_color = "Cyan"
[disk_filter]
is_list_ignored = true
list = ["/dev/loop\\d+"]
regex = true
[flags]
basic = false
case_sensitive = false
dot_marker = false
group_processes = true
hide_table_gap = true
rate = 700
[[row]]
[[row.child]]
ratio = 2
type = "cpu"
[[row.child]]
type = "mem"
[[row]]
[[row.child]]
ratio = 2
type = "net"
[[row.child]]
ratio = 2
type = "disk"
[[row.child]]
type = "temp"
[[row]]
ratio = 3
[[row.child]]
default = true
type = "proc"
---
- name: After benchmark
hosts: all
tasks:
- name: Copy alp config
import_tasks: ../roles/after_bench/alp.yml
become: true
- import_tasks: ../roles/after_bench/result.yml
---
- name: Before benchmark
hosts: all
tasks:
- name: Git Pull
import_tasks: ../roles/before_bench/git-pull.yml
- name: Prepare golang
import_tasks: ../roles/before_bench/prepare.yml
- name: Truncate Task
import_tasks: ../roles/before_bench/truncate.yml
become: true
- name: Nginx Task
import_tasks: ../roles/before_bench/nginx.yml
become: true
- name: Mysql Task
import_tasks: ../roles/before_bench/mysql.yml
become: true
- name: Redis Task
import_tasks: ../roles/before_bench/redis.yml
become: true
# - name: Run migrate
# import_tasks: ../roles/before_bench/sqldef.yml
---
- name: Install tools
hosts: all
become: true
tasks:
- import_tasks: ../roles/install_tools/bottom.yml
- import_tasks: ../roles/install_tools/alp.yml
- import_tasks: ../roles/install_tools/dotfiles.yml
- import_tasks: ../roles/install_tools/gh.yml
- import_tasks: ../roles/install_tools/percona-toolkit.yml
- import_tasks: ../roles/install_tools/script.yml
- import_tasks: ../roles/install_tools/sqldef.yml
- import_tasks: ../roles/install_tools/dstat.yml
- import_tasks: ../roles/install_tools/graphviz.yml
- import_tasks: ../roles/install_tools/tig.yml
- import_tasks: ../roles/install_tools/redis.yml
- import_tasks: ../roles/before_bench/sysctl.yml
---
- name: Sandbox
hosts: all
tasks:
- name: echo 'Hello world'
shell: echo 'Hello world'
---
- name: Copy alp config.yml
copy:
src: ../../etc/alp/config.yml
dest: /etc/alp/config.yml
---
- name: Copy result.sh
copy:
src: ../../shell/result.sh
dest: /home/isucon/result.sh
mode: 0755
- name: Aggregate result && Report to github issue
shell: bash /home/isucon/result.sh
- name: Pull From Git
git:
repo: [email protected]:<<qualified-repo()>>.git
dest: /home/isucon
update: yes
version: "{{ branch }}"
force: yes
---
- name: Create directory
file:
path: /etc/systemd/system/mysql.service.d
state: directory
- name: Copy systemd mysql.service.d limits.conf
copy:
src: ../../etc/systemd/mysql.service.d/limits.conf
dest: /etc/systemd/system/mysql.service.d/limits.conf
mode: 0644
- name: Copy mysqld.cnf
copy:
src: ../../etc/mysql/mysqld.{{ env }}.cnf
dest: /etc/mysql/mysql.conf.d/mysqld.cnf
mode: 0644
- name: Change file ownership /var/log/mysql/error.log
ansible.builtin.file:
path: /var/log/mysql/error.log
owner: mysql
group: adm
mode: 0644
- name: Change file ownership /var/log/mysql/mysql-slow.log
ansible.builtin.file:
path: /var/log/mysql/mysql-slow.log
owner: mysql
group: adm
mode: 0644
- name: Restart mysql
service:
name: mysql
state: restarted
enabled: yes
---
# - name: Copy nginx.conf
# copy:
# src: ../../etc/nginx/nginx.{{ env }}.conf
# dest: /etc/nginx/nginx.conf
# mode: 0644
# - name: Copy isucon.conf
# copy:
# src: ../../etc/nginx/sites-enabled/isucon.{{ env }}.conf
# dest: /etc/nginx/sites-enabled/isucon.conf
# mode: 0644
- name: Change file ownership /var/log/nginx/access.log
ansible.builtin.file:
path: /var/log/nginx/access.log
owner: www-data
group: adm
mode: 0640
- name: Change file ownership /var/log/nginx/error.log
ansible.builtin.file:
path: /var/log/nginx/error.log
owner: www-data
group: adm
mode: 0640
- name: Restart nginx
service:
name: nginx
state: restarted
enabled: yes
---
- name: Build go
environment:
PATH: /home/isucon/local/golang/bin:{{ ansible_env.PATH }}
make:
chdir: /home/isucon/webapp/golang
target: build
params:
DEST: /home/isucon/webapp/golang
- name: Restart go
become: true
service:
name: isuride-go.service
state: restarted
enabled: yes
---
- name: Restart redis
service:
name: redis
state: restarted
enabled: yes
---
# - name: Migrate down from trigger
# shell: mysql -u isucon --password="isucon" <<project-name>> < trigger_down.sql
# - name: Migrate from sqldef(<<project-name>>)
# shell: mysqldef -u isucon -p isucon <<project-name>> < schema.sql
# - name: Migrate from sqldef(isudns)
# shell: mysqldef -u isucon -p isucon isudns < schema_dns.sql
# - name: Migrate up from trigger
# shell: mysql -u isucon --password="isucon" <<project-name>> < trigger_up.sql
---
- name: Create directory
file:
path: /etc/systemd/system/mysql.service.d
state: directory
- name: Copy systemd mysql.service.d limits.conf
copy:
src: ../../etc/systemd/mysql.service.d/limits.conf
dest: /etc/systemd/system/mysql.service.d/limits.conf
mode: 0644
- name: Restart mysql
systemd:
name: mysql.service
state: restarted
daemon_reload: yes
enabled: yes
---
- name: Truncate /var/log/nginx/access.log
community.general.filesize:
path: /var/log/nginx/access.log
size: 0
- name: Truncate /var/log/nginx/error.log
community.general.filesize:
path: /var/log/nginx/error.log
size: 0
- name: Truncate /var/log/mysql/mysql-slow.log
community.general.filesize:
path: /var/log/mysql/mysql-slow.log
size: 0
---
- name: Download alp tar.gz archive
get_url:
url: https://github.com/tkuchiki/alp/releases/download/v1.0.21/alp_linux_amd64.tar.gz
dest: /tmp/alp.tar.gz
mode: 0644
- name: Extract alp tar.gz archive
unarchive:
src: /tmp/alp.tar.gz
dest: /usr/local/bin
remote_src: true
mode: 0755
- name: Create alp directory
file:
path: /etc/alp
state: directory
- name: Copy config.yml
copy:
src: ../../etc/alp/config.yml
dest: /etc/alp/config.yml
- name: Copy alp.sh
copy:
src: ../../shell/alp.sh
dest: /home/isucon/alp.sh
mode: 0755
---
- name: Download bottom package
ansible.builtin.get_url:
url: https://github.com/ClementTsang/bottom/releases/download/0.10.2/bottom_0.10.2-1_amd64.deb
dest: /tmp/bottom_0.10.2-1_amd64.deb
- name: Install bottom package
ansible.builtin.apt:
deb: /tmp/bottom_0.10.2-1_amd64.deb
state: present
- name: Create directory for bottom configuration
ansible.builtin.file:
path: /home/isucon/.config/bottom
state: directory
- name: Copy bottom.toml
copy:
src: ../../etc/bottom/bottom.toml
dest: /home/isucon/.config/bottom/bottom.toml
---
- name: Copy .vimrc
copy:
src: ../../etc/vim/.vimrc
dest: /home/isucon/.vimrc
- name: Copy .gitconfig
copy:
src: ../../etc/git/.gitconfig
dest: /home/isucon/.gitconfig
---
- name: Install dstat
apt:
name: dstat
state: latest
---
- name: Install graphviz
apt:
name: graphviz
state: latest
---
- name: Install gh command
shell: |
type -p curl >/dev/null || (sudo apt update && sudo apt install curl -y)
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
&& sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& sudo apt update \
&& sudo apt install gh -y
- name: Create gh directory
file:
path: /home/isucon/.config/gh
state: directory
owner: isucon
group: isucon
mode: '777'
- name: Copy gh hosts.yml
copy:
src: ../../etc/gh/hosts.yml
dest: /home/isucon/.config/gh/hosts.yml
owner: isucon
group: isucon
mode: '777'
---
- name: Install percona-toolkit
apt:
name: percona-toolkit
state: latest
- name: Copy pt-query-digest.sh
copy:
src: ../../shell/pt-query-digest.sh
dest: /home/isucon/pt-query-digest.sh
mode: 0755
---
- name: Install redis
apt:
name: redis
state: latest
- name: Restart redis
service:
name: redis
state: restarted
enabled: yes
---
- name: Copy alp.sh
copy:
src: ../../shell/alp.sh
dest: /home/isucon/alp.sh
mode: 0755
- name: Copy pt-query-digest.sh
copy:
src: ../../shell/pt-query-digest.sh
dest: /home/isucon/pt-query-digest.sh
mode: 0755
- name: Copy result.sh
copy:
src: ../../shell/result.sh
dest: /home/isucon/result.sh
mode: 0755
- name: Copy before_bench.sh
copy:
src: ../../shell/before_bench.sh
dest: /home/isucon/before_bench.sh
mode: 0755
---
- name: Download mysqldef tar.gz archive
get_url:
url: https://github.com/k0kubun/sqldef/releases/latest/download/mysqldef_linux_amd64.tar.gz
dest: /tmp/mysqldef.tar.gz
mode: 0644
- name: Extract mysqldef tar.gz archive
unarchive:
src: /tmp/mysqldef.tar.gz
dest: /usr/local/bin
remote_src: true
mode: 0755
- name: Download psqldef tar.gz archive
get_url:
url: https://github.com/k0kubun/sqldef/releases/latest/download/psqldef_linux_amd64.tar.gz
dest: /tmp/psqldef.tar.gz
mode: 0644
- name: Extract psqldef tar.gz archive
unarchive:
src: /tmp/psqldef.tar.gz
dest: /usr/local/bin
remote_src: true
mode: 0755
- name: Download sqlite3def tar.gz archive
get_url:
url: https://github.com/k0kubun/sqldef/releases/latest/download/sqlite3def_linux_amd64.tar.gz
dest: /tmp/sqlite3def.tar.gz
mode: 0644
- name: Extract sqlite3def tar.gz archive
unarchive:
src: /tmp/sqlite3def.tar.gz
dest: /usr/local/bin
remote_src: true
mode: 0755
---
- name: Install tig
apt:
name: tig
state: latest
---
- name: Update net.core.somaxconn
sysctl:
name: net.core.somaxconn
value: 10000
reload: true
- name: Update net.ipv4.ip_local_port_range
sysctl:
name: net.ipv4.ip_local_port_range
value: 10000 65535
reload: true
sudo cat /var/log/nginx/access.log | alp json --config /etc/alp/config.yml
sudo pt-query-digest /var/log/mysql/mysql-slow.log
# for gh command
REPO="${qualified_repo()}"
TITLE=$(date -u -d '+9 hours' +"%Y/%m/%d(%a)%H:%M:%S")
ISSUE_URL=$(gh issue create --repo $REPO --title $TITLE --body "")
# for alp command
echo "alp:" > /tmp/alp
echo "\`\`\`" >> /tmp/alp
sudo cat /var/log/nginx/access.log | alp json --config /etc/alp/config.yml >> /tmp/alp
echo "\`\`\`" >> /tmp/alp
gh issue comment $ISSUE_URL --body-file /tmp/alp
# for pt-query-digest command
echo "pt-query-digest:" > /tmp/pt-query-digest
sudo pt-query-digest /var/log/mysql/mysql-slow.log| dd bs=1 count=65500 of=/tmp/pt-query-digest-raw
echo "\`\`\`" >> /tmp/pt-query-digest
cat /tmp/pt-query-digest-raw >> /tmp/pt-query-digest
echo "\`\`\`" >> /tmp/pt-query-digest
gh issue comment $ISSUE_URL --body-file /tmp/pt-query-digest
#!/bin/bash
# truncate logs
echo "Truncate Logs..."
sudo truncate -s 0 /var/log/nginx/access.log
sudo truncate -s 0 /var/log/nginx/error.log
sudo truncate -s 0 /var/log/mysql/mysql-slow.log
# truncate middleware
echo "Truncate Middleware..."
sudo systemctl restart mysql &
sudo systemctl restart nginx &
sudo systemctl restart redis &
wait
# build golang
echo "Building Go application..."
export PATH=/home/isucon/local/golang/bin:$PATH
make -C /home/isucon/webapp/go
echo "Restarting isuride-go.service..."
sudo systemctl restart isuride-go.service && sudo systemctl enable isuride-go.service
#!/bin/bash
set -euox pipefail
ssh_host=${1:-isucon-2}
cd "$(dirname "$0")"
cd ..
# deploy
rsync -av -e ssh ./webapp/go/ $ssh_host:/home/isucon/webapp/go/
# restart
ssh "$ssh_host" "bash /home/isucon/before_bench.sh"
name: Run db_tbls
on:
workflow_dispatch:
push:
paths:
- schema.sql
permissions:
contents: write
jobs:
db-tbls:
if: ${{ github.ref == 'refs/heads/main' }}
runs-on: ubuntu-latest
timeout-minutes: 300
services:
mysql:
image: mysql:8
options: --health-cmd "mysqladmin ping -h localhost" --health-interval 20s --health-timeout 10s --health-retries 10
ports:
- 3306:3306
env:
MYSQL_DATABASE: isucon
MYSQL_ROOT_PASSWORD: isucon
MYSQL_ROOT_HOST: '%'
steps:
- uses: actions/checkout@v4
- uses: k1low/setup-tbls@v1
- name: Run schema.sql
run: mysql --host="127.0.0.1" --port=3306 --user="root" --password="isucon" isucon < schema.sql
- name: Run tbls for generate database document
run: tbls doc --dsn "mysql://root:[email protected]:3306/isucon"
- name: Deploy dbdob
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dbdoc
publish_branch: dbdoc
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
[*.conf]
indent_size = 4
indent_style = space
[.go]
indent_size = 2
indent_style = tab
[{Makefile, *.mk}]
indent_style = tab
indent_size = 4
# ISUCON14(isuride)