卜部昌平のあまりreblogしないtumblr RSS

Archive

Jun
2nd
Sun
permalink
Visualizing git blame

Git には git blame というコマンドがあり(他のツールでも同様の機能は提供されている)、これを使うことでソースコードのどこを書いたのが誰か、という情報がline-by-lineで取得できる。この情報は行単位なので一次元の情報だけれど、適切な空間充填曲線に乗せることで二次元にマッピングできて、それに適当に作者ごとに色をつけるということをやってみると色々楽しい。そのスクリプトはひじょうにstraight-forwardな記述だとこういった感じになる。上の絵はruby 1.8.7に対する実行結果で、ChangeLogとかのあきらかに面白くないファイルは除外してあるからまあ、そのままの結果ではないけれど、これを見ると色々な思いが去来する。

Ruby 1.8.7 は多数の開発者が手を入れており、少数の支配的な貢献者といったような存在をみいだすことができない
しかしながら、全体がのっぺりと灰色になっているわけではなく、局所的に色がぜんぜん違う。これは、開発者ごとに専門性があり、すべてのファイルに手を入れている人がいないことを示している。

Visualizing git blame

Git には git blame というコマンドがあり(他のツールでも同様の機能は提供されている)、これを使うことでソースコードのどこを書いたのが誰か、という情報がline-by-lineで取得できる。この情報は行単位なので一次元の情報だけれど、適切な空間充填曲線に乗せることで二次元にマッピングできて、それに適当に作者ごとに色をつけるということをやってみると色々楽しい。そのスクリプトはひじょうにstraight-forwardな記述だとこういった感じになる。上の絵はruby 1.8.7に対する実行結果で、ChangeLogとかのあきらかに面白くないファイルは除外してあるからまあ、そのままの結果ではないけれど、これを見ると色々な思いが去来する。

  • Ruby 1.8.7 は多数の開発者が手を入れており、少数の支配的な貢献者といったような存在をみいだすことができない
  • しかしながら、全体がのっぺりと灰色になっているわけではなく、局所的に色がぜんぜん違う。これは、開発者ごとに専門性があり、すべてのファイルに手を入れている人がいないことを示している。
May
30th
Thu
permalink

#rubykaigi バイヤーズガイド ‘13

あえてアマゾンのリンクは貼らないので会場で会おう

たのしいRuby 第四版

  • これを買うべき人: 全員
  • ひとこと: ついにRuby 2.0の時代が本格的に始まったことを宣言する決定打的一冊であり、必携。今後「情報がないから2.0は不安」などとうそぶくことはこれで不可能になった。

テストから見えてくるグーグルのソフトウエア開発

  • これを買うべき人: テストを日常的に書いている人と、テストを書く習慣がない人
  • ひとこと: これはずばり俺が読みたいので買います。こちらからは以上です。

白と黒のとびら

  • これを買うべき人: 「記号と再帰」がおもしろかった人
  • ひとこと: まあなんていうんですかね、形式言語とか好きな人って結局そっちに道を踏み外しちゃうきっかけってテングワールだったりするわけじゃないですか。だからこういうふうに攻めてくるのって変化球のようでいて実はど真ん中だと思うんですよね。

型システム入門

  • これを買うべき人: RHGがおもしろかった人
  • ひとこと: 久々に本気手加減なしの全力投球本が来たってところ。これに「入門」とつけるセンスはさておき、内容はといえば大学院レベルなので流し読みではなかなか辛い。そういうのが好きな人にはたまらない。ええ。1章だけですでに価格分の価値はあります。

講座ITと日本語研究4 Rubyによるテキストデータ処理

  • これを買うべき人: 俺とうささん
  • ひとこと: 数ヶ月か1年くらい前にIRCで話題にしてた本! なぜ入荷している… これはRubyプログラムとして読むべきものは書いてなくて、日本語研究が好きかどうかでしかない。なので好きな人だけ買えばいいです。

プログラマの考え方がおもしろいほど身につく本

  • これを買うべき人: じつはプログラマこそ読むべき
  • ひとこと: 俺が知ってる中でこれにもっとも近いのは「エレガントな問題解決」あと「いかにして問題をとくか」。ようするにプログラマの考え方とは、そういうことだと分かる。そして意外に実践されていないので、ぜひ身につけるべき。

インフォメーション

これについては山形浩生の書評があるので自分が何か付け加える必要性はあまり感じない。

進化するアカデミア

  • これを買うべき人: 表紙に騙された人
  • ひとこと: 進化と呼ぶべきかは分らないが、敷居は確実に低くなってきてるよね。研究で食べようとさえ思わなければいいだけで、すごい時代になったもんです。

その他

まだまだたくさん入荷してるっぽいけど時間がないのでこのへんで。多分、たとえばオライリーのとかはガイド以前の問題として全員全種もれなく購入されることと思いますので、そういうのはまあ、言うまでもないかと思います。けど誰の趣味が反映されてるのか知らんがRubyKaigiでは案外人文系が売ってる(何年か前にダールグレン置いてたのはびびった)ので、そういうのもちょっと読んでみるとよいですよー

May
15th
Wed
permalink
People blame me for merging others people changes to fast. But this merge button looks just to tasty. It’s kind of a sin to not use it.

https://www.facebook.com/bovensiepen/posts/10200155061579359

「マージ早すぎっていうけどさー、このマージボタンが燦然と輝いてるんだよ。押さないなんてある種の罪」

May
6th
Mon
permalink

nonnon21:

CiNii 論文 -  Tumblrにおける情報の伝播経路に着目した記事の特徴付け

effective-tumblr:

少し前に論文「マイクロブログの文脈付き投稿情報の体系化に基づく重要ユーザ推薦と情報集約支援への応用」を紹介しましたが、これの参照している先行研究である表記論文を、共著者のkiyoyaこと山口清弘さんから送っていただきました。論文は次のような背景認識から始まっています。

オンラインコマースにおけるコア技術となっている,アイテムのクラスタリングや推薦においては,アイテムをどう特徴付けるかが,その結果を大きく左右する.ここで,記事の特徴付けとは,記事を何らかの視点で数理的に表現すること,および,それに基づいて記事同士の類似度を算出することから可能であると考える.

統計学を知らない僕なりに読み進み、砕いてみます。最近はニュースサイトでもオンラインショップ(eコマースサイト)でも「お勧め」をされることが増えてきました。これは、よく似た記事、よく似た商品をグループ化しておいて、そのグループ内の一つがピックアップされたら、別の一つを推薦してみる、ということをしています。でも「よく似た」と簡単に書きましたが、ある記事と別の記事、ある商品と別の商品が「似ている」というのは、どういう意味で、どうやって決めるんでしょう?

一般に推薦システムにおけるアイテムの特徴付けには,誰がどのアイテムを評価したかという共起関係用いられる傾向にある.Tumblr のような,記事が人の間を伝播していくネットワークにおいては,共起関係のみを考慮するよりも,記事の伝播経路を用いた記事の特徴付けの方がより有用であると考えられる.

一般的に広く使われているのは、「この商品を買っている人はこんな商品も買っています」という情報を活かした判断です。AとBとCはよく同じ商品を買っている。つまり彼らは好みが似ているということだ。そして彼らの好みにあった商品が二つあるなら、それの二つは似ているということだ。こういう判断が下せれば、二つのうち一方を買った人には、もう一方も勧めると買ってくれそうだ、と考えられることになります。

こうした「誰と誰と誰が」という関係、共起関係で似ている度合いを図ることもできますが、Tumblrではさらに「誰がいつ誰からリブログしたか」という時系列や伝播経路を考えることもできます。則のぞみ氏、山口清弘氏らはこれらを考慮したほうが、より妥当な(精度のよい)にている度合いを測れるだろうという仮設を立て、実際に実験して確かめています。

ここから実験方法と実験結果になると、数式と数値が乱れ飛ぶ、私にはなんとなく程度には分かっても正確なところはギブアップの世界に入るので割愛。いきなり考察のうち、特に面白かった、木構造、順序指標を考慮した結果を。

カット率6割から,順序指標が共起指標に比べて有意に高い再現率となった.これは,共起指標では,カット率の増加に応じて再現率も下がっていくが,順序指標では,カット率6 割から8 割の間で再現率がほぼ変化しないことによる.この理由として,Tumblr においては,ある記事を誰が最初の方でリブログしたのかという,最初の方の順序が,後の伝播を決定付ける重要な要因になっていることが考えられる.Tumblr においては,特に伝播の初期における順序を考慮することが有用であると言える.

言い換えれば、「誰と誰と誰が」という共起関係に基づいたアプローチでは、興味を示す層のうち実際にリーチできた層が減るほど、残りの人たちを推測する精度が悪くなります。ところが「誰と誰と誰がそれぞれいつごろ」という順序を指標に入れると、5割を切ったあたりと2割まで減ったあたりで同等の推測制度が出ています。

もっと言えば、共起関係だけで考えていた頃であれば5割、多分アーリーマジョリティまでを観察してはじめて浮かんできた潜在顧客層が、木構造における順序にも注目することで2割、多分アーリーアダプタぐらいを観察すれば浮かんでくるということです…だと思います。もちろん「マイクロブログの…」もこの論文も、Tumblrのような「リシェアの経路と時刻が可視化された」世界だからこそ役立つ、ある種のニッチな世界向けのアプローチといえるでしょう。でもニッチだったそのリシェア・ワールドが、いまやTwitterやFacebook、そしてGoogle+へと領地を拡大しています。

おそらく「バイラルでは経路が重要」という考え方は新しくないでしょう。ですが購買層という古典的な視点でも、つい先日、4,500台の自販機から集めた2億件のビッグデータをもとにすることで新製品が生まれたことが報じられました。現在(※’12/01/27)165億件強のTumblrの投稿合計数から経路情報を調べ上げると、そこにはまた新しく見えてくるものがありそうです。そしてオンラインコマースにおけるリコメンドを背景に上げたこの論文は、やっぱりそこを睨んでいるんだろうな、と思います。

それが来た時に、その手法に先鞭をつけ、かつデータを総なめするのではなくある程度小規模なサブセットで代替したときの精度に言及したこの論文は、結構面白いポジションにあったりしないかな、と思いました。

Apr
30th
Tue
permalink

#naruhounix について

どうなんですかねえ。まあぶっちゃけ、この本にツッコミを入れることが容易な種族はいる。たとえば「プロセスがfork(2)するときにPOSIX semaphoreをsem_wait(3)してたらそのセマフォはどうなってまうの?」とかそういうの(実際書いてない)ね。けど、それって、そういうの目ざとく気がついてしまう人、はっきりいって対象読者じゃないというべきだろうなあ。LinuxとBSDのカーネルコミッターの皆さん、セプキャン講師陣の皆さん、未踏スーパークリエーターの皆さん、お疲れさまです。おまえらはお呼びじゃない。

でね。俺もどっちかというとお呼びでない側っぽいので、色々考えた。昔はCで書くしかなかったサンプルコードがRubyで書いてあるというのはよいですね。なにがよいかってCほど煩瑣じゃないから、本質的な記述(だけとは言わないまでも)の割合が大きくて、いわゆる密度が高い気がする。なのでページ数のわりに内容薄い印象は受けない。高速道路理論ってやつだな。この本で学べるところまでいけば、まあRubyでプログラム書く上では標準的と言ってよい理解度なのだろうし。

もちろん上に書いたように、抜けてる箇所は多々あって、それは自力でmanを読んだりしてなんとかする必要がある。ただ、この本を最後まで読めばmanを使う体力は得られるだろうとは思いました。あとは原著は実は3部作だったりするので、全部通して読めばもう少し理解が深まるとかはあるのかもしれない(が翻訳されるかは…売れ行き次第なのかも)。

というわけで率直な感想を言えば「目次見て知らなそうな事が書いてそうなら、買いじゃないっすかね」とかそういう感じ。これと同様の知識を得るためには一番の近道ではありそうに感じました。

http://tatsu-zine.com/books/naruhounix

Mar
20th
Wed
permalink

OSの標準インストールでPerl入ってるからPerl最強とか言ってるそこのおまえら、10年古い。

Heroku使いなさいよ。

10年前、たしかに、自宅サーバでApacheでCGIでPerlっていう時代がありました。でもさすがに今それはないわ。10年前それやってたサイトのほとんどが結局メンテナンスコスト払えなくて鬼籍に名を刻んだ。あるものはクラックされ、あるものは更新が止まった。そういう歴史の流れですので。今更OS標準だから偉いとか偉くないとかさすがに。ありえんです。

ああ、おまえらがプロのシステム管理者なら(つまりサービス提供側なら)ちょっと話は違う。システム管理者のくせに贔屓の言語とか持っちゃいかん。本当に。どんなシステムでも同様に管理できないようではプロ失格。Perlが来たらPerlでRubyが来たらRubyを鼻歌歌いながら管理できないようでは、半人前です。猛省すべき。

まあいずれにせよ、今更OS標準だから強いとか強くないとか、ないわ。

Mar
3rd
Sun
permalink

どうも。グリーのアカウントは持ってる1けどモバゲーのアカウントは持ってない卜部です。

ところでPerlリスクですか。まあ、あるんじゃないですか。ぶっちゃけ。でもさあ、さすがにPerlしか書けない人たちは転職先の選択肢のなさくらい自覚してると思う。なのでPerlがどうとかいう話はしないです。各自でどうぞ。

でね、ポイントはそこじゃないだろうと思うわけですよ。どんな選択をしても同様のリスクはあるんですよ。たとえばMacromedia ShockwaveでLingoで作ってたソフトとかさあ。今ではだれもメンテできないでしょう? だから今隆盛をきわめてる技術で作ったものが、何年か後にリスクになるってのは、それはそういうものなんですよ。べつにPerlに限らん。Perlはたまたま今そういうフェーズってだけで、明日は我が身ですよ。hamlとかsassとか。

だからまあ、こう言ってしまうと身も蓋もないかもしれないけど、リスクはPerlじゃない、Perlに固執することにあるのです。

あなたがプログラマなら:

いつでも今のスキルセットを捨てれるようにしましょう。捨てれる==他を獲得できるってことです。たとえば俺はRubyやってから逆にモダンPerlの世界に来てるけど、そういうことね。今の俺はPerlが死んでもRubyが死んでも生きていける自信がある。まあ、実際捨てるかは状況次第だけれども、捨てれるってのは強さですよ。

あなたが事業者なら:

いつでも今のシステムを捨てれるようにしましょう。いや、サービスを捨てろとは言ってない。今動いてるそのシステム、それが動き出した瞬間から、すでに技術負債になっているのです。システムを「安心して」作り直せる仕組みを考えましょう。たとえば明確な外部仕様に基づく機械による検証などです。所詮、システムはシステム。それに引きずられて本当に革新的なビジョンが実現できないのは、本末転倒ですよ。

あなたが言語作者なら:

いつでも今の文法を捨てれるようにしましょう。言語にとって「変わらない」のはとっても簡単。放置すりゃそれでいい。でもね、それって立ち枯れっていうか、立ち腐れですよ。なんでか。世の中はこっちの都合におかまいなくどんどん変わるからです。そして話者いてこその言語です。言語ってのは、ここに挙げた中ではもっとも長期的なビジョンが求められる。それが、当たるか外れるかは、分からない部分もあるけど、外れたなって思ったら迷わず軌道修正しないと。良いものは良い、と素直に受け入れるようにしましょう。


  1. id:18667。アカウントをとった当時まだグリーはゲーム屋じゃなかったどころか会社ですらなく、ただの 田中さんの個人サイト に過ぎなかったという点は指摘しておくべきであろう。2004年くらいの話だ。 

Dec
29th
Sat
permalink

RabbitMQ と再送について

概要 : AMQP のプロトコルを読むと、一瞥して送信はパケットを送るだけ、受信はソケットを読み込むだけのようにも見える。しかしながら、実際に書いてみると、再送処理を自前で実装する必要があるため、現実には大変に複雑な処理が必要だ。

そもそもなぜ RabbitMQ を使うのかという話、あるいはなぜ再送が必要かという話

たんにコンポーネント同士が疎結合で通信したいのであればわざわざ MQ を使う必然性は皆無である。ごくあたりまえに TCP で通信すればそれでいい。暗号通信が必要なら当然 SSL でいいし、パケットエンティティに依存する複雑な L7 リバースプロキシを MQ を使って実現することも、不可能ではないが、普通そういうのは varnish とかでやるだろう。

MQ において優れているのはデータの durability だ。つまり、一旦キューにためておけば、その両側のコンポーネントは好き勝手に落ちたり立ち上がったり、あるいは数を増やしてスケールアウトしていい。複数のコンポーネントが複雑に入り乱れているシステムでは、その一部だけを落としてメンテナンスできるというのは非常に重要な要件だし、通信で間に MQ をかますことで、それを実現できるというのが非常に大きなアドバンテージである。

だから逆に言うと MQ を使うのであればピアのエンドポイントが突如いなくなるというのは、最初から考慮しておかなければ MQ の意味がない。システムが神のように無停止で動くのであればそもそもキューなんぞ不要である。ただのバグでプロセスが落ちるのが仮に排除されたとしても、おかんが掃除機かけたらブレーカーが落ちたとか、落雷で電話線からサージ電流が来てモデムが爆発したとか、光ファイバーだから平気だぜと思ったらセミが産卵したとか、様々な理由でシステムというのはすぐ落ちるものだし、みんな知ってるとおり 100% の SLA というものは存在しないのだ。

この節のまとめ : おまえらは本当に MQ が必要なのか? もしどうしても必要なのであれば、一切の希望を捨てよ。

再送処理の実際 (#1) 受信編

MQ から受信する側のプログラムは(比較的)そんなに難しくない。なぜかというと MQ からデータが来ていて自分のプログラムも動いているということは要するに、両側が生きていることは自明だからだ。

しかしながらそれが自明なのは受信側だけで、送信側である MQ からしたら、受信プログラムがだんまりを決め込んでしまうと、生きているか死んでるか分からんということになってしまう。そこで、プログラムは MQ からデータを受信した後に、適切に basic.ack パケットを返してあげる必要がある。逆に言うと、ack しなかったパケットはやがて MQ 側から再送されてきてしまう。

#! ruby

require 'amqp'
EM.run do
   AMQP.connect $your_settings_here do |conn|
      AMQP::Channel.new conn do |ch|
         ch.queue $your_another_settings do |q|
            q.suscribe $your_yet_another_settings do |hdr, bdy|
               hdr.ack # <- don't miss it
            end
         end
      end
   end
end

Ack 戦略を考える

ここでいくつかの戦略が考えられる。つまりどこまで処理したら ack することにするかという話だ(図)。

受け取った直後に ack するというのは、 ack したあとに処理の途中で例外で死ぬこととかをかんがえると筋が悪いかのようにも見える。しかしながら、処理の最後に ack するというのだと、処理自体が無限ループしちゃったら永遠に ack できないとかありうる。一長一短と言える。どちらにせよ正常時には問題ない。が、今回考えているのはプログラムが突如死んだりする場合なので、そこを勘違いしないように。

別の考え方としては nak (not ack, 「受け取れませんでした」)を積極的に応答するというのもありうる(図)。nak されたパケットは、当然、MQ から後で再送されてくる(されてこないようにも指定できるが)。最初の受信時に処理をトリガしておいてから nak を返信して、再送時すでにトリガされた処理があれば、それが終了しているかで ack/nak を出し分けるということだ。

これは賢そうに思えるのだけれど、実際どうかというと、処理するワーカーが一個だけしか動いてなければまあ、そこそこ程度にはうまくいく。しかしながら MQ 使っててワーカーが一個というのはかなり考え辛くて、普通は横方向にたくさんスケールアウトしているだろう。そうなってくると、再送パケットがどのワーカーに届くかはロシアンルーレットだ。つまり処理をしているワーカーではないワーカーに再送されるというのが典型的なシナリオである。

この際、当然、二重に処理をしてしまってはいけないので、ちゃんとロックをとる必要がある。当然、プロセス間にまたがったロックだから、いわゆる分散 Mutex という話になるだろう。ところで、今、正常に動く場合の話はしていない。つまりプロセスが Mutex を握ったまま死んだらどうなるのか? このシナリオは、別途考える必要があるといえるし、そう一筋縄で解決できる話ではない。

この節のまとめ : 再送されてくるパケットを適切に無視するために分散 Mutex に逃げるというのは複雑さのレイヤーが MQ から Mutex に移動しただけの話で、本質的な解決になってない。

再送処理の実際 (#2) 送信編

さて、送信側では先程「 MQ からしたら、受信プログラムがだんまりを決め込んでしまうと、生きているか死んでるか分からんということになってしまう。」と書いたことの逆が発生する。つまり、 MQ が生きているかどうかを判定して、死んでそうなら手元にためておき、再起動してきたら送り直すというコードを自分で書かなくてはいけない。 Ruby の amqp ライブラリの場合で言えば、再接続まではライブラリの責任範囲だが、データの送受信は当然、クライアントプログラムの領分だ。とりうる戦略は二つある。

トランザクションを使う

MQのプロトコルにはトランザクションを宣言できる機能がある。これの流れ(図)は、まずクライアント側がトランザクションを宣言、次に通常のデータ通信を行い、最後に tx.commit を発行すると、トランザクションが有効であった間に送信したデータが確実にMQのデータストレージに書き込まれて再起動に耐えれる状態になるまで、 ブロックする。つまり間に MQ の再起動とかはさまってても、 commit-ok が返ってきたら送信できてたということをキュー側で保証してくれる(ちなみに失敗したら例外が発生)。簡単であるし、確実でもある。

#! ruby

require 'amqp'
EM.run do
   AMQP.connect $your_settings_here do |conn|
      AMQP::Channel.new conn do |ch|
         AMQP::Exchane.new ch, $your_another_settings do |xchg|
            ch.queue $your_yet_another_settings do |q|
               q.bind xchg, nowait: false do
                  xchg.tx_select # start transactoin
                  $your_ary_to_send.each do |i|
                     xchg.publish i
                     xchg.tx_commit # this blocks
                  end
               end
            end
         end
      end
   end
end

ただ問題は明らかなようにブロックするので速さが出ない。下層の RTT にもろに影響されるし、 MQ 側でも様々なロックをとったりディスク書き込みで fdatasync(2) したりするだろうから、ばーっとアクセスがくると今度はサーバのディスク速度が律速しだす。MQ に DB のような行の概念はないので、行単位にロックしたりとかということもない。

この節のまとめ : MQにもトランザクションがある。それはそれで便利ではある。が、万能ではない。

Publisher confirmation を使う

ようするにトランザクションはちょっと overkill なのである。どうせ TCP で通信しているのだからパケットの再送とかは基本は TCP でなんとかしているはずなのだ。そこはわざわざ待ち合わせる必要はない。問題はピアの MQ ブローカーが落ちたときで、それだけ検出できればいいでしょう、というのが、 RabbitMQ の拡張プロトコルである publisher confirmation だ。

Publisher confirmation はようするに MQ 側から「今ここまで読んだわー」っていう情報を送り返してくれる。そんだけである。したがって、流れ(図)としては送信すべきデータは送信後も一旦手元に残しておく。で、完了の通知を待たずにどんどん次のパケットも送ってしまう。のちに、完了通知が来たら、そのパケットはもう届いたから捨ててよくて、完了通知が来なかったら対向は死んでるので、再接続して送りなおす。

これはクライアント側に待ちが発生しないし、正常系(つまり運用時間の 99%)ではほとんど何も負荷がないので原理的には TCP のプロトコル限界までスピードが出せるし、ピアが死んでも救済できる。素晴らしそうに思えるのだけど、問題は正しく実装するのがめどい。つまりデータの再送はライブラリでは手助けしてくれないので、自力で正しく書くしかないのだけど、データの送信は exchange というエントリに向かって投げるのだけれど、どこまで読んだかの応答は channel というエントリから返ってくるという謎仕様(いや作りから考えれば謎ではないがまあ頭悪い感はある)になっているため、それをつきあわせたりしないといけない。

というわけで、たとえば以下のようなコードが必要になる。本気で必要な人以外は「ああ長くて面倒ですね」「ひどいコールバック地獄ですね」ってのが理解できればだいたいOK。興味がある人は、上と比べてみてどこがどう変わっているかを追いかけてみると良い。

#! ruby

require 'amqp'

PendingEvents = Struct.new :tag, :retry, :xchg, :msg, :block do
   def publish
      $publishing_events ||= []
      self.xchg.publish self.msg, $your_yet_yet_another_settings
      $tag += 1
      self.tag = $tag
      $publishing_events.push self
   end
end

EM.run do
   AMQP.connect $your_settings_here do |conn|
      cap = conn.server_capabilities
      raise 'RabbitMQ TOO OLD; please upgrade' unless cap and cap["publisher_confirms"]
      AMQP::Channel.new conn do |ch|
         ch.confirm_select do
            $tag = 0
            ch.on_ack do |ack|
               n = ack.delivery_tag
               ok = []
               ng = []
               if ack.multiple
                  ok, $publishing_events = $publishing_events.partition {|i| i.tag <= n }
               else
                  ng, $publishing_events = $publishing_events.partition {|i| i.tag < n }
                  if $publishing_events.empty?
                     # the packet in quesion is lost?
                  elsif ev = $publishing_events.shift
                     ok = [ev]
                  end
               end
               ng.each do |e|
                  EM.next_tick do
                     # we need to re-send
                     e.retry += 1
                     publish e
                  end
               end
               ok.each do |e|
                  EM.next_tick do
                     # OK, reached
                     e.block.call if e.block
                  end
               end
            end
            ch.on_nack do |nack|
               n = nack.delivery_tag
               ng = []
               if ack.multiple
                  ng, $publishing_events = $publishing_events.partition {|i| i.tag <= n }
               else
                  ng, $publishing_events = $publishing_events.partition {|i| i.tag < n }
                  if $publishing_events.empty?
                     # the packet in quesion is lost?
                  elsif ev = $publishing_events.shift
                     ng = [ev]
                  end
               end
               ng.each do |e|
                  EM.next_tick do
                     e.retry += 1
                     e.publish e
                  end
               end
            end
            AMQP::Exchane.new ch, $your_another_settings do |xchg|
               ch.queue $your_yet_another_settings do |q|
                  q.bind xchg, nowait: false do
                     $your_ary_to_send.each do |i|
                        $publishing_events ||= []
                        e = ::PendingEvents.new 0, 0, xchg, i, nil
                        e.publish
                     end
                  end
               end
            end
         end
      end
   end
end

この節のまとめ : publisher confirmation は限界近くまでパフォーマンスを引き出しつつメッセージ到達性を確保するには最適だがライブラリ側からの支援が不足している等の理由により扱いが面倒。

まとめ: 結局どうすればいいのか?

まあ、結論はない。 RabbitMQ を導入することにより得られる利便性と、コンポーネントが増えたことによる複雑さの上昇は一種のトレードオフなので、あたりまえの話ではある。最悪なのがコンポーネントは増やして複雑さを上昇させたのに利便性はさして上がってないパターンで、これは防ぐ必要があるだろう。たとえば RabbitMQ を使わないというのは立派な選択肢の一つだ。 MongoDB にトランザクションがないからといって MongoDB がゴミではないのと同様に、 RabbitMQ を使わなかったからといってあなたのプロダクトはゴミではないだろう。

おまけ: 正しいシャットダウンのやりかた

上では「ピアがふいに死んだらどうするんだ」という話をしていたが、当然、行儀の良いプログラムとしては死ぬときはちゃんと死ぬと宣言してから死ね、というのはある。それをどうやるかというと、まずqueueから取り出すのをやめて、停止したのを確認したら次にchannelを消して、消えたのを確認したら次にconnectionを消して、消えたのを確認してから死ね。つまりこう:

#! ruby

require 'amqp'

def setup_traps conn, ch, q
   %w(INT TERM HUP QUIT KILL).each do |signal|
      trap(signal) do
         q.unsubscribe do
            ch.close do
               conn.disconnect do
                  EM.stop
               end
            end
         end
      end
   end
end
Oct
30th
Tue
permalink

やっぱ社内mixiとか社内facebookとか社内twitterとか社内LINEとかもうあるからこれからは社内tumblrっしょ、と思って企画でも書くべとワード開いたものの課金する方法がないから回収できないしダメだこりゃ。アイディア放流しとくので他社さんで適当に実現しといてください。pixivさんとか。

Oct
1st
Mon
permalink

DeNAに転職します

宮川達彦さんがCOOKPADでRuby書いてるなら俺がDeNAでPerl書くのもまあありなんじゃないかと思ったので。

よくある質問とその答え

  • Q. 一時金もらえるんでしょ? 200万? やったー! ごちそうさまです

    A. ねーよ。おまえはいつの話をしてるんだ。そのキャンペーンはずいぶん前に終わりました。

  • Q. ベイスターズファンだったの?

    A. 好きでも嫌いでもねーよ。野球の趣味を理由に転職するの必ずしもダメとは申しませんが、俺はそういう類の輩ではございません。

  • Q. モゲマス作るの?

    A. 作らねーよ。Mobageだからといって全部のゲームをDeNAが作っているわけでは、実はないのです。モゲマスは違います。

  • Q. Rubyやめちゃうの?

    A. やめねーよ。コミュニティ活動に関しましては、むしろ推奨されていると聞き及んでおります。あと当然、素性を隠しておりませんので、俺が何者かは分かった上で採用しているはずと存じます。

  • Q. Perl書く仕事なの?

    A. 書かない理由がねーよ。ただ、Perl以外をまったく書かないかというと、そういうわけではないだろうという理解ではおります。ふたを開けてみないと分からない部分も多々ございますが。

  • Q. NaClについて一言。

    A. それを今の俺に聞いても通り一遍の答えしか返せねーよ。しかも通り一遍以外の答えは一言じゃ終わらねーよ。まあ若干詳しく言うのであれば、円満に終了しました、ということですかね。無職の状態から拾っていただいて、長らくお世話になりました。概ね好きなように働かせていただき、概ね自分の好きな仕事を割り当てていただいて、感謝しています。ありがとうございました。御社の今後とも益々のご発展を信じて疑いませんし、それに直接には貢献できない立場になってしまうのは、本当に残念です。

Sep
11th
Tue
permalink
Sep
6th
Thu
permalink

Re: Tempfile被害者の会

http://r7kamura.hatenablog.com/entry/2012/09/05/194630

しょうがないなー。gem作ってあげたからこれでも使いな。

使い方

  1. Gemfileに

    gem "open-temporary"
    

    と書く。

  2. 一時ファイルを使うところに

    require 'open-temporaruy'
    

    と書く。

  3. open-uriと同様にopenが拡張されており、無引数のopen、つまり

    File.open # => 一時ファイル
    

    とすることで一時ファイルを作成可能。

    • このファイルは本物のFileなのでdupしても平気。

なぜこれがRuby本体に入らないのか?

移植性がないからだよ。

この実装でなぜOKかというとOSが頑張ってディスクリプタやファイル領域をリークしないように回収してくれるからに他ならない。つまり振る舞いがOS依存であり、したがって動かないところでは動かない。特にこのようなAPIはWindows上で実装する方法がたぶんない。たぶんJavaもない。

なので諦めましょう。

Aug
21st
Tue
permalink

.travis.ymlめぐり

Travis CI というGithubと連動してGithubにコミットすると勝手にテストが走ってテスト結果を通知してくれる、ようするにJenkins as a Serviceみたいなやつがあって、とても便利なので知らなかった人はこの際使いましょう。

そんでTravisの設定ファイルが.travis.ymlで、プロジェクトのディレクトリに置いておくだけでいいんだけど、ごく最近rubyの.travis.ymlを書き直したので、そのときに調べたものを開陳しておこうというエントリ。

その他TravisにはClosure, Erlang, Groovy, Haskell, Scalaのモードがあるようですが、これらの言語実装もGithubに置いてあるようですが、それぞれ .travis.yml はありませんでした。Travis側からの愛はこれらの言語には伝わっていないようですね。

Jul
21st
Sat
permalink

本年もRubyConfに行っていただきたく思います。

昨年に引き続き今年もRubyConfに行きたい人は実質無料で連れていきますので、行きたいと思った人は会社・学校の休みを調整してもらうのだけやればOKということにしました。

よくある質問とその答え

この項の文責は俺(Rubyの会の公式見解ではありません)。

  • Q: 去年の続きなの?

    A: はい。Rubyの会に企画を持ち込んで俺がやってます。事務局も俺。

  • Q: にしては趣意が変わったようだが。

    A: まあそれは俺個人がやるのとRubyの会がやるのでは必要な大義名分は違うよね。

  • Q: 提供されるサポートは去年と一緒?

    A: 微妙に違います。去年は航空券の手配とかも俺がやりましたが、今年はそれは各自やってください(領収書方式)。航空券の手配をするにはパスポートのコピーとかが発生する為、Rubyの会としては、センシティブなデータを扱うには慎重な姿勢にならざるをえないのです。正直、避けて通りたい部分です。

    ただ、こういう取り方がおすすめだよ、みたいな話は情報交換としては提供できると思います。

  • Q: RubyConfで発表しないといけないのってハードル高いんですけど。

    A: そのハードルを下げたい。Rubyの会は俺個人と違って会員がいるので、それを差し置いてなんの脈絡もない個人にいきなり予算を投下するのはいかがなものか、とかいわれると事務局である俺が面倒。というわけで、「RubyConfへの参入障壁を下げる事業」ってことにすればRubyの会の目的とも合致していいのでは、という理論武装である。

    実際、金銭以外のサポートが必要であれば、言ってもらえばちょっと考えます(内容により確約できないが)。みんなRubyConfいくべき!

    (あとぶっちゃけ落選しても、べつに… なので、必ずしも… ごにょごにょ)

  • Q: なんで未成年NGなん?

    A: これは戦ってみたんだけどやっぱ調整できませんでした。申し訳ない。

  • Q: 予算はどうなってんの?

    A: 昨年俺が金を出すということにかんして、まあやはり批判もあった。というわけでしかるべき機関がバックにつくべきということでRubyの会に持ち込んだ。つまりありていに結論だけ言うとRubyの会から出る。

    ただし今年は(任意団体だったころからの)内部留保がじゅうぶんあるのでRubyの会から出せてもらえてるけど、来年以降、Rubyの会としてひもつきでない収入が増える見込みはまったくないので、可分所得が増える方向になく、そういう意味では継続性に関して俺一人でやってる時と比べて何が変わったかというと、ほとんど変わってない。

    まあ寄付… 寄付ねえ… Grantっぽい事業で集金しようとして盛大にやらかした方がおられますのでねえ… 今年に関しては時期が悪かったねえ。

Jun
22nd
Fri
permalink

バックアップ考

というわけでPCを買ってバックアップをセットアップしたので考えてみるわけだけども、やはりバックアップはどちらかというとバックアップのしやすさよりもリストアのしやすさが重要と思うわけだ。ZFS send/recvだとかiSCSIでネットワーク越しにLVM論理ボリュームを構築してミラーさせたりとか、原理的には可能かもしれないが、リストアの面倒臭さの面でぜんぜんダメと言わざるを得ない。ZFSはそれはそれでよいものだが、だからといってそれだけではバックアップとして成立しない。RAIDがバックアップではないのと同程度には、ZFSもバックアップではないのだ。バックアップは基本的に、奇をてらわないコンサバティブな技術が要求されている分野。すなわち、

  • バックアップ先メディアは大容量低速回転HDDのRAID1クラスタを使うということ(次点テープ)。容量と入手性の観点からHDD以外のバックアップメディアの選択肢が壊滅的ということ。しかしHDDは離散的なタイミングで確率的に壊れるものであるということ。したがってRAIDを組むしかないが、RAID1以外のレベルでは信頼性はほとんど向上しないか、レベルによっては低下するということ。何発壊れようが最後の一発が生き残ってさえいればデータが吸い出せる上に、その状況で虎の子のアクティブHDDをアレイから切り離してしまったとしても(きわめてありがちなオペレーションミス)、まだそのHDDを外付けHDDケースに入れてUSBかなんかで繋いでdd(1)で吸い出せる可能性があるのは、RAID1しかないということ。

  • rsync(1)でバックアップし、rsync(1)でリストアするということ。つまり普段からよく使い、手に馴染んでいて、動作もよく理解している方法を使うということ。かつrsync(1)であれば、遠隔バックアップ、増分バックアップに対応しており、大抵のものはバックアップできる上に、rsync(1)でバックアップしたものをrsync(1)でリストアするのに特別な操作は不要であること。

  • バックアップ元メディアには必ずスナップショットFSを使うということ。いまどきスナップショットが取れないFSしか提供されていないOSでは、バックアップが必要なほど重要な情報を置くべきでないということ。どうしても必要であればスナップショットをとれるVMの上に環境構築して、そのVMのスナップショットをバックアップすること。

ここまでは基本中の基本と思われる。大体誰に聞いても大差ない。これに俺の個人的な趣味をあえて加えるとすれば、

  • 自動的にバックアップする設計にせよということ。ただし手動でバックアップ可能にせよということ。手動でバックアップして失敗するほどアホなことはないこと。しかしながら、自動でバックアップするのが失敗していたときに手でフォローできないことは輪をかけてアホであること。

  • リストアしてみよということ。本番稼働前に一回はHDDを故意に活線挿抜してみて復旧を試せということ。

  • 人生のなるべく早い段階でデータロスを実際に経験せよということ。大人になって金銭や信用のダメージが大きくなる前に、データがなくなった悲しさとか設定が失われた困難さを経験しておけということ。

  • 他人のデータは頼まれても絶対預かるなということ。

まあこんなもんですかね。がんばって生きてください。