Shogo's Blog

Oct 16, 2014 - 1 minute read - perl redis

Redis::Fast 0.13をリリースしました

Redis::Fast 0.13をリリースしました。 主な変更点は以下のとおりです。 passwordオプションの対応 maxclientsに達した場合に、deep recursion することがある問題の修正 トランザクション内で再接続処理が行われる問題の修正 passwordオプションの対応 今更感のある機能ですね。昔は対応してたんです。 対応してたんですが、Sentinel対応のために接続開始周りをごそっと入れ替えて、そのときに間違ってパスワード認証機能を削除しちゃってたっぽいです(・ω<) なんというかごめんなさい。 実際実装してテストしてみると、認証失敗したときにdouble freeで落ちてちょっとハマりました。 hiredisを使う場合はredisAsyncSetConnectCallbackに指定する関数内で、コネクションを切断するような処理(password認証とか)はしないようにしましょう。 maxclientsに達した場合に、deep recursion することがある問題の修正 Redis::Fastでは、接続処理の中で、コネクションに名前をつけたり、パスワード認証したり、その他独自の処理を実行しています。 この処理の途中でも再接続処理が走ってしまい、 再接続処理の中で再接続処理が実行されて、その再接続処理の中で再接続が… というような無限ループに突入する場合があります。 maxclientsに達した場合、一度コネクションの確立に成功したあとに接続が切られるので、この無限ループに入ってしまうようです。 接続処理中は再接続処理を行わないようにすることで対応しました。 トランザクション内で再接続処理が行われる問題の修正 Redis::Fast 0.07以降、MULTI-EXECコマンドを遣ったトランザクションの中にいるときは再接続処理が行わないようになっています。 その仕組みを作るにあたって、トランザクションの中にいるか外にいるかを表すフラグをコマンド送信前に更新していました。 再接続を禁止する MULTI コマンドを送る 結果を受け取る 必要なコマンド発行を行う 再接続を許可する EXECコマンドを実行する 結果を受け取る しかしこれだと 5 と 6 の間で再接続が起こってしまいます。 EXECコマンドがまだ実行されていないので、ここはまだトランザクションの中ですね。 Redis::Fast 0.13ではフラグの更新はコマンドが成功したときに変更してあります。 MULTIコマンドを送る 結果を受け取る 再接続を禁止する 必要なコマンド発行を行う EXECコマンドを実行する 結果を受け取る 再接続を許可する これでトランザクション中に再接続処理が走ることは無いはずです。

Oct 4, 2014 - 2 minute read - git

gitで作業ディレクトリの変更を破棄したのに差分が出続けて困った話

gitで変更した覚えの無いファイルに差分が出ていたので、 作業ディレクトリの変更を破棄したのに、 git statusで差分が出続けて困ったのでメモ。 症状 gitではgit checkout -- <file> ってコマンドを叩くと、 作業ディレクトリの変更を破棄できます。 $ git checkout -- hoge.txt $ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: hoge.txt しかし、差分が出続ける… git checkout -- <file> ならさっきやったよ! git reset --hard HEAD して全変更を破棄してもダメでした。 原因 .gitattributesに改行コードの指定があったからでした。 *.txt text=auto eol=crlf これが指定されていると、CRLFなファイルをコミットしようとしても、 レポジトリには改行コードがLFで保存されるようになる。 $ cat .

Oct 3, 2014 - 1 minute read - isucon

ISUCON4にチームぽわわで参加しました

遅くなりましたが、ISUCON4のレポートです。 まこぴーとchroneさんとともにチームぽわわで参加し、惨敗してきました。 2014-10-06 追記: 競技中に使ったレポジトリを公開しました。 事前準備 メンバー三人で集まって、去年のnopasteアプリで練習 chroneさんは初参戦なので雰囲気を掴んでもらう Ansibleを使っていこうっていう話になったので、プレイブックを書いて遊んでみる githubにprivate repositoryを予め建てる PayPalに対応してるっぽいので、ログインを試みるも何故か失敗 諦めてクレカ情報を直接入力 どうなってるんですかgithubさん!!! 競技 10時くらいまで お題確認 サーバのセットアップはchroneさんにお願いしスムーズにできた サーバは人数分準備 僕がコミット&実行確認をこまめに繰り返すタイプなので、書いたコードはすぐにデプロイしてテストに回したい!! サーバ一台だとインフラの調整とアプリの確認がかぶって面倒 かといってローカルで同じ環境用意するのも面倒 AMIがあるならそれを使っちゃえ!(って記事を去年見た気がしたので) 密かにUkigumoで自動デプロイする仕組みを作っておいた 書いたコードはすぐにデプロイしてテストに回したい!! あらかじめukigumo-agentを起動 github-hookを設定してコミットしたら実行 Github::Hooks::Receiverいじってたのはこれやるためだったんだけど、Ukigumoさんで十分でした。便利ですね!! 去年はサーバに入って作業する人(まこぴー)がかなり忙しそうだったので、なんとか解消したかった お昼くらいまで nginxで静的ファイル配信とかMySQLのクエリ分析とか いっちーさんは早速Redis::Fastに手を付ける みんなもRedis::Fast使ってね!! あとUkigumoさんのおもり UkigumoとAnsibleのお陰で僕が何もしなくても、まこぴー氏が「nginxで静的ファイル配信したよ!」って言って数分後には確認できる状態になっていて便利 これのおかげでページが真っ白になっているのに気がつく 普通に設定を書き換えるとMIMEの設定がなくなるらしい Ukigumo++ 14時くらいまで chroneさんにMySQLのクエリ改善 COUNT() している部分を一行SELECTだけにする修正とか 一部Redis::Fastに書き換えた版も一応スコアでる アプリが単純すぎてMySQLでもRedisでも大差ないスコア 自分の環境でmy.cnfの調整をしたら、MySQL gone awayしてしまってつらいことに Redisに書き換えたものの、reportのロジックには手をつけてなかったので、効果あるのではと MySQLだけ再起動したらそうなるらしいけど、ansibleのplaybookにアプリの再起動手順も含まれていたので全部再起動かかってたと思うんだけど・・・ 結局サーバごと再起動しました(・ω<) 17時くらいまで workloadを上げるとfailが大量にでて/reportのチェックでコケる問題 トランザクションとかFOR UPDATEの問題かと思ってSQLをいじくりまわす 初期データの考慮を忘れてたことに気が付き、初期化スクリプトを組む 18時まで workload変えてベンチ走らせたり最後のあがき まとめ 初期化大事!! 社内ISUCONに参加したときも初期化で散々な目にあった Ansibleがあまり効果的に使えてなかった configいじるのが速いので、どうしても直接いじっちゃう 各個人にサーバ用意したけど、微妙に環境が違ってつらい

Sep 23, 2014 - 1 minute read - perl

Github::Hooks::ReceiverがX-Hub-Signatureをサポートしました

Github::Hooks::ReceiverにX-Hub-SignatureをサポートするPull Requestを送ったら、 速攻取り込まれ、さらにGithubのコミット権とPAUSEのco-maintパーミッションをもらったというお話。 X-Hub-Signature GithubのWebhookは大変便利なんですが、特に対策をしないままだと 他の人にcurlとかで叩かれてしまう可能性があります。 本来であればIPアドレスで制限をかけるべきなんですが、 iptablesの設定とかよくわからないし・・・と思ってGithubのドキュメントを読んでいたら、 もっとお手軽な方法発見。 Securing your webhooks GithubからのリクエストにはX-Hub-Signatureというのがついていて、 これを使うとPayloadの検証ができるらしい。 Github::Hooks::Receiverは このヘッダを全くみていないようだったのでPull Requestを送ってみた。 Github::Hooks::Receiver 0.02以降で、以下のようにsecretの指定ができるようになります。 use Github::Hooks::Receiver::Declare; my $receiver = receiver { secret 'secret1234'; # Webhookの設定画面のsecretの項目と同じものを入力 on push => sub { # レポジトリにPushされた時の処理とかをゴニョゴニョ書く }; }; my $psgi = $receiver->to_app; $receiver->run; これでsecretを知らない人がリクエストを偽装できなくなるので安心です。 secretはエントロピーが高いほうがいいので ruby -rsecurerandom -e 'puts SecureRandom.hex(20)' みたいなコマンド使うといいらしいですよ。 String::Compare::ConstantTime Signatureの比較にはRubyのsecure_compareのような関数を 使ったほうがいいらしい。 Github::Hooks::Receiverでは、そのPerl版のString::Compare::ConstantTimeを使ってみた。 ちょっと引数のチェックに甘いところがあって、segmentation fault場合があったので、こちらにもPull Requestを送っておきました。 Github::Hooks::Receiverは使う前にチェックを入れてあるので、現行バージョンでも問題なく動くはず。 String::Compare::ConstantTimeはXSで書かれたモジュールなんですが、 この手のバグが入り込みやすいのでXS難しいですね。 まとめ XS怖い Github::Hooks::Receiverにsecretを指定できるようになったので、IP制限がかけられない場合でも安心 でも、可能であればIP制限もしましょうね XS怖い 追記 IP制限について Songmu先生よりコメントをいただきました。

Sep 13, 2014 - 1 minute read - git

Githubさんにpack exceeds maximum allowed sizeって言われた

Githubに手元のレポジトリをpushしようとしたら、 「Pushできないよ!!」って言われたときのメモ。 コミット数が17kほどあって、画像とかサイズが比較的大きいファイルがたくさんあるレポジトリを、 一度に全部pushしようとしたら「制限を超えてます」って言われてダメだった。 $ git push origin master Counting objects: 280874, done. Delta compression using up to 4 threads. Compressing objects: 100% (60497/60497), done. remote: fatal: pack exceeds maximum allowed size error: pack-objects died of signal 13 error: failed to push some refs to 'git@github.com:***/****.git' ググってみると、おんなじような症状が見つかった。 Github remote push pack size exceeded リモートへのPushはオブジェクトを全部一つにPackしてしまうので、 一度に大量のコミットをPushしようとすると制限に引っかかるらしい。 (そして、サイズを制限する方法はないみたい) 解決策は「2回以上に分けてPushしてね」とのこと git push remoteB <some previous commit on master>:master ... git push remoteB <some previous commit after the last one>:master git push remoteB master 頑張ってコミットログを遡ってコミットハッシュを調べるのはつらかったので、 打ってあったタグからコミットハッシュを調べてPushした。

Sep 3, 2014 - 1 minute read -

秘密鍵から公開鍵をつくる

githubに公開鍵を登録しようと思ったけど、 手元に秘密鍵しかなくて困った時のメモ。 ssh-keygenを使うとできます。 # 秘密鍵を読み込んで公開鍵を出力する ssh-keygen -y -f ~/.ssh/id_rsa この公開鍵って登録したっけ? ってときには以下のコマンドでフィンガープリントを確認できます。 # 公開鍵のフィンガープリントを取得する ssh-keygen -l -f ~/.ssh/id_rsa.pub

Aug 31, 2014 - 1 minute read - perl

YAPC::Asia 2014 に行ってきた #yapcasia

YAPC::Asia 2014 に参加してきました。 「ブログに書くまでがYAPC」らしいので、メモ書き。 見たトーク Perl meets Real World 〜ハードウェアと恋に落ちるPerlの使い方〜 デモ中のURLが「localhost」になってたんであれ?って思ったんですが、WebサーバはPC上にあったんですね。RaspberryPi上でPerl動くんじゃなかったんですか! ネギ振りミククラウド化するって言ってたんで期待してます Go For Perl Mongers お待たせしました。Perl で BDD を簡単に実践する最高にクールなフレームワークができました DBIx::Class - what is it and what is it good for? HashRefInflatorの存在を初めて知りました 今関わってるプロジェクトでDBICのRowObject生成コストが問題になってるんで、後で試してみたいです Scala In Perl Company : Hatena WHERE狙いのキー、ORDER BY狙いのキー Get a kick out of CPAN 初心者が Web エンジニアのコミュニティに触れてみて感じたこと - ゆとりエンジニアの成長戦略 突然ITインフラを任された人のための…監視設計入門 半端なPHPDisでPHPerに陰で笑われないためのPerl Monger向け最新PHP事情(5.6対応) MacにはPHPが最初から入ってるらしいですよ モバイルアプリとAPIのありかたを考える2014 Mobile Application Development for Perl Mongers [ninjinkun x gfx] シングルトンは嫌だシングルトンは嫌だ そんなにビッグでもないデータ処理手法の話 一日分の解析ならなんとか一台で、でも一ヶ月分となると・・・ってことが多いんでもうちょっと調査して、どれかに手を出してみようかな・・・ typester先生のキーノート

Jul 5, 2014 - 1 minute read - perl

PerlのXS中に起きたシグナルの扱い

Redis::Fast にIssueが来ていたので、 それに関して調査したお話です。 接続タイムアウトすると double free check に引っかかる brpop みたいな長時間ブロックするコマンド中にシグナルが入ると、最初の1回が無視される 前者はC言語つらいって話で頑張って double free になる条件を探せばいいんですが、 後者はシグナル時のPerlやPOSIX APIの挙動を知らなくと解決できなそう。 そういうわけで、主に後者について調べた結果をまとめておきます。 PERL_ASYNC_CHECKってXS中から呼んでもいいの? 言いたいことは最初に書いとけって偉い人に言われたので、最初にこの記事の結論を。 「よしななタイミングでPERL_ASYNC_CHECKを呼べばいいっぽい」みたいです。 でも、 ** 「PERL_ASYNC_CHECKってXS中から呼んでもいいの?」 ** という点に確証が持ててないので、 識者のご意見を募集してます! selectの挙動を調べる Redis::FastはRedisからのレスポンスを待つのにLinuxのselect apiを叩いてます。 ファイルとかが読み書き可能になるまで処理をブロックしてくれるいいやつです。 しかし、select が処理をブロックしている間にシグナルを受信すると、うまく処理ができてないらしい。 そこで割り込み発生時の挙動を確認してみます。 困った時のmanページ(select) をちゃんと読めば書いてありますね。 エラーならば -1 を返し、 errno にエラーを示す値が設定される; EINTR シグナルを受信した。 Redis::Fastはerrnoを特に確認せず、とにかくエラーが発生したらリトライになってたのでダメだったみたいです。 通信にエラーが起きたわけではないので、再接続処理とかみたいな複雑なリトライ処理は必要なく、 単にもう一度selectしなおせば良さそうです。 Perlさんのシグナル処理のタイミング 「割り込みかかったら再度select」っていうふうに修正してみたんですが、 今度はPerlのシグナルハンドラがなかなか呼び出されない!! use Redis::Fast; $SIG{TERM}= sub { warn "TERM handler called"; }; my $c =->new(reconnect=>2, every => 100, server => "localhost:6379"); $c->brpop("a", 100); # 100秒経ったら諦めて戻ってくる このコードを実行中にSIGTERMを送ると、送った瞬間に"TERM handler called"と表示されて欲しいのですが、 brpopコマンドが終わるまで実行されない……

Jun 4, 2014 - 1 minute read - perl unazusan

IRCに癒やしボットを入れてみた

別チームがIRCに癒やしボットを入れてたので、自分のチームのチャンネルにも入れてみた。 Instagramに登録する InstagramのDeveloperサイトに開発者として登録します。 Authentication のページを見ながら、Server-side (Explicit) Flow を参考にアクセストークンを取得します。 Instagram APIを叩く https://api.instagram.com/v1/tags/$TAGNAME/media/recent?access_token=YOUR_ACCESS_TOKENを叩くと TAGNAMEに関連する画像の情報がJSONで帰ってくるので、 Perlからこのエンドポイントを叩きます。 IRCとのやりとりにはUnazuSanを使いました。 !/usr/bin/env perl use 5.014; use warnings; use strict; use utf8; use Encode qw/encode_utf8/; use Furl; use JSON; use UnazuSan; sub neko { state $data = undef; state $time = 0; if( !$data || time - $time > 60 * 60) { $time = time; my $furl = Furl->new; my $res = $furl->get('https://api.instagram.com/v1/tags/%E7%8C%AB/media/recent?access_token=YOUR_ACCESS_TOKEN'); my $hash = JSON::decode_json($res->content); $data = $hash->{data}; } my $media = $data->[rand(scalar @$data)]; return $media->{images}{standard_resolution}{url}; } my $unazu_san; my $NICKNAME = 'iyashi'; $unazu_san = UnazuSan->new( host => '127.

Jun 1, 2014 - 1 minute read - javascript

キレイになったコトバとハートを元に戻すツール作った

現実世界にご満足の方消えてなくなってほしいの!!! しずかったーを使うと個性あふれるコトバを使ってもキレイにしてくれるので とっても便利ですね! でも、本当は何を言っているのか真意を知りたい・・・。 そんな人のために、キレイになったコトバとハートを元に戻す アンチしずかったー を作りました。 仕組み しずかったーは単純な文字列置換で動いているみたいなので、 対応表を頑張って作りました。 それをMeCab用の辞書に変換し、 Igoを使ってバイナリ辞書に変換、 igo-javascriptでブラ失礼しちゃう上で解析できるようにしました。 既知の問題点 しずかったー前後の文脈関係なく変換しちゃうので、 同音異義語は元に戻らないことがあります。 特にひらがな・カタカナは失敗することが多いです。(「(お昼寝したい)ふわふわ」だとか「ブラ失礼しちゃう」だとか) あと、マシュマロ的な内緒の言葉はさすがのしずかちゃんでも代替表現が思いつかなかったらしく、 全部ハートになってしまいます。 元に戻せと言う方が頑張ればなんとかできそうなので期待しないでく時代が変わればかっこいい。 まとめ またおもしろいものを作ってしまいましたが、 igo-javascriptのバグを発見できたりしたので、いいのです。 自宅警備員でお時間ある方の皆様、天才だと思ったらぜひおしゃべり広場や「いいね!」広場で共有をお願いします。