Shogo's Blog

Sep 28, 2015 - 1 minute read - Comments - perl go golang

AnySan::Provider::Slackとape-slackを書いた

先週、今のプロジェクトでのメインのコミュニケーションツールをIRCからSlack切り替えました。 それにともないIRCに済んでいたボットたちもお引越しする必要があったので、 ボットとSlackをつなぐためのライブラリを書きました。 AnySan::Provider::Slack ape-slack Perlとgoのボットが住んでいるのでそれぞれの言語で実装してあります。 AnySan::Provider::Slack PerlのAnySan用のモジュールです。 use AnySan; use AnySan::Provider::Slack; my $slack = slack token => 'YOUR SLACK API TOKEN', channels => { 'general' => {}, }; $slack->send_message('slack message', channel => 'C024BE91L'); AnySan->run; AnySanを使うだけでも便利なんですが、 今のプロジェクトではAnySanを対話形式で使いやすくするようにUnazuSanを使っています。 UnazuSanはIRC前提で書かれていて、AnySan::Provider::Slackをインストールしてもそのままは使えません。 UnazuSanを置き換えるもの面倒なので、イベントの名前を書き換えて投げ直すことで、 SlackのメッセージをIRCに見せかける方法をとっています。 またSlackのOutgoing Webhookで@つきのmentionを捕まえるにもあるように、 Slackのメンションは <@U08DGJVJ7>のような形式になってしまい、UnazuSanは自分へのメッセージとして扱ってくれません。 これをUnazuSanが解釈できる形式に置き換えるのがポイントです。 use 5.010; use warnings; use utf8; use Encode qw/encode_utf8/; use UnazuSan; use AnySan; use AnySan::Provider::Slack; my $unazu_san = UnazuSan->new( host => 'example.com', password => 'xxxxxxxxxxx', enable_ssl => 1, join_channels => [qw/arcade/], respond_all => 1, ); my $slack = slack( token => 'YOUR SLACK TOKEN', channels => {}, as_user => 1, ); AnySan->register_listener( slack => { event => 'message', cb => sub { my $receive = shift; # fake irc privmsg $receive->{event} = 'privmsg'; $receive->{message} =~ s/<\@xxxxx>:/unazusan:/; AnySan->broadcast_message($receive); }, } ); $unazu_san->on_command( help => sub { my ($receive, @args) = @_; $receive->reply('help '.

Sep 28, 2015 - 1 minute read - Comments - isucon

ISUCON5の予選に参加して惨敗してきた

こんにちは、チームぽわわ4 feat. ネコトーストラボです。 ISUCON5の予選に参加してきて見事に惨敗してきました。 お題 「ISUxi」という名前の「高負荷に耐えられるSNSコミュニティサイト」。 日記やコメントの投稿ができて、ホーム画面には「あしあと」「あなたへのコメント」「あなたの友だちの日記エントリ」「あなたの友だちのコメント」が表示されています。 日記にはprivateとpublicの公開範囲があって、これの出し分けも必要です。 やることおおい・・・。 やったこと 〜開始 時間余裕でしょと思ったら全くそんなことなかった — ひさいち (@hisaichi5518) 2015年9月25日 時間余裕でしょと思ったら全くそんなことなかった — Ichinose Shogo (@shogo82148) 2015年9月25日 5時間で決着をつける https://t.co/AbnnSyHuZ8 — Ichinose Shogo (@shogo82148) 2015年9月26日 バッテリ残量との戦いがすでに始まっている #ISUCON #アダプタ忘れた — Ichinose Shogo (@shogo82148) 2015年9月26日 〜午前中 ソースコードをgit管理下に置くとか準備したあと、ソースコードを眺めてスキーマやクエリの改善ができないかを見てました。 主にインデックスに不足は無いか、ループクエリは無いかを見てみました。 インデックスに関しては必要そうなところにはすでに貼ってあって、これ以上することなさそうな感じ。 ループクエリに関しては、ホーム画面の「あなたの友だちのコメント」の部分で、エントリ情報や、関連するユーザの情報を取ってくるところで見つけたので、JOINに書き換えられないか着手。 しかし、実行計画が大きく変わって極端に遅くなってしまい、なんだこれーってなってました。 〜14時 SQLじゃ無理だってことで、Redisに切り替え。 エントリやコメントをRedisのリストで管理して、 エントリやコメントを投稿したときに友だち全員に配信する形式に変更しました。 ある程度書けてこれで動くのでは!ってとこまで書けたんだけど、 「投稿した時に友だちに配信」形式だと、友だち関係があとから変化するケースに対応できないという気がつく。 いろいろ考えてみたものの、友だち関係が変化した場合は元の実装を使うしか思いつきませんでした。 そしてここでバッテリー切れ・・・ あと3%…(ヽ´ω`) — Ichinose Shogo (@shogo82148) 2015年9月26日 〜16時 アダプタを借りることができて延命しました。ありがとうございます! アダプター貸していただけました。ありがとうございます!m(__)m #isucon — Ichinose Shogo (@shogo82148) 2015年9月26日 コメント部分のキャッシュが一応は動いたので、エントリ部分についてもRedisを使ったキャッシュ化を進めてました。 200位スコアはあがるものの劇的な改善にはならず・・・(ヽ´ω`) 〜19時 コメントや日記部分これ以上の改善案を思いつけなかったので、諦めてあしあとの改善に着手。 DATE()関数をGROUP BY句に使っていてインデックスが使えない感じだったので、 カラムにしてインデックスが効くように書き換え。 しかし、ベンチが最後まで通らず、この修正は断念・・・。

Sep 19, 2015 - 1 minute read - Comments - perl

テストでも:ok_maopy:したい人へ

shogo82148/p5-Acme-OkMacopy use strict; use Test::More; use Acme::OkMacopy; ok_macopy "macopy is cool", "ok_macopy"; done_testing; 様子です pic.twitter.com/sA96GmqKmQ — トーカナイザの守護霊 (@mackee_w) 2015年9月17日 :ok_macopy:

Sep 19, 2015 - 1 minute read - Comments - perl go golang

Go言語でPerlのテストを早くする

Test::mysqld::Multiというモジュールを書いてみたみたいな涙ぐましい努力により5分で終わるようになったテストですが、 プロジェクトのコードも増えて人も増えた影響で、 テスト時間が約7分まで伸び、テストのキューに10個近く並んで順番待ちさせられるという状況になってしまいした。 この状況を解決すべく go-prove というものを書いてみたので、そのご紹介です。 proveが遅い理由 proveがテストの結果を読むところがブロッキングI/Oになっているらしく、そのせいで遅くなっているらしいです。 Perl-Toolchain-Gang/Test-Harness#30 実際に結果読んでいるところはこの辺ですかね。 selectとか使っていてなるべくブロッキングしないような作りにはなっていそうですが、どこかでブロッキングしてしまっているようです。 今のプロジェクトだと32コアのCPUで32並列で動かしてもCPUを100%使い切ることができませんでした。 Shunme ググるとShunmeというプロジェクトでproveの問題を解決しようという試みが行われているようです。 Shunmeというperl用のテストハーネスモジュールを書き始めました magnolia-k/p5-Shunme しかし残念ながらproveのプラグイン機構はサポートしておらず、Formatterの指定オプションもないようです。 今のプロジェクトではプラグインでMySQLを立てたり、JUnitでテスト結果をフォーマットしたりということをしているので、そのままは使えなさそう。 ちょっと改造するにはソースコードの理解が大変そうなので断念。 「(逆に遅くなるときも有ります)」というところも気になりますね・・・。 go-prove いろいろテストの実行方法を調べてはみましたが、どの方法も並行処理に苦労している模様。 テストファイル自体はただのPerlのスクリプトなので、実行して集計する部分は別にPerlにこだわる必要ないのでは? 並行処理といえば今ならGolangでしょ!ってことでproveのGo実装を書いてみました。 go-prove 例えば以下のようなテストをかいて、 use Test::More; ok "macopy"; done_testing; go-proveコマンドと実行すると、JUnit形式でテスト結果が出力されます。 $ go-prove 2015/09/19 21:45:44 start t/macopy.t 2015/09/19 21:45:44 finish t/macopy.t <testsuites> <testsuite tests="1" failures="0" time="0.225" name="t_macopy_t"> <properties></properties> <testcase classname="t_macopy_t" name="" time="0.225"></testcase> </testsuite> </testsuites> go-prove -j 32とするとgoroutineを32個生成して、32並列でテストを実行してくれます。 I/Oの処理をGolangのランタイムがよしなにやってくれるので、楽ちんです。 また、今のプロジェクトではApp::Prove::Plugin::MySQLPoolを使っているので、それ相当の機能をgo-prove -plugin mysqldで使えるようにしました。 プラグインを有効にするとMySQLサーバを立ち上げて、その接続先情報をGO_PROVE_MYSQLD環境変数に設定してくれます。 実際にプロジェクトのコードで試してみたところ7分かかっていたテストが4分を切るようになりました。 CPUの使用率も100%近くになって、有効活用できているようです。 まとめ Perl製のproveは並列実行に弱い Goで書きなおしてCPUをフル活用できるようになった 早くはなるものの、既存のテストコードに手を加える必要があってちょっと怖いかなと思ったので、プロジェクトへの組み込みはやってません。 まあ本番環境で走るものではないので、ある程度動くことが確認できたら置き換えてみたいですね。

Aug 30, 2015 - 2 minute read - Comments - perl go golang

PerlからGolangを呼び出す

GoのコードをPerlから呼び出せるようにするgo2xsを書いてみました。 使い方 Perlから使いたい関数に以下のようにgo2xsで始まるコメントを付けておきます。 package main //go2xs hello func hello(str string) string { return "Hello " + str } go2xsをgo getして、xsのグルーコードを作成。 その後通常のPerlモジュールと同じ手順でコンパイルします。 Go 1.5から入ったShared Libraryの機能を使っているのでGo 1.5が必要です。 go get https://github.com/shogo82148/go2xs/cli/go2xs go2xs -name hoge hoge.go perl Makefile.PL make あとは普通に呼び出すだけ。 perl -Mblib -Mhoge -e 'print hoge::hello("World")' Hello World 制限事項 今はまだ、整数・浮動小数点型・文字列しか扱えません。 あとGoのShared Libraryを複数回読み込むことができないっぽい? (ref. https://github.com/golang/go/issues/11100 ) ので、go2xsを使ったコードを二つ以上useすると死にます。 FFI::Rawを使う方法 go2xsはGoをShared Libraryとしてコンパイルしているだけなので、go2xsを使わなくても頑張れば呼び出すことができます。 Golang で Shared Library を出力する。で紹介されているこちらのコードで試してみます。 package main import ( "C" "log" ) //export fib func fib(n int) int { if (n < 2) { return n } return fib(n - 2) + fib(n - 1) } func init() { log.

Aug 23, 2015 - 1 minute read - Comments - perl

YAPC::Asia2015へ行ってきた

YAPC::Asia2015へ行ってきましました。 Blogを書くまでがYAPCらしいので、簡単に 今年の会場は東京ビッグサイトです。 ▼▼みたいになってるところの中にはじめて潜入してきました。 あの中って会議室なんですね。 去年は毎回立ち見ですごく大変だったけど、今年はかなり会場が広くなったおかけで、 大体席を確保できて楽にトークを聴けました。 しかし会場が東京ビッグサイトであっても、人気トークは立ち見になってしまうのがYAPCのすごいところ・・・。 それでも、前の人の頭でスライドが全く見えないみたいなことはなかったので、広い会場は便利です。 以下、今年見たトークです。 言語開発の現場 はてなブックマークのトピックページの裏側 技術ブログを書くことについて語るときに僕の語ること タイトルが9割 世界展開する大規模ウェブサービスのデプロイを支える技術 全サーバで一斉にgit pullするつらい話だった と、思ったら途中からstretcherの話になった HTTP/2時代のウェブサイト設計 CSSスプライトみたいなファイルを一つにまとめてリクエストを減らす技術はHTTP/2ではオワコンになる 何よりもデータ量を減らすことが大事 【sponsored contents】若手エンジニア達の生存戦略 Google Cloud Platformの謎テクノロジーを掘り下げる 朝寝坊して途中からの参加でした(=_=) Googleのコンテナ技術BorgやGoogleのネットワークについての話 我々はどのように冗長化を失敗したのか MySQLで2億件のシリアルデータと格闘したチューニングの話 データ分析基盤を支える技術 いろいろなツールの比較についてのお話でした なんか色々なオープンソースのソフトウェアを紹介していたけど、「自分で構築しようとするな」とのこと D言語みんな使ってね Parallelism, Concurrency, and Asynchrony in Perl 6 Perl6では並列・並行・非同期処理が簡単に書けるらしいので、その紹介 Promiseやawaitみたいな他の言語で取り入れられている概念がPerlでも使えるらしい 来年Perl6でドローンが飛んでいるのを期待してます Profiling & Optimizing in Go Goのプロファイリングと最適化のデモでした sync.Pool 存在は知っていたけど実際に使っているコード始めて見た気がする。bytes.Bufferの作成に使っていたんだけど、メモリアロケート程度なら同期コストの方が高いのでは〜って思っていた。 改めて見返してみるとPerlについての話がPerl6の並列・並行・非同期処理くらいしかないきがする。 (YAPCのPとは一体) 最後に、呪いを掛けられたのでMySQL5.7の罠についてリンクを貼っておきますね。 http://yoku0825.blogspot.jp/2015/08/yapcasia-mysql-57lt.html Passwordの有効期限のデフォルトがいつの間にか360日になるのは話題になってたのを知っていたけど、他にも罠満載でした。

Jun 21, 2015 - 1 minute read - Comments - go golang

go-webtailってのを書いた

Rubyで書かれたwebtailのGo移植を書いてみました。 go-webtail オリジナルのwebtailはRubyなので、Rubyistではない僕が使おうとするとまずRubyの実行環境からそろえないといけなくてつらい。 ワンバイナリでダウンロードするだけで使えるやつが欲しいなあと常々思っていたのでGolangです。 htmlやjavasctiptの部分もバイナリに含まれているので、インストールも簡単です。 引数無しで実行すると8080ポートで待ち受けて、標準入力から読み込んだ結果をWebsocketで読めるようにしてくれます。 go get github.com/shogo82148/go-webtail/cmd/webtail # インストール echo hogehoge | webtail ファイルもtailできます。 webtail hoge.log fuga.log それぞれ、http://localhost:8080/hoge.logとhttp://localhost:8080/fuga.logで見れるようになります。 mirageと一緒につかう mirageは待ち受けポートを複数設定できます。 (SEE ALSO Dockerで非エンジニアでも開発環境を上げ下げできる、mirageというツールを作りました) その一つをwebtailに割り当てて以下のようにDockerfileに書いておけば、非(サーバサイド)エンジニアでも開発環境のログが見れるようになります。 (見れても理解できるのか?って疑問もあるけど、まあ、全く見れないよりは・・・) ADD webtail / CMD ./docker_run.sh 2>&1 | /webtail --prefix webtail # ブラウザで見れる代わりにdocker logsで見れなくなるのでこっちのほうがいいかも CMD ./docker_run.sh 2>&1 | tee hoge.log | /webtail --prefix webtail 残念ながらwebsocket対応はしていないので、websoket対応にしたmirageが必要です。 httputil.NewSingleHostReverseProxy互換のrproxyってのを使ったら簡単にwebsocket対応ができて素晴らしいですね。 (mirage自身に手を加える必要があるなら、mirageにこういう機能をつけるべきだったのでは説はある)

Jun 20, 2015 - 1 minute read - Comments - perl

Test::mysqld::Multiというモジュールを書いてみた

Test::mysqldのインスタンスを一度に大量に作りたい人向けに Test::mysqld::Multiというモジュールを書いてみました。 2016/12/22追記: Test::mysqld::MultiはTest::mysqld 0.20 の一部として取り込まれました (p5-Test::mysqld#13)。 APIは少し変わっているので、詳しくはPODを参照してください。 合わせてApp::Prove::Plugin::MySQLPool 0.06 より、 本記事で紹介した高速化が利用できます。 背景 先日Jenkins EC2 Plugin で Spot Instance を使ってテストを回すというのを、 tkuchikiさんにお願いして僕の関わっているプロジェクトでやっていただきました。 CPUのたくさん載ったインスタンスを安く使えるようになったので、 8並列で動いてたテストを24並列で動かせるようになりました。やった3倍速だ!!! 9分程かかってたテストが7分で終わるようになりました!!! あれ・・・思ったほど早くなってない・・・。 ログを眺めているとproveコマンドが立ち上がってから、実際にテストが走り始めるまで数分の時間がありました。 App::Prove::Plugin::MySQLPoolを使っているのですが、 ここで時間がかかっているようです。 App::Prove::Plugin::MySQLPoolはテストの並列度分だけMySQLのインスタンスを立ち上げますが、 一個インスタンスを立ち上げたら、それにアクセスできるようになるまでずっと待っているようです。 MySQLの起動に5秒かかるとして24並列で動かしたら2分かかるわけで無視できない長さになります。 作ったもの n個一度に立ち上げて全部にアクセスできるまで待つ実装にすれば速くなるのでは!ってことでTest::mysqld::Multiというのを書いて、 App::Prove::Plugin::MySQLPoolからそれを使うようにしました。 とりあえずtest-mysql-multiブランチにコミットしてあります。 App::Prove::Plugin::MySQLPoolに取り込んでもらうか別のモジュールとして分離するか、後々のことは未定。 今のプロジェクトで使ってみてちょっとの間様子見してみます。 7分かかってたテストが5分程度で終わるようになったので、効果はあるようです。 ちなみに、並列度が24と半端なのはそれ以上並列度を上げても速くならなかったため。 32コアあるマシンなんだけど使い切れてません。 どこにボトルネックがあるんだろうな・・・。 まとめ プロセス一覧にmysqldが24個並ぶの楽しい

Jun 2, 2015 - 1 minute read - Comments - mecab python python3

MeCabをPython3から使う(中間報告)

先日このようなツイートを見かけて、 「Python3になってGCの挙動変わったのかな?」と疑問に思ったので調査してみました。 MeCabをPythonから使う注意点とか - Shogo's Blog http://t.co/vJnOqZfUd7 @shogo82148さんから python3だと変数に代入しなくても動くのだけど2.xでは留意しないといけない — NOKUBI Takatsugu野首貴嗣 (@knok) 2015年6月1日 Python3へのMeCabインストール 手元のPython3.4.3にMeCab Bindingをインストールします。 MeCabの公式(Google Codeサービス停止にともないgithub pageへ移行している模様)から落とせる Python BindingはPython2.x向けのため、setup.pyがそのままでは動きません。 Python3.xでは非互換な文法の変更が入ったので以下のように書き換える必要があります。 diff --git a/setup.py.org b/setup.py index 4486cbb..657945a 100644 --- a/setup.py.org +++ b/setup.py @@ -7,7 +7,7 @@ def cmd1(str): return os.popen(str).readlines()[0][:-1] def cmd2(str): - return string.split (cmd1(str)) + return cmd1(str).split() setup(name = "mecab-python", version = cmd1("mecab-config --version"), あとは python setup.py install で入ります。 動かしてみる 以前書いた「MeCabをPythonから使う注意点とか」を見返しながら、 GCされて上手く動かない例 をPython3.4.3で動かしてみます。 文字列の扱いが変わったり、print文の扱いが変わったりしているので、その部分だけ書き換えが必要です。 import MeCab tagger = MeCab.

May 21, 2015 - 1 minute read - Comments - git

各ブランチの最後にコミットした人を知る

ブランチが大量にあるので整理したい、けど大人数で開発しているから誰がどのブランチいじってるか分からない、 ということがあったので、出し方のメモ。 githubのbranch一覧も見ればいいじゃん!っていう意見もあると思うんだけど、 「自分のbranch一覧」は見れるんですが「特定のだれかのbranch一覧」が見れない・・・。 git-for-each-refを使うと各ブランチに対していろいろ操作できるようです。 各ブランチの最後にコミットした人一覧を出すには以下のコマンド。 git for-each-ref --format='%(authordate:short) %(authorname) %(refname)' --sort=-committerdate refs/remotes/origin/ formatは自由にいじれるのでいろいろ遊べます。 例えば、ブランチをたくさん抱え込んでいる人の一覧を表示する例。 git for-each-ref --format="%(authorname)" refs/remotes/origin/ | sort | uniq -c | sort -nr 参考 git-for-each-ref - Output information on each ref リモートブランチも含め更新日時が新しい順番にソートする ブランチ一覧を更新時刻つきで表示したい場合、gitのfor-each-refが使える。