社内版ISUCON2015のメモ
社内版ISUCONに出場してきた。自分は現在サーバサイドエンジニアだけど、少し前の職種であるインフラエンジニアとして誘われ、参加。
サーバにもう繋げず、あまり痕跡残ってないけど、手元のメモ参考に記事にしてみる。
現地についてレギュレーション読んだところ、ほとんどインフラやれることなく、サーバサイドでの実装勝負になりそうかもと思う。この時点で、実装やりたいって言えばよかったな。
説明があり、スタート。
SSH鍵の設定とかホスト名の設定とかして、MySQLインストール。
rpm -ivh http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-community-common-5.7.9-1.el7.x86_64.rpm rpm -ivh http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-community-libs-5.7.9-1.el7.x86_64.rpm rpm -ivh http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-community-client-5.7.9-1.el7.x86_64.rpm wget http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.9-linux-glibc2.5-x86_64.tar.gz tar xvzf mysql-5.7.9-linux-glibc2.5-x86_64.tar.gz cp -rp /usr/local/src/mysql-5.7.9-linux-glibc2.5-x86_64 /usr/local/mysql cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld cp /usr/local/mysql/support-files/my-default.cnf /etc/my.cnf chmod 755 /etc/init.d/mysqld mkdir /data/mysql -p /usr/local/mysql/bin/mysqld --initialize adduser mysql chown -R mysql. /data/mysql/ /etc/init.d/mysqld start
まぁ、データ量150万行ぐらいで、1GBぐらいだったから、ほんとはオンメモリがよかったのかもな。
とりあえず、5.7系と戯れて、初めてちゃんと触ってみる。
ユーザ作ったら、運営上のトラブルなのか他のインスタンスからつなげず、ユーザ作成したり、削除したりpingしたりtelnetしたり相当試行錯誤した。ここが一番疲れたな・・・
mysql> delete from mysql.user where host='172.1.1.0/255.255.255.0'; mysql> create user ‘app’@'%.%.%.%' identified by '' mysql> set password for 'root'@'localhost' = 'hogehoge'; mysql> GRANT ALL ON *.* TO 'app’@‘%.%.%.%' IDENTIFIED BY '';
みたいにしてユーザ作成後、DB作成。
mysql> create databaase xxxdb default character set utf8;
こうせずに、「create database hogehoge」だけしかしなかったから、文字化け発生。
mysql> ALTER DATABASE testdb character set utf8;
して、変更。
character-set-server=utf8 default-storage-engine=InnoDB default-character-set=utf8 skip-character-set-client-handshake
入れたりしたけど、きかなかったな。default-character-setか何かも使えなかった気がする。
次にテーブル作成。テーブル作らないとimportできないことを知る。あと、TEXTはインデックスはれないのね。
create table user ( userId CHAR(8), userNo INT, userPublicScore INT(3), userFriends TEXT, userImage VARCHAR(255) ); create table item ( itemId CHAR(8), itemNo INT, itemSupplier TEXT, itemSoldQuantity INT, itemSalePrice INT, itemTags TEXT, itemImage VARCHAR(255) ); create table post ( postId CHAR(8), postDateTime INT, postUserId CHAR(8), postItemId CHAR(8), postItemScore INT, postItemState TEXT, postLikeUsers TEXT, postTags TEXT ); create table user_friends ( userId CHAR(8), friendId CHAR(8) ); create table item_tags ( itemId CHAR(8), itemTag TEXT ); create table post_like_users ( postId CHAR(8), likeUser CHAR(8) ); create table post_tags ( postId CHAR(8), postTag TEXT );
こんな感じで適当に。
次に、データのインポート。TSVだったので、以下のようにする。
mysqlimport -r honban_database ~/sample_data/user.tsv --fields-terminated-by='¥t' -S /tmp/mysql.sock -uapp
あとはスロークエリとインデックス使ってないSQL吐かせて、それにあわせてインデックスはって、一旦終わり。
SELECT * FROM post WHERE postId = 'img'; CREATE INDEX idx_post_postId ON post(postId);
こんな感じ。
あとはperconaツールキットいれたり。
次に、タブ区切りのデータのなかにカンマ区切りのデータがあるので、Pythonでスクリプト書いて、別テーブルに。サーバに繋げないから、このコード消えちゃったけど、TSV読み込んで、readerをループで回し、さらにカンマ区切りのカラムをループで回す感じ。
Varnish
varnishはシンプルに。ちゃんと触ったのは初めてなので、新鮮。
# Default backend definition. Set this to point to your content # server. # backend default { .host = "127.0.0.1"; .port = "80"; } sub vcl_recv { set req.grace = 30s; } sub vcl_fetch { #set obj.grace = 30s; # キャッシュ時間のデフォルト設定 60秒*60分 set beresp.ttl = 3600s; # 不要なヘッダーは除去 unset beresp.http.expires; unset beresp.http.Pragma; return(deliver); } ----------------------------- # Configuration file for varnish # # /etc/init.d/varnish expects the variable $DAEMON_OPTS to be set from this # shell script fragment. # # Maximum number of open files (for ulimit -n) NFILES=131072 # Locked shared memory (for ulimit -l) # Default log size is 82MB + header MEMLOCK=82000 # Maximum number of threads (for ulimit -u) NPROCS="unlimited" # Maximum size of corefile (for ulimit -c). Default in Fedora is 0 # DAEMON_COREFILE_LIMIT="unlimited" # Set this to 1 to make init script reload try to switch vcl without restart. # To make this work, you need to set the following variables # explicit: VARNISH_VCL_CONF, VARNISH_ADMIN_LISTEN_ADDRESS, # VARNISH_ADMIN_LISTEN_PORT, VARNISH_SECRET_FILE, or in short, # use Alternative 3, Advanced configuration, below RELOAD_VCL=1 # This file contains 4 alternatives, please use only one. ## Alternative 1, Minimal configuration, no VCL # # Listen on port 6081, administration on localhost:6082, and forward to # content server on localhost:8080. Use a fixed-size cache file. # #DAEMON_OPTS="-a :6081 \ # -T localhost:6082 \ # -b localhost:8080 \ # -u varnish -g varnish \ # -s file,/var/lib/varnish/varnish_storage.bin,1G" ## Alternative 2, Configuration with VCL # # Listen on port 6081, administration on localhost:6082, and forward to # one content server selected by the vcl file, based on the request. Use a # fixed-size cache file. # #DAEMON_OPTS="-a :6081 \ # -T localhost:6082 \ # -f /etc/varnish/default.vcl \ # -u varnish -g varnish \ # -S /etc/varnish/secret \ # -s file,/var/lib/varnish/varnish_storage.bin,1G" ## Alternative 3, Advanced configuration # # See varnishd(1) for more information. # # # Main configuration file. You probably want to change it :) VARNISH_VCL_CONF=/etc/varnish/default.vcl # # # Default address and port to bind to # # Blank address means all IPv4 and IPv6 interfaces, otherwise specify # # a host name, an IPv4 dotted quad, or an IPv6 address in brackets. # VARNISH_LISTEN_ADDRESS= #VARNISH_LISTEN_PORT=6081 VARNISH_LISTEN_PORT=80 # # # Telnet admin interface listen address and port VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 VARNISH_ADMIN_LISTEN_PORT=6082 # # # Shared secret file for admin interface VARNISH_SECRET_FILE=/etc/varnish/secret # # # The minimum number of worker threads to start VARNISH_MIN_THREADS=50 # # # The Maximum number of worker threads to start VARNISH_MAX_THREADS=1000 # # # Idle timeout for worker threads VARNISH_THREAD_TIMEOUT=120 # # # Cache file location VARNISH_STORAGE_FILE=/var/lib/varnish/varnish_storage.bin # # # Cache file size: in bytes, optionally using k / M / G / T suffix, # # or in percentage of available disk space using the % suffix. VARNISH_STORAGE_SIZE=1G # # # Backend storage specification #VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}" VARNISH_STORAGE="malloc,1G" # # # Default TTL used when the backend does not specify one VARNISH_TTL=120 # # # DAEMON_OPTS is used by the init script. If you add or remove options, make # # sure you update this section, too. DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \ -f ${VARNISH_VCL_CONF} \ -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \ -t ${VARNISH_TTL} \ -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \ -u varnish -g varnish \ -S ${VARNISH_SECRET_FILE} \ -s ${VARNISH_STORAGE} \ -p thread_pool_min=200 \ -p thread_pool_max=4000 \ -p thread_pool_add_delay=2 \ -p session_linger=100" # -s malloc,3G" # ## Alternative 4, Do It Yourself. See varnishd(1) for more information. # # DAEMON_OPTS=""
慣れない設定で少し戸惑った。基本メモリに載せて、スレッドプール増やしてみた。とりあえず、動いたのでよかった。
そして、キャッシュが聞いているかどうかはログとかで見られるけど、ヘッダー自由に見たいから、これも簡単にPythonスクリプト書いて、ageヘッダーとか見て確認。これもコード消えてしまったので載せられないけど、requestsモジュール使って、中身見るだけのシンプルなやつ。
終わりに
まぁ、もうちょっと臨機応変にできてもよかったのかもしれない。ただ、MySQL5.7とかVarnishという普段触らないものが触れたので、よかったかな。
チームに誘ってくださったI君ありがとう!実装頑張ってくださったMさんありがとうございました!