日曜日, 12月 23, 2012

【BPStudy#64】RDBじゃだめな理由を2つほど このエントリーを含むはてなブックマーク

皆さん、昨日はお疲れ様でした。 また、運営していただいたBeProudの皆さん、ありがとうございました。

10人くらいだったら完全非公開にしようと思ったんだけど、30人くらい来てくれたので公開することにしました。 UST録画はこちら



BDBの代わりにRDBのインスタンスを複数配置するんじゃだめなの?というのはよく聞かれる質問だけど、昨日も当然のように質問された。

いつもうまく答えられなくて歯がゆいけど、それは、O/Rマッパーも必要なくなって、RDBを導入管理する必要がないから。だけど、そこはやっぱり伝わんなかったかな~。

O/Rマッパー無くしてソフトスキーマで


開発の4割がマッピングといわれ、 それに、テーブル設計、正規化、SQL、チューニングなど、 ほとんどがデータベースまわり。要は、これを全否定したいわけ。 直接オブジェクトを格納するわけだからO/Rマッパは不要になる。

 昔、EUC(Enduser computing)とか言ってたっけ。 
Lotus Notesでアプリ開発したことある人ならわかると思うけど、 RDB不要な感じでスキーマを自由に作れる開発環境は、(流行ってるかどうかは別として)、珍しいものでも何でもなく、一度経験するとその高い生産性に慣れてしまって、もう元には戻れなくなる。RDBは大変な負荷だったんだと気づく。

最近では Google App Engineや最近ではBaaSといったWebサービスもソフトスキーマで、アプリケーション内で自由に項目を設定できる

ACIDのDどうすんの?

   だって、APサーバごとにRDB導入するわけにはいかないでしょう? だから普通はDBサーバのインスタンスを分けようという話になる。でもそれだけでスケールするんだったら苦労なんてしないわけ。 
 結局、AP側にキャッシュを入れようという話になって、今だとRedisが使われるじゃないですか。で、永続化すればI/Oが詰まるので、どう溜めるかをよく考えないといけなくなる。つまり、ACIDのDをどうするか。トランザクションリカバリーとか、むしろ障害対策を頑張って作る必要があるんだけど、皆さんどんなふうに解決しているんだろうね。Append only fileで頑張ってる? まあ、2.4で非推奨になったVirtual Memoryを自力で作るぐらいの覚悟があれば大丈夫なんだろうけど。
 一方のBDBは、DBMSと同等のACIDがあるので、トランザクションログからのリカバリもDBMSと同じようにできる。単純なログファイルに書かれるだけだから、スケールアウトして複数ノードになったとしても運用はチョー楽チンだ。

BDBは、他のKVSと比較して特別に速いもんじゃないし、高機能というわけじゃない。
でも、APのプロセスで動作する一つのjarがあって、処理自体は当然メモリー内で実行されるからキャッシュ技術と同等のパフォーマンスぐらいは出せる。また、APサーバ内だけで完結するからDBサーバは実質的になくても動作する。この辺りが魅力かな。

ついでにスクリプト言語も(ry


もうそろそろ、サーバはデータを返すだけでよくないか? 

Javaなんかダセーって、一方で、HTMLタグが混在したスクリプト言語のソースを堂々とgithubで晒している。そして、パフォーマンスを競って、サーバのレンダリングを一所懸命チューニングしている。 どうかと思うよ。

twitterの例はあるとは思うけど、レンダリングはクライアントでもう十分だろ?

こんな感じで、乱筆すみませんでした。

みなさん、よいお年を。

火曜日, 12月 11, 2012

ReflexWorks開発における選択と集中の話 このエントリーを含むはてなブックマーク


何事も選択と集中が大事です。時間もお金も人も無限にあるんだったら何も苦労しません。私たちは、ReflexWorksを作るにあたって何を自作すべきか、あるいは他を利用する方がいいのか、色々悩みながら開発してきました。

標準化技術は採用すべきでしょうし、車輪の再発明は避けるべきでしょう。それは当然です。私たちも無い機能は作るし既にあれば利用させていただくという方針で基本的にはやっています。

かつてJava全盛の時代は楽でした。単にJavaの標準化技術を後追いすればよかったからです。でも、今はなかなか思うようにいきません。

10年ぐらい前からJavaの動きに鈍くなり、後追いだけでは対応できなくなってきました。
今盛んに訴えられている、JavaScriptやThin Server Architectureの重要性の話なんて(私には)4年ぐらい前のメッセージに聞こえます。

ReflexWorksもThin Server Architectureが基本ですが、既に大規模事例があり1年以上前から運用されています。
ということはどういうことか。システム構築開始は2年前で、ReflexWorksの開発はもっと前ということです。

今、JavaのThin Server Architectureに影響を受けた人が、これからフレームワーク作ってシステム構築して運用したとして、評価されるまであと何年かかるのでしょう?そのときデビューして果たして競争力はあるのでしょうか。(ReflexWorksに競争力があるとは到底思ってませんが・・)

JSONにしても2006年時点では自作するしかありませんでした。シリアライザもXML pull parserもXStreamを改造して使っています。
でも、これは当時の事情でしかたなくです。今ではご存知のようにJAX-RSなどのJavaの標準APIがあります。でも遅いんです。

今更、それに準拠するためだけにフレームワークを修正することは、少なくとも私たちにとっては無意味です。
それは、ReflexWorksフレームワークのテストには数年、数百人月という膨大な工数が費やされており、高い品質を維持しているからです。
品質は不具合の数だけでなくパフォーマンスやセキュリティなど総合的な評価が大事です。いくらJava標準といっても品質が高いとは限りません。

テストがきちんと実施され本番でも期待通りに動作している。これが最も価値ある状態であり、これでやっと他のお客様にも自信をもって最高のパフォーマンスを提供できるのです。

一方で、そのクオリティをさらに高める努力をしていくつもりです。継続的に投資していきます。

例えば、MessagePack対応。

ReflexWorksのボトルネックである、通信とシリアライザと永続化の3つの大きな要素のうち、通信とシリアライザについてMessagePackを採用することで大きな改善を見込めます。

残る永続化の部分ですが、私たちはKVSをゼロから作るなんて無謀なことはいたしません。世の中にある優れたKVSを利用しようというスタンスです。
現在はOracle BDB JEと、Google App EngineのDatastoreの2つを採用しています。(選択できます)

Oracle BDB JEを採用している理由は信頼性です。いい意味で枯れており、情報が豊富で、何よりOracleの技術サポートを受けられます。(保守契約が必要)
FAQを見ていただけるとわかりますが、トランザクションログのリカバリやトラブルシューティングも大変わかりやすく運用も楽です。

BerkeleyDB JE FAQ

トランザクションはロック方式ですが、現在はそれほど大きなボトルネックになってはいません。(他の改善効果に比べて低い)

パフォーマンスに優れたKVSは他にもいろいろありますが、トランザクションをサポートしており、かつ安心して利用できるという点で、BDB JEには一日の長があると考えています。

とはいえ、私が知らないだけかもしれません。他に信頼性に絶対的自信のあるKVSがあればぜひご紹介ください。
ちなみに、次の候補としては、Amazon DynamoDBを検討しております。



月曜日, 12月 10, 2012

バーチャルがリアルに語ります。本物のクラウドを。 このエントリーを含むはてなブックマーク


BPStudy#64の集まりが悪いので決めました。 少人数だからできる本音トーク。資料も上げたりしません。tweetもやりません。ふっふっふ。 プライベート・クラウドは良くないアイデアっていうけれど本当は凄いこと。規模の経済性だけでは語れない、本当のプライベートクラウドのメリットは確かにある。それを僕は今回のプロジェクトで体験した。 この感動を来てくれた皆に伝えたい。

300万トランザクション/日を処理するスケールアウト型オンライン帳票システムの仕組み



Agenda(案) ※内容が変わる可能性があります
  • 分散KVSについて
    • なぜ分散KVSを採用したか
      • RDBのインスタンスを複数持つんじゃだめなの?
      • RedisやMongoDB、Cassandra、HBaseじゃだめなの?
    • 分散KVSを業務アプリで使うには
  • トランザクション処理
  • スケーラビリティ
    • シャーディングのPros/Cons
  • パフォーマンス
    • 本当のボトルネックはどこか
    • Thin Server Architecture
      • 動的コンテンツをサーバで作成しない
      • 帳票作成においてサーバに負荷をかけない
  • 可用性
    • ミッションクリティカル。でも実際は・・。
    • 実際に障害に遭遇した話
  • まとめ
    • 全体最適解としてのプライベートクラウド

土曜日, 12月 01, 2012

ajn22のBTで発表してきました このエントリーを含むはてなブックマーク


ajn22、皆さんお疲れさまでした! 

また大変盛り上がって楽しかったですね〜。ajnのこの独特の楽しい雰囲気の源は一体なんだろうといつも思います。単なる事例紹介とは違って、秒間最大2000reqを処理する大規模なサービスだったり、SharededCounterの議論だったり、機械学習だったり、あるいは、クライアントMVCやリアクティブプログラミングといったことを、皆さん独自の視点や発想で研究実践され、そしてそれが惜しげもなく披露される。それは刺激的です。 

そりゃ、勉強も大事ですよ。並列分散トランザクション技術やリアルタイム処理、関数型言語・・・、いろいろ勉強しないといけない。でも、それらは実際に使われてナンボなわけで、そこからは実践的なプラクティスはなかなか生まれてこない。

ところがajnでは実際に数億のトランザクションを運用していてCounterがボトルネックなんですよ〜という話が出てきて議論が始まり、そこで、実はShardedCounter がいまだにベストプラクティスということを知るわけ。過去議論したSkiplistとか、Memcacheの利用、あるいはロックフリー技術とか駆使して何とか解決できればいいのだけれど現状はまだまだという感じ。これは大きなテーマだから今後もぜひ研究していきたいところですね。私自身、モチベーションの原点を再発見した感じです。 

あと、DEMOを見ていただいた方にお願いです。

以下のFacebookページにもいいねしてあげてください。(昨日言い忘れてました)


公報一括ダウンロードサービス

以下にTwitterのまとめと僕の資料を置いておきます。
それでは。







金曜日, 8月 17, 2012

ぶいてく流 スケーラブルアプリの作り方 2012 (前編) このエントリーを含むはてなブックマーク

明日のクラウド温泉3.0@小樽の発表資料の前編(導入部分のみ)を公開しておきます。ちょっと詰め込みすぎて1時間以内に終わらないこと確実なので・・・。あらかじめ読んでおいていただけると嬉しいです。

日曜日, 7月 08, 2012

RESTに関する3つの間違い このエントリーを含むはてなブックマーク

楽観的排他制御を利用する非同期的なトランザクション実行であればスケーラビリティを損ねることなく2phase commitが可能である。これは、分散KVSにおけるスケーラビリティと一貫性の両立について で主張したように、同期的な2phase commitは密結合に誘導することになるため、矛盾するように思えるかもしれない。だがそんなことはない。
前半はまずこの話から入るが、後半ではRESTに関する間違いについて、3つほど思うところを述べたい。

楽観的排他制御と2phase commit

 reflexworksではFeedやEntry単位でatomicなトランザクション処理を行えるが2phase commitはサポートしていない。これを許すと密結合になってスケールしないからである。だが、これはあくまで同期的な処理の話であって、ネットワーク障害への耐性を考慮され、非同期処理やオフラインで使えるのであれば2phase commitでもスケールすると考えている。
 RESTにおける2phase commitについては、REST におけるトランザクションについて (Re: Web を支える技術) が詳しい。
トランザクションレイヤを RESTful に表現する手法は理解しておいて損がないものだと思います。具体的には、
  • トランザクションの開始は POST を使ったトランザクションリソースの生成
  • トランザクション開始後は POST ではなく PUT を使い、クライアントがリクエスト ID を指定することで、ネットワーク障害への耐性を確保
  • トランザクションのコミットも再送可能じゃないと困るので PUT
  • コミットの返り値を確認してからトランザクションリソースを DELETE
といったあたりが基本になると思います。
ポイントは、クライアントがリクエスト ID を指定する点。IDはPOSTで返却されたリソースIDになるが、楽観的排他制御のためには、論理シーケンス番号 (LSN)も同時に必要になるはずだ。
もう少し具体的に説明しよう。

reflexworksでは、LSNに該当するものはリビジョン番号であり、POST /buy でリソースURL(/buy/934085,1)が返却される。(この,1がリビジョン番号で更新の都度+1される)次に、 PUT /buy/934085,1 を実行。もし既に更新されていたらリビジョン番号不一致となるため、409 conflict(optimistic locking failed)が返る。DELETEも同じくリビジョン番号を指定して実行する。
前述の例では自分しか更新しない前提ではあるが複数回実行される可能性は考慮すべきところで、べき等性の保証が必要なのだが、この場合は楽観的排他エラーで「既に更新されています」というメッセージを出してあげる方が親切だと思われる。
ちなみに、同一リソースURLでリビジョン番号も同じであれば、システム全体で同じものであることが保証されている。これは、複数のノードに散在するデータの整合性を保証するためのreflexworksの基本的な考えにもなっている。(エンタープライズクラウドにおけるスケールアウトの現実解

また、POSTはリソース作成時にのみ使い、PUTは既存のリソース更新に使うのはrelfexworksも同様である。「 一般に、リソース作成時に PUT を使うべきでないとされる理由は、クライアント間で名前の競合が発生する可能性があるから」という理由はもちろんだが、CRUDの4つは明確に区別したいという理由もある。SQLにおいても、INSERTとUPDATEは区別されている。

RESTはステートレスでなければならないか

さて、ここからRESTの3つの間違いの話に入る。
ステートレスはRESTの原理原則であり、実際に疎結合にすることでシステムはスケールラブルになる。私は、ステートレスをスケーラビリティ確保の絶対条件と考え、reflexworksではセッションは使わない方針を貫いてはいた。そして、ログイン処理においてさえセッションIDは使わずに都度認証することを徹底していた。たしかにステートレスにするとスケールはする。だが、最近は度が過ぎるとかえって不自由な設計を招いてしまうことになることがわかってきて、逆にセッションはアリなんじゃないかと思うようになってきた。

はっきりいおう。私は間違っていた。


一つは、ユーザログイン管理において毎回認証を実行させる必要があり、擬似的なセッションIDを発行する必要があったこと。具体的には、認証に成功したら新たに時間制限をつけたcookieチケット(ワンタイムパスワード)を発行し擬似的なセッションIDで対応していた。また、そのチケットはあくまでログイン認証用であり、セッションオブジェクトは管理しないようにしていた。ユーザにログイン入力を強要させるわけでもなく、名前もStateless Session ID(SSID)にしていた。
 しかし、ユーザIDとワンタイムパスワードを含むトークンを毎回クライアントと通信してやりとりするのはセキィリティ上よろしくない。私は頑にステートレスを守る一方でセキュリティをないがしろにしていたわけだ。
 また、パフォーマンスも悪くなる。
前述した2phase commitでは、払い出したチケット(/buy/934085,1)は一時的な揮発性の情報であり、これらはむしろセッションオブジェクトかキャッシュメモリに置くべきである。こうすることで、パフォーマンスも格段によくなり、KVSとの間にメモリという緩衝材が入ることでI/O負荷も軽減できる。
というわけで、最近はRESTであっても必要最低限のセッションオブジェクトだけは認めてもいいと考えるになった次第である。実際に最新版のreflexworksでは標準のセッションオブジェクトが使えるようになっている。また、一時的なオブジェクトはなるべくキャッシュさせるような設計を推奨している。

リソースは本当にドメインロジックを必要としないか

2つ目の間違いはリソースとドメインロジックの置く場所についてである。
MVCの話のなかでも触れてはいるが、ドメインロジックはバウンダリだけでなくコントロールやエンティティの層においても構わない。



にもかかわらず、当初のreflexworksでは、リソースを特定するURLに対して単純なHTTPリクエストのCRUD操作(GET,PUT,POST,DELETE)しか用意していなかった。
これだと、例えばECサイトの金額チェックなどをサーバ側で行うことができない。金額を正確にチェックするにはサーバ側でマスター参照する必要があるはずである。たとえ認証を付けたところで、リクエストデータが正しいかどうかという話は別である。どんなに頑張ってクライアントでチェックしてもサーバ側では無条件では受付けられない。
だからといって、自由にサーバ側のインターフェースを作らせたくはない。
サービスを自由に作らせると、きっとこんな感じのインターフェースになってしまうだろう。

entry = getFoo(entry)
entry = updateFooByBar(entry)
・・・

これでは、サービス志向の二の舞になってしまう。せっかく、RESTでリソースを一意に定義できているのだから、こういう感じにしたい。

entry = Foo.service(entry)

 例えば、GET  /p/Foo?item=abc などと実行すると、/p servletが呼び出され、URLパラメータとentityにもとづいて処理されるといった感じになる。/p servletの中では、reflexContext.get("Foo");とすることで実際のリソースにアクセスできる。(もちろん、POST,PUT,DELETEメソッドもある)

ちなみに、/d/Fooに対して実行すると、/d servletが呼び出され、以前のバージョンと同様に、サービスは実行されずにリソースの内容がそのまま返される仕組みとなっている。(/dはdata、/pはproviderの頭文字)

最近では、単純にデータだけが提供される、BaaS(Backends as a Service)やDBaaS(Database as a Service)が流行っているが、本当にサービスのドメインロジックが必要ないか、よく検討して使うべきだろう。

イベントドリブンなアーキテクチャーは受け入れられるか

先日、MOVEが話題になった。
コントローラをOperationsとEventsに分けた方がいいという案だが、望まれなかった子にあるように、MVCの一つの解釈(あるいは間違えているの)であり、MVCを否定するものではない。
ただ、closureや、あるいは、Deferredのような非同期処理をなんとか中心に考えたいという気持ちもわからないでもない。

実は、reflexworksでもイベントドリブンな設計はいけると思った時期があった。実際にイベントをトリガーにサーバサイドJSを実行できる。でも開発者の多くが難しいと感じ、オーソドックスな方を好んだので、今は廃止しようと考えている。オーソドックスな方とは、前述したような単純な/p servletによるフィルターのような処理のことである。

単にユニークであることが使いやすいとは限らない。




また、コントローラをOperationsとEventsに分けるより大事だと思うのは、Modelをデータ(スキーマ)とドメインロジックに分けることである。スキーマは一貫させる一方でドメインロジックは各レイヤの最適な場所に配置させる。貧血症みたいなオブジェクトにはなってしまうが、それを恐れてはいけない。

以上が、RESTに関して私が犯した間違いの3点である。
だが、もしかしたら、こうやって原理原則を修正した結果、RESTのアーキテクチャーとは到底呼べないものになってしまっているかもしれない。だがそれでも構わない。なぜなら、これらは実務に落としたときに実際に問題となって一つ一つ解決してきたものだからである。

今流行のリーンスタートアップ流にいうなら、クールなアーキテクチャだと思って採用(Build)するのは結構なことだが、測定(Measure)して、学習(Learn)してから最終的に判断しないとだめである。それが本当に素晴らしいかどうかは、実務に落としたとき初めてわかるものだから。

<ご紹介>
reflexworks           <= 製品についてはこちら
reflexworksで分業開発しよう!  <= 開発案件募集中です


月曜日, 7月 02, 2012

KVS上でアプリを動作させるために必要なたった2つのこと このエントリーを含むはてなブックマーク

先の記事で、ReflexWorksにおけるデータ操作の方法について触れ、ツリー構造の仮想フォルダ管理とREST APIによるデータアクセスについて説明した。ここでは、もう少し掘り下げて、KVS上でアプリを動かすための条件とは何なのかについて考えてみたい。(たった2つのことといいながら長文失礼します)

SQL vs NoSQL: Battle of the Backends

タイムリーにも、Google IO でSQL vs NoSQL: Battle of the Backendsというセッションがあったようだ。ここでは、SQL(MySQL)とNoSQK(Datastore)を、Queries、Transactions、Consistency、Scalability、Management、Schemaの6つの項目について比較していて、前半の3つについてはSQLが、後半の3つについてはNoSQLが優れているという結果になっている。最後は両者同数でどっちもどっちだね、みたいな話になっているが、セリングトークも含まれるのでこれは真に受けて欲しくないとにかく、これまで主張してきた通り、トランザクションが増えるとRDBがボトルネックになり、オンライン処理ではそのうち限界になってくるはずだ。
 また肝心のパフォーマンスについては、「基幹系システムでCloud SQLは使えるか試してみた」を見てもわかるように、Datastoreとはまだ相当の差があるようだ。

とはいえ、丸山先生もおっしゃっているように、GAEでもMySQLが使えるようになったことは、まあ、それはそれで結構なことだとは思う。(ということでお茶を濁す)

アプリにKVSを意識させないことが大事

さて、今WebアプリといえばHTML5などのリッチコンテンツが主流である。クライアント上のネイティブアプリのように小気味好く動作することが求められている。またスマートデバイスではオフラインや非同期更新などもある。もはや、JSPやJSF、あるいはPHPでHTMLを動的に作るといった古いアーキテクチャーは通用しない。エンジニアは利用者に最大限のエクスペリエンスを与えようと頑張っており、UI/UXに多くの時間と労力をかけている。可能なかぎり画面だけに集中したいと思っているはずだ。なので、JavaScriptを中心としたフレームワークのムーブメントが今起きていると思う。

このような要求にもReflexWorksであれば対応できる。ReflexWorksは、疎結合を基本としているためクライアント開発者がUI/UXに専念できるように、なるべくサーバ開発を意識させないようにしている。クライアントシンプルなREST APIでサービスを呼び出すことだけ考えればよく、結果もJSON/XMLで取得できる。

KVSで業務アプリを動かす条件とは

冒頭で、GAEではDatastoreはよいがCloudSQLはビミョーであるといった。
一方、AWSのRDSやSQL Azureはまずまずのようだが、実は、Amazon DynamoDBや、Azure Storage Service(KVSの方)にもビミョーなところがある。

一つ目はトランザクション。
GAEではEG(エンティティグループ)のトランザクションが扱える。Azure Storage Serviceでも、同一テーブル、Partitionkeyのデータはトランザクション処理可能である。しかし、DynamoDBではトランザクションを扱えない。(ドキュメントによるとatomic counter程度はできそうだが・・)



http://www.slideshare.net/kentamagawa/amazon-dynamodb-11808513
クラウドのエンタープライズ利用を考えた場合、数msで返せるとか、数万qpsとかいっても単体のスループットであれば実はそれほど重要ではない。ブラウザ表示で数msと数百msの違いは感じられないので、単純にKVSパフォーマンス比較してもあまり意味はない。逆にどんなに高速でもトランザクション非サポートは痛い。トランザクション機能がないと結局は参照系など用途は限定されることになるため、単体性能は悪くてもノードを増やすことでリニアに性能向上できることの方がはるかに重要だ。たとえ数百msのレスポンスで数十tpsになったとしてもトランザクション機能とスケーラビリティは必須である

2つ目はセカンダリインデックス。
実はKVSであっても単純なkeyとvalueだけでなく高度な検索ができるようなものもある。例えば、GAEのDatastoreには、データがソートされて格納されている。そしてRANGE検索ができるため前方一致で検索できる。これはRDB(2次元)とKVS(1次元)の間の1.5次元の性質をもつというのだそうだ。(このあたりについては、kazunoriさんの記事:BigTableと分散KVS がとても参考になる)
キー検索以外にもプロパティ検索も欲しくなる。DynamoDBやAzure Storage Serviceでは、プロパティ検索は可能だが、GAEのproperty indexのような、Built-in indexが存在しないためプロパティ検索は全スキャンになってしまうようだ。これでは大量のデータ検索には使えない。




ReflexWorksにおける基本設計と検索について

元へ。クライアント開発では単なるJSON呼び出しなので、それほど苦労しないことは理解いただけたと思うが、サーバ側ではそれなりのサービスを準備するのが結構大変だと思われるかもしれない。だが、実はそんなことはない。以下に示すように、ReflexWorksはドキュメント指向でありORMは不要であり設計も単純明快だ。



ReflexWorksにおける設計の基本となるのはエンティティである。エンティティとは、簡単にいえば、一単位として扱われるデータのまとまりのこと。難しくいえば、貧血症をおこしたオブジェクトのこと(笑)。POJOでもJSONの連想配列でも何でもいい。とにかく、クラスやプロトタイプに複数の項目がプロパティとして付いているものをエンティティと呼んでいる。ただし、CSVのようにデータを列挙したものではなく、項目と値がペアになっておりまた親子関係も表現できる。

ReflexWorksでは、このエンティティにユニークなアドレス(URL)をつけることで、データ全体を階層管理している。そして、そのアドレスに対してREST APIで操作する。



BDBはセカンダリインデックスが使えるという(1.5次元の)KVSである。このセカンダリインデックスにより、様々なプロパティ検索やソートなどを高速に実行できる。

例) GET /d/{selfid}?{name}{=|.eq.|.lt.|.le.|.gt.|.ge.|.ne.}{value}&{name}{=|.eq.|.lt.|.le.|.gt.|.ge.|.ne.}{value}&...&l={n}


重要なことは、どんなに分散しても全体の階層管理は崩れず一貫した操作が可能になっているということ。RDBであればデータ量が増えるとテーブル分割などで頭を悩ませることになるが、ReflexWorksであればアプリはBDBのことを気にせず単にREST APIを実行すればよく、裏にあるノードの数なども気にする必要はない。

ReflexWorksにおけるトランザクション処理

トランザクションに関して説明する。
reflexworksでは、最小単位のentryにaliasという別名フォルダを複数付けることができ、またatomicな更新ができる仕組みを提供している。別名フォルダとは、/foo/doc1.xmlを/bar/doc1.xmlでもアクセス可能にする仕組みで、UNIXファイルシステムのシンボリックリンクだとおもっていただければ結構だ。


atomicity(原子性)、isolation(分離性)、consistency(一貫性)
  • (ATOMの)entryはトランザクションの最小単位であり原子性をもつ
    • つまり、RDBの1レコードに相当
  • alias(別名)の追加削除はentry内であるためatomicでありisolationが保たれる
    • 例えば、entryがフォルダ移動しても2重に見えたりはしない
  • 複数のentryはfeedで括られる
  • feedのPOST/PUTは1トランザクションで実行されるため、どれか一つでも失敗するとロールバックする(一貫性は保たれる)

例えば、本を買う例でいえば、本はカートに入れられるか、入れるに失敗するかでなければならない。あるいは、買うか買わないかである。




これは、フォルダをカートとみなせば、注文データ(Document)がフォルダ移動する問題に置き換えることができる。以下のように、異なるフォルダで同時に見えてはいけないし、どちらにもないという状態があってはいけない。




これを、reflexworksで実装すると以下のようになる。selfはこのドキュメントの実体があるフォルダを示す。(固定)一方のalternate(別名)のフォルダがfolder1からfolder2に更新されることで上記のフォルダ移動を実現する。entryの更新はatomicなので一貫性は保たれる。


最後に

KVS上でアプリを動作させるために必要なこととは、トランザクション処理とセカンダリインデックスの2つということを説明してきたが、あくまでこれはオンライン業務のアプリに関してであり、一貫性を必要としないような検索系のアプリなどは他のKVSを使ってさらに高速化できるだろう。あるいは、BDB以外でトランザクション処理とセカンダリインデックスをサポートするKVSがあるかもしれない。実はReflexWorksはBDBに特化したものではなく、他のKVS上でも動作するように、TaggingServiceとDatastoreはレイヤーを別けて作ってある。実際にGAE上でも動作するし、本当は、DynamoDBやAzure上でも動かしたいと思っている。 繰り返しになるが、ReflexWorksであれば、単純なRESTサービスのAPI実行になるため、下位のレイヤーがどのようなものになろうと開発者は意識する必要がない。また、こうすることでベンダーロックインを防ぐことにもなる。
 ちなみに、先日からFacebook上で開発案件を募集しはじめたので、あわせて紹介しておきたい。 


 ReflexWorksで分業開発をしよう! 
「HTML5や画面デザインなどをお得意とされている方は画面開発だけに集中し、サービスのことは考えなくて構いません。サービスの実装部分はJavaなので、サービス開発担当、もしくは弊社メンバーがお手伝いできます。お互いに得意なところを役割分担しながら分業開発できればいいなと考えています。」


金曜日, 6月 29, 2012

エンタープライズクラウドでも破壊的イノベーションを このエントリーを含むはてなブックマーク

昨日の記事はちょっとわかりにくかったと思うので補足したい。

RDB不要論

浅海先生よりコメントをいただいた。(ありがとうございます)

全くおっしゃるとおりで、「昔から普通にやってきたこと」で今でも大変有効な技術は多いと思う。ISAMやVSAMのKSDSにしても昔は実際にオンライン処理をやっていたわけだからできないはずがない。というより、もしかしたらRDBより向いているんじゃないか?というのが私の率直な印象。結局のところ、データの集計や分析では、わざわざRDBからデータ抽出してHadoopでバッチ処理するか、カラムナDBに入れ直すとかやっているわけである。実際、大規模トランザクションを処理するオンラインシステムでは「リレーショナル」機能はほとんど利用されておらず、まるでKVSのように使われているのが現状ではないだろうか。そう考えるとそもそもオンライン処理でリレーショナルは必要ないんじゃないかとさえ思えてくる。

それからもっと厄介なのがO/Rマッピングの件。オブジェクトの構造や関係性をリレーショナルモデルに効率よく変換できない問題(インピーダンス・ミスマッチ)があって、その結果作られた効率の悪いSQLが全体のパフォーマンスを劣化させてしまうという現状がある。
なので、やはり、O/Rマッピングなどの「癌」はアプリから排除すべきであり、そのためにはRDBではなくオブジェクトを直接ストアできるKVSを使うべきというのが私の意見である。それでやっと純粋にオブジェクトの世界だけでアプリを作れるようになるのだ。
 
また他方で、RDBはオンライン処理系から排除されてバッチ処理系の仲間になるわけだが、これは前述したとおり、カラムナDBにするか、いっそのことHBASEにしてしまうのがいいのではないかと思っている。そして、バックエンドのHBASEなどに対しては、今流行のFluentdを利用することで、うまくやれば、ほぼリアルタイムに更新可能になるかもしれない。ただし、データロスは許されないので信頼性の担保についてはもう少しよく検討する必要があるとは思うが。


これでいいのだ

データ操作と破壊的イノベーション

リレーショナル機能がないとしたら、データ操作をどうするかという問題が出てくる。RDBはなんだかんだいって、複合検索やソート、JOINといった、とても便利な検索が可能である。そして、これはアプリにとって大変重要で必要不可欠な機能でもある。

そこで、ツリー構造の仮想フォルダ管理とREST APIによるデータアクセスで解決することを考えた。実際にReflexWorksでは、以下のように、UNIXのファイルシステムのパスのようなイメージで直感的に操作でき、アクセス制御、共有設定、暗号化といった設定も可能である。例えば、GET /foo/bar/doc1.xml と実行すると、doc1.xmlを取得できる。(GETコマンドはリモートからのHTTPリクエストかローカルのAPIからのどちらからでも実行できる。また、doc1.xmlはATOM Entryを拡張したもので、様々な項目をユーザ自身で自由に追加できる。もちろんJSONも可能だ)ちなみに、GET /foo/bar とすると、barフォルダ配下のエントリが全てリストで取得でき、?item=hello* など、項目に検索条件を指定することも、前方一致検索、ソートなども可能だ。アプリで必要な機能はほぼ満たしており、リレーショナルを意識することなく、オブジェクトに集中して設計開発できるのは大変嬉しいところである。



RDB不要論とか偉そうに言っているが、実はこういった発想はGoogle AppEngineからいろいろ学んで得たものである。ひがさんの記事の破壊的イノベーションのような発想の転換があり、それから、コスト1/30でスケーラビリティの衝撃 で紹介したような実際にKVSで動作するスケーラブルなアプリが多数作られるにつれ、自信が確信に変わっていった・・。

CQRSとの比較

で、CQRSの話に移るが、恥ずかしながら、浅海先生から指摘されるまで知らなかった。
CQRSとは には以下のようにある。


CQRSは「Command Query Responsibility Segregation」の略語である。日本語で言えば「コマンドクエリ責務分離」もっと解りやすく言えば「更新処理と参照処理とに対する応答部分を明確に分離する」事である。構造としてSystemを次の四つに分類する。
  • Query(参照)
  • Command(更新)
  • 内部Event
  • 外部Event(公開Event)

これを読む限りにおいては、ReflexWorksはCQRSではないようである。
更新処理と参照処理はKVS内で完結するため分離ではなく同一である。KVS内であれば参照と更新を分けなくても高速に処理できる。どちらかというとRDBの負荷を軽減させるというよりRDBを無視して単独で動作するという表現に近い。また、MVCを否定しているわけではなく、MVCモデルは進化する で述べた以下の発想に基づいて設計されている。


ドメインサービスとしてのReflex BDB
Reflexの新3層アーキテクチャーにおけるドメインは、EntityCRUD操作以外の何ものでもないのだが、登録変更削除においては、「外から何をされてもデータの整合性が壊れない様にすること」がもちろん保証されなければならないし、検索においては、単なるPKによる検索だけではない点は補足すべきだろう。例えば、PK以外のKeyによる検索、大小比較、全文検索、Pagingといった検索などについては、要求仕様に応じて、それなりにドメインロジックを実装しなければならない。 まだ公表する段階ではないのだが、Private CloudのソリューションであるReflex BDBの次のバージョンにおいて、単なるKey/Valueの検索ではなく、ドメインサービスとして機能するようなものを作っている。内部的にはBDBなのでKey/Valueではあるが、GAEProperty Indexのような仕組みを追加することで、汎用的なKeyによる検索などができるようにするつもり。ちなみに、これはConsistent Hashと伝染プロトコルを使ったスケールアウトアーキテクチャーとなっており、Dynamoのようにそれぞれのノードを柔軟に追加削除できる。(予定)



この記事を書いたのが2009年10月で、完成してお客様事例になったのが2011年1月だから、まともに使えるようになるまで2年以上かかったことになる。現在、事例1 のお客様で
約100万件/日のトランザクション、約10万枚/日の伝票印刷を処理しているが平均500msのレスポンスを維持できている。(2012/10現在) 150万ops/日、99.96%が100ms以内のレスポンス
自分自身、その性能発揮ぶりに驚愕すると同時に、「クラウドを空想してあれこれ議論するよりも論より証拠。100の理論より1つの事例」ということをあらためて認識した次第である。

木曜日, 6月 28, 2012

エンタープライズクラウドにおけるスケールアウトの現実解 このエントリーを含むはてなブックマーク

企業のWebシステムの3-tierモデルでは、ロードバランサーを置くことで、複数のWebサーバとAPサーバに処理を分散させることが可能だが、ある程度の規模になると今度はDBがボトルネックとなりスケールしなくなる。 これを解決するにはどうすればいいのだろうか?ReflexWorksでは、DBMSに依存しないオンライントランザクションシステムの構築を可能にしている。そのポイントについて述べてみようと思う。

キャッシュ技術の限界

 DBMSのボトルネック解消手段としてよく使われるのがキャッシュ技術である。キャッシュ技術には、OSSのMemcachedや、JavaEE7のJCache、Oracle Coherence, WebSphere eXtreme Scaleといった商用製品などがあり、メモリキャッシュをAPサーバに置くことでDBのボトルネックを軽減させることができる。 なかには、トランザクションをサポートしているのもあり、読込だけでなく書込においても効果を発揮して、DBMSの負荷は大きく軽減できるようになる。

たしかに、キャッシュ技術を使うことで高速化(低レイテンシ)を実現できるが、一方で実は改善できるのは高速化した分だけ、という見方もある。頻繁に使うマスタ参照や数千tps以上といった大規模リクエストの緩衝機能として効果は見込めるものの、実際にキャッシュ読込のために最低1回はDBにアクセスしなければならず、永続化の問題(揮発性のためデータがロスする)やDBとの整合性の問題がある。また大規模なメモリが必要になるとコスト面でもメリットは少なくなる。つまり、キャッシュはあくまでキャッシュであり、リニアに無限にスケール拡張ができる技術とはいえないということである。

2008年当時、企業内クラウドは、最初は大手ベンダーによるキャッシュ目的で導入され、最後はアーキテクチャ変更をもたらす(参照)といったような楽観的な予測もあったが、いろいろ経験するにつれ、もう少し踏み込んだ発想をしないとブレークスルーはしないと私は考えるようになった。

主従逆転の発想

前述のように、キャッシュメモリをどんなに積んだって最後はRDBがボトルネックになるのは必然であり、これを解決するにはアーキテクチャー変更が伴うわけだが、だからといってRDBを否定してKVSで全部代用できるとは思えない。企業にはRDBのために特別に用意された耐久性に優れた高性能サーバが厳然と存在しており、今後もRDBがシステムの中心として君臨し続けることは間違いないからだ。Webの3-Tierアーキテクチャーも基本的には変わらないだろう。

しかし、オンライントランザクション処理に限っていうとトランザクション処理とデータストアの分離ができれば、スケールしないRDBを必ずしも使う必要はなくなる。つまり、単にRDBをデータの格納場所として使い、オンライン処理の基盤としては別のものを使うことで、RDBがボトルネックになるのを防ごうという発想である。

具体的には、キャッシュの発想をもう少し進化させたような感じで、APのKVS内だけでトランザクション実行を完結させ、RDBとはEventual に同期するような仕組みとすることで、RDBに負荷が集中することを防ぐ参照系(マスタ、トランザクションのREAD)はRDBへアクセスしなくてもKVS内で実行できるようにする。要はKVSだけでアプリの実行(READ,WRITE)ができるようにすること。これを実現するには、KVSでアプリのデータ操作をすべて賄える必要があり、ACIDトランザクション処理を確実に実行できかつ永続性を備えることは必須となる。

1.マスタ等をKVSに配置する。参照(READ)はKVS内で実行しRDBに参照しにいかない。
2.  トランザクションの参照(READ)はKVS内で実行する。RDBに参照しにいかない。
3.  トランザクションの更新(POST,PUT,DELETE)をKVS内で実行して保存する。非同期に更新結果をRDBに送信する。




この図を見てもわかる通り、実はWeb-AP-DBの3 Tierのアーキテクチャーは崩していない。ただAPサーバ内にKVSというトランザクション処理基盤を導入しているだけである。(3Tierというだけで企業にとってはずいぶん敷居の低いものに見える)

だがこうすると今度はRDBとの整合性が問題になる。RDBはEventualに更新されるためタイムラグが発生する。例えば、実際にはKVSで既に注文を受け付けているのに、RDBではまだ受け付けられてない状態になっているかもしれない。

実はここが最も重要なポイントで、整合性※などが問題ないように、うまく設計する必要がある。(※ 整合性と一貫性はどちらもConsistencyの意味で使われるが、私は、オンライン処理などの同期処理において矛盾の無いことを保証する場合に一貫性といい、非同期処理においてデータに矛盾の無いことを保証する場合に整合性といっている。この使い分けが正しいかどうかはわからない。)

1点目は、遅延を許容すること
 正のデータは常にKVS上にありリアルタイムに更新されているが、RDBは若干遅れて更新されることを前提に考える。オンラインの範疇はKVSまでとし、RDBから以降はバッチ処理と割り切ることができるかどうか。ここはeventually consistencyというと語弊があるので、単なる非同期更新と考えてもらえればと思う。

2点目は、整合性を保証するプロトコルとすること
 データはレコード単位に(システム全体で)ユニークかつバージョン(リビジョン)管理する。また同じデータが複数ノードに散在している可能性があり、RDBを更新する際は何回更新されても同じ結果になるようにする(べき等性)
 さらに、あるノード上のデータがRDB更新前にダウンした際にも、KVSのログ等からコミット分を抽出してRDBに反映できること。(トランザクションリカバリー)


ReflexWorksでは、データはユニークなIDとバージョン(リビジョン)番号で管理されており、整合性は常に保たれる。もともとスマホやChromeのオフラインアプリなどでネットワーク分断があっても整合性を保つために導入した概念だが、APとDB間を含むシステム全体で整合性を保証することにも利用している。






月曜日, 6月 18, 2012

分散KVSにおけるスケーラビリティと一貫性の両立について このエントリーを含むはてなブックマーク

先日、容易なスケールアウト拡張とトランザクションの正確性を担保する分散KVS基盤、ReflexWorksを発表した。(http://reflexworks.jp/)
エンタープライズシステムの多くは強い一貫性が要求されるため、これまではRDBMSを使うことが多かった。しかし、簡単にシステム増強できないことから、増え続けるデータに柔軟に対応できないという欠点があった。
分散KVSは、単純なキーとバリューのデータからなるデータストアを複数のマシンに分散配置したものである。これをデータストアにすることで、システム稼働後であってもサーバー資源を動的に追加できるなど、柔軟なスケーラビリティを実現できる。

ReflexWorksは分散KVSにBerkeley DB Java Editionを採用、システムをスケーラブルにしつつ、同時にトランザクションの正確性を担保しており、大規模なトランザクション処理が求められる企業システムの構築を容易にする。

ReflexWorksはスケーラブルな企業システムを構築するための実用最小限の製品(MVPMinimum Viable Product)である。

スケーラビリティと一貫性の両立について

CAP定理を勉強している方々は、スケールしながらトランザクション処理の正確性を担保するといった、ReflexWorksの特長に違和感を感じられるかもしれない

クラウドの多くは「ScalableAvailableで、かつ、Eventually Consistentなシステムは可能である。」というように、Consistencyの部分を緩くすることで実現しようとしてきたが、3つを同時に満たすなんてことは不可能というのがCAP定理の原理の原則のはずである。

ReflexWorksでは、容易なスケールアウト拡張とトランザクション処理の両立は実現しているが実はAvailabilityを若干緩めている。実際にノード障害があってフェイルオーバするまでの間は多少の停止時間があり、また、マスター更新の際は各ノードの同期を取るために運用を停止したうえで実行しなければならないなどの制約がある。

つまらん お前の話はつまらん



まあ、少し待ちなさい。
実際の運用で大事なのは、MTTRMean Time to Repair)つまりどれだけ早く復旧できるかである。
ReflexWorksは、特定のノードが故障するとシステム全体がダウンするような単一障害点はなく、サービスの継続利用が可能な仕組みになっている。また、障害により担当ノードにアクセスできなくなった場合でも自動的に他のノードに引き継がれるため障害の影響は部分的であり、再ログインは必要になるものの)ユーザ単位にリストアするため数分程度で復旧できる。実際の復旧時間で比較すればRDBのフェイルオーバよりも短いかもしれない。

Cloud = Scalability + Consistency!?

ミッションクリティカルな企業システムでは、非常に高い可用性が要求されるのは当然なのだが、何よりも重要なのはデータの一貫性であって、AvailabilityをとるためにEventually Consistentなシステムにするというのは本末転倒である。かねてより、Eventually Consistentはナンセンスだと主張される方もいらっしゃったが(スケールアウトアンチテーゼ)、実際に一貫性を緩くするのはビジネス的に受け入れられないケースは多い。

ビジネスだけではない。以下の事例を見れば、コンシューマ向けWebサービスにおいても、一貫性は大きな課題であることが伺える。

twitterがHBASEを選択した理由の一つがシンプルな一貫性モデルであったこと。
Facebookが新サービスの基盤にしたのは、MySQLでもCassandraでもなく、HBaseだった


Instagramがスケールさせてきた際に一貫性問題が発生していたこと。
「バックエンドの経験はなかった」Instagram創業者は、どうやってシステムをスケールさせてきたか
クラウド = 「Scalability + Availability」といわれた時代もあったが、今後の主流は「Scalability + Consistency」、つまり、スケールさせつつ、どうやって一貫性を保証するかが重要になっていると思う。

スケーラビリティの実現手段

ReflexWorksが実現しようとしていることとは、容易なスケールアウト拡張と一貫性の両立である。では、可用性を緩めさえすればこの2つは両立できるのだろうか。

実はそんなに甘くない。

サギー

まあ、少し待ちなさい。
実際のオンラインシステムでスケールが必要になるケースというのは、多くの場合はユーザ数増加などによる負荷増大が原因である。それであればユーザID単位のシャーディング(分散配置)で解決できる。1ユーザあたりのデータ量の大きさが問題になる場合は利用期間や容量制限などで解決すればよい。

このシャーディングの考え方は特別に新しい技術ではないがとても実用的である。
Salesforceのマルチテナントアーキテクチャーにおける組織IDであったり、先ほどのInstagramのスケール化でもシャーディングで解決しているそうである。


ReflexWorksにおいてもユーザID単位でのシャーディングを基本としており、ConsistentHashアルゴリズムにより担当ノードを決定する。一度担当ノードが決まれば基本的にそこだけアクセスすればよく、ユーザ数が増えて処理能力が足りなくなったら単純にノード追加すればよい。


ただし、他ノードのデータを参照したい場合はリモート呼び出しで対応する必要があり、この場合はACIDは保証されない。「容易なスケールアウト拡張と一貫性の両立」といっておきながら分散トランザクション処理ができないなんてイミフwww、と思われるかもしれないが、複数ノードに跨がった更新処理はパフォーマンスのことを考えたらやるべきではないし、これを許してしまうと密結合の世界に誘導してしまうことになりかねない。

とにかく、疎結合であることは重要。密結合になってしまうと絶対にスケールしない。

分散トランザクションがなくても、実際にはユーザのグルーピング機能などを使って同一ノードに配置するなどの代替案で対応できると思われるので、本当に分散トランザクション処理が必要なのか設計の段階でよく検討すべきところではある。

その他、ReflexWorksでは、サーバはデータを返すだけでクライアントでページを動的に生成したり、帳票印刷といったような重い処理をクライアントで実行したりと、サーバの負荷軽減のための工夫が随所でなされている。単なるシャーディングだけではなく、疎結合を基本に全体的にサーバ負荷軽減がなされるようなアーキテクチャーになっている。




月曜日, 3月 12, 2012

はてなブックマークボタンを外しました このエントリーを含むはてなブックマーク


はてなブックマークボタンを外した。ついでにはてなスターも。
http://www.nantoka.com/~kei/diary/?20120312S1

ツイートボタンとか、いいねボタンとかまだあるけど、もしかしたら何か悪さしている可能性を否定できないけど、とりあえず、はてなは外すことにした。

それから、Google AdwordsAdsenseも外した。

こいつも情報を収集しているそうだが、ここを見ても、どのようにサイトポリシーを書けばいいのかわからなかった(「プライバシーポリシー変更の詳細についてはこちら 」のリンクが切れている)

とりあえず言えることは、サイトポリシーを書かないでGoogle Adsenseを表示させるとまずそうだということ。
たぶん、はてブボタン設置と同じ罪になると思う。(でもサイトポリシーを正しく書けば大丈夫そう)

ちなみに、Google Analiticsを使っている表記だけはしてある。
はてなブックマークボタンを非難してる輩はAdsenseも要注意。

<追記>
3/14
はてなの日記が出たので元に戻した。
はてながどうというより、本サイトに訪れる人の行動履歴が勝ってに収集されず、第三者にも渡らないのであれば、それで十分だと思うからです。Adsenseは戻したくないので戻しません。
 
© 2006-2015 Virtual Technology
当サイトではGoogle Analyticsを使ってウェブサイトのトラフィック情報を収集しています。詳しくは、プライバシーポリシーを参照してください。