Cassandra 2.0 に CAS が入るとか入らないとか

Cassandra

CASSANDRA-5062でCAS (Compare and Swap) を入れようという話になっているらしく、一体どんなすごいアトミックブロードキャストを使うのか気になっていた。どういうことなのだろうとスレッドをナナメ読みしてみたのだが…議論の流れとしては

  1. カウンターだけじゃなくてCASほしいよねAPIとして
  2. ZooKeeperのロック使うのがシンプルでいんじゃね?
  3. いやいやサーバーの種類増やすとかあり得ないし
  4. 基本方針は、コーディネーターみたいなのをレプリカセット毎に決めてそこから Chain Replication ぽく
  5. コーディネーターどうやって決める
  6. やっぱPaxosじゃね?
  7. 再実装ヤダよZAB使おうよZKの実装あるよ
  8. (なんかプロトコル上の理由があって)やっぱPaxos実装するしかないか…

となって、結局 Jonathan Ellis が Paxos を素で実装してしまった模様。 Thrift API無事に cas というのが増えて非常にわかりやすい感じではある。分かったことは、テキストベースで非同期通信の議論なんてするもんじゃないということだ。まして英語なので大変辛く結局ポイントを抑えられていない。だれか有識者に補足していただきたいところ。

個人的にはPaxosの実装って大変だと思うのだが、1ヶ月でサクッとできてしまったりするものなんだろうかというところ。まあテストはこれからなんだろうけども。あとはCoordinatorが落ちた瞬間ちょっとCASできなくなるところかな。性能を求めてるわけじゃないから…とは書いてあったけど、じゃあ何のためにCASにするんだろう。そこだけはどうしても分からなくて、便利だからというだけの理由でこの類の難しい機能を入れたら大変なことになる予感しかしなくて心配している。

追記

そういえばふと心配になって、PaxosベースでCoordinatorを決めるとして、その故障検知がPhi Failure Detectorで動いていたら大丈夫なのかなと思って調べたら相変わらずΦ故障検知だったので安心した。

改めてソースのファイル名だけを見ていると故障検知に関係ありそうなファイルはない。故障検知まわりがノータッチだと仮定するとちょっと怖いことになる。FUDだったらすみません。
故障検知をトリガーにして次のPaxosによるLeader Electionが動き出すのだとすると、たとえばCoordinatorが過負荷とか瞬断で見えてない瞬間があって、たまたまFollowerの故障検知が短かったときに(Φ故障検知だと起こりうる)Coordinatorさんは自分がまだCoordinatorだと思っている瞬間にリクエストを処理してしまい、FollowerはFollowerでPaxosで次のCoordinatorを選出してしまっていると、それぞれのサーバーで別のCASが同時に走ってしまう気がする。Lease Timeをちゃんと設計していれば大丈夫なのだけど... 有識者とかスレッドを全部読んだ偉い人教えてください。

医薬品クライシス

僕自身は病院の世話になるようなことはなく、花粉症か胃腸薬しか利用しないものだからほとんど医薬品業界に興味がなかった。結婚してから妻子が病院の世話になることが多く(他から比べたら少ない方だろうとは思う)、医薬品業界に崩壊されても非常に困るので購入した。

医薬品クライシス―78兆円市場の激震 (新潮新書)

医薬品クライシス―78兆円市場の激震 (新潮新書)

前半は、医薬品とは何なのか、ここ30年の医薬品の研究開発はどのようにして行われるのか、世界中のエリートが不断の挑戦を続けて一生に一度当たるか当たらないかの世界だ。当たれば大きく、ひとつの薬が数百億円から数千億円の売上がある。大抵の製薬会社はそうやって当てた少数の薬で屋台骨を支えているということだった。

さて、近年の医薬品は小分子化合物の組み合わせで勝負するのが主流だった。せいぜい原子数十個くらいのピンポン玉くらいのものが、バスケットボールくらいの大きさの差がある生体内のタンパク質に作用して(阻害とかもろもろ)病原を断つ、あるいは緩和する。経口摂取がほとんどなので胃腸で消化されない、細胞膜を透過できる、他の蛋白質に作用しない、などの条件を兼ね備えた分子を見つけるためには膨大な研究開発費がかかる。
頑張ってみつけた新薬といえど特許が20年で切れるから、実際に利益を稼げるのは10〜15年程度しか見込めないから、その間にまた次の新薬を開発しなければならない。走るのを止めれば死ぬレースだ。
一方で新薬の臨床試験や審査はますます厳格化しており…という問題もあり。

そういった化合物は10の60乗程度の総数があると言われているが、めぼしいものはこの2〜30年で探索しつくしてしまい、よいものを見つけるための研究開発の賭金はどんどん上がってきた。なので製薬企業が合従連衡して巨大企業になってきた。ただし企業が巨大化しても新薬開発の速度は上がらず、大企業病が発生したこともありむしろ下がってきたという。
また、特に日本では研究者への敬意がないらしく、印象的なセリフがひとつあった。年間4000億円を売り上げるクレストールという薬の開発者に対する報奨金は当初たったの15,000円だった。その後1450万円支払おうとしたが、開発者の渡辺氏はこれを拒否して8億7千万円の訴訟を起こした。そのことに言及して、成果を出した研究者にはプロフェッショナルとして報酬を支払うべきだと筆者は主張している*1

渡辺氏の例でもわかる通り、中途半端な報酬は研究者のプライドを逆なでし、モチベーションを失わせるだけだ

このまま製薬企業の特許が切れていくと各社とも研究開発ができなくなり、医薬品の生産や医療の進歩は停滞していく…というのがクライシスの正体だ。

これ以降はネタバレなのだが、実は最後に希望を残しているのが本書の面白いところだ。まさにイノベーションのジレンマなのだが、実はバイオベンチャーは多く産まれてきており、既存の製薬企業はこれらの買収に躍起になっているという。バイオベンチャーを買収し、企業体力を生かして臨床試験、大量生産、認可手続きなどを行うことにより医薬品として実現する。イノベーションの正体は、小サイズの化合物ではなく、選択的機能を持った蛋白質を生産して体内に注射するタイプの医薬品が登場しているという。
これまでの小サイズ化合物とは異なり、生産が難しい(のでジェネリックの脅威がない)ので特許切れが怖くない、分子が大きいので研究開発がやりやすい、などのメリットがあり産業構造が変わるのではないかと言われている。

また、その後にはRNAの作用を利用した医薬品が、そのさらに後にはiPS細胞による医薬品が期待されており、後に続く弾は沢山ある。希望はまだ沢山ある。というとてもよい下げでございました。
これは、私の属しているITの業界でも同じことがいえるだろう。クラウドとかビッグデータという分野はおそらく事業者の統廃合を進めて、世界には5台のコンピュータだけが存在するようになる…というのがアナリストを始めとする有識者の考えだし私もそう思っていたが、そうなることは金輪際ないだろう、と思い直した。それが読後の変化だ。

*1:失敗するリスクもあり、報酬が低いのは保険料だという主張もある。私の考えでは、高い報酬そのものがモチベーションであってはならないが、低い報酬は研究者のモチベーションを下げる効果を確実に発揮するので報酬は低くてはいけないと思う

集中してテキストを書く環境

Intense concentration

4月はなんだかんだで書かないといけないまとまった文章が4本もあったので、ずっとEmacsと向き合っていたのだが、正直いって素のEmacsは日本語の文章を書くには向いていない(私はこの手の道具はカスタマイズを最小限にしてなるべくデフォルトを使う主義だ)。昔はTeXで論文のようなものを書いていた時期もあって、そのときも同様の違和感があり、wysiwygエディタの素晴らしさを痛感したものだった。かといってwysiwygを使うと不自由さを痛感したものだが。

最初の殴り書きではgistに直接書いていたが、原稿を仕上げる段階になってからはそれでは不安がある。かといってEmacsではどうも合わない。というわけで2日ほど Writebox というChromeアプリを使っていたらこれが非常にフィットして気分よく文章がかけた。MacでChromeだとEmacsキーバインドで軽快に書けるし、スクロールもEmacsと違って非常にスムーズだ。問題があるといえば reST で書いてもハイライトされないしちょーっとだけ不便だなと思っていた。だから、自然言語を書くときにはまずWriteboxを薦める。ファイルをGoogleドライブかDropbox上に置けるのもよい(他のローカルファイルシステムには置けない)。使いたいときはブラウザでログインしてダウンロードとかしなくてよいし、 mv コマンドでよい。そして気付いた。Emacs自然言語を書くときの違和感の正体は左右のマージンがないことだったのだ。左右のマージンがあることによって、全画面表示にしても狭く感じない - 空間とはかくも大切なものだったのかと気付いた。

そこで私は調べた。Emacsで左右のマージンを設ける方法を。と思ったら、EmacsでDarkroomを作るという記事があり、まあこれは入れるほどでもないかと思ったがマージンを入れる方法が書いてあった。

(set-window-margins (selected-window) 20 20)

これを、 M-x eval-expression で実行する。これで左右にマージンが適当にうまれる。20がマージンを表しているので、この数値を適当に調整してほしい。これとMacOSでのCarbon Emacsのフルスクリーンを組み合わせて使うことであと3年くらいは戦える気がする。シンタックスハイライトがほしい、Emacsが恋しい、懐かしいという方には朗報である。これからもEmacsを使い続けることができる。

メモリリークとは何か

Warltersville Rd leak

メモリリークに悩まされている技術者は多いだろう。メモリリークが嫌でGCという技術が開発されたといっても過言ではないし、歴史的にはC++からJavaへシフトが起きた大きな理由のひとつといっていい。Unix系の簡単な定義でいえば、ヒープ領域を指すポインタ(アドレス)をロストしてしまえばそのメモリはもう漏れたといってよい。たとえばこういったコードだ。

struct { int i; char c; } spam;
int main(){
  void* p;
  int i;
  for(i=0; i<1024; ++i){
     p = malloc(sizeof(struct spam));
  }
  pause();
}

このコードではpause(3)の時点で約5KBのメモリが漏れている。free(3)を使えばメモリをOSに返却できるが、アドレスが分からないので返却できない。

ところが、ここでいいたいのは、メモリリークはそれだけじゃないということだ。この時点でピンと来た方には、この話はもしかしたらつまらないかもしれない。
さて、そもそもメモリリークとは何か、Wikipediaをみてみよう。

メモリリーク (Memory leak)とは、プログラミングにおけるバグの一種。プログラムが確保したメモリの一部、または全部を解放するのを忘れ、確保したままになってしまうことを言う。プログラマによる単純なミスやプログラムの論理的欠陥によって発生することが多い。

いわゆる一般的で古典的なメモリリークのことだ。この記事の最後に、リソースリークという項目で漏れるのはメモリだけでなないと書いてある。DBの中の忘れられたレコード、忘れられたTCPソケット、忘れられたiノード、わたしたちの歴史には忘却されたものが沢山あるはずだが、悲しんでいたところで彼らは戻ってこない。

次のコードはPythonで書かれている。これはメモリリークかどうか、考えていただきたい。

class Stack:
  def __init__(self):
    self.stack = []
    self._stack = []
  def push(self, obj):
    self.stack.append(obj)
    self._stack.append(obj)
  def pop(self):
    if len(self.stack) > 0:
      obj = self.stack[0]
      self.stack = [1:]
      return obj
    else:
      return None

s = Stack()
while(True): s.push('spam ham egg')

Pythonだからメモリリークは起きるわけがないか? ポイントは Stack の _stack というメンバだ。もともとは何か目的があって _stack が追加されていたはずだが、いつしかそれは不要になって、 Stack.push のときにpushされるようになっていった。ここでは while(True): の中にあるが、たとえばこのオブジェクト、1日に1000個だけpushされるようなサーバーで動いていたら一年かけて365000個のだけスタックが伸びる。
Pythonのリストのオーバーヘッドにもよるが、1KB の文字列が追加されていくのであれば、少なくとも 1年で365MBのメモリが漏れていることになる。え、そんなの大したことないって? ミドルウェアの開発者は貧乏性なんだよほっとけ。

さて、最初の定義に戻っていただきたい。このとき _stack への参照はコンテキストに残っている。残っているのだからメモリリークではないということになる。いざとなればこのコンテキストを抜けてしまえばよい(ここではトップレベルコンテキストになっているが、普通そんなPythonコードは書かないだろう)。そうすれば refcount が0になるだろう。

だがちょっと待ってほしい。よく考えてほしい。考えなくても分かるか。そのメモリは必要ないのだ。必要ないのに使える状態でプログラム中に残っている。つまり、メモリリークの定義は「プログラム上必要がないメモリ空間が確保されている」ということだ。

世間にはこうやって忘れ去られたメモリやオブジェクトが沢山あるはずだ。valgrindやその他の静的・動的含めた解析ツールでは要不要を判断する手段がない。使われていないかどうかを検証すれば分かるか?その問題はNP困難だかNP完全に見える。

これはJavaだろうがErlangだろうがCだろうが、どんな言語どんな処理系でも同じだ。そのメモリやオブジェクトが必要か不要か、設計者や開発者でないと判断できない。だから、ソースコードのレビューや長期耐久試験*1を通してメモリが太っていかないことを人間の手で見つけ出すしかない。
という話を、遠い昔に職場の先輩としたのを、昨日ふと「Erlangメモリリークなんて起きるわけがない、起きたら大事だ」と自分で言って思い出して反省したのであった。

Debug Hacks -デバッグを極めるテクニック&ツール

Debug Hacks -デバッグを極めるテクニック&ツール


Binary Hacks ―ハッカー秘伝のテクニック100選

Binary Hacks ―ハッカー秘伝のテクニック100選

*1:前職の職場では長安試験と言っていた。私はこの呼称が割と気に入っているが一般的ではないだろうから、この言葉はやめた

Rubyにyaml

僕はRuby 1.9.3-p392 を prefix=/usr/local で入れて使っているのだけど、libyamlが MacPorts で prefix=/opt/local に入っている。でコイツのせいで

$ ./configure

とか普通にやっていたら、bundlerなりgemなり使っていると

$ gem update --system
$SANDBOX/usr/lib/ruby/1.9.1/yaml.rb:56:in `':
It seems your ruby installation is missing psych (for YAML output).
To eliminate this warning, please install libyaml and reinstall your
ruby.

というのが毎回でてきて邪魔くさい。特に bundle exec しているときにこれが毎回でてくるととても精神衛生上悪い。ので

$ ./configure --prefix=$PREFIX --with-opt-dir=$OPT

みたいにできる。つまりMacOSの場合は

$ ./configure --prefix=/usr/local --with-opt-dir=/opt/local

とやればよい。
ちなみにまだ 2.0.0-p0 はビルドに成功していない。

そろそろGoについて一言いっておくか

Play on Words

昨日、GoCon(ごうこん)なるイベントに参加してきた。以下に続く話は5割以上がフィクションなので虚実織り混ざっている様を楽しみながらお読みいただけたらと思う。

最初に発表されたニュースを聞いたときは、Goはよい車輪のよい再発明で、結局GoogleC++Javaを使い続けるだろうし、世間はGoogle独自言語としてみなすのだろうなという予感はあったし、2010年だから2011年ころはそういう見方をされていたように記憶されている。私もそういうものだと思っていたし、特に関心を持つこともしなかった。いま思えば正常性バイアスだったのだろう。

実際に昨日のカンファレンスで一番興味深かったのは鵜飼さんによるGoの解説だった。比較対象がC++, Python, Javaだったことが最も印象的で、普段からErlangOCamlといった関数型言語に接していた身として新鮮だった。話を聞くうちにGoogleの本気度が分かってきて、これまでの言語では巨大なサーバーシステムを0から構築するためには不十分であったり、やや行き過ぎたところをバランスをとって…と、そういった問題点をひとつひとつ解決していきたいという意図が見えた。つまり、

  • メソッドやメンバを追加できないのは不便だがダックタイピングはメンテナンス性が非常に悪い
  • コンパイル時間が長いのは地獄
  • メモリ管理は地獄
  • 言語仕様がシンプルなのがいい、難しいことはやりたくない
  • シンプルでいてある程度は型安全なプログラミングがしたい

といったところで、最後の汎用言語を作りたいのだろう。これといって尖ったところもなく、言語仕様の設計がとてもバランスがとれていてよい。実際に検索エンジンのバックエンドはC++Javaで書かれているだろうし、巨大なコードベースがあっていくら天才たちとはいえそのメンテナンスに苦労しているのだろう。他のex-Googlerの講演で数時間かかってビルドしたバイナリが数GBあったという笑えないフィクションの話も非常に興味深い。
Tech Conferenceなのであまり相応しくはないだろうが、おそらくJavaもオラ◯ルさんの手中にあってどうなるか分からない*1し、gccもどうなるか分からない*2し、まあLinuxはしばらく大丈夫だろうけどもというくらいの妄想は僕にも働く。

ところで、ここからはフィクションの話だが、ある知り合いが巨大な分散システムの開発をしていたことがあった。そのシステムはC, C++, Rubyが入り交じっており*3、コードはとりあえず書けたものの、オブジェクトのシリアライズやマルチスレッドプログラミングに伴うロック管理、メモリ管理に多くのコストを費やした。複数リソースのタイムアウトや受信などを待ち合わせるコードをCで実装し、さらにメモリ安全性も保証しなければならない。ここまでくるとほぼ組み込み系のほぼリアルタイムシステム*4のプログラミングになり、もともとそういうノウハウを持ってなかったこともあり荷が重かった。さらには複数のコンピュータが特殊なプロトコルで協調して動作しながら、いつ故障してもデータの整合性を保たなければならないという古くて新しい難しい問題も同時に解かなければならないし、分散システム特有のカスケード故障、多重同時故障も想定しなければならず、デバッグやテスト、特に長期安定試験や性能試験の際に大きな苦労をした。
クリティカルなバグが見つかると、コードの大部分を再度レビューにかけて類似の問題点がないかを時間をかけて検討することもあった。修正範囲が大きくならざるを得ないときは本質的な解決を諦めてコードにさらに泥を塗って汚したこともあった。だから、Goのように筋のよい言語があればもっとやりようがあったのかもしれないと思う。
Concurrency Bugは大抵Segmentation Faultかカスケード故障、またはシステム上重要なメッセージ通知の喪失として現れてくる。複数の種類の問題が複雑にからみ合って登場してくるのだ。Rubyに至っては1.8系を利用していた*5ので、グリーンスレッドとpthreadとGCには嫌でも詳しくなれたことだろう。どうしてRubyにforkというAPIがあるんだと恨んだりもしたことだろう。
当時の担当者は「これがErlang/OTPなら…」と何度思ったか知らないと語っていたが、(主に人数と費用が)大規模な開発に特有の問題として、有名でない言語・処理系は採用しにくいということもあり悶々としていたという。ちなみに当時はまだGo言語が発表されておらず、「これがGoなら…」と思うことはなかったし、Goの発表を聞いても、いくら筋がよくても未熟で普及していない言語なので採用されることはなかっただろう。

しかし、当時、Goの1.1がstableになっていたら…と思うと非常に残念な気持ちにもなるし、なかったものは仕方ないのだと諦めもついている。

僕自身は、libcへの依存を排除して全て静的リンクするところが一番気に入った。簡単なので実際に試してみてほしいのだが(これはMacの例なのでLinuxならotool -Lの代わりにlddとすればよい)、

$ go build hello.go
$ otool -L hello
hello:
$

という風に、依存ライブラリが全くない。ここから分かるのは、Goでライブラリの依存性で困ることは全くないということだ*6RubyPythonなのでもたまに依存ライブラリで苦労することはあるだろうが、CやC++の動的リンクに比べたら全く大したことない。
もうひとつよかったのは例外がないということだ。Cはデフォルトで例外安全な言語だ。それだけの理由でC++を嫌う人もいるし、多くの規約が例外の使用を禁止している。panic / recover の処理をdeferで先に設定できるというのはこれまでになかった発想で、例外処理を分離できてよいのかもしれない。個人的にはクロージャは便利だけど、コンテキストやスタックの内容がわかりにくくなるので好きじゃない…

気になるのはネットワークやディスクのI/Oまわりの実装だ。せっかくgoroutineがあるのだから、goroutineと非同期I/Oを組み合わせて同期I/Oっぽいプログラミングができるようにしたらよいと思うのだが、@methaneの話を聞いているとどうもI/O待ちをしている間はPは手放すけどネイティブスレッドは一人捕まえておくようになっているらしい。それだとI/O待ちをしているgoroutineが1000とか10000いたときにどうにもならないと思うのだが、もうちょっと調べた方がよいだろう。
あとはGCか。グローバルに共有できる変数を宣言できるしMutexなどの並行プリミティブがあるのでどういう挙動を示すのかよくわかっていない(勉強が必要)。メモリ空間を多くのgoroutineで共有したときにGCが終わらない問題が出るだろう(それがDerekがスタックを推していた理由でもある)。

しかし型宣言を後置でつけるのはどうしても理解できない。前につけたらいいじゃないか。テンプレート型がないのはC++で苦労したからなのかもしれないが、やっぱり僕はこんな風に型を記述したい*7:

fold_left :: (fun a b -> c) [a] b -> c

したいです。あとは、goroutine supervision treeをつくるために spawn_link という関数を用意すべきだ。

まとめると、マルチコアを使いつつネイティブコードで動作させたくて、かつ金融的なデリバティブ評価関数を書くのでなければGoを使えということだ。

*1:そのためのDalvik VMなのだろうが、そもそもJVMJavaも…

*2:FSFって、僕のような人間からすると実態がよくわからない、かといってLLVMってAppleの息がかかっているような気もする

*3:幸運なことにみんなJavaが嫌いだった

*4:この「リアルタイム」はクラシックな意味の方です

*5:既に動いているシステムは偉大だ

*6:組み込みではまだサイズが大きくて困るケースもあるだろう

*7:どこのソースを見たら

ビッグデータの倫理

これまで、個人のプライベートに関する情報は計算機の貧弱さと古典統計学の強力さの合間にあってほぼ安全といっていい状態であった。我々は大衆として形式化・典型化されて統計処理されていたが故に危険から遠かった。目立つことをして大衆から出る杭になると全く事情は違っていて、大衆の圧倒的な暴力によって車輪の下であwせdrftgひゅjとなっていたものであった。
…が、近年の計算機の処理能力の発展によって事情は大きく変わった。全体の傾向をつかむためのパラメータを定量的に評価するのではなく、個人にある程度フォーカスした計算(いわゆる全数集計・全数シュミレーションといった体のアレ)が強力な効果をもち、莫大な利益を齎すようになった。らしい。私も直接携わったことはないから知らん。

それで、個人のフォーカスすることができるということは、その情報処理能力によって危険も近くなった。昔から諜報といえば公刊情報の分析が6割以上を占めたものだが、その延長で公刊情報の分析を小ピュータにさせることによって諜報活動としてもコンピュータによる計算は強力であるということが分かるだろう。それでは、誰もが諜報や犯罪といった危険に近くなったとき、守るべきものは何か、正義とは何か、はたまた社会はどうあるべきか…といった哲学的・社会的な議論と合意をしなければならない。こと近代においては、科学技術はいつも人間の社会制度や哲学的認識の一歩先を行くものだから、なおさら急がなければならない。急いでどうにかなるものでもないかもしれないが。

とにかく、そんなときに我々に求められる倫理とは…という問題意識でこの本を読んではダメだ。どちらかというと実践的な内容で、ビッグデータ(笑)で儲けたい個人・法人がどのようなことを実践すればよいかが問題と対応付けてツラツラと書いてある。本書の目的はデータを正しく扱い、儲ける?ためのフレームワークをつくるのが目的なのだそうだ。

Ethics of Big Data

Ethics of Big Data

古典から現代の哲学や倫理学の流れの中で位置づけて議論した本が待たれるが、まあIT業界の人そういうことはあまり興味ないのだろうな。倫理学の許可を得てからでないと技術を実現できませんなんてのはゴメンだが、哲学界の人はもっと科学技術の知識を持っているべきだし科学技術界の人はもっと哲学書を読むべきだ。カネにならないけど、そうしたらもうちょっとよい世界になるんじゃないかと希望して。

「翻訳書の根本的な問題点は、ある言語から別の言語への完璧な写像は存在しないということだ。今のところ知性という写像を利用するしかなく、その翻訳書の品質は写像の知性に依存する」民明書房、"Why translation book sucks"

話はかわるけど、これが初めてまともに読んだ電子書籍iPhoneで簡単に読めるから悪くないのだけど、電車の中で10分ずつとか読むには若干…な種類の本ではある。