web-dev-qa-db-ja.com

JPAとHibernateを使用して読み取り専用トランザクションと読み取り/書き込みトランザクションを分割する方法

私は非常に重いJava webappを持っており、数千のリクエスト/秒を処​​理し、ストリーミング(非同期)レプリケーションを使用して1つのセカンダリ(読み取り専用)データベースに自分自身をレプリケートするマスターPostgresqlデータベースを使用します。

そのため、レプリケーション時間が最小限であることを考慮して、バグプライマリデータベースへの読み取り専用呼び出しを回避するために、URLを使用してリクエストをプライマリからセカンダリ(読み取り専用)に分離します。

[〜#〜] note [〜#〜]キーに基づいて使用するdbを検索するspringが提供するRoutingDataSourceで1つのsessionFactoryを使用します。マルチテナンシーをサポートするHibernate4.3.4を使用しているので、マルチテナンシーに興味があります。

2つの質問があります:

  1. トラフィックの10%しか移動できないため、読み取り専用URLが少ないため、URLに基​​づいて分割するのが効率的だとは思いません。どのようなアプローチを検討する必要がありますか?
  2. どういうわけか、URLに基​​づいて、両方のノード間である程度の分散を実現している可能性がありますが、クォーツジョブ(個別のJVMもある)で何をしますか?どのような実用的なアプローチを取るべきですか?

これは本当に広いので、ここで完璧な答えが得られないかもしれないことを私は知っていますが、文脈についてのあなたの意見が欲しいだけです。

私のチームにいる男:

  • Spring4
  • Hibernate4
  • Quartz2.2
  • Java7/Tomcat7

興味を持ってください。前もって感謝します。

20
Sachin Verma

あなたが持っている必要があります:

  1. プライマリノードに接続するように構成されたDataSource
  2. 1つまたは複数のフォロワーノードに接続するように構成されたDataSource(これらにはラウンドロビンアクセススケジューリングを使用できます)
  3. ルーティングDataSourceは、これら2つの前にあり、SessionFactoryが使用するルーティングです。
  4. @Transactional(readOnly=true)フラグを使用して、読み取り専用トランザクションをフォロワーDataSourceに確実にルーティングできます。
  5. プライマリとフォロワーの両方DataSourceには接続プールメカニズムが必要であり、最速のものは間違いなく HikariCP です。 HikariCPは非常に高速なので、 私の1つのテスト 平均接続取得時間は100usになりました。
  6. 大きな違いが生じる可能性があるため、接続プールに適切なサイズを設定する必要があります。これには、 flexy-pool を使用することをお勧めします。あなたはそれについてもっと見つけることができます ここ そして ここ
  7. あなたは非常に勤勉である必要があり、それに応じてすべての読み取り専用トランザクションにマークを付けるようにしてください。トランザクションの10%のみが読み取り専用であるのは珍しいことです。そのような書き込みが最も多いアプリケーションを使用しているのでしょうか、それともクエリステートメントのみを発行する書き込みトランザクションを使用しているのでしょうか。
  8. SQLロギングフレームワーク を使用して、すべてのクエリの実行を監視します。クエリの実行が短いほど、ロックの取得時間が短くなり、システムが対応できる1秒あたりのトランザクション数が多くなります。
  9. バッチ処理 の場合は間違いなくほとんどの書き込みトランザクションが必要ですが、OLTP一般的に、特にHibernateはOLAPに最適ではありません。それでもHibernateを使用することにした場合クォーツジョブの場合は、必ず JDBCバッチ処理を有効にする であり、次のHibernateプロパティを設定する必要があります。

    <property name="hibernate.order_updates" value="true"/>
    <property name="hibernate.order_inserts" value="true"/>
    <property name="hibernate.jdbc.batch_versioned_data" value="true"/>
    <property name="hibernate.jdbc.fetch_size" value="25"/>
    <property name="hibernate.jdbc.batch_size" value="25"/>
    

バッチ処理には、別の接続プールを使用する別のデータソースを使用できます(すでに別のJVMがあると言っているので、それがすでにあります)。すべての接続プールの合計接続サイズが、PostgreSQLが構成されている接続の数よりも少ないことを確認してください。

したがって、バッチプロセッサは、プライマリに接続する個別のHikariCPDataSourceを使用します。各バッチジョブは専用のトランザクションを使用する必要があるため、適切なバッチサイズを使用するようにしてください。ロックを保持し、トランザクションをできるだけ早く終了する必要があります。バッチプロセッサが並行処理ワーカーを使用している場合は、関連付けられている接続プールのサイズがワーカーの数と等しいことを確認してください。そうすれば、他のワーカーが接続を解放するのを待つことはありません。

10
Vlad Mihalcea

アプリケーションのURLは読み取り専用で10%しかないため、他の90%には少なくとも何らかの形のデータベース書き込みがあるとおっしゃっています。

10%READ

データベースの読み取りパフォーマンスを向上させる可能性のある CQRS設計 の使用を検討できます。確かにセカンダリデータベースから読み取ることができ、読み取り/表示レイヤー専用のクエリとドメインモデルを設計することで、より効率的になる可能性があります。

10%のリクエストが高額であるかどうかについては、まだ述べていません(例:レポートの実行)

ロード/キャッシュされるオブジェクトは書き込まれるオブジェクトとは異なる可能性が高いため、CQRSの設計に従う場合は、別のsessionFactoryを使用することをお勧めします。

90%書き込み

他の90%が行く限り、潜在的に古いデータが関与することを望まないので、いくつかの書き込みロジック中に(プライマリへの書き込み中に)セカンダリデータベースから読み取ることは望まないでしょう。

これらの読み取りの一部は、「静的」データを検索している可能性があります。 Hibernateのキャッシュが読み取りのデータベースヒットを削減していない場合は、 Memcached またはこのタイプのデータのRedisのようなメモリ内キャッシュを検討します。この同じキャッシュは、10%-読み取りプロセスと90%-書き込みプロセスの両方で使用できます。

静的ではない読み取り(つまり、最近書き込んだデータの読み取り)の場合、Hibernateは、適切なサイズのデータ​​をオブジェクトキャッシュに保持する必要があります。キャッシュのヒット/ミスのパフォーマンスを判断できますか?

[〜#〜]クォーツ[〜#〜]

スケジュールされたジョブが別のジョブと同じデータセットに影響を与えないことが確実な場合は、それらを異なるデータベースに対して実行できますが、疑わしい場合は、常に1つの(プライマリ)サーバーに対してバッチ更新を実行し、変更を複製します。レプリケーションの問題を導入するよりも、論理的に正しい方がよいでしょう。

DB PARTITIONING

1秒あたり1,000リクエストが大量のデータを書き込んでいる場合は、 partitioning データベースを確認してください。あなたはあなたがこれまでに成長しているテーブルを持っていることに気付くかもしれません。パーティショニングは、データをアーカイブせずにこれに対処する1つの方法です。

アプリケーションコードをほとんどまたはまったく変更する必要がない場合もあります。

アーカイブは明らかに別のオプションです

免責事項:このような質問は常にアプリケーション固有のものになります。常にアーキテクチャをできるだけシンプルに保つようにしてください。

1
Brad

私が正しく理解していれば、WebアプリへのHTTPリクエストの90%は、少なくとも1回の書き込みを伴い、マスターデータベースで操作する必要があります。読み取り専用トランザクションをコピーデータベースに直接送信できますが、この改善はグローバルデータベース操作の10%にのみ影響し、読み取り専用操作でさえデータベースに影響を与えます。

ここでの一般的なアーキテクチャは、優れたデータベースキャッシュ(InfinispanまたはEhcache)を使用することです。十分な大きさのキャッシュを提供できる場合は、データベースの読み取りの大部分がキャッシュにヒットするだけで、読み取り専用トランザクションの一部であるかどうかに関係なく、メモリのみの操作になることを期待できます。キャッシュの調整は微妙な操作ですが、高いパフォーマンスを実現するにはIMHOが必要です。これらのキャッシュでは、構成が少し難しい場合でも、分散フロントエンドが可能です(Ehcacheを使用する場合は、Terracottaクラスターを探す必要がある場合があります)。

現在、データベースレプリケーションは主にデータを保護するために使用され、データを読み取るだけの情報システムの高い部分がある場合にのみ、同時実行性の向上メカニズムとして使用されます。これは、説明している内容ではありません。

0
Serge Ballesta