5

これが私のシナリオです:

  • それぞれにマルチスレッド メッセージ キューイング コンシューマーを備えた 2 つのサーバーがあります (合計 2 つのコンシューマー)。
  • 多くのメッセージ タイプ (CreateParent、CreateChild など) があります。
  • 悪いレガシ コードで立ち往生しています (子を作成すると、部分的に親が作成されます。悪いことはわかっていますが、それを変更することはできません。)
  • メッセージの順序を仮定することはできません (メッセージのキューイングの原則!)
  • RabbitMQ は、私のメッセージ キューイング ブローカーです。

私の問題:

  • 2 つのスレッドが同時に実行されている場合 (1 つは CreateParent を実行し、もう 1 つは CreateChild を実行)、2 つのスレッドがデータベースに Parent を作成しようとするため、競合が発生します (レガシー コードを思い出してください!)。

私の最初の解決策:

  • コンシューマの内部では、「エンティティ ロック」の概念を作成しました。たとえば、スレッドが CreateChild メッセージを処理するとき、CreateParent メッセージの処理が待機できるように、子と親 (レガシー コード!!) をロックします。基本的な .net Monitor と Id のリストを使用して、この概念を実装しました。それはうまくいきます。

私の最初のソリューションの制限:

  • 私の「エンティティ ロック」の概念は、1 つのサーバー上の 1 つのプロセス内の 1 つのコンシューマーに対してうまく機能します。ただし、複数のコンシューマーを実行している複数のサーバー間では機能しません。
  • 共有データベースを使用してエンティティ ロックの概念を「保存」することを考えているため、各プロセス (およびスレッド) がデータベースにアクセスして、どのエンティティがロックされているかを確認できます。

私の質問(ついに!):

これらすべてが非常に複雑になり、バグのリスクとコードのメンテナンスの問題が増加しています。私は本当にそれが好きではない! 誰かがすでにこの種の問題に直面していますか? それらは許容できる回避策ですか?私のシナリオのクリーンなソリューションのアイデアはありますか?

ありがとう!

4

1 に答える 1

1

最後に、シンプルなソリューションは常に優れたソリューションです。

「エンティティ ロック」の複雑な概念をすべて使用する代わりに、要求を実行する前に、必要なすべてのデータとエンティティの状態を事前に検証することを最終的に断りました。

より正確には、CreateChild プロセスが CreateParent によって作成された既存のデータに遭遇したときにそれ自体をクラッシュさせるのではなく、CreateChild メッセージを実行する前に、データベース内のすべてが正常であることを完全に検証します。

このソリューションの欠点は、CreateChild の実装が、CreateParent が生成する特定のデータを認識し、実行を開始する前にその存在を確認する必要があることです。しかし真剣に、これはクロスシステムですべてのものをロックするよりもはるかに優れています!

于 2013-03-20T15:27:15.437 に答える