2015年振り返りと2016年

※仕事納めしながら書いてる


今年はまれに見る激動の年だった。
とくに後半は何してたかもあんまり覚えてない。

登壇

自分にしては例年よりか登壇して喋ったような気がする。
しかも嬉しいことにお声がけ頂くことも。。

ただ、話すのがそんなに得意ではないのもあり
毎回トーク後に反省してました…
もっとうまく喋れるように来年はがんばります。

仕事

前半にHAROiDに転籍してから
無事リリースまで漕ぎ着けることが出来た。よかった。
今年はほぼこのリリースに注力した年だった。
完全に言い訳になるが、目の前の仕事が忙しすぎてほとんど技術系への投資が出来なかったのは反省。
本もほぼ読めてない…

2016年

おそらく会社としても自分としても転機になりそうな年。
モチベーションはかなり高いので攻めの姿勢でがんばります!

YAPC::Asia 2015で「Docker3兄弟」というお話をしました+QA補足 #yapcasia

※2015/08/29 追記
現在DockerToolboxでVirtualBoxもインストールすると最新の5.0.2がインストールされますが
このバージョンがDockerMachineと相性が悪く、VMが起動しないという罠があります。
https://github.com/docker/machine/issues/1716
VirtualBoxのバージョンを5.0.0に下げるか、
こちらから次期テストバージョンの5.0.3をインストールしましょう。


まずはじめに、足を運んでお聞きいただいた皆様ありがとうございました。
30分(トークは20分)にこれら3つのツールを紹介するにはボリュームが少し多すぎた感があり
きちんと伝えたいことが伝わったかどうか不安。。
また、QA時に英語で質問されテンパってしまってきちんと回答できず、質問していただいた方に大変申し訳なく思っております。。


QA時に回答できなかった分について補足します。
※kitematicについては英語でQAされたもので、きちんと理解出来ていない可能性があるので2通りの回答してみます
Q. kitematicでlinux上のリモートホストを管理できる?
A. 現在は出来ないようです。issueにはあがっているのでそのうち対応するかもしれません
Q. kitematicはlinux os上で動く?
A. 現在は出来ないようです。issueにはあがっているのでそのうち対応するかもしれません。
Q. docker-machineでREST APIはある?
A. 現在は出来ないようです。がロードマップ(c/sアーキテクチャ)には記載されているのでそのうち対応するでしょう。


あと一つ強調し忘れていたこととしては
「docker composeは冪等である」ということです。
どの環境でもdocker-compose up すれば動く!最高!!
開発環境やインフラでは冪等性が大事だと思っています。
docker-composeはその手助けをしてくれるでしょう。

YAPCについて

自分はWeb業界に入って間もない頃、perlを使ってアクセスログ解析ツールなどを開発してました。
そんなころにYAPC(たしか2009)を知って初参加し、とても刺激を受けたのを覚えています。
今の自分にも多大な影響を受けたカンファレンスでした。
今回で終了とのことで残念ではありますが、フィナーレに相応しい素晴らしいイベントだったと思います。
関係者の方々、参加者の皆様、本当にお疲れ様でした!!!

#tvrendo テレビ連動サーバ勉強会 で発表しました

http://connpass.com/event/10424/
弊社にて、テレビ連動サービスに特化した勉強会を開催しました。
で、自分も発表してました。


スライドはこちら。
http://www.slideshare.net/tsuyoshitorii5/public-43549341


時間配分全然わかってなかったので、(特に後半)かけ足になってしまいました。
申し訳ございません。



デモの辺りの補足

背景

そもそもだいぶ前から
「こういう感じでsocket.ioコンテナ化して自由に上げ下げできると面白いな。
 で、実際どうなのかな?実運用できそう?」
ということを考えていました。
そして今回いい機会なので急ぎでプロトタイプ書いてみたところ
なんとなく上手くいったのでデモとして公開してみました。
またこの構成だとLBが最初にサチるので、この構成単体だと限界があります。
あくまでサーバ1台辺りのリソースをうまく使いきりたいなーというところが目的です。
あと半分は遊びですねw

デモ動作説明

スライドにも書いてますが、以下のような仕組みで実現しています。

  • LBは Openresty+Luaで実現。sticky idからsocket.ioサーバを決定
  • socket.ioコンテナを増やすと以下のような処理が動く
    • Registratorが増えたコンテナ情報をconsulに通知する
    • consulと繋がっているconsul-templateに変更情報が通知される
    • consul-templateがnginx.confのサーバリストを書き換え、自動で restart が行なわれる
  • 複数コンテナはsocket.io-redis adapterで繋がっているのでブロードキャストも通知される
デモでやったこと

定期的にsocket.ioクライアントでコネクションし続け、
その状態でDockerコンテナ増やしたり減らしたりしても
問題なく接続/再接続できる様子を動画にしてみました。
反応ないのでわからないんですが、この手法どうだったんだろうかw
(動画アップロードしてもいいんですが、やりかたわからん…)



感想

クラスメソッドさんの大規模通知の話も共感しながら聞けましたし、
voluntasさんのMQTT話も本当にとてもわかりやすくて勉強になったし、
a2cさんのマル秘話も非公開にするのが惜しいほどすごいお話で刺激受けました。


正直言うと自分はめっちゃ面白かったので
第2回もあると良いですね!!!

omnibus-gitlabを利用したGitlabアップグレードの手順メモ

毎回ドキュメント見つつ実行するのがダルいのでメモしておく。

7.10.x 以降: 手順

これだけでOKになりました:)

# ubuntuバージョン
sudo apt-get update 
sudo apt-get install gitlab-ce

7.9.x 以前のバージョンから上記手順に移行したい場合は
普通に最新版install手順から繰り返せばそのまま移行することができます。
https://about.gitlab.com/downloads/





※一応前バージョン移行手順も残しておきます

7.9.x 以前: 手順

1. 最新バージョンのGitlabダウンロード

こちらのページから最新バージョンを確認し、ダウンロードをしておきます。
https://about.gitlab.com/downloads/
ex) Gitlab-7.6.2の場合

wget https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.6.2-omnibus.5.3.0.ci-1_amd64.deb
2. デーモン停止
sudo gitlab-ctl stop unicorn
sudo gitlab-ctl stop sidekiq
sudo gitlab-ctl stop nginx
3. バックアップ実行(※必須ではないが、念のため)

バックアップ先は /var/opt/gitlab/backups です。

sudo gitlab-rake gitlab:backup:create
4. 1. でダウンロードしたパッケージをインストール
# Ubuntu/Debian:
sudo dpkg -i gitlab_x.x.x-omnibus.xxx.deb

# CentOS:
sudo rpm -Uvh gitlab-x.x.x_xxx.rpm
5. プロビジョニング実行
sudo gitlab-ctl reconfigure
6. デーモン再起動
sudo gitlab-ctl restart

Redmineと連携している場合)

a. リポジトリへの権限付与
sudo gpasswd -a www-data gitlab-www
# redmineとgitlabの連携アクセス
sudo gpasswd -a redmine git
sudo chmod +rx /var/opt/gitlab/git-data

isucon4予選問題のLua(Lapis)バージョンを書いてみた

isuconアプリを書いてみましたシリーズ。
生でOpenresty+Luaで書いても良かったんですが
せっかくなのでLapisというWebフレームワークを使ってみました。
実は自分も初触り。

最初にLapisの概要など

http://leafo.net/lapis/


LuaのWebアプリケーションフレームワークです。*1
バックエンドはOpenresty(Nginx)を利用しています。既に速そうな感じがしますね…!
WebFrameworkBenchmarksでも割と上位にいます。

Lapis、実は生のLuaスクリプトではなく moonscript で書くのを推奨しているようです。
JavaScriptにおけるCoffeeScriptのようなものですね。
構文も似ているのでJS書いている人には取っ付き易いかもしれません。

コーディング/サーバ起動

moonスクリプトを書いたあとに

moonc *.moon

を実行するとコンパイルされます。
その後

lapis server <env>

を実行すると nginx.conf を nginx.conf.compiled にコンパイルし、
Webサーバを起動します。

もっと便利にコーディング
moonc -w *.moon

を実行しておくと、カレントディレクトリ以下をウォッチして
moonscript > luascript に自動コンパイルをしてくれます。
また、nginx.confに

lua_code_cache off;

を設定しておくと
サーバリロードしなくてもLuaスクリプトを反映してくれるので便利です。
開発中は offにしておくとよいでしょう。



isucon4 Lapis版ソースコード

こちら。
https://github.com/toritori0318/isucon4

また、Gistにitamaeレシピを置いておきました。
こちらを実行すると Openresty+Luarocks+Lapis がインストールされますので
試したい方はお使いください。

# itamaeインストール
gem install itamae

# レシピダウンロード
wget https://gist.githubusercontent.com/toritori0318/2f2e080f906dbbbd0dea/raw/b0de3d7e8ece81fc81514b074e49549d0975da16/isucon4_lapis_recipe.rb

# レシピ実行
itamae ssh isucon4_lapis_recipe.rb -h xxx.xxx.xxx.xxx -u ec2-user -i /path/to/aws.pem
isucon4 Lapisバージョンを動かすための手順

1. isucon4アプリを上記ソースコードに置き換えます
2. /etc/supervisord.confのminfdsを増やしておき、 service supervisord restart を実行します。

[supervisord]
logfile=/tmp/supervisord.log
loglevel=info
pidfile=/var/run/supervisord.pid
nodaemon=false
minfds=100000
minprocs=200

3. /etc/supervisord.confに以下を追記し、supervisorctl reload を実行します。

[program:isucon_lua]
directory=/home/isucon/webapp/lua
command=/opt/openresty/nginx/sbin/nginx -p /home/isucon/webapp/lua -c "nginx.conf.compiled"
#command=/home/isucon/env.sh /usr/bin/lapis server production
user=isucon
environment=LAPIS_OPENRESTY="/opt/openresty",PATH="/opt/openresty/nginx/sbin:$PATH"
stdout_logfile=/tmp/isucon.lua.log
stderr_logfile=/tmp/isucon.lua.log
autostart=true

ベンチマーク

kazeburoさんの "ISUCON4 予選でアプリケーションを変更せずに予選通過ラインを突破するの術" を参考にし、
サーバに対してほぼ同じ修正をした後のベンチマークです。

perlアプリケーション(kazeburoさんversion)で実行
$ ./benchmarker bench --workload 8
18:17:59 type:info	message:launch benchmarker
18:17:59 type:warning	message:Result not sent to server because API key is not set
18:17:59 type:info	message:init environment
18:18:07 type:info	message:run benchmark workload: 8
18:19:07 type:info	message:finish benchmark workload: 8
18:19:12 type:info	message:check banned ips and locked users report
18:19:15 type:report	count:banned ips	value:593
18:19:15 type:report	count:locked users	value:4357
18:19:15 type:info	message:Result not sent to server because API key is not set
18:19:15 type:score	success:186360	fail:0	score:40258
Lapisアプリケーションで実行
$ ./benchmarker bench --workload 8
18:54:06 type:info	message:launch benchmarker
18:54:06 type:warning	message:Result not sent to server because API key is not set
18:54:06 type:info	message:init environment
18:54:14 type:info	message:run benchmark workload: 8
18:55:14 type:info	message:finish benchmark workload: 8
18:55:19 type:info	message:check banned ips and locked users report
18:55:22 type:report	count:banned ips	value:859
18:55:22 type:report	count:locked users	value:4747
18:55:22 type:info	message:Result not sent to server because API key is not set
18:55:22 type:score	success:221580	fail:0	score:47865

やはり速かった。



Lapis雑感

全体的につらい方が多い :(

つらい点

実例が少ない
Lapis(Lua)自体のユーザ数が少ないこともあり、ノウハウ的な情報はほぼ皆無です。
自力で頑張る必要があるでしょう。
Webに情報が少ない公式ドキュメント以外は情報少ないというかほぼ皆無です。
自力で頑張る必要があるでしょう。
エコシステムが弱い
そもそも便利ライブラリが少ない、またはメンテされていないのが多いので
普通のWebアプリケーションを作ろうとした時につらいです。
自力で頑張る必要があるでしょう。
MySQL非対応
PostgreSQLはバッチリ対応していますが、現時点で何故かMySQLは非対応です。
Pull Requestはされているようなのでその内当たるかも。
しかも現時点ではそのまま利用しようとすると動かないバグがあるので
1行パッチを当てる必要があります。(こちらのレシピでもパッチを実行しています)

良い点

Openrestyの遺産が使える
普通にngxの情報にアクセスできますし、Openrestyのライブラリも使えます。
これは結構な利点だと思います。
速い
パフォーマンスはだいぶ良いので
単純なアプリでパフォーマンスが必要であれば
選択肢として考えてもよいかもしれません。



まとめ

Lapisでisucon4予選問題アプリを書いてみました。
実際のWebアプリケーションを作るにはだいぶ茨の道だと思いますが
LLのように書ける割には速いですし
isuconのような一発アプリに使うのはアリかなと思いました。


またLua/MoonScript、実際書いてみるとわかるのですが
構文はJavaScript/CoffeeScriptに似ている部分があるので
実は(書くだけであれば)そんなに違和感なく書けたりします。
Go速いけどまだちょっと手を出しにくい…という人には
割とマッチするかもしれません。
ぼくはオススメはしませんが!!!

*1:ほぼデファクト

2014年振り返りと2015年

まずは振り返ってみる。

家電その他の故障率が異常

最初に仕事の話持ってこようかと思ったんですが、
去年一番印象に残っているのは とにかくモノがよく壊れた ということ。
壊れたもの一覧。

  • 冷蔵庫
  • 洗濯機
  • 炊飯器
  • 給湯器
  • 自転車
  • イヤホン

「家電は一気に壊れる」といいますが、本当に立て続けにきたのでびびった。
これだけで50万くらい飛んでる。。
というわけで家電用に自分で修繕積立することにした。
みなさまもしておいたほうが良いですよ!



仕事

2014年前半はかなり駆け抜けた感がありますが、後半は今後に向けてひっそりと動いてた感じです。
(サボっていたわけではない!!!!)
今年は忙しくなりそうなヨカン。たぶん。


業務内容のほうですが、サーバ運用の部分を勉強しつつ
新たにLuaGolang触ってみたり、相変わらず広く浅くやってる感じでした。
Dockerはそれなりに触っていて開発フローにも組み込んでいたりするので
来年は本番運用にも持って行きたいと思っています。


またあまり技術的な話ではないんですけど、去年はチーム開発をするにあたって
自分の中で HRT(謙虚/尊敬/信頼) を特に意識していました。
システム開発ではメンバー間の衝突*1することはよくあることですが
基本的には自分よりも相手の方を尊重して進めてた(つもり…)*2
というか「チームの雰囲気を悪くしない心構え」というか。
結構大事だと思った。


その他ではYAPCでトークできたこともあってか色んな意味で広がりました。とても良かった。


今気になってるOSSやキーワードなど。いくつか取り入れていきたい。

  • Atlas
  • Consul
  • AWS Lambda
  • AWS EC2 Container Service
  • AWS Service Catalog
  • AWS Aurora
  • FoundationDB
  • Aerospike
  • RedisCluster

家庭

上の子はすっかり大きくなって、きちんと(?)人っぽくなってきた。
ただ最近また言うこと聞かなくなってきているので真面目にしつけしないとなぁと思ってる…
下の子は3才になってますます可愛くなってる…が、女の子だからかわからないけど主張が強い。
あとジャイアンみたいに「人のものは私のもの」という感じなので見ててヒヤヒヤする。
パンチ、キックが得意。



2015年

特にこれといって大きな目標は決めてないんですけど、*3
今年は色んな意味でバリュー出すチャンスがありそうなので
それを逃さずに自分を高められればいいかなと思ってます。


では、本年もよろしくお願いします!!!!

*1:仲が良くないという話ではなく、設計上の考え方の違いとか

*2:もちろん明らかに悪手の場合は反論する

*3:小さいのはたくさんある

lua-resty-woothee というモジュールを書きました

Lua Advent Calendar 2014 7日目の記事です。


wootheeというUA解析プロジェクトを最近知ったのですが、
Lua版が無さそうだったので書いてみました。
本当はLua単体で動くようにしたかったんですが、諸事情によりOpenresty依存となっております。
理由は後述。

ちなみに書いた動機など。

  • ちょうど、エンドユーザのUA解析してDB登録したりゴニョゴニョ出来たらいいなーと思っていた
  • Nginx+Luaを書き始めているが、がっつりLuaを触っていたわけではないのでライブラリっぽいのも練習がてら書いてみたかった
  • 期待された https://twitter.com/songmu/status/525610905946447872

使い方

READMEそのままですが…

インストール
luarocks install https://raw.githubusercontent.com/toritori0318/lua-resty-woothee/master/lua-resty-woothee-dev-1.rockspec

または git clone でリポジトリダウンロード後に
lua_package_path をよしなに指定すると使えるようになります。
アップデートしたい場合は、再インストールしてNginxをリスタートするだけで行けるはず。

基本
server {
    location /test {
        content_by_lua '
            local woothee = require "resty.woothee"

            -- parse
            local r = woothee.parse(ngx.var.http_user_agent)
            --  => {"name": "xxx", "category": "xxx", "os": "xxx", "version": "xxx", "vendor": "xxx"}

            -- crawler?
            local crawler = woothee.is_crawler(ngx.var.http_user_agent)
            --  => true

            ngx.header.content_type = "text/plain"
            ngx.say(r.name)
        ';
    }
}

あとはparseメソッドにUserAgent渡せば結果がtableで返ってきます。簡単。

応用編

parseした結果をアクセスログに直接埋め込んだり、プロキシしているバックエンドサーバに渡したりと
いろいろ応用が効きそうですね。
この辺りのサンプルもREADMEに書いてあるので参考にどうぞ。
アクセスログ出力した時はこんな感じでparseした情報を付与できます。

xxx.xxx.xxx.xxx - - [01/Nov/2014:15:47:38 +0000] "GET /test HTTP/1.1" 200 17 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36" "Chrome" "pc" "Mac OSX" "38.0.2125.111" "Google" "10.9.5"
xxx.xxx.xxx.xxx - - [01/Nov/2014:15:47:41 +0000] "GET /test HTTP/1.1" 200 18 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:33.0) Gecko/20100101 Firefox/33.0" "Firefox" "pc" "Mac OSX" "33.0" "Mozilla" "10.9"
xxx.xxx.xxx.xxx - - [01/Nov/2014:15:48:01 +0000] "GET /test HTTP/1.1" 200 17 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/600.1.17 (KHTML, like Gecko) Version/7.1 Safari/537.85.10" "Safari" "pc" "Mac OSX" "7.1" "Apple" "10.9.5"

Openresty依存になった理由など

実は最初はLua単体で動くように書いていました。
実装がだいたい終わってよっしゃーテストやるぞーとテスト通し始めたら

で、あとで知ったんですが(オイ) Luaのは正規表現というか独自パターンマッチングなのでそりゃ通らないわけですね。
最初は独自の方に寄せようとしたんですが「(a|b)」とか「()?」とか使えなくてだいぶ辛い…

正規表現ライブラリ使うことも考えたんですが
あまり他のライブラリに依存するとユーザの導入障壁が高くなるでしょうし、
自分は(そして多分殆どの人が)Openrestyでしか使わないでしょうし、
OpenrestyはPCREの正規表現実装を含んでいるのでそれ使えば解決するし、
という感じでOpenresty依存にしました。
(関連する会話 https://twitter.com/toritori0318/status/527151195719077891


この辺り、うまく共存してOpenresty依存無くすことも出来るかもしれないですが
自分は必要なかったのでそこは頑張りませんでした。
もしLua単体で動かしたいという要件があれば挑戦してみてください。



まとめ

Nginx+luaで解析することによって
高いパフォーマンスで、かつ汎用的に解析結果を使えるようになりました。
大抵はアプリケーションサーバよりNginxのほうがリソース空いていることが多いと思いますし、
そちらによけいな処理をお任せしてしまうのは悪いことではないと思います。
よろしければ使ってみてください〜

おまけ1:luayamlモジュールでハマった

http://yaml.luaforge.net/
これの最新版使ったらバグなのかわからないけどtestsetsのparse結果がおかしくてめっちゃハマった。つらい*1

おまけ2:Nginxのset変数はLuaから定義出来ない

Nginxのset変数もライブラリの中からよしなに出来ればもう少しシンプルに書けるかなと思いましたが
"That is, nginx variables cannot be created on-the-fly." とのことでした:(

おまけ3:Openrestyモジュールのテストについて

Openrestyモジュールのテスト、coreから野良モジュールまでほとんどperlのTest::Nginxで書かれています。
perl...うっ」となるかもしれないですが、実際にperlを知らなくても書けます。
なかなか面白い手法だったので紹介してみます。

# vim:set ft= ts=4 sw=4 et:

use Test::Nginx::Socket::Lua;
use Cwd qw(cwd);

repeat_each(1);

plan tests => repeat_each() * (3 * blocks());

my $pwd = cwd();

our $HttpConfig = qq{
    lua_package_path "$pwd/lib/?.lua;;";
};

$ENV{TEST_NGINX_RESOLVER} = '8.8.8.8';

no_long_string();
#no_diff();

run_tests();

__DATA__

=== TEST 1: basic
--- http_config eval: $::HttpConfig
--- config
    location /t {
        content_by_lua '
            local woothee = require "resty.woothee"
            ngx.say("OK")
        ';
    }
--- request
    GET /t
--- response_body
OK
--- no_error_log
[error]

たとえばこちら、lua-resty-wootheeのテストです。
__DATA__ 以下のところだけ変えればOKです。
見たらわかりますが、Nginxコンフィグをそのまま記述して、期待するレスポンスを書く感じです。簡単ですね。
(ただ、printデバッグなどが非常に面倒なのが少し辛い…)

おまけ4:ベンチマーク

単純なLuaスクリプトと比較し、どの程度性能劣化するかを検証してみました。

now()を返すだけのLuaスクリプト
ab -c 10 -n 50000 -H "User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)" http://localhost/now
Requests per second:    10291.40 [#/sec] (mean)
woothee.parse ON
ab -c 10 -n 50000 -H "User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)" http://localhost/test
Requests per second:    8541.17 [#/sec] (mean)

たぶんUser-Agentによって多少は性能変化すると思いますが、許容範囲ではないでしょうか。


*1:datasetのテストをするときのみyamlモジュールに依存している