Skip to content

Instantly share code, notes, and snippets.

@myumx
Last active August 24, 2021 13:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save myumx/9310181644ae0209f68f6ad6c53584a3 to your computer and use it in GitHub Desktop.
Save myumx/9310181644ae0209f68f6ad6c53584a3 to your computer and use it in GitHub Desktop.
isucon memo

ISUCON memo

インフラ・MWを担当する

準備周り

インフラ観点でのメモ

  • AWSのSGの穴あけどうなる→マニュアル要確認。最後に戻さないと失格になる
  • AWS構成の把握・インスタンスタイプ、CPU,mem,ebsのスペック,CPU最適化やもろもろ→同じ構成だった
  • VPCフローログやCloudWatchなどは有効化しても良いのかもしれない→不要だった
  • ブロック対象のアドレスとかは決め打ちでブロックするのも手かも?→不要だったし、失格の可能性もあった

事前にやっておいた方が良いこと

・サーバ構成などをメモるGoogleドキュメントを用意する ・昼食を買っておく、当日は食べながら作業する

作業中のルール

  • ベンチマークの結果はSlackで必ず共有する
  • その他重要そうな計測結果はSlackで適宜共有する
  • Gitのコンフリクトへの対処はリーダが修正するときに各メイン担当に声がけする
  • 作業のコンフリクトはアプリが起動しなくなる等の重大なエラー以外は無視する、重大なエラーが発生した場合、適宜連携する
  • Gitはmasterブランチのみの運用にする、別ブランチを作るなどはしない
  • 常にGoogle Meetで繋いだ状態にし、音声は適宜ミュートにする

基本

git

git clone git@[git_hostname]:[repository]
git pull --rebase origin master

ssh

~/.ssh/configを台数分作る

Host isuconX
  HostName XXX.XXX.XXX.XXX
  User isucon
  Port 22
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile ~/.ssh/id_rsa
  IdentitiesOnly yes
  LogLevel FATAL
  ServerAliveInterval 60
ssh isuconX

systemctl

  • サービス起動systemctl start ${Unit}
  • サービス停止 systemctl stop ${Unit}
  • サービス再起動 systemctl restart ${Unit}
  • サービスリロード systemctl reload ${Unit}
  • サービスステータス表示 systemctl status ${Unit}
  • サービス自動起動有効 systemctl enable ${Unit}
  • サービス自動起動無効 systemctl disable ${Unit}
  • サービス自動起動設定確認 systemctl is-enabled ${Unit}
  • サービス一覧 systemctl list-unit-files --type=service

network

  • ss -tlpn

alp

  • ログ出力 sudo alp ltsv --sort sum -r --file /var/log/nginx/access.log
  • 正規表現でログ出力 sudo alp ltsv --sort sum -r --file /var/log/nginx/access.log -m /api/estate/[0-9]+,/api/estate/req_doc/[0-9]+
  • ログ削除 sudo bash -c 'echo > /var/log/nginx/access.log;'

slowquery

  • 匿名化あり sudo mysqldumpslow /var/log/mysql/mysql-slow.log
  • 匿名化なし sudo mysqldumpslow -a /var/log/mysql/mysql-slow.log
  • ログ削除 sudo bash -c 'echo > /var/log/mysql/slow.log;'

役割分担

時間の使い方

  • 1時間:セットアップ
  • 6時間:各自の担当領域で改修
  • 1時間:最終動作確認(サーバを再起動して問題なく動作するかなど

最初の1時間自分がやること

DBサーバの選定

スペック、バージョンを確認しえいやで決める mysql5系なら後半で変更を検討する

Nginxアクセスログ計測

既存のアクセスログ設定をalp用のログフォーマットに変更する(Change existing access log settings to log format for alp)

nginx.conf

    log_format ltsv "time:$time_local"
              "\thost:$remote_addr"
              "\tforwardedfor:$http_x_forwarded_for"
              "\treq:$request"
              "\tstatus:$status"
              "\tmethod:$request_method"
              "\turi:$request_uri"
              "\tsize:$body_bytes_sent"
              "\treferer:$http_referer"
              "\tua:$http_user_agent"
              "\treqtime:$request_time"
              "\tcache:$upstream_http_x_cache"
              "\truntime:$upstream_http_x_runtime"
              "\tapptime:$upstream_response_time"
              "\tvhost:$host"
              "\treqbody:$request_body";
    access_log /var/log/nginx/access.log ltsv;

設定を反映する

sudo cp nginx/nginx.conf /etc/nginx
sudo systemctl restart nginx.service
sudo bash -c 'echo > /var/log/nginx/access.log;'

install alp

wget https://github.com/tkuchiki/alp/releases/download/v1.0.4/alp_linux_amd64.zip
unzip alp_linux_amd64.zip
sudo install ./alp /usr/local/bin

run alp

sudo alp ltsv --sort sum -r --file /var/log/nginx/access.log

URI matching -m option

sudo alp ltsv --sort sum -r --file /var/log/nginx/access.log -m /api/estate/[0-9]+,/api/estate/req_doc/[0-9]+,/api/chair/[0-9]+,/api/chair/buy/[0-9]+,/api/recommended_estate/[0-9]+

mysqlスロークエリ計測

mysqld.confをクエリログを出力する設定に変更する(Changed mysqld.conf to output query log)

slow_query_log         = 1
slow_query_log_file    = /var/log/mysql/mysql-slow.log
long_query_time = 0

設定を反映する

sudo cp mysql/mysql.conf.d/mysqld.cnf /etc/mysql/mysql.conf.d/ 
sudo systemctl restart mysql.service

sudo cp mariadb/mariadb.conf.d/50-server.cnf /etc/mysql/mariadb.conf.d/
sudo systemctl restart mariadb.service

sudo bash -c 'echo > /var/log/mysql/mysql-slow.log;'

スロークエリログの要約

sudo mysqldumpslow /var/log/mysql/mysql-slow.log

全てを表示

sudo mysqldumpslow -a /var/log/mysql/mysql-slow.log

外部からMySQLに接続可能にする

mysqldのuserテーブルの設定

rootユーザにする必要があるかも

sudo su -

以下コマンドでユーザの権限状態を確認

mysql -u root mysql

mysql> select user, host from mysql.user\G

Hostでlocalhostからのみ接続になっている場合、外部から接続可能なユーザを作成&パスワード設定

mysql -u isucon -p -e "GRANT ALL PRIVILEGES ON *.* TO isucon@'%' IDENTIFIED BY 'isucon' WITH GRANT OPTION; FLUSH PRIVILEGES;"
SET PASSWORD FOR 'isucon'@'%' = PASSWORD('isucon');

ポートの確認

デフォルトではMySQLがTCPポート3306番でListenしているので、ポートが開いているか確認。

netstat -tlpn

0.0.0.0:3306 ~ LISTEN xxxx/mysqld の表示があればOK

127.0.0.1:3306で起動している場合、外部公開用にmysqlを起動する(mysql is exposed to the outside)

mysqld.cnf(/etc/mysql/mysql.conf.d/mysqld.cnf)を以下のように修正

# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
- bind-address          = 127.0.0.1
+ # bind-address          = 127.0.0.1

mysqlを再起動する

sudo systemctl restart mysql.service

他サーバでmysql停止

sudo systemctl stop mysql.service
sudo systemctl disable mysql.service
systemctl status mysql.service
systemctl is-enabled mysql.service

ファイアウォール設定

ファイアウォール設定を確認

sudo ufw status

ファイアウォールが有効になっている場合は、無効化する

sudo ufw disable

AWSの場合、セキュリティグループでMySQLのポート(3306)を許可する

インフラの改修で役立ちそうな点

mysql indexの有効化

ALTER TABLE landing_pages ADD INDEX index_name(user_id)

 INDEX index_name(column1 {asc|desc},column2{asc|desc})

空間index https://dev.mysql.com/doc/refman/5.6/ja/creating-spatial-indexes.html

mysql5to8 update

アップデートではなく、入れ直して再セットアップのほうが早いかもしれない。 その場合はメインDBサーバではないものでやってから、本メインDBでやっても良さそう。 安全を取るならDockerで初期DDLが動くか確認するのも手かも https://variable.jp/2018/04/23/mysql5-7%E3%81%8B%E3%82%89mysql8-0%E3%81%B8%E3%81%AE%E3%82%A2%E3%83%83%E3%83%97%E3%82%B0%E3%83%AC%E3%83%BC%E3%83%89/

OS、MWもろもろ

https://gist.github.com/south37/d4a5a8158f49e067237c17d13ecab12a

config

nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;
worker_rlimit_nofile  4096; # worker_connections の 4 倍程度
events {
  worker_connections 1024; # 大きくするなら worker_rlimit_nofile も大きくする(file descriptor数の制限を緩める)
}

http {
  # alp用のlog format
  log_format ltsv "time:$time_local"
              "\thost:$remote_addr"
              "\tforwardedfor:$http_x_forwarded_for"
              "\treq:$request"
              "\tstatus:$status"
              "\tmethod:$request_method"
              "\turi:$request_uri"
              "\tsize:$body_bytes_sent"
              "\treferer:$http_referer"
              "\tua:$http_user_agent"
              "\treqtime:$request_time"
              "\tcache:$upstream_http_x_cache"
              "\truntime:$upstream_http_x_runtime"
              "\tapptime:$upstream_response_time"
              "\tvhost:$host"
              "\treqbody:$request_body";
  access_log /var/log/nginx/access.log ltsv;
  # access_log  off; # 不要になったらOFFにする

  # 基本設定
  sendfile    on;
  tcp_nopush  on;
  tcp_nodelay on;
  types_hash_max_size 2048;
  server_tokens    off;

  # mime.type の設定
  include       /etc/nginx/mime.types;

  # Keepalive 設定
  keepalive_timeout 65;
  keepalive_requests 500;

  # Proxy cache 設定
  proxy_cache_path /var/cache/nginx/cache levels=1:2 keys_zone=zone1:1m max_size=1g inactive=1h;
  proxy_temp_path  /var/cache/nginx/tmp;

  # 複数serverへ proxy
  upstream app {
    server 192.100.0.1:5000 weight=2;  // weight をつけるとproxyする量を変更可能。defaultは1。多いほどたくさんrequestを振り分ける。
    server 192.100.0.2:5000;
    server 192.100.0.3:5000;
    # keepalive 60; app server への connection を keepalive する。app が対応できるならした方が良い。
  }

  server {
    # HTTP/2 (listen 443 の後ろに http2 ってつけるだけ。ブラウザからのリクエストの場合ssl必須)
    listen 443 ssl http2;

    # TLS の設定
    listen 443 default ssl;
    # server_name example.com;
    ssl on;
    ssl_certificate /ssl/oreore.crt;
    ssl_certificate_key /ssl/oreore.key;
    # SSL Sesssion Cache
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1m;  # cacheする時間。1mは1分。

    # reverse proxy の 設定
    location / {
      proxy_pass http://127.0.0.1:5000;
    }

    # Proxy cache
    location /cached/ {
      proxy_cache zone1;
      # proxy_set_header X-Real-IP $remote_addr;
      # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      # proxy_set_header Host $http_host;
      proxy_pass http://localhost:9292/;
      # デフォルトでは 200, 301, 302 だけキャッシュされる。proxy_cache_valid で増やせる。
      # proxy_cache_valid 200 301 302 3s;
      # cookie を key に含めることもできる。デフォルトは $scheme$proxy_host$request_uri;
      # proxy_cache_key $proxy_host$request_uri$cookie_jessionid;
      # レスポンスヘッダにキャッシュヒットしたかどうかを含める
      add_header X-Nginx-Cache $upstream_cache_status;
    }

    # static file配信
    location ~ .*\.(htm|html|css|js|jpg|png|gif|ico) {
      root /home/isucon/webapp/public;
      expires 24h;
      add_header Cache-Control public;

      open_file_cache max=100 inactive=20s; # file descriptor などを cache

      gzip on;  # cpu 使うのでメリット・デメリット見極める必要あり。gzip_static 使えるなら事前にgzip圧縮した上でそちらを使う。
      gzip_types text/css application/javascript application/json application/font-woff application/font-tff image/gif image/png image/jpeg image/svg+xml image/x-icon application/octet-stream;
      gzip_disable "msie6";
      gzip_static on;  # nginx configure時に --with-http_gzip_static_module 必要
      gzip_vary on;
    }
  }
}

mysqld.cnf

[mysqld_safe]
socket          = /var/run/mysqld/mysqld.sock
nice            = 0

[mysqld]
user            = mysql
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
port            = 3306
basedir         = /usr
datadir         = /var/lib/mysql
tmpdir          = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
bind-address            = 0.0.0.0 # どの接続先からも接続可
max_allowed_packet      = 300M
log_error = /var/log/mysql/error.log
max_connections=10000  # connection の limit を更新
innodb_buffer_pool_size = 1GB # ディスクイメージをメモリ上にバッファさせる値をきめる設定値
innodb_flush_log_at_trx_commit = 2 # 1に設定するとトランザクション単位でログを出力するが 2 を指定すると1秒間に1回ログファイルに出力するようになる
innodb_flush_method = O_DIRECT # データファイル、ログファイルの読み書き方式を指定する(実験する価値はある)

# スロークエリの設定
slow_query_log         = 1
slow_query_log_file    = /var/log/mysql/mysql-slow.log
long_query_time = 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment