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




 
© 2006-2015 Virtual Technology
当サイトではGoogle Analyticsを使ってウェブサイトのトラフィック情報を収集しています。詳しくは、プライバシーポリシーを参照してください。