Dec 21, 2011

Cloud Foundry の Services について

この記事は Cloud Foundry JP Advent Calendar 21日目の記事として投稿です.えっ,投稿時間が過ぎているって?GMT ではまだ 23 時ですよ :)

概要
Cloud Foundry では,MySQL や RabbitMQ などの,デーモンとして起動するソフトウェアを "Service" として定義している.本稿では,Service の構成と概要について説明する,

何故 Service が必要なのか
アプリを立ち上げる毎に,PCのリソース確認して, MySQL を立ち上げる場所を決めて,テーブル作って,アクセス権限して,っていうルーチンワークを作成するのは面倒ですよね.その場所を自動化するのが Servicesである.

Service の実態について
1つのServiceは,2つのパーツから構成されている.
  1. Service Proxy
  2. Service Node
Service Proxy は,Cloud Controller からのリクエストを受け付けて,Service Node とのひも付けを行う.Service Node は,Service Proxy からのリクエストを受け付けて,実際にService インスタンスの割り当てを行う.全体像を把握するために,vmc client,CloudController,Service Proxy,Service Node,Message Bus (NATS)の関係を以下に示す.



vmc コマンドと挙動をのマッピングを示すと,
  1. vmc create-service : Service Proxy 経由で,自分用の Service を Service Node から割り当てる.
  2. vmc bind-service : Service と app をひもづける.
  3. vmc delete-service : Service を削除する.
といった具合になる.なお,create と bind の順序を別コマンドにすることで,複数アプリから 1つの Service (たとえば,DB)に対してアクセスする,といったことが可能になる.もし,RabbitMQ を複数アプリから共有すればアプリ間の連携が可能になるだろし,MySQL を複数アプリから共有すればユーザ情報を共有する,といったことが可能になるだろう.

まとめ

Services について,必要な理由とその仕組みについて大まかに説明した.Cloud Foundry ではデプロイだけでなく,アプリ間の連携もできるように設計されている.そのため,Cloud Foundry ユーザは煩わしいデプロイや管理の手間を最小化し,アプリを作成するのに集中できる環境を手に入れることができるだろう.

Dec 6, 2011

RabbitMQ の高可用構成について

本稿は CloudFoundry Advent Calendar の 6日目の記事として投稿させて頂いています.

本当はどの辺りをいじったら CloudFoundry から RabbitMQ を cluster setup できるのか調査…したかったのだが,そこまで終わらなかったので,VMware つながり && 昨日の y_wakai さんによる RabbitMQ の記事つながりで, RabbitMQ のクラスタセットアップについてまとめておく.

RabbitMQ は 2.6.x から複数台による Active-Active Standby 構成をとることができる.以前は DRBD による Active-Stanby 構成しかとれなかったので,2.6 以降で,より柔軟性が上がっている.

前準備
最新の RabbitMQ をインストールするには,http://www.rabbitmq.com/install-debian.html が参考になる.インストールが終了し,RabbitMQ がマシン h1, h2, h3 で動作していると仮定する.
まず,高可用構成をとるには,RabbitMQ のインスタンス識別子である cookie を同一にしておく必要がある.Debian の場合,cookie ファイルは /var/lib/rabbitmq/.erlang.cookie にある.もし編集していない場合は,

h1 $ echo "cookie" > /var/lib/rabbitmq/.erlang.cookie
h2 $ echo "cookie" > /var/lib/rabbitmq/.erlang.cookie
h3 $ echo "cookie" > /var/lib/rabbitmq/.erlang.cookie

などとして,クラスタに参加させたいノードの cookie を併せておく.

前知識
高可用構成のセットアップに入る前に,いくつかクラスタセットアップに必要なクラスタのノードの種類について説明する.クラスタのノードの種類には RAM ノードと Disk ノードの2種類がある.その名前の通り,RAM ノードのキューの状態はメモリの中にのみ保存され永続化は行われない.一方,Disk ノードのキューの状態は外部記憶に永続化される.ただし,複数台 Disk モードで動作させたとしても,複製はディスクに書くことを保証しないので注意.DRBD の Bモードで動作させている状態だと思えば良い.高可用構成のクラスタ内には,最低でも1台の Disk ノードが必要なので注意.

高可用構成のセットアップ
高可用構成のセットアップを行うには. rabbitmqctl コマンドを用いる.

h2 $ rabbitmqctl stop_app          # Erlang は起動させたまま RabbitMQ プロセスを停止
h2 $ rabbitmqctl reset             # RabbitMQ の保持している状態,および DB を初期化
h2 $ rabbitmqctl cluster rabbit@h1 # rabbitmq@h1 をディスクノード,rabbitmq@h2 をRAMノードにしてセットアップ
h2 $ rabbitmqctl start_app          # RabbitMQ プロセスを再開

これで,h1 をDiskノード, h2 を RAMノードにしてセットアップが完了した.
ポイントとしては, rabbitmqctl cluster で選択したノードが Disk ノードになることだ.
クラスタの状態を調べるには rabbitmq cluster_status を使う.
h1 $ rabbitmqctl cluster_status # クラスタ設定を調べる
[{nodes,[{disc,[rabbit@h1]},{ram,[rabbit@h2]}]},
 {running_nodes,[rabbit@h1,rabbit@h2]}]

h2 $ rabbitmqctl cluster_status
[{nodes,[{disc,[rabbit@h1]},{ram,[rabbit@h2]}]}, {running_nodes,[rabbit@h1,
rabbit@h2
]}]


disc,となっているのが Disk ノード,ram となっているのが RAM ノードである.
3台構成でも同様に行ける.

h3 $ rabbitmqctl stop_app          # Erlang は起動させたまま RabbitMQ プロセスを停止
h3 $ rabbitmqctl reset             # RabbitMQ の保持している状態,および DB を初期化
h3 $ rabbitmqctl cluster rabbit@h1 # rabbitmq@h1 をディスクノード,rabbitmq@h2 をRAMノードにしてセットアップ
h3 $ abbitmqctl start_app          # RabbitMQ プロセスを再開

h1 $ rabbitmqctl cluster_status 
h2 $ rabbitmqctl cluster_status
h3 $ rabbitmqctl cluster_status
h1 と h2 など,複数ノードを disc ノードにしたい場合は,
rabbitmqctl cluster rabbit@h1 rabbit@h2
とすれば良い.

ついでに,昨日の記事にもあった Bunny のライブラリについての補足もしておく.
Bunny のドキュメント中には,リモートの RabbitMQ の接続を行う方法が記述されていない.その方法を知るには,コードを読んで追いかける必要がある.以前調査を行ったので,以下に,リモートの RabbitMQ に接続して enqueue, deque するサンプルを示す.ポイントは,Bunny.new する箇所で :host でホストネームを渡してあげる部分.
#!/usr/bin/env ruby
require "bunny"

if ARGV.size < 3
  puts "Arguments Error! "
  exit(1)
end

hostname = ARGV.shift.to_s
num = ARGV.shift.to_i
msgsize = ARGV.shift.to_i

b = Bunny.new(:host => hostname, :persistent=>false, :immediate=>true)
val = "a" * msgsize
# start a communication session with the amqp server
b.start
b.tx_select
# declare a queue
q = b.queue("test1")
# declare default direct exchange which is bound to all queues
e = b.exchange("")


def push(b, e, num, val)
  num.times do |num|
    # publish a message to the exchange which then gets routed to the queue
    e.publish(val, :key => 'test1')
    b.tx_commit
  end
end

def pop(q)
  while msg = q.pop(:ack => true)[:payload]
    if msg == :queue_empty
      break
    else
      q.ack
    end
  end
end

push(b, e, num, val)
pop(q)
というわけで,次回こそは RabbitMQ と vcap のについて追いかけて説明したい.


Nov 12, 2011

OSS を運営する上でのルールについて

最近 Accord という ZooKeeper like な OSS をリリースした.その中で,「OSS として守るべきルール」を学んだのでまとめておく.以下の内容は他の人に使われることを目標とした Linux 的な開発に話が偏っているかもしれないので,注意されたし.

学んだことは,以下の3つ.
  1. 基本,議論は ML ですべき.
  2. コミッタであろうとなかろうと,変更はすべて ML に投げる.
  3. ターゲットとしている層の自然言語でドキュメントを記述する.
1, 2 について.

本当の OSS なら,開発がオープンであることをアピールする必要がある.ソースが github に上がっていても,開発プロセス,議論が不透明な場合はコミュニティから不満が出るだろう.Eucalyptus が良い例だ.

また,コミッタのあなたにとって都合が良い変更でも,他のデベロッパにとって都合の悪い変更もあるかもしれない.都合が悪い変更を見たデベロッパは思うだろう...「言ってくれれば良かったのに」,と.あなたがコミッタであっても,議論,変更を隠したままコミットしたら,それは職権乱用であり,信頼を失ってしまうだろう.

"気にくわないなら fork してコードを改変すれば良い.それが OSS" というスタンスの人も居るかもしれないが,fork されたコードのメンテナンスは fork した本人で行う必要がある.もし似たようなプロジェクトがあれば,皆はfork するよりも,よりオープンな競合プロジェクトに移る方を選ぶだろう.

もっとも,競合のプロジェクトが存在せず,独占状態であるのであれば話は別だ.でも,それならプロプライエタリソフトウェアとして商売した方が成功する可能性は高いように思う.

3. について.

当然だが,英語圏の人に使ってもらいたいのに ML やドキュメントが日本語のみだったら使ってもらえない.まずは,狙っている層で ML/ドキュメントを整備すべきだ.


まだまだ自分も配慮しきれていない点も多いので,気をつけたい.その他に気づいた点があったら,追記していく予定.

Nov 7, 2011

Thunderbird で受信したメールに対して git am する


git am を用いることで,git format-patch で作成された Singed-off-by (署名)付きのメールをパッチを直接現在のブランチにマージできる[注1].Mew などターミナルベースのブラウザを使っている場合は問題ないが,ローカルの Thunderbird でメールを管理している場合,パッチをどう Export したら良いのか不明だったので調査した.

結論から言うと,
1. git-format-patch スタイルのメール( [PATCH 0/5] )のソースをThunderbird で表示し,0000.patch - 0005.patchとして保存する.
2. git am 000[1,2,3,4,5].patch 

とすれば良い.もう少し格好の良い方法があれば良いのだが.

[注1] git merge コマンドや git apply コマンドはお手軽ではあるが,パッチを書いてくれた人の署名が消えてしまうので著作権上よろしくない.

Nov 5, 2011

スケーラビリティ自体に魅せられちゃいけない

自戒を込めた日記.

IT システムというのは何らかの問題を解決するために存在している.しかし,技術的な面白さから,システム自体にとりつかれていしまう人々が存在する.多くの場合,それは "hacker" と呼ばれている人々に多いように思う.それ自体はすばらしいことだ…仕事にさえしなければ.

仕事の場合,ユーザはITシステムを問題を解決するために導入している.中身がどうなっているかは知ったこっちゃない.言い換えると,ユーザがシステムにお金を払ってくれるのは「実際にある問題を解決しているから」である.「決して技術的に楽しそうだから」ではない.

さて,ここ1-2年で NoSQL という技術が流行している.RDBMSの提供しているセマンティクスのうち一部を弱めて,RDBMS では得ることが難しかった利点を得られる技術と心得ている.例えば,Cassandra は一貫性を犠牲として可用性を高め,さらに数百インスタンスまで書き込み性能がスケールするという.ここで一つ考えてほしいのは,そんなスケーラビリティが必要なサービスがどの程度存在するか,である.

最も分かりやすい例は,MapReduce 2.0 である.彼らは次世代 Hadoop で1万台のスケーラビリティを目標としているが,それを利用するユーザはどこに居るのだろう.恐らく,そのユーザは彼ら自身以外には存在しないのではないだろうか.技術的には面白いし,楽しいかもしれないが,その恩恵を預かるユーザは限りなく少ないであろう.

言い換えると,次世代 Hadoop (のうち,特にスケーラビリティの部分)は,プロダクトとしてのインパクトはさほど大きくない,むしろ小さいのではないだろうか.
  • 何のためのスケーラビリティなのか.
  • 何のための可用性なのか.
  • 何のための機能なのか.
研究をする上で,これらを自身に問い続けなければならない.さもなければ,使えない研究成果が世に出てしまうだろう.これを心に留めて,研究をしていきたいと思う.

P.S システムの話を主にまとめてみたが,これはエンドユーザ向けのサービスにもいえることだと思う.つまり,「これまでのサービスで解決されていなかった問題を新しいサービスで解く」というものでなければユーザはつかないだろう,ということだ.

Nov 3, 2011

fluent-logger-scala について

fluent-logger-scala の設計についてまとめておく.
概要図は以下の通り.
|fluent-logger-scala| <-- |Serialized JSON over TCP| --> |fluend|

検討事項
  1. 通信部分のシリアライズ方式について
    MessagePack-Scala は以前試したところインストールに失敗したため,JSON を用いる.ライブラリは com.twitter.util.JSON を用いる.
  2. スレッド構成について
    fluentd への書き込みは,ネットワークを介するためブロックする可能性がある.ログをとる部分でブロックしてしまうと,アプリケーション性能に大きなインパクトを与えてしまう.この問題を解決するため,送信用 Actor を用意する.fluent-logger-scala をセットアップすると,送信用 Actor(スレッド) が立ち上がる.
  3.  バッファ管理について
    自前で管理するのはしんどいので,com.twitter.util のリングバッファ(com.twitter.util.RingBuffer.scala)を採用する.
  4. エラー処理について
    今のところは指数的にリトライの時間を増やしていく方式をとる.
  5. API
    初期バージョンでは, Log.setup, Log.log,Log.close のみを実装する.
後は,実装が終わったらここに追記する予定.

Nov 2, 2011

RabbitMQ のクライアント

RabbitMQ  のクライアントについて調査したので,主観をまじえてまとめておく.
まずは python.
  1. pika : 一番枯れている RabbitMQ クライアント.ドキュメントを見る感じだとbasic_publish() が非同期に呼べなさそうであった.
  2. puka : 操作をすべて非同期で処理を行えるために pika を再設計したクライアント.しかし,まだまだ安定していない.
次に Ruby.
  1. amqp : AMQP 0.91準拠のクライアント.AMQP の仕様がそのまま実装されており,高機能な分学習コストが高い.
  2. carrot, bunny : 同期操作のみを行える AMQP クライアント.bunny の方が開発が盛んなようである.同期操作しか実装されていないため,シンプルで安定している.
コードを含めた解説は後で書く.pika が安定しているが,非同期呼び出しができなさそうなので悩ましい.現在 ML に問い合わせ中なので,判明し次第追記していく.



#include <stdio.h>
int main(void)
{
    // Hello World!
    printf("Hello World !");
}