カイワレの大冒険 Third

技術的なことや他愛もないことをたまに書いてます

社内版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さんありがとうございました!