IBM Cloud チュートリアル

マイクロサービスのための正しいデータベースの選択

記事をシェアする:

この投稿は、2020年6月24日に、米国 IBM Cloud Blog に掲載されたブログ(英語)の抄訳です。

マイクロサービスのアプローチにリファクタリングする際に、最適なデータベースを決定するために考慮すべきさまざまな要因を探ります。

 

以前の記事(英語, IBM外のWebサイトへ)では、コードをマイクロサービスベースのアプローチにリファクタリングするためのさまざまな側面について触れました。最後に触れたのは、大規模なエンタープライズアプリケーションではデータをどうするかという問題ですが、これはしばしば最も困難な問題であり、より詳細に扱う価値があります。コーディングの問題なのか、それともコーディングの問題を装ったデータモデリングの問題なのかを判断するのが難しい場合があるからです。

本記事ではいくつかの例を見ながら、リファクタリングされたコードを単純化して改善するためにできるデータモデリングの選択方法についてお話しします。しかし、まず最初に、既存のエンタープライズ・アプリケーションをマイクロサービス(英語)にリファクタリングするチームがよく最初に疑問に思うことについてお話していきましょう。

 

1つの大きなデータベースか、それとも多くの小さなデータベースか?

もしあなたのアプリケーションがマイクロサービスへのリファクタリングを開始しているのであれば、そのアプリケーションは単一の大規模なリレーショナルデータベース(英語)で動作しているでしょう。データベースにはOracleやDB2、SQL Server、Informix、あるいはMySQLやPostgres(英語)のようなオープンソースのデータベースが使われていることと思います。実際、コストのかかるエンタープライズ・リレーショナル・データベースからの移行は、マイクロサービスへのリファクタリングでよく推進されるメリットの1つです。

さて、マイクロサービスのために NewSQL(英語)またはNoSQL(英語)のいずれかを選択することは大きなメリットがあります。しかし、現在使用しているリレーショナルデータベースを一度に放棄するのは、無謀な決断です。その代わりに、既存のJava(英語)コードをリファクタリングする際にインクリメンタルなアプローチを提唱しているように、データベースを変更する際にも、よりインクリメンタルなアプローチを検討した方が良いでしょう。

しかし、私たちが提唱しているコーディングのインクリメンタル・アプローチと同様に、データベースのリファクタリングのためのインクリメンタル・アプローチをする際の最大の問題は、どこから始めるかを決めることです。インクリメンタル・アプローチを決めたら、最初に決めなければならないのは、1つの大きなデータベースを使うべきか、多くの小さなデータベースを使うべきかということです。これは、ナンセンスなことのように聞こえます。もちろん、あなたは大きなデータベースを一つも欲していないでしょう。なぜならモノリスの中に存在するものですから。でも、その意味を説明させてください。

基本的には、データベースサーバーとデータベーススキーマを区別することから始めなければなりません。OracleやDb2のようなエンタープライズ規模のデータベースに精通している人にとっては、この区別は自然なことです。これが行われる理由は、ライセンスが多くの場合、CPUごとに設定されているため、企業はお金をかけて得られる使用量を最大化したいと考えているからです。そのために複数のチームを1つの大きなサーバーにまとめることは、よく行われます。MySQLやPostgreSQLのようなオープンソースのデータベースをよく知っている人にとっては、このような区別はあまり必要ではないので、あまり一般的ではありません。

なぜなら、マイクロサービス用のデータベースを構築する際には、データベースでの結合を減らしたり、排除したりすることが重要だからです。問題は、同じ情報、つまり同じスキーマ内の同じテーブルを使用する2つの異なるマイクロサービスがある場合に発生します。図1を見ていただければ、その意味がお分かりいただけると思います。

 

図1: 1つの大きなスキーマで動作するモノリシック・アプリケーション

 

モノリシックアプリケーションのデータベースに相当するものは、すべてのテーブルを接続する大きなスキーマを持っています(「大きな泥の玉」とも呼ばれます)。そうなると、テーブルを分離するためには膨大な量のもみほぐしが必要になります。

しかし、マイクロサービスに移行すると、サーバーレベルでのハードウェアやライセンスの共有による問題が少なくなります。実際、マイクロサービスへの最初のリファクタリングを行う際には、新しい、よりきれいに分離されたスキーマを同じ企業のサーバーに維持することができます。

ある意味では、企業がハードウェアとソフトウェアを提供し、企業データベースを管理することで提供しているのは、DBaaS(Database-as-a-Service)(英語)の限定的なバージョンです。これは特に、図2に示すように、モノリスの一部を機能領域ごとにきれいに分離するアプローチに適しています。

 

図2: モジュラーモノリスと複数のリファクタリングされたスキーマ

 

この例では (リファクタリングの進行中の作業を示すために)、リファクタリングされたアプリケーションの特定のモジュールに対応する 3 つの新しいスキーマ (A, B,  C) に対応するテーブルを分離することで、データベースがどのように分割されたかを見ることができます。一度このように分離されると、それらは明確なマイクロサービスにきれいに分割することができます。しかし、D と E はまだリファクタリングされていますので、まだ相互接続されたテーブルを持つ単一のスキーマを共有しています。

最終的には、データベース・サーバレベルでのリンクさえも問題になるかもしれません。例えば、エンタープライズ・データベースを選択した場合、利用可能な機能が制限されます。リレーショナルモデルであっても、すべてのスキーマがすべての機能を必要としているわけではありませんし、別のサーバーでサポートされている方が良い機能を必要としているかもしれません(例えば、より良いシャーディングがNewSQLデータベースを使用する理由としてよく挙げられています)。同様に、複数のマイクロサービスで共有されているデータベースサーバーをアップグレードすると、複数のサービスが一度にダウンする可能性があります。

しかし、これは先延ばしにできる課題であり、プロジェクトの開始時にすぐに決断する必要はありません。チームが初期リファクタリングを開始したときに、少なくともリファクタリングプロジェクトの初期段階では同じデータベースサーバーにとどめておくことは、チームがコードとデータベースのリファクタリングで必要な経験を積みながら、段階的に変更を加えていく方法です。

 

非リレーショナルモデルを検討する

前のセクションでお話したように、リファクタリングのプロセスを進める際には、データベースのオプションについてもう少し慎重に考える必要があるでしょう。すべてのデータセットがリレーショナルモデルに完全に適しているわけではありません。これらのデータセットを管理するための最適なアプローチを決定するには、「実際にデータベースに何を保存しているのか」という問題に行き着くことがよくあります。

私たちは、企業がオブジェクト・リレーショナル・マッピング・フレームワークを構築し、維持し、しばしば負荷をかけるのを何年もかけて支援してきましたが、実際の問題として、格納されているデータがリレーショナル・データ・モデルに全くうまくマッピングされていないケースがいくつかありました。そのような場合には、リレーショナル・モデルを「ひねって」適合させるか、あるいはコードをリレーショナル・データ・ストアに適合させるために、プログラムの中で大騒ぎをしなければならないことに気付きました。

ポリグロット永続化の選択の時代に移行した今、これらの決定のいくつかを再検討することで、より良いものを作ることができます。特に、リレーショナルモデルが最良の選択肢ではなかったことが明らかな4つの異なるケースを見て、次にリレーショナルモデルが最良の選択肢であり、データを別の形式で保存することが適切なアプローチではなかったケースを考えてみたいと思います。

 

Blob ストレージを扱う

企業システムの永続化コードを何度も見てきましたが、驚いたことに、実際にリレーショナル・データベースに格納されているのは、シリアル化されたJavaオブジェクトのバイナリ表現であることに気がつきました。これらは「Binary Large Object」または「Blob」カラムに格納されており、通常、Javaオブジェクトをリレーショナル・テーブルやカラムにマッピングしようとする複雑さにチームが手を焼いた結果です。Blobストレージには、特定の欠点があります。また、Javaオブジェクト自体の構造の変化に敏感で、オブジェクトの構造が大きく変化した場合、古いデータは読み取れなくなる可能性があります。

アプリケーション(あるいはアプリケーションのサブセット)がリレーショナル・データベースでBlobストレージを使用している場合は、MemcachedやRedis(英語)のようなキー・バリュー・ストアを使用した方が良いかもしれないということを示しています。一方で、一歩下がって、何を保存しているのかを少し考えてみるのもいいかもしれません。ただの構造化されたJavaオブジェクト(おそらく深い構造化されているがネイティブのバイナリではない)であれば、Cloudant(英語)MongoDB(英語)のようなDocumentストアを使った方が良いかもしれません。さらに、ドキュメントをどのように保存するかに少しの努力を払えば (例えば、上記のデータベースはどちらも JSON ドキュメントストアであり、JSON パーサはどちらも広く利用可能でカスタマイズも簡単です)、「スキーマドリフト」の問題を、保存メカニズムがずっと不透明な Blob ストアのアプローチよりもずっと簡単に処理することができます。

 

フラットオブジェクトとアクティブレコードパターン

数年前、マーティン・ファウラーが「Patterns of Enterprise Application Architectures」を書いていた頃、私たちはその多くのパターンについて活発な文通や何度かの活発なレビュー会議を行っていました。特に1つは、いつも変なカモとして目立っていました-アクティブ・レコード・パターンです。それは、Javaコミュニティから来た私たちが一度も遭遇したことがなかったからです(マーティンは、Microsoft .NETプログラミングコミュニティでは一般的なパターンだと断言しましたが)。しかし、私たちがこのパターンについて本当に驚いたのは、特に iBatisas のようなオープンソース技術を使用したいくつかの Java 実装を見始めたときに、これを使用するのに最適なケースは、オブジェクトが、まあ、フラットである場合にあるように思えたことです。

データベースにマッピングしようとしているオブジェクトが完全にフラットで、他のオブジェクトとの関係がない場合(ネストされたオブジェクトなどの限られた例外を除いて)、リレーショナルモデルの機能をフルに活用できていない可能性があります。むしろ、ドキュメントを保存している可能性の方が高いでしょう。私たちがこれまでに見てきたケースでは、チームが顧客満足度調査や問題のチケットなど、紙の文書の電子版を文字通り保存していることがよくあります。このような状況では、CloudantやMongoDBのようなドキュメントデータベースが最適でしょう。その種のデータベースで動作する独自のサービスにコードを分割すると、大規模なエンタープライズデータベースの一部として同じことを行うよりも、コードがずっとシンプルになり、メンテナンスも簡単になることがよくあります。

 

参照データを扱う

ORMシステムでよく見られるもう一つのパターンは、”インメモリキャッシュに吸い込まれたテーブル内の参照データ “の組み合わせです。参照データとは、頻繁に更新されない(あるいは更新されない)が、常に読み込まれているもので構成されています。この良い例としては、米国の州やカナダの州のリストや、医療コードや標準部品のリストなどがあります。この種のデータは、GUIのドロップダウンによく使用されます。

一般的なパターンは、リストが使用されるたびにテーブル(通常はフラットな2カラムか、多くても3カラムのテーブル)からリストを読み取ることから始めます。しかし、毎回それを行うのはパフォーマンス的に無理があることに気づくでしょう。

この問題が発生するたびに、よりシンプルで高速なキャッシュメカニズムにリファクタリングされます。繰り返しになりますが、これは Memcached や Redis が完全に妥当な状況です。参照データがデータベース構造の残りの部分から独立している場合(そして、多くの場合はそうであるか、せいぜい疎結合である)、データとそのサービスをシステムの残りの部分から切り離すことが助けになるでしょう。

 

地獄からのクエリ

ある顧客システムでは、複雑な財務モデリングを行っており、プログラムが操作しているオブジェクトを作成するためだけに、非常に複雑なクエリ(6つまたは7つの方法で結合する)を必要としていました。更新はさらに複雑で、何が変更されたのか、データベースにあるものが自分たちが作成して操作した構造と一致しているかどうかを確認するために、楽観的なロックチェックをいくつかの異なるレベルで組み合わせなければなりませんでした。

振り返ってみると、私たちがやっていたことはもっと自然にグラフとしてモデル化されていたことは明らかです。このような状況(この場合、私たちはファンドのトランシェをモデル化していましたが、それぞれが異なるタイプの株式と債務で構成されており、それぞれが異なる通貨で価格設定され、それぞれの評価を取り巻く異なるルールで期限が異なります)は、本当にやりたいことを簡単に実行できるようにするために、グラフを上下に移動したり、グラフの一部を自由に移動したりできるようなデータ構造が必要になります。

これは Apache Tinkerpop や Neo4J のようなソリューションが良いアプローチになるでしょう。解決策を直接グラフとしてモデル化することで、複雑な Java や SQL コードの多くを避けることができ、同時に、おそらく実行時のパフォーマンスを大幅に向上させることができました。

 

伝統的なSQLとNewSQLが輝くとき

特定のデータ構造に対してNoSQLデータベースが適切な論理的アプローチである場合も多くありますが、リレーショナル・モデルの柔軟性とパワーに勝るものはありません。リレーショナル・データベースの素晴らしいところは、同じデータを非常に効果的に「スライスしてサイコロ状にする」ことができることです。Database Viewsのようなトリックでは、同じデータの複数のマッピングを作成することができ、複雑なデータモデルの関連するクエリのセットを実装する際に便利です。

なお、NoSQL と SQL の比較については、「SQL vs. NoSQL: What’s the Difference?(英語)」を参照してください。

以前の記事で説明したように、マイクロサービスの「下界」が、そのデータ上で動作するサービスの関連するセットと共にアグリゲートにグループ化されたエンティティのセットである場合、関連するクエリのセットを表すビューを実装するのは、多くの場合、SQLを使用して最も簡単で簡単です。

前回の記事(英語, IBM外のWebサイトへ)で簡単なAccount/LineItemの例につながった顧客の例で初めてそれがわかりました。このケースでは、そのようなシンプルなモデルをドキュメント指向のNoSQLデータベースで動作させようと懸命に努力していた銀行がありましたが、CAP定理(英語)に敗北してしまいました。しかし、そのチームは間違った理由でそのデータモデルを選択していました。彼らは、アーキテクチャの一貫性を求める見当違いの欲求から、多様なマイクロサービスのすべてにDocument-orientedデータベースを使用することを選択していました。

この場合、彼らはACIDモードのすべての属性を必要としていましたが、シャーディング(パーティショニングなど)は必要ありませんでした。しかし、システムのコアはACIDトランザクションを必要とし、パーティショニングは必要ありませんでしたが、それは必ずしもシステムの異なる部分すべてに当てはまるわけではありませんでした。SQL データベースが得意とすることはいくつかありますが、ACID トランザクションはその一つです。マイクロサービスシステムでは、それらのACIDトランザクションを、それらが動作する最小のデータセットを中心にグループ化することが、通常は正しいアプローチです。

しかし、SQLは必ずしも従来のSQLデータベースを意味するわけではありません。多くのマイクロサービスアーキテクチャでは、そのような場所があるのは確かですが、SQLは他にも少なくとも2種類のデータベースで実装されており、マイクロサービスを実装する多くのチームにとって有用な選択肢となります。1つ目は「小さなSQL」で、MySQLやPostgresのようなオープンソースのデータベースの領域です。マイクロサービスを実装する多くのチームにとって、これらのデータベースは多くの理由から完全に合理的な選択です。

  1. 既存のアプリケーションをマイクロサービスにリファクタリングするチームは、通常、SQLとHibernateやSpring Persistenceのようなオブジェクトリレーショナルマッピングフレームワークの両方の経験を持っています。マイクロサービスのアプローチの範囲内でその知識を活用することは、確かに合理的です。
  2. これらのデータベースは、オープンソースコミュニティやサポートを提供している多くのベンダーによって、非常によくサポートされています。これらのデータベースのドキュメントやチュートリアルを見つけたり、それらに熟練した開発者を見つけるのは比較的簡単です。
  3. これらのデータベースは小さくて軽量なので、簡単にコンテナ化(英語)でき、アプリケーションコードに使用しているのと同じGitOpsの仕組みを使ってデプロイやアップデートができます。
  4. これらのデータベースは、ハイパースカラーのパブリッククラウドの大部分またはすべてからのSaaSバージョンでサポートされています。

これらの「小さなSQL」データベースを使用する主な欠点は、しばしばエンタープライズデータベースがサポートできるのと同じレベルのスケール(特にシャーディングに関して)をサポートしていないことです。しかし、これは新しいデータベース・ベンダーやオープンソース・プロジェクトによって見事に解決されており、小さなSQLデータベースの最高の属性とNoSQLデータベースのスケーラビリティを組み合わせています。しばしば「NewSQL」データベースと呼ばれるこれらのデータベースには、CockroachDB、Apache Trofidion、およびClustrixが含まれます。

ACID トランザクションのすべて、リレーショナルモデルを完全にサポートする SQL エンジン、そして幅広いスケーリングとシャーディング機能を必要とする場合はいつでも、NewSQL データベースはチームにとって良い選択となります。しかし、この選択にはコストがかかります。これらのデータベースは、旧来の「小さなSQL」ソリューションよりもセットアップや管理が複雑になることがよくあります。また、これらのデータベースのスキルを持った人材を見つけるのも困難です。いずれにしても、選択肢を検討する際には慎重に検討する必要があります。

 

ここからどこへ行くのか?

私たちは、コーディングの問題を装って、さまざまなデータベースモデリングの問題を見て回ってきました。もし、これらの特定の問題が1つ以上あることがわかったら、既存のエンタープライズ・データ・ストアを分割して、別のタイプのデータ・ストアで再定義した方が良いかもしれません。いずれにしても、ゆっくりと段階的に行うことをお勧めします。すべてのアプリケーションがすべてのタイプのデータモデルを必要とするわけではないこと、また、大規模な実装を始める前に、時間をかけてスキルを身につけ、選択したデータベースの運用能力を理解する必要があることに注意してください。

最後に、マイクロサービス全体のアプローチは、各マイクロサービスを構築するチームが、どのデータストアが自分たちに適しているかを自分たちで決定できるという考えに基づいているという事実を認識しておいてください。私たちが遭遇した最大の問題は(これらの話の多くが示唆しているように)、単一のデータ表現とストレージのアプローチをすべての状況に対応させようとすることです。

私は何度も、チームがNoSQLデータベースを使用するべきではなかった状況でCAP定理の現実に対処しようとしなければならないのを見てきました。同様に、NoSQLデータベースから複雑なレポートを作成しようとすると、しばしばフラストレーションが溜まってしまいます。一方で、これまでに示した状況は、リレーショナル・モデルがすべてを網羅しているわけではないことを示しています。他のモデルにもそれなりの場所があります。私たちができる最善のアドバイスは、各マイクロサービスに適したモデルを選択するために必要な自律性をチームが持っていることを確認することです。


翻訳:IBM Cloud Blog Japan 編集部

 

More IBM Cloud チュートリアル stories

セキュリティー・ロードマップ

IBM Cloud Blog

統合脅威管理、耐量子暗号化、半導体イノベーションにより、分散されているマルチクラウド環境が保護されます。 2023 安全な基盤モデルを活用した統合脅威管理により、価値の高い資産を保護 2023年には、統合された脅威管理と ...続きを読む


量子ロードマップ

IBM Cloud Blog

コンピューティングの未来はクォンタム・セントリックです。 2023 量子コンピューティングの並列化を導入 2023年は、Qiskit Runtimeに並列化を導入し、量子ワークフローの速度が向上する年になります。 お客様 ...続きを読む


ハイブリッドクラウド・ロードマップ

IBM Cloud Blog

コンポーザブルなアプリケーション、サービス、インフラストラクチャーにより、企業は複数のクラウドにまたがるダイナミックで信頼性の高い仮想コンピューティング環境の作成が可能になり、開発と運用をシンプルに行えるようになります。 ...続きを読む