2014年振り返り

各月ざっくり

1月

  • AsakusaSatellite導入した
  • 各種通知をAsakusaSatelliteに流す対応をする

2月

3月

  • Perl 5.8.8から5.18.2への移行対応
  • CartonとかApp::FatPackerとか試す
  • Coroを使って非同期処理を書く
  • でんぱ組.incの曲に何故かハマる

4月

5月

6月

7月

  • Test::mysqldの素晴らしさを理解する
  • メインPCをMacBookAirに変える
  • スクフェスで初URを引いた
  • SQL::Translator::Diffを試したけどOracle対応してなかったので泣いた
  • 帰省した

8月

  • A Tour of Goを完走
  • beatmania IIDXを頻繁にプレイした
  • SlackにHubotを住まわせた
  • Travis CIを初めて使う
  • Herokuを初めて使う
  • MySQL5.1を5.6にアップグレードする対応してた
  • YAPC::Asia 2014に参加

9月

  • ゲーム実況やたらと見てた
  • 風来のシレンを一時期やってた
  • 引越し準備に追われる
  • ISUCON4に参加(予選敗退)
  • iPhone6に機種変更する
  • 第二子誕生

10月

  • 引っ越し
  • Data::Section::Simpleが便利なことに気づく
  • 古のサーバ移行に苦しむ
  • Chiba.pm#5に参加
  • Apache(httpd)と戯れる
  • BrainWarsにハマる
  • PerlCasual#6に参加
  • boot2docker入門

11月

  • DockerHubでAutomation Build
  • Net::POP3を使って一部のメールをHipChatに通知させた
  • VagrantとChef使って環境構築をコード化
  • Coverallsを初めて使う

12月

  • Time::Piece::Iteratorというモジュール書いた
  • Advent Calendarに初参加
  • Serverspecを導入
  • Circle CIとDocker使って自動テスト

ブログ

17記事を投稿。前年に比べると倍に増えてるけど、まだまだアウトプットが足りない。
Perlの記事が比較的多かったかな〜。

読書

f:id:waniji:20150103104612p:plain

http://booklog.jp/users/waniji/chart/2014/total

技術書1冊、ラノベ3冊、その他1冊。壊滅的。どげんかせんといかん。

Pocket

f:id:waniji:20150103104549p:plain

年末時点でPocketの残り記事数は70。追加した記事が2,655件、読んだ記事が2,721件だった。
積み記事は消化出来てるのでいい調子だけど、もうちょっと減らしたい。

まとめ

2014年は育児の年だったなぁ。第2子も生まれて更に賑やかになった。
技術に関して下半期はそこそこ頑張れてる印象。ISUCONに参加したり、仲間内でもくもく会したり。まさか業務でDocker使うことになるとは思わなかったけど、趣味で触っててよかったと思えた。
自分の自由時間が少なくなったことに慣れてきたので、来年は有効活用したい。

2015年

業務でRubyを使用することが決まったので、2015年はRubyかな〜。Golangは入門しかしてないので本格的に使いたい。
後は基礎を固めたい。何するにも基礎が固まってると飲み込みが早い気がするので。
それと英語......。

ある範囲内の日付時刻を、指定間隔で反復するTime::Piece::Iteratorというモジュールを作った

この記事はPerl Advent Calendar 2014の18日目の記事です。

17日目の記事はid:kfly8さんの間接オブジェクト記法のアンチパターンでした。

Time::Piece::Iterator

Time::Piece::Iterator

指定した範囲内の日付時刻を、指定した間隔で反復するモジュールが欲しかったのですが、見つからなかったので作成しました。(他にあれば教えて下さい!)
日付とか年月を引数に取るバッチを、特定の期間分(半年とか)実行したい時に使ってます。

使い方

Time::Pieceオブジェクトを2つ渡すと、その範囲内の日付時刻を返してくれます。

use Time::Piece;
use Time::Piece::Iterator;

my $iterator = day_iterator(
    localtime->strptime('2014/01/01', '%Y/%m/%d'),
    localtime->strptime('2014/01/03', '%Y/%m/%d'),
);

while( my $t = $iterator->next ) {
    print $t->ymd, "\n";
}
2014-01-01
2014-01-02
2014-01-03

間隔はdayだけではなくsecond/minute/hour/week/month/yearを用意しています。
例えば、今年の各月最初の平日を知りたい場合はこんなかんじです。

use Time::Piece;
use Time::Piece::Iterator;
use Time::Seconds;
use Calendar::Japanese::Holiday;

sub is_weekday {
    my $t = shift;
    my $is_holiday = isHoliday( $t->year, $t->mon, $t->mday, 1 );
    if( $is_holiday || $t->wday == 1 || $t->wday == 7 ) {
        return 0;
    }
    return 1;
}

my $from = localtime->strptime('2014-01-01', '%Y-%m-%d');
my $to = $from->add_years(1) - ONE_DAY;

my $iterator = month_iterator( $from, $to );
while( my $t = $iterator->next ) {
    while( !is_weekday($t) ) {
        $t += ONE_DAY;
    }
    print $t->ymd, "\n";
}

用意されている間隔では要件が満たせない場合は、自分で設定することが出来ます。
以下の例は、間隔が3週間の場合です。

my $iterator = custom_iterator(
    $from, $to,
    sub {
        my ($t, $sign) = @_;
        return $t + ( $sign * 3 * ONE_WEEK );
    }
);

第1引数が現在の日付時刻、第2引数が符号(plus or minus)です。過去に遡ることも出来るので、符号を受け取れるようにしています。

注意点

month_iteratorとyear_iteratorはTime::Pieceのadd_monthsとadd_yearsを使っているので、月末の扱いに注意する必要があります。

今後

無限iteratorを可能にする、Time::Piece::Plusも扱えるようにする、などを考えています。

あと、CPANには上げていないのですが、使っていただける方がいれば上げたいなと思っています。

明日

19日目はid:y_uukiさんです!

Chefでdirectoryをrecursive trueで作成するときの注意点

階層の深いディレクトリを作成するとき、mkdir -pのように一気に作ろうとrecipeを作った。

directory '/home/user/foo/bar' do
    owner 'user'
    group 'user'
    mode '0755'
    recursive true
end

しかし、これだとownergroupmodeの指定が、一番深い階層のディレクトリ(bar)のみに適用され、中間のディレクトリ(foo)には適用されないので、以下のように書く必要がある。

%w[
    /home/user/foo
    /home/user/foo/bar
].each do |path|
    directory path do
        owner 'user'
        group 'user'
        mode '0755'
    end
end

公式ドキュメントにも書いてた。
http://docs.getchef.com/chef/resources.html#recursive-directories

過程を伝える

調査依頼された時、結果だけ伝えるのではなく、過程もある程度伝えたほうが良い。あれやこれはやったか?という確認をする手間も省けるし、過程に誤りがあった場合に指摘がしやすいので効率的。

Chiba.pm #5 に行ってきた #chibapm

Chiba.pm #5に参加し、LTもして来ました。
初めてこういった場でLTをさせて頂いたので、とても緊張しましたが、良い経験になりました。

(reveal.jsで作った資料をPDFエクスポートしたらレイアウト崩れてしまいました)

内容は、最近使っているPath::Tinyというモジュールについての紹介とハマったことです。

感想

メイントークが「MySQLの歴史」と「職業訓練」でPerlが一切出てこなくて驚きましたが、どちらもとても興味深く面白い内容でした!
特にMySQLの歴史についてのトークは、業務でMySQLのバージョンアップ対応をやっていたこともあり、それについての知見が得られたのは嬉しい誤算でした。

主催者の@kaztrさん、@8GRTさん、ありがとうございました&お疲れ様でした!

ISUCON4の予選に参加してきた #isucon

ISUCON4の予選にkyokomiyasuunとチームを組んで参加してきました。
1日目に参加し、最終送信結果は15107、benchmark v2では17124と予選通過には程遠いスコアでした。
しかも、AMI審査方法の通りに実行してみたら見事にレギュレーション違反!
来年リベンジするためにも記録を残しておこうと思います。

予選当日までにやったこと

ISUCON初参加だったので、感覚をつかむために前回予選のAMIを使って3人で練習。
正直、この練習をやってなければもっとひどい結果になっただろうと思えるくらい、問題点や準備しなければならないことが山ほど出てきて泣きそうでした。

アクセスログMySQLのスローログの分析方法を事前に調べて手順化しておき、当日に慌てないように準備することにしました。

使う言語もこの時に決定。得意言語はバラバラで、Perl2人、Go1人だったんですが、作業分担的にGoにすることに。

リポジトリGitHubのプライベートリポジトリ、テキストでのやりとりはSlackを使いました。ISUCON用のチャンネルを作って、そこにGitHubにpushした内容などを通知させるように設定。

予選当日 午前

まずは当日のマニュアルに目を通し、起動したインスタンスのIPをSlackに貼る。
鍵は練習で使用したものを流用。.ssh/configにIPと鍵の場所を書いて簡単にログイン出来るようにした。

ログインしたらまず/home/isucon配下でgit initして remote add & push。
最初は修正は行わずに、アプリケーションの内容やミドルウェアなどの情報を調べることに。
アプリにログインしたあと何も出来なかったので、この機能が動くように修正するのか!?と勘違いしましたが、すぐにログインゲーだと気づく。

次にnginxのログとMySQLのスローログ(long_query_time=0)を出力する設定にしてベンチ初回実行。
access.logはApache::Log::Parserを使って集計、MySQLのスローログはmysqldumpslowを使って集計。

bench.shを作成。内容は、今あるnginxのログとMySQLのスローログをrenameして空にし、nginx、MySQL、supervisordの再起動して、ベンチを実行という感じ。

ひと通り見たので修正方針の話し合い。
login_logテーブルで禁止IPの判断、禁止Userの判断、前回ログイン情報の取得と色々やってたので、これを分割することにする。
禁止IPカウントテーブル、禁止Userカウントテーブルを作り、それをメモリに載せることにした。役割分担は以下。

  • waniji: 初期データ投入スクリプト作成
  • kyokomi: メモリに載せるようにアプリ修正
  • yasuun: nginxの設定周りを修正

午後

禁止IPカウントテーブルと禁止Userカウントテーブルの初期データ投入をPerlで作成。
Perlのアプリ実装を見てみたらlocal配下にDBIx::Sunnyがいたので、perl -I でそこを指定して初期データ投入スクリプトで使った。

禁止IP、禁止Userのカウント情報をメモリに持つ修正が出来てきたので計測したらスコアが12304。
更にnginxで静的ファイルをさばく設定がきて16002。
この時にcannot assign requested addressがでたけど、ローカルポートを食いつぶしてるとはわからず……。

次に、前回今回ログイン情報を持つテーブルを作ってlogin_logを廃止するとこに。
しかし、初期データ投入スクリプトが1分を超えてしまってウンウン悩んである間に時間がなくなってあえなく中断……。

ユーザーテーブルの情報をメモリに持つようにしたが、スコアが下がったので戻し。

この辺りで時間がなくなったのでworkload数を調整して、再起動して問題ないか確認をしてたらタイムアップ。

反省点

  • レギュレーション違反

データをメモリ上にしか持っていなかったので、再起動後のreport内容が不一致となってOUTでした。問題外なので次はこういったことがないように気をつけたい。

  • login_logにインデックスを貼らなかった

スローログを見て遅いのは分かっていたのに、どうせ無くすテーブルだからとインデックスを貼らなかったのが間違いだった。他チームの方の記事を見てみると、インデックスを追加するだけでクエリのチューニングが不要になるくらい早くなるとの事だったので、これは完全に判断ミスでした。

  • ローカルポートの食いつぶしに気が付かなかった

完全に知識と経験不足でした。予選終了後にいろいろ試したところ、ポートの設定を弄らないと20000弱で頭打ちになったので、これを対処できない人は足切りされる感じだった。

まとめ

予選は惨敗だったけど、チーム全員が準備も含めて楽しんでやってたし、色々と良い経験が詰めました!
来年も開催されたら絶対リベンジしたい!