ISUCON6 予選参加記
ISUCON6 予選 9/17 土曜日に「応答5マイクロセカンド」で take4、Takky と参加していました。
参加当日からずっと風邪引いてたりしてたのでまともな振り返りはしてないですが記録として書いときます。 (箇条書きで同列っぽく書いてますが事実と主観が混在してます)
準備編
やったこと
- 過去問練習会
- Azure 環境の確認
- newrelic のアカウント準備および使い方の確認
準備での雑感
- azure の初期セットアップおよびリカバリで時間がかかる場合があるのでリストアはしっかりできるようにする
- newrelic は CPU やメモリは確認できたが MySQL のクエリおよびアプリケーションについては使い方が確認できなかったので当日は使わないことにした
- 3人のスキルセットから php を使うことを検討したが php.ini のチューニングに時間がかかりすぎる場合があるので Go に変更
- ここで Go を書ける人が1人しかいないのでアプリ担当が1人になる
当日編
午前
- 準備を完了する
- アプリデプロイ
- メトリクス収集用設定
- アプリに一通り触れて使用感を確認する
- アプリやSQLを眺める
- 方針の決定
わかったこと
- isuda, isutar, isupam の3つのサービスがある
- isuda がメインサービスで isutar は http で通信 isupam は外部プロセス呼び出しで連携する
- newrelic の結果より
isuda > mysql >> その他
で CPU を消費している - MySQL の slow query は出ていない
- MySQL の general log から一部 SELECT の間隔が遅い
- 初期状態は fail で 0 points
以上より
- ボトルネックはアプリケーションとして作業する
- 最も遅い所は / や /keyword で基本的に
htmlify()
があるのでこれを何とかする - その他こまごまとしたものは最後にまとめて対応か暇になったら都度対応
午後
- keyword の完全オンメモリ化
- initialize 時にロードする実装
- 追加およびソートの実装
- (削除処理は実はすっかり忘れてた)
- htmlify のキャッシュ化
- matcher のキャッシュ
- アンカータグのキャッシュ
- キーワード毎の htmlify のキャッシュ
- キーワード追加時の htmlify キャッシュのパージ
- SQL の不要なデータの取得をなくす
上記対応後でもずっと 0 点だったためどれがどの程度効果があったかは不明です。
雑感
- メトリクス収集してアタリをつけられるようにするのはやはり必要と思った
- チーム構成にもよるかもだけど 午前方針ぎめ、飯食いながら相談、1時間前まで作業、30 分まえまでに落とし所に収束させる、30 分で再起動確認という流れで考えてたけど間違ってはいないかなと思う。
- 点数が正の数になって景気つけようとしてたけど Fail 0 だった
- いつの間にか 307 点ぐらいとったけど気のせいレベル
- ボトルネック部分把握した所で「競プロ勢有利な問題じゃん」と叫んでいた。
- 実際にどうかは知らない(競プロ雑魚勢の感想)
- 途中というか最初から make 叩くだけでは Go アプリのビルドが成功しなかった
- 今回は複数環境を用意したり linux 上のユーザをわけたりはしなかったが特に不都合はなかった
- 以前参加したときのように個々で修正して個々でベンチマーク実行などを行うようなことをしなかったため?
- 秒速5センチメートルは未視聴です(君の名は。は先週観ました)
道に迷ったおばあさんを待ち合わせ場所にデプロイしていた #isucon
— nise_nabe (@nise_nabe) 2016年9月17日
さくっと newrelic 入れて動かしたら アプリが大体 CPU 使ってたからこれクエリ勝負じゃねーなと思ってた pic.twitter.com/KOQoAdFzbX
— nise_nabe (@nise_nabe) 2016年9月18日
コミットログです #isucon pic.twitter.com/u520RWnqVU
— nise_nabe (@nise_nabe) 2016年9月18日
昼食
260 円
とりあえず MySQL Connector/J 6.0 をビルドする
MySQL :: MySQL Connector/J 6.0 Developer Guide :: 4.4 Installing from the Development Source Tree
$ git clone -b release/6.0 git@github.com:mysql/mysql-connector-j.git
lib というディレクトリがあるので、最低限必要なものとして hibernate4 を ダウンロードしてきて展開して、中にある lib の jar を含むディレクトリをそのまま lib 以下に設置する。ant dist するだけなら hibernate4 だけがあればよさそう。(動くかは知らない)
$ tar zxvf hibernate-release-4.2.21.Final.tgz $ ls hibernate-release-4.2.21.Final/lib envers jpa optional osgi required $ mkdir /path/to/mysql-connector-j/lib/hibernate4 $ mv hibernate-release-4.2.21.Final/lib/* /path/to/mysql-connector-j/lib/hibernate4
ちなみに mysql-connecotor-j/lib 以下に直接展開すると関係ないファイルが邪魔してビルドに失敗する。
そして以下のように実行する。JAVA_HOME は設定されてなければ自分で設定する。
$ ant dist -Dcom.mysql.cj.build.jdk=$JAVA_HOME
Intellij IDEA 上で Ant の Run Configuration から起動する場合はなぜか文字コードが変になるので下記のように javac のところに encoding="utf8" が必要になる。
diff --git a/build.xml b/build.xml index a6ba44c..beffab7 100644 --- a/build.xml +++ b/build.xml @@ -814,7 +814,8 @@ See also com.mysql.cj.core.conf.PropertyDefinitions.SYSP_* variables for other t fork="yes" executable="${com.mysql.cj.build.jdk.javac}" compiler="modern" - includeantruntime="false"> + includeantruntime="false" + encoding="utf8"> <include name="**/*.java" /> <exclude name="testsuite/**" /> <exclude name="com/mysql/cj/jdbc/integration/**" />
とりあえず 5.1 とは違ってちゃんとビルドできる。すばらしい。以上。
MySQL Connector/J 6.0 の Service Provider について
下記 記事は Connector/J 5.1 についての記事。
6.0 の場合は
$ curl -L -O https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-6.0.3.tar.gz $ tar xvf mysql-connector-java-6.0.3.tar.gz $ cd mysql-connector-java-6.0.3
build.xml を確認してみると下記のようになってます。
592 <!-- JDBC 4+ support of service provider mechanism. --> 593 <mkdir dir="${com.mysql.cj.build.dir.driver}/META-INF/services/" /> 594 <echo file="${com.mysql.cj.build.dir.driver}/META-INF/services/java.sql.Driver" 595 message="com.mysql.cj.jdbc.Driver" />
じゃあどのドライバを使うかというのはどこで決めてるかというと ConnectionString クラスらしい。
src/main/java/com/mysql/cj/core/ConnectionString.java 55 SINGLE_CONNECTION("jdbc:mysql://") { 58 LOADBALANCING_CONNECTION("jdbc:mysql:loadbalance://") { 70 FAILOVER_CONNECTION("jdbc:mysql://") { 82 REPLICATION_CONNECTION("jdbc:mysql:replication://") { 144 FABRIC_CONNECTION("jdbc:mysql:fabric://") { 155 X_SESSION("mysql:x://") {
ちなみに 5.1 では下記のように場所がばらけているうえにわりと力技っぽく解決してるので 6.0 でだいぶ綺麗に書きなおされているらしいということがわかる。
src/com/mysql/jdbc/NonRegisteringDriver.java 63 private static final String REPLICATION_URL_PREFIX = "jdbc:mysql:replication://"; 65 private static final String URL_PREFIX = "jdbc:mysql://"; 67 private static final String MXJ_URL_PREFIX = "jdbc:mysql:mxj://"; 69 public static final String LOADBALANCE_URL_PREFIX = "jdbc:mysql:loadbalance://";
src/com/mysql/fabric/jdbc/FabricMySQLDriver.java 97 if (!url.startsWith("jdbc:mysql:fabric://")) {
DragonFlyBSD + letsencrypt インストールログ
環境
- DragonFly v4.4.3-RELEASE
ログ
letsencrypt 日本語ドキュメント certbot ドキュメント
ものによっては certbot-auto とか letsencrypt-auto とかよくわからんのでまずは検索。
$ sudo pkg search letsencrypt letsencrypt.sh-0.2.0 Pure BASH/ZSH Lets Encrypt client
https://letsencrypt.org/docs/client-options/
中身から察するにおそらくこれらしい https://github.com/lukas2511/letsencrypt.sh
$ cd /usr/local/etc/letsencrypt.sh/
とりあえず下記のものがサンプルとしてあるので .sample を消したものを設置
config.sh domains.txt hook.sh
今回の場合はすでに nginx + php-fpm で動いてるドメインに対して 証明書が欲しいので既存の server ディレクティブに letsencrypt.sh が作るファイルが読めるような設定を追加します。 nginx についてそんなに詳しくないので、今回は .well-known/acme-challenge 以下に来るアクセスをそのまま letsencrypt.sh が生成するディレクトリのパスにしてしまう設定にします。
# for letsencrypt location ^~ /.well-known/acme-challenge/ { default_type "text/plain"; root /usr/local/etc/letsencrypt.sh/.acme-challenges/; }
/usr/local/etc/letsencrpyt.sh/config.sh
#WELLKNOWN="${BASEDIR}/.acme-challenges" WELLKNOWN="${BASEDIR}/.acme-challenges/.well-known/acme-challenge"
一応 nginx を再起動などしたあと、下記コマンドを実行して取得する。
# /usr/local/bin/letsencrypt.sh --cron
取得した後は下記のように設定すると良いと思います。最低限の設定しかいれてないのでもっと安全にするにはググッてください。
listen 443 ssl; ssl_certificate /usr/local/etc/letsencrypt.sh/certs/example.com/fullchain.pem; ssl_certificate_key /usr/local/etc/letsencrypt.sh/certs/example.com/privkey.pem;
ここまででとりあえず https でアクセスできるようになると思います。
証明書の更新についてですが、インストールしたときに下記のように表示が出ますが、この通りに /etc/periodic.conf に設定を追加すると勝手に更新されるようです。まだ動作確認まではしてません。
To use this script you should copy the examples in /usr/local/etc/letsencrypt.sh/ and at least add a domain and a contact mail address. You should also copy the openssl.cnf.sample file in /usr/local/openssl so you won't get warnings about it missing. In order to run the script regularly to update the certificates add this line to /etc/periodic.conf weekly_letsencrypt_enable="YES" Additionally the following parameters can be added to /etc/periodic.conf To run the certification renenewal as a different user weekly_letsencrypt_user="_letsencrypt" To run a script after the renewal (as root) weekly_letsencrypt_deployscript="/usr/local/etc/letsencrypt.sh/deploy.sh"
DragonFlyBSD + owncloud インストールログ
(途中)
環境
- DragonFly v4.4.3-RELEASE
- nginx 1.10.0
- PHP 7.0.6
ログ
以前に owncloud 8.2 で運用していたものを一旦動かすのと、 php7 を使いたいため pkg にあるものではなく src からインストールする。構成は nginx + php-fpm。そして news アプリを動かしたい。
https://owncloud.org/changelog/#latest8.2
とりあえず設置位置は /var/local/www 以下に置く。
# cd /usr/local/www # curl -OJL https://download.owncloud.org/community/owncloud-8.2.5.tar.bz2 # tar xvf owncloud-8.2.5.tar.bz2
下記 URL を参考に nginx 設定をする。 https://doc.owncloud.org/server/8.0/admin_manual/installation/nginx_configuration.html
pkg から インストールしたままの nginx だとそこに nginx.conf に設定を書くしか無いのでほかの linux ディストリなどで入るように conf.d を作って include する構成にする。
(後で書く)
実際に動かすと幾つか undefined error が出るので下記で入れる。
# pkg install php70-hash php70-json php70-pdo php70-pdo_mysql php70-session php70-zip php70-dom php70-xml php70-ctype php70-gd php70-zlib php70-curl php70-xmlwriter php70-simplexml
このままだと owncloud が生成する data ディレクトリなどに書き込み権限がないので書き込み権限をなんとかする。
(後で書く)
News アプリを動かす場合。
# pkg isntall php70-iconv
あと直接エラーは出てないけど下記のものが必要かもしれない。news-updater のほうで動かした時にエラーになりました。
# pkg install php70-mbstring php70-pcntl
後始末
# rm /usr/local/www/owncloud-8.2.5.tar.bz2
ついでに owncloud 8 -> 9 の際に必要なパッケージは下記の通り。
# pkg install php70-filter
そして全部終わって cron.php を動かそうとした時には下記パッケージが必要でした。
# pkg install php70-xmlreader php70-posix php70-xmlwriter
DragonFlyBSD + php7 インストールログ
目的としては php-fpm を使いたい。
環境
DragonFly v4.4.3-RELEASE
ログ
適当に検索すると下記のものが出てくる。とりあえず php7 を使うので php70 を入れる。( fpm で検索しても出てこなかった)
php55-5.5.35 PHP Scripting Language php56-5.6.21 PHP Scripting Language php70-7.0.6_1 PHP Scripting Language
$ sudo pkg install php70 Updating Avalon repository catalogue... Avalon repository is up-to-date. All repositories are up-to-date. The following 1 package(s) will be affected (of 0 checked): New packages to be INSTALLED: php70: 7.0.6_1 The process will require 17 MiB more space. 2 MiB to be downloaded. Proceed with this action? [y/N]: y php70-7.0.6_1.txz : 100% 2 MiB 350.8kB/s 00:06 Checking integrity... done (0 conflicting) [1/1] Installing php70-7.0.6_1... [1/1] Extracting php70-7.0.6_1: 100%
php-fpm が入っていることを確認
$ php-fpm -v PHP 7.0.6 (fpm-fcgi) (built: May 27 2016 16:49:24) Copyright (c) 1997-2016 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
sudo php-fpm すれば動くけど rc.conf には書けるんだろうか
適当に rc.conf に書いたら動いた
$ sudo sh -c 'echo "php_fpm_enable=\"YES\"" >> /etc/rc.conf'
unix socket を使う場合、デフォルトで入っている設定が /usr/local/etc/php-fpm.d/www.conf
にあるので下記のように変更する。とりあえず /var/run 以下に socket を設置。 owner や group も nginx と同じユーザでないと permission denied になる。
listen = /var/run/php-fpm.sock ... listen.owner = www listen.group = www listen.mode = 0660
DragonFlyBSD + nginx インストールログ
単純に pkg で nginx インストールするだけ.
環境
DragonFly v4.4.3-RELEASE
ログ
事前に sudo を入れてあります。
$ sudo pkg install nginx
現時点ではバージョンは 1.10.0 らしい。
$ nginx -v nginx version: nginx/1.10.0
OS 起動時に nginx が起動するようにする。
$ sudo sh -c 'echo "nginx_enable=\"YES\"" >> /etc/rc.conf'
nginx 起動
$ sudo service nginx start Performing sanity check on nginx configuration: nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful Starting nginx.
設定ファイルは 上記のとおり /usr/local/etc/nginx/nginx.conf にある。