ようへいの日々精進XP

よかろうもん

ISUCON 2016 の予選に参加して何も出来ずに泣いた

tl;dr

isucon.net

同僚の武川さんに声掛けて頂いて、「チーム初老丸」として初参加。参加チームの平均年齢だけであれば間違いなくダントツだったのではないか。

振り返り

どうだったのか(結果)

  • とにかく遅い Web アプリケーションサービスを目の前にまったく歯が立たず泣いた
  • 点数は書くのもはばかれる点数だったので泣いた
  • 何をすればいいのかがパッと思いつかずに辛くて泣いた
  • 雀の涙程のスキルやキャリアが全く役に立たずに泣いた

反省、感じたこと

  • 事前準備は絶対に必要(過去問をやっておくなど)
  • 調査用のコマンドはまとめておくべきだった
  • インフラもアプリケーションもプロファイリング力が最も重要
  • 「あー、ここにキャッシュを挟めば良さ気」と思っても実装を追加することが出来なかったのが辛かった
  • ということで、アプリケーションの実装力必要(実装力とまではいかないけど、コードを読むチカラは必要だと思う)
  • 各種参考実装は初期段階でスコアは出ないけど焦らない
  • インフラ側で出来ることは限られているかもしれない(今回はほとんどインフラは触れず)
  • systemd 慣れて無さすぎ

これからどうするか

  • 今年の問題が公開されたら、改めて手元でチャレンジしてみる
  • プロファイリングのチカラを付けたい

メモ、 当日得た知見等

systemd 関連

  • chkconfig の代替
sudo systemctl list-unit-files -t service
  • service xxxx [status|start|stop|restart] の代替
sudo systemctl status ${service} -l
sudo systemctl [enable|disable] ${service}
sudo systemctl [stop|start|restart|status] ${service}
  • systemd ユニットファイルを修正した後
sudo systemctl daemon-reload
  • systemd 配下のアプリケーションログ
sudo journalctl -f

Ruby 関連

  • Rack アプリケーションのプロファイルには rack-lineprof が良かった
  • String#gsub よりも String#tr が速かった
  • Gemfile の凍結方法
$ cat .bundle/config
---
BUNDLE_FROZEN: "0" #=> 1 だと凍結
BUNDLE_PATH: "vendor/bundle"
BUNDLE_DISABLE_SHARED_GEMS: "true"

Perl 関連

carton exec -- plackup -s Starlet -p ${port_number} --max-workers=5 xxxxx.psgi
carton exec -- plackup -s Starlet --listen /tmp/xxxxx.sock --max-workers=5 xxxxx.psgi

MySQL 関連

  • テーブルの index 確認
SHOW INDEX FROM ${table};
  • slow log
slow_query_log                = 1
slow_query_log_file           = /path/to/mysqld-slow.log
long_query_time               = 0
log-queries-not-using-indexes = 1

最後

来年は今年よりもスコアが取れるように頑張りたい。

参加された方々、お疲れ様でした。運営の皆様、大変お疲れ様でした。

Elasticsearch の Multi Search API メモ

tl;dr

  • 定期的に Elasticsearch に問い合わせを行うバッチスクリプトで Elasticsearch への問い合わせ回数を減らしたい

memo

状況

  • Amazon ES に保存されたログを検索するバッチスクリプトで特定の ID 毎に日付を範囲してログの件数を取得する
  • 当初は ID が少なかったのであまり意識していなかったけど、テストで ID を増やしていったところ CPU 負荷も上がるし、たまに Amazon ES への接続エラーも発生している(認証辺りも絡んでいるかもしれない)
  • ID 毎に Elasticsearch に問い合わせを行う実装にしていた(先に気づけよ的な話ではある)

戦略

www.elastic.co

Multi Search API で実装すれば良さそう。

Multi Search API を使う前

以下のような感じのスクリプトで ID 毎に Elaseticsearch に検索していた。

#!/bin/bash

declare -A _hash
_hash["foo"]="2016-09-19T10:00:00+09:00"
_hash["bar"]="2016-09-19T10:00:00+09:00"
_hash["baz"]="2016-09-19T10:00:00+09:00"

while true;
do
  for key in ${!_hash[@]}; do
    curl -s -XGET "https://${AMAZON_ES_ENDPOINT}/cwl-*/_search" -w "\n" -d "
    {
      \"size\": 0,
      \"query\" : {\"term\" : { \"param_id\" : \"${key}\" }},
      \"aggregations\": {
        \"id_name\": {
          \"terms\": {\"field\": \"param_id\"},
          \"aggregations\": {
            \"id_count\": {
              \"filter\":{
                \"range\": { \"@timestamp\": { \"gte\": \"${_hash[${key}]}\", \"lte\": \"now\" }}
              }
            }
          }
        }
      }
    }" | jq -c '.aggregations.id_name.buckets[0]|{"id": .key, "count": .id_count.doc_count}'
    sleep 1
  done
  sleep 3
done

実行すると以下のような出力が得られる。

{"count":867,"id":"foo"}
{"count":863,"id":"bar"}
{"count":865,"id":"baz"}

Multi Search API を使った場合

以下のような感じで検索する。コードの行数も減らせてイイ感じ。

#!/bin/bash

declare -A _hash
_hash["foo"]="2016-09-19T10:00:00+09:00"
_hash["bar"]="2016-09-19T10:00:00+09:00"
_hash["baz"]="2016-09-19T10:00:00+09:00"

while true;
do
  queries=""
  for key in ${!_hash[@]}; do
    queries+="{\"index\": \"cwl-*\"}\n"
    queries+="{\"size\": 0,\"query\" : {\"term\" : { \"param_id\" : \"${key}\" }},\"aggregations\": {\"id_name\": {\"terms\": {\"field\": \"param_id\"},\"aggregations\": {\"id_count\": {\"filter\":{\"range\": { \"@timestamp\": { \"gte\": \"${_hash[${key}]}\", \"lte\": \"now\" }}}}}}}}\n"
  done
  echo -e ${queries} | curl -s -XGET 'https://${AMAZON_ES_ENDPOINT}/_msearch' --data-binary @- | \
  jq -c '.responses[].aggregations.id_name.buckets[0]|{"count":.id_count.doc_count,"id":.key}'
  sleep 3
done

実行すると以下のような出力が得られる。

{"count":1778,"id":"foo"}
{"count":1744,"id":"bar"}
{"count":1841,"id":"baz"}

Multi Search API を使う場合、クエリは以下のような内容となる。

{"index": ${インデックス名}}
{"query" : ${実際のクエリ}
{"index": ${インデックス名}}
{"query" : ${実際のクエリ}

Elasticsearch へのリクエストは以下のような内容となる。

echo -e ${queries} | curl -s -XGET 'https://${AMAZON_ES_ENDPOINT}/_msearch' --data-binary @-

で、Multi Search API を使ったらどうなったか

以下のようにバッチを動かしているコンテナの CPU 使用率が少しだけ下がった。

f:id:inokara:20160919214204p:plain

以上

必要に応じて Multi Search API を使いましょう。