ページ

2010年11月30日

Tweetボタンを動的に作る

最近は至る所でTweetボタンを見かけます。Tweetボタンってこれね。


こんな感じのボタンはよく見かけます。で、今しこしこ作っているものはこの、Tweetボタンが憑いています。そして、WebSocketとかAJAXで動的にごりごりこのTweetボタンをつけたいのであります。Tweetボタン自体の説明は、公式サイトに事細かに書かれていています。基本はhtmlのaタグにクラス名をtwiiter-share-buttonってつけてhttp://platform.twitter.com/widgets.jsをロードしてあげれば、aタグがかっこいい(?)ボタンに生まれ変わります。これって、ドキュメントをロード後のこのクラスのaタグの要素に対して操作しています。ということは、AJAXとか、ドキュメントをロード後に追加したAタグは残念ながら今時のボタンにはなってくれません。

Google先生にお伺いすると、Creating Tweet Buttons Dynamicallyという記事に動的に追加する方法が書いてあります。jQueryを使っていますが、僕の作っているものもjQueryを使っているので、同じようなものです。記事のコードをそのままのせるのも悲しいので、AJAXでHTMLの断片がとれてきたものを加工することにします。

コードはこんな感じ。fragmentはAJAXで取得した断片をinsert_pointというIDの要素に追加しています。
var newelem = $("#insert_point").append(fragment);
newelem.find('a.twitter-share-button').each(function(i) {
    var thisTweetButton = new twttr.TweetButton($(this).get(0));
    thisTweetButton.render();
});

このfragmentの中にAタグの要素があります。こんな感じ。

<a href="http://twitter.com/share" class="twitter-share-button" data-count="none" data-via="liris" data-lang="ja">Tweet</a>

それから

<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>

はヘッダーの中に一回書いとけばいいです。これで、動的にTweetボタンが追加されていきます。めでたし、めでたし。
まあ、こんな感じになるだけです。まだ、よく止まります。それから止めます。もし見るんだったらChromeかSafariの最新版かFirefox4.0ベータでプロキシのない環境だとちょっと楽しいかもよ。

でわでわ。

2010年11月22日

mongodbのmap reduceを使ってみた

MongoDBにはMap Reduceを簡単に使う機能があります。それ以外にコレクション(テーブル)にgroupというメソッドが定義されていて、RDBMSのgroup by相当のことができるとマニュアルには書かれています。ただ、次のような怖い注意書きがあります。

注意: 現在のところ、shardの環境では、group()の代わりにmap/reduceを必ず使ってください。
結果はなるべく小さくしてください(10,000キー以内)。大きすぎる場合例外が発生します。
Shard環境では問答無用にMap Reduceを使うしかなさそうです。結果はなるべく小さくしろと言うことですが、10000キーあればそこそこ大きいような気がします。最初の制限の「現在のところ」というのが気にならなくもないですが、処理結果はMapReduceと大差ないし、MapReduceの方がもう少しいろいろできそうな気もします。たとえば、結果は実行後すぐに取得できますが、これをコレクションとしてMongoDBの中に永続化するとかです。なので、groupメソッドはいらねんじゃね?Map Reduceだけで十分じゃね?と思います。

さて、それで、MapReduceですが、map関数とreduce関数をJavaScriptで書くだけです。PythonでもJavaScriptです。はい。それ以外にもfinalizeするときのメソッドも定義できます。マニュアルをよむと、結果で平均値を求めたりするらしいです。reduceの中でやっちゃえばいいような気もするので、あまり使い道を思いつきません。

それじゃ、コードのお時間です。
import pymongo
import pymongo
from pymongo.code import Code
conn = pymongo.Connection()

tbl = conn.my_db.my_table

m = Code("""
function() {
  emit(this.url, this);
}
""")

r = Code("""
function(key, values) {
  var total = 0;
  var len = values.length;
  for (var i=0; i<len; i++) {
    total += values[i].count;
  }
  var url = values[0].url;

  return { count:total, url: url};
}
""")
res = tbl.map_reduce(m, r
for r in res.find():
    print r["value"]["count"]

my_tableは、urlとcountというフィールドを持ちます。それぞれ文字列と数字です。map関数はmです。これは、URLをキーとしてemitしてます。valueはめんどいのでレコード自身です。rがreduce関数になります。これは、valuesはemitしたvalueが配列になって渡されます。一個づつイテレートしながらcountの光景を求めています。終わったら、countとurlを返しています。
map_reduceで実行すると結果として、コレクションが返されます。このコレクションに対して、findなどいろいろできます。結果を永続化するにはout="result"という引数をmap_reduceに追加してあげればよいです。簡単です。
新しく作られたコレクションは、keyとvalueという二つのフィールドからなります。キーはreduce関数に渡されたものです。valueはreduce関数が返したものです。
group関数を使った場合は、結果が配列ですべてオンメモリで返されます。ソートを行うにしても自前でソートしないと行けません。いやんですね。

まあ、groupは使わずにmap reduceでよくね?という話です。
でわでわ。

2010年11月20日

そのうちMacPortsをuninstallする

homebrewでいい気がしてきたので、MacPortsをアンインストールするための来るべき日のためのメモ。アンインストールする方法がMacPortsのページにのっているのは、好感がもてます。
とりあえず、今インストールされているものをメモっておきます。
$ port installed > installed.txt
そのあと、portでインストールしたものをアンインストールします。
$ sudo port -f uninstall installed
最後にディレクトリや残骸のゴミをすてます。
$ sudo rm -rf \
    /opt/local \
    /Applications/DarwinPorts \
    /Applications/MacPorts \
    /Library/LaunchDaemons/org.macports.* \
    /Library/Receipts/DarwinPorts*.pkg \
    /Library/Receipts/MacPorts*.pkg \
    /Library/StartupItems/DarwinPortsStartup \
    /Library/Tcl/darwinports1.0 \
    /Library/Tcl/macports1.0 \
    ~/.macports
よし、これでHomebrewに乗り換えられそうです。

2010年11月19日

flask + gevent + websocket

ざっと3分間Google様で調べたところ、FlaskでWebsocketを扱うものはまだないらしいです。まあ、Flaskじゃなくてもwsgiを使っている何かでもいいのですが・・。

悲しいというか、使いたかったので、とりあえず、書いてみたものがこれです。以前geventでWebSocketを使ったもののコードをちょっとだけ変更したものです。といっても、myappでリクエストを受けて、websocketのパスでなければFlaskのアプリケーションに流し込んでいるだけです。パスの扱いが若干かっこわるいですが、変に処理するよりは単純なものの方がいいです。

以下、コードの抜粋です。chat用のhtmlは前回と同じなので、省略しています。まあ、大した話じゃないですね。

from geventwebsocket.handler import WebSocketHandler
from gevent import pywsgi
import gevent
from flask import Flask, request, flash, render_template, url_for
from flask import session, redirect, g
from flaskext.babel import Babel, gettext

app = Flask(__name__)

chat_html = """
[省略。chat用のhtmlです]
"""

chat_clients = set()

def handle_chat(ws):
    chat_clients.add(ws)
    while True:
        message = ws.wait()  
        if message is None:
            break
        for client in chat_clients:
            client.send(message)

    chat_clients.remove(ws)

@app.route("/")
def index():
    return "hello"

def myapp(environ, start_response):
    path = environ["PATH_INFO"]
    if path == "/":
        return app(environ, start_response)
    elif path == "/chat":
        handle_chat(environ["wsgi.websocket"])
    elif path == "/chat.html":
        start_response("200 OK", [])
        return chat_html
    else:
        return app(environ, start_response)

if __name__ == "__main__":
    server = pywsgi.WSGIServer(("", 5000), myapp, handler_class=WebSocketHandler)
    server.serve_forever()


2010年11月13日

tweepyでtwitterのstreaming APIを使う


OAuthの問題などのせいで、twitter apiのライブラリとしてtweepyを使っています。以前作った「ありえるたん」は実用的ではないので、もうちょっと自分が欲しいというか、やってみたいことがあったので、そのためにStreaming APIを使ってみました。Streaming APIはtweepyでもサポートされているので、そのまま使うだけです。Stream APIって、名前の通り、streamで処理します。接続を張りっぱなしにして、イベントが起これば勝手にデータが流れてきます。Twitterのインフラはどうなっているんでしょう?すごいですね。

Streaming APIは、
1. listenerのオブジェクトを作る
2. Streamオブジェクトを作る
3. filterメソッドなどで検索させる
4. 1で作ったlistenerオブジェクトにイベントがあがるので、各イベントに対して処理を記述する

とう流れになります。


import sys
import tweepy

class StreamListener(tweepy.StreamListener):
    def on_status(self, status):
        print status.user.screen_name.encode("utf-8") + " : " + status.text.encode("utf-8")

def main(argv):
    user = "my_twitter_id"
    passwd = "my_twiter_password"

    listener = StreamListener()
    stream = tweepy.Stream(user, passwd, listener)
    stream.filter(track=["http"])

if __name__ == "__main__":
    try:
        main(sys.argv)
    except KeyboardInterrupt:
        pass

StreamのListenerはon_dataでデータを受信したときにイベントが上がります。on_statusでtweetがヒットしたときの処理が実行されます。他にどんなイベントがあるかは、忘れました。on_dataは引数で渡ってくるものはjson形式の文字列なので、自分でパースしないといけません。on_statusはStatusオブジェクトが渡されます。。
イベントが来たときに、コールバックで処理を記述するだけなので、簡単ですね。きっと。

StreamのコンストラクタにユーザIDとパスワードとリスナを指定します。で、filterメソッドをコールすればtracで指定した文字列を検索して、ヒットすればコールバックが呼ばれます。このAPIはブロックします。asyncでTrueを渡してやると非同期で処理するみたいです。

まあ、とっても気軽にStream APIを使えるのはすてきです。
でわでわ

2010年11月12日

JVM言語のFantom - fantomのfanは大好きのfan

Fantomは最近注目されている(?)新しい言語です。これは、そう、僕らみんなが大好きなJVM上で動きます。Javaは偉大です。(棒読み)。Fantomのfanは楽しいのfanです。これだけで、楽しくなってきました。さすがはJavaです。(やっぱり棒読み)

さて、この言語ですが、シンタックスはJavaっぽいですが、Javaではないです。Javaっぽいので、世界中にうじゃうじゃいるJavaプログラマにはとても取っつきやすい言語です。で、なんでJavaっぽいならJavaじゃいけないの?って、誰もが思います。理由はいくつかありますが、FantomはJVM上で動きますが、それだけじゃなくって、.netのcli上でも動きます。PythonやRubyなど既存の言語で両方で動くというのは聞いたことがありますが、新規の言語で両方で動くというのは珍しいかと思います。

で、Javaじゃだめなの?っていう理由のもう一つですが、基本的にFantomは静的な型付け言語ですが、ローカル変数などは型宣言を明示しなくてもよいです。このあたりは、golangとよく似ていると思います(思想的にもシンタックス的にも)。Java(というかほとんどの静的型付け言語)でめんどいな〜、と思うところが改善されています。インターフェースになる部分には型は明示されていた方がコードは書きやすいですが、ローカル変数までそれをやると冗長なだけです。

あとはAPIが洗練されていると書いてあったりしますが、そのあたりはそんなに主張するところじゃないでしょう。それから、JVM上で動く言語は既存のJava資産が使えるって声高に主張している人がいますが、Thriftをみていると、わざわざJVM上で動かさなくてもいいんじゃないか?と思ったりもします。

それじゃ、前置きが長くなりましたが、それそろ始めます。一応、Mac上で動かしてます。Javaのランタイムはすでに入っているという前提で・・・。まあ、XCode入れれば勝手にはいるし。

1. セットアップ
ダウンロードは、先ほどのページにダウンロードのリンクをクリックして、ダウンロードします。ダウンロード後、アーカイブを展開します(xの部分は適当なバージョン番号)。
$ unzip fantom-x.x.xx.zip
さて、このあと、システム全体にインストールしてもいいのですが、メインで使うわけもないので、やめます。とりあえずは、展開したディレクトリのbinディレクトリにPATHを通せばいいです。
$ export PATH=$path_to_bin_dir:%PATH
binディレクトリの中のファイルには実行属性がついていないので、つけてあげます。で、exeファイルがたくさんあってうっとうしいので、消しちゃいます。
$ cd $path_to_bin_dir
$ chmod +x *
$ rm *.exe
これでおしまい。

2. 動作確認
セットアップが終わったら動作確認です。fanshというしょぼいインタラクティブシェルがついてくるので、それでおきまりのHello, World.です。
$ fansh
Fantom Shell v1.0.55 ('?' for help)
fansh> echo("Hello, World!")
Hello, World!
fansh> quit
$

おー、動きました。

3. ざっとした文法とか・・・
みんなJavaプログラマなので、ここのサンプルコードをみれば、10分で理解できます。JavaプログラマじゃなくってPythonとかそれ以外のプログラマなら8分で理解できます。なので、省略します。ちゃんと勉強したいという頭の固い人は、こちらからどうぞ。
型がすべて大文字で始まるのですが、Voidっていうのは何度見てもキモイとか、言わないの!

4. ちょっとだけ
インタラクティブシェルで書いたHello, Worldをfantomのスクリプトファイルとして書いてみましょう。次のコードをhello.fanとして保存して、fan hello.fanとして実行します。
class MyScript {
    static Void main() {
        echo("Hello, World")
    }
}
まず、ファイルの中のトップレベルはclassでなければなりません。Javaの悪しき風習は守られています。ただし、一つのファイルの中に沢山classをつくれるので、すべての悪を引き継いだわけではありません。
で、実行がめちゃくちゃ遅い。Javaのバイトコードにコンパイルするからです。遅い理由もうなずけます。golangがコンパイルスピードまでこだわったのとは対照的です。

もう一個。
class MyScript {
    static Void main() {
        s := gets
        s = s[0..5]
        echo(s)
        t := Script()
        echo(Type.of(t))
    }
    static Str gets() {
        return "hello, world"
    }
}

なんとなく雰囲気がわかるとおもいます。配列のスライスとか、Javaと違ってすっきりしています。それと、Map型(Pythonの人なら辞書)も[]で表記します。こんな感じ。
[1:"ichi", 2:"ni", 3:"san"]

便利そうなんだけど、空のMapを作るのはどうするんだろう?

5. もっと
fantomはconcurrentがちゃんとサポートしているとか言っています。マルチスレッドで動くときは同じメモリを参照するものは自動で排他制御tかimmutableな変数して扱うとか、Actors model for message passing (Erlang style concurrency)とか、言っています。

それ以外にもGUIをサポートしていたりとか・・・。まあ、Javaの人にはわりと取っつきやすい言語じゃないかな?

2010年11月10日

クラウドエクスポ

アリエルのブース。お昼時で人がいないときにとっています。人がいたときに撮った写真はうまくとれてません。
この写真のブースはバイク王じゃなくって、アリエルのブースです。コンパニオンのおねーちゃんと写真を撮りました。

コードの読まれ方がわかっても工数見積もりに寄与するのか?

「コードの読まれ方が分かった」、工数見積もり精度向上に寄与」という記事は、はっきり言っておもしろくありません。まず、コードリーディングでの結果から導き出されたことを纏めてあるのですが、導き出されたことはごく当たり前のことで、全く新鮮味がありません。新鮮味はないかもしれませんが、定量的にそれらが証明されたらしいということは評価できるとおもいます。「らしい」と言うのは、上の記事からは数字なども示されていないので、判断できなくって、書いてあることを信用するだけだからです。

全体的には悪い記事じゃないんですが、工数見積もりの精度向上とか書かれていると、タイトルとしては気持ちはわかるんですが、身構えちゃうのは心が汚れているからでしょうか? 


「追加、修正行数だけによる工数見積もりは難しい」を実証

とあるんですが、見積もりする方からすれば最初に行数はわからないなので、それをベースに見積もるようなこの表記はちょっとおかしんじゃないかな? と思ったりもします。

そんなことを言っても何も生まれないし、上の表記も完全な間違いじゃいのでアリエルではどんな風に工数見積もりしているかを書いてみます。ちなみに、新機能の追加だけです。バグ修正は調査工数が見積もれないことがあるので範囲外です。

さて、どんな風に工数見積もりしているか?それはほとんど職人の経験によって決めています。で、経験をもとに何を判断しているかと言えば、

1. 影響を受けるモジュール

すべてはAPIのように階層的な構造をもっていて、下のレイヤーは上のレイヤーの知識を知らない状態です。また、OO的に開発していて、隠蔽は進んでいます。といっても影響する範囲はそこそこでるものです。そのあたりをざっと判断します。

2. 変更するソースコードの規模の判定

影響を受けそうな範囲がわかったところで、ソースコードの規模をざっと見積もります。影響を受けるモジュールなんてのは丁寧に時間をかければ調べればわかりますが、 これは、うーん、みんなどうやっているんだろう?こっちは経験としか言いようがないと思います。

3. 単体テストの規模と結合テストの規模

修正や機能追加自体は、アリエルの人の場合はすぐです。ものにもよりますが、一週間は割と長い期間です。 でも、実装の後にテストがあります。単体テストと結合テストの規模は、上の二つを元にやった方が良さそうなことをあらいだして、どれくらいか見積もります。これは、以前のテストケースの量などをいいわけにして、やっぱり経験で決めています。

こんな感じだと思いますが、割と意識せずにやっているので、間違っているかもしれません。うーん、うーん、なんか結局、経験という名目の勘のような気がしてきました。 



2010年11月9日

オフィスの引っ越し前で・・・

アリエルは中目黒には7年ぐらいいました。その間、紆余曲折あったわけですが、人数も増えてきて手狭になって五反田に引っ越したのが2年前です。12月のクリスマス直前に引っ越したので、正確には2年たっていません。

それが訳あって、2週間後に六本木に引っ越すことになりました。理由は聞かないでください。人がこれ以上入れなくなりそうだからです。スペース的に。

つい最近五反田にやってきたつもりなので、とても早くオフィスの引っ越しという印象です。あんまり実感はないのですが、引っ越し用の段ボールが大量に積み上げられているのをみると、えーと、なんて言うか、そのー、一言で言えば、「めんどいの〜」。

僕の持ち物の準備はたぶん、10分ぐらいでおわります。引き出しとか机の上のものを乱雑に段ボールの中に押し込めて、PC関係は適当に包むだけなので・・・。私物じゃないので、壊れても構わないと思っているので、気が楽です。

本とか、会社の荷物は若い衆がきっとやってくれるので、指示を出すだけです。サーバ関係は、マスター浜岸という人がほんとど趣味として面倒見てくれます。 そういえば、ちょっと古いPCが大量に破棄されるので、ほしい人はとりに来てくれればプレゼントしてもらえるかもしれません。古いものは10年近く前の今はなきSotecのマシンもあるので、お一つどうでしょうか?

オフィスの引っ越しの風物詩と言えば、新しいオフィスの席取りですが、なぜか今回は一部の人の独断と偏見できました。偉い人と、偉そうな人の席が決まってから、残りの人の席が勝手に割り振られました。まあ、どこに座るかは強制じゃないので、とりあえずの荷物の届け先だけ確定しておけばいいのです。

うーん、五反田、割と気に入っていたんだけどな・・・。次に引っ越すときはマウンテンビューあたりがいいです。



MongoDBのベンチマーク@おうちのiMac

Membaseのベンチマークが遅かったのですが、VMWareのせいかも?とか、思わなくもないので、MongoDBでも同様におうちのiMacでも計測してみました。コードは、以前の記事のものをほぼ、そのまま使用しています。

で、早速結果のグラフです。

左側はサーバをローカルのマシン上で動かしています。左側はVM上で動かしてます。ローカルではmembaseは動かしていません。ごめんなさい、ごめんなさい。

まず、フェッチのスピードですが、MongoDBとMembaseでほとんと違いがありません。MacBookAirで動かしたときは、MongoDBは0.4秒ぐらいでしたが、それにくらべて速いです。MacBookAirで計ったときのmemcacheとの相対比では2から3倍でしたが、ほぼ同じです。ローカルでは0.2秒でmemcacheに比べて約3倍、でも、vm上だと10倍の開きがあります。
localのフェッチの時間よりVM上のものが1.5倍ぐらい遅いです。CPUというよりディスクIOの違いかもしれません。でも、インサートはlocalよりVM上のものの方が速かったりします。意味がわかりません。不思議です。memcacheもやっぱりローカルのものよりVM上のもののほうが速いです。これもわけわかめ。vm上のものが速くなる理由は全く見つかりません。コンパイラの差?Mac Portsだめ?Gentooのようにコンパイラオプションをいじりまくって最速を目指すべき?

うーん、解釈に困るデータです。ローカルのデータだけにしとけばよかったです。仮想環境は難しいです。

まとめると、MongoDBは検索はmembaseと同じぐらいの遅さで、インサートに関しては、membaseよりはかなり速いです。でも、memcacheに比べると十分遅いので、単純にmemcacheの置き換えにはむきません。Mongoの検索のスピードはmemcacheにくらべて環境に依存して3から10倍遅くなるので、インフラ周りなどで注意が必要です。いずれにしても、membaseは機能の割には遅いので、使わないのがいいでしょう。

iMacのHDDをSSDにして動作を見てみたいと思う今日この頃です。redisのベンチマークもしろという声も聞こえてきますが、めんどいし、もっとやりたいことがあるので、ベンチマークそろそろお開きです。

2010年11月6日

membase、めちゃくちゃ遅い?いや、遅すぎ?

最近はいろいろとベンチマーク的なことをやったりして、それが仕事なのか趣味なのかよく分からない日々を送っています。しかも、会社の人はみんな忙しそうにしているので、暇そうなのはCTOと僕ぐらいです。そんなこんなで、自分で手を動かしている訳ですが・・・。

さて、membaseが気になるお年頃で、membaseとmemcacheで速度比較してみました。以前、repcacheとの速度比較もしたのですが、データをなくしちゃったというか、ほとんど劣化しなかったので、とってもつまらなかったです。membaseもmemcache互換プロトコルをサポートしてくるので、コードを書き換える必要はありません。会社で試したときは、うまく動かなかったのですが、家ではちゃんと動いています。何が違うのでしょう?

まず、membaseの独断と偏見の特徴は次の3つです。
  • クラスタ構成
  • memcache互換プロトコル
  • レプリケーションとデータの永続化
それでは、ベンチマークします。コードは以前の記事で使ったこれです。測定環境は、家のiMacです。会社のマシンより遥かにいいマシンです。えへん。memcache,membaseのサーバはVMWare上のUbuntu 10.10で動かしています。なので、ネットワーク構成がブリッジになっています。

で、membaseはdata bucket(データの保存形式)が二つあります。一つがmembaseのオリジナルのもので、もう一つがmemcacheです。違いがあまりわからないのですが、memcacheはon memoryということでしょうか?

で、測定結果です。

まず、addする時間。1000回addした時の平均ですね。テーブルにするのがめんどいので普通のリストで書きます。ごめんなさい。
  • membase (membase bucket) : 0.32 m sec
  • membase (memcache bucket) : 0.22 m sec
  • memcache : 0.034 m sec
まず、addする時間ですが、memcacheに比べて10倍遅いです。なんど計っても、違いがありません。memcacheのbucketなら多少速いですが、memcacheと比べるとやっぱり遅すぎます。

それでは検索というか、フェッチするスピードです。
  • membase (membase bucket) : 0.30 m sec
  • membase (memcache bucket) : 0.22 m sec
  • memcache : 0.032 m sec
検索もやっぱり一桁遅いです。membaseはとても魅力的な機能を持っていますが、10倍の速度差は許容できないです。多分、一般的にmemcacheより10倍遅ければ、APIが同じでも全体の作りを変えないといけません。
MongoDBがより複雑なことをしておきながらKVSとして使う場合2から3倍の速度劣化しかないのにくらべると、やはりmembaseは納得できる遅さではありません。

ということで、membaseはmemcacheの代替ではなく、使いどころをちゃんと考えないと行けないです。
でわでわ。

2010年11月5日

リーダにふさわしいかチェックしてみた

ちょっと古い記事になりますが、「あなたはリーダーに相応しいか」の7つのリストをやってみました。このチェックリストが本当にリーダーに相応しいかどうかを反映しているか、知りません。

1. 人に好かれたいという思いが強いか

うーん、 いきなりすごい質問です。好かれたいかどうかで言えば、ほとんどの人が好かれたいと答えると思います。でも、説明に書いてあるように必要なことであれば実行する、ということであれば、実行するかな。まあ、そんなに好かれているとは思っていないけど。

2. 民主的な管理体制を築き、合意に基づいて決断を行うというスタイルに価値を見出しているか?

最初の質問と違ってこっちは答えやすいです。少なくとも僕のプロジェクトの運営は民主的ではなかったからです。いいことだとは思っていませんが、すべての最終的な決定は合意ではなかったです。でも、合意に基づいて行った方がモチベーションが上がると思う場合は、合意したように見せかける努力はしたような気がします。時々、誘導したと言われますが。

3. 難しい会話のことを考えると夜も眠れなくなるタイプだろうか?

うーん、そういう理由で眠れなかったことはないな・・・。 

4. 中間管理職というものは、上位の管理職とチームの板挟みにならざるを得なくなるということを理解しているだろうか?

中間じゃなくても、いろいろと板挟みになるような気がする。ちなみに、僕は中間管理職になるんだろうか?

5. 会議の場で立ち上がり、話をしなければならないと考えると、胃が痛くなるだろうか?

日本人に対して英語じゃなければたぶん、胃は痛くないです。そういえば、家族で海外に行ったとき、「パパの英語、ママより下手くそ」と言われました。

6.  思いやりであっても、過ぎたるは及ばざるがごとしとなる場合もあるという事実を受け入れることができるだろうか?

言いたいことがあんまり、わかりません。「リーダーであれば誰でも、遅かれ早かれ、相手にとって嬉しくないことや、不公平なこと、筋の通らないことを言ったり、行ったりする必要が出てくるからだ。」というのは、まあ、そういうものです。 筋が通らないこと、っていうのはちょっと違うと思うけど・・・。

7. 人生において、「バランス」は重要な位置を占めているだろうか?

うーん、仕事を私生活より優先させて、何が残るんだろう?起業したとかいうならともかく、単なる中間管理職に対して何を期待しているんだろう?

 



2010年11月4日

MongoDBのshardとreplica その1

MongoDBのshardingとreplicaについてのメモ。間違っていたらごめんさい。

まず、MongoDBの負荷分散、もしくは、データの分散については、shardingという仕組みで行っています。shard自体は通常のmongodのプロセスです。各shardには、データがchunkの単位で保存されています。chunkは、キーに対してデータの連続性が確保されているので、連続したデータへのアクセスが高速化されます。一つのmongodのプロセスにchunk単位以上のデータがセットされたり、サーバの数が増加すると、他のshardにデータが自動的に移動します。この仕組みだけをみると、shardは増えることはあっても、減るのは苦手のように聞こえます。

shardが自動でデータの分散を行ったり、どこにデータがあるのかを見つけるためにconfigサーバがいます。mongodが実データを扱うのに対して、configサーバはメタデータを扱います。メタデータは、shardなどのサーバの情報とchunkの情報です。configサーバはchunkの情報を更新するために2フェーズコミットを採用しているようです。また、製品レベルで運用する場合は、3つのconfigサーバを別々のマシンで動作させておくように言っています。configサーバがいないと、shardでのchunkの更新は行われなくなります(データの移動などが行われない)。

mongosというプロセスが、shardのフロントエンドに配置されます。mongosはconfigサーバとやりとりして、クライアントからのリクエストなどをどのshardに送信するか決めます(ルーティング)。また、複数のshardにリクエストした場合は、それらの結果を一つに纏めてクライアントに返します。


レプリケーションは各shard単位(replica set)で行われます。各shard内のmongodはprimaryとsecondaryのプロセスにわかれます。mongodのプロセスがreplica setに追加されると、データは自動的にコピーされます。masterのプロセスが落ちた場合は、自動的にsecondaryのmongodがmasterに昇格します。一度昇格すると、設定で降格させられないか、敵前逃亡してプロセスが死なない限りは、masterのままです。複数のsecondaryがいる場合は、どの順番にmasterになるかは、設定によって自動的にきまります。

server1,2,3とあった場合、データAはserver1と2、データBはserver2と3、データCはserver3と1のように分散させて配置するパターンもありますが、MongoDBはshard単位でreplicaを制御するようになっています。
単純なKVSとしてみた場合、configサーバをみれば、データがどこにあるか判別できるのは速度的にすてきかも。

その2に続くかも。でわでわ。

2010年11月2日

MongoDBとmemcacheのパフォーマンス比較

単純なキー・バリューの構造でパフォーマンスがどうなのか、memcacheと比較してみました。mongodbとmemcachedはそれぞれ、ローカルの一台のちびえあたんの中で動かしています。比較するためのコードは、次のところにあります。
Javaのコードは恥ずかしいので公開しません。計測はちびえあたんでやっています。
やっていることは、MongoDBではnoとbodyというフィールドにデータを設定して、10000件登録しています。memcacheでも同様にキーにシーケンシャルな数、値にMongoDBでセットしたものと同じ値をいれてaddしています。
登録にかかる時間は、MongoDBでは1.39秒で、一件あたりにすると0.139ミリ秒です。memcacheは1.86秒で、一件あたり、0.186ミリ秒です。ほぼ誤差の範囲内のような気もしますが、若干MongoDBの方が速いです。
MongoDBはデータベースが空の状態から開始しているので、一番最初はファイルの作成などで遅くなっているので計測から外しています。

次に検索です。MongoDBでは、0から10000までと10000から0までのキーで検索しています。それぞれ、インデックスのありなしでも計測しています。その結果のグラフです。縦軸はミリ秒で、一回あたりの検索にかかった時間です。

インデックスのない状態で検索スピードが大きく違うのは、ファイルの先頭からフルスキャンして、見つかるまでやるからです。find_oneでやっていますが、findで検索するとデータ量に比例して一律遅くなると思います。
これに対してインデックスをはると、データ量にかかわらずほぼ一定の値になります。グラフがつまらないので、そのデータは載せていませんが、一件あたりの検索時間が0.4ミリ秒前後です。
memcacheの検索の時間は大体0.19ミリ秒でした。検索の時間はMongoDBでは2倍から3倍弱遅いです。この性能差をどう見るか・・・?うーん、難しいです。

次はmembaseを計測しよう!と思ってhomebrewのパッケージにはなっていなかったので、やめました。

でわでわ