56

私はこれに数日間取り組んできましたが、いくつかの解決策を見つけましたが、どれも信じられないほど単純でも軽量でもありませんでした。問題は基本的に次のとおりです。10 台のマシンのクラスターがあり、それぞれがマルチスレッド ESB プラットフォームで同じソフトウェアを実行しています。同じマシン上のスレッド間の同時実行の問題はかなり簡単に処理できますが、異なるマシン上の同じデータに対する同時実行の問題はどうでしょうか?

基本的に、ソフトウェアは Web サービスを介して顧客のデータをある企業から別の企業にフィードする要求を受け取ります。ただし、顧客が他のシステムに存在する場合もあれば、存在しない場合もあります。そうでない場合は、Web サービス メソッドを介して作成します。したがって、ある種のテスト アンド セットが必要ですが、他のマシンが競合状態を引き起こさないようにロックアウトするための何らかのセマフォが必要です。以前、1 人のローカル カスタマーに対してリモート カスタマーが 2 回作成されたという状況がありましたが、これはあまり望ましくありません。

私が概念的にいじった解決策は次のとおりです。

  1. フォールト トレラントな共有ファイル システムを使用して、お客様に応じて各マシンでチェックされる「ロック」ファイルを作成します。

  2. データベースで特別なテーブルを使用し、ロック レコードの「テストと設定」を行うためにテーブル全体をロックします。

  3. スケーリングを支援するオープン ソース サーバー ソフトウェアである Terracotta を使用しますが、ハブ アンド スポーク モデルを使用します。

  4. メモリ内の「ロック」の同期レプリケーションに EHCache を使用します。

この種の問題を経験したことがあるのが私だけだとは想像できません。どのように解決しましたか?社内で何か調理しましたか、それともお気に入りのサードパーティ製品はありますか?

4

13 に答える 13

34

Hazelcast分散ロックの使用を検討することをお勧めします。超軽量で簡単。

java.util.concurrent.locks.Lock lock = Hazelcast.getLock ("mymonitor");
lock.lock ();
try {
// do your stuff
}finally {
   lock.unlock();
}

Hazelcast - 分散キュー、マップ、セット、リスト、ロック

于 2008-09-18T23:11:36.040 に答える
13

テラコッタを使っているのでそちらに投票したいと思います。

私は Hazelcast をフォローしてきましたが、これは別の有望なテクノロジのように見えますが、使用したことがないため投票できません。また、P2P ベースのシステムを使用していることを知っているので、あまり信用できません。スケーリングのニーズ。

しかし、Yahoo から出てきた Zookeeper が Hadoop の傘下に移動しているという話も聞いたことがあります。新しいテクノロジーを試す冒険好きなら、これは非常に無駄がなく、調整だけに焦点を当てているため、本当に多くの可能性があります. まだ青すぎるかもしれませんが、私はビジョンと約束が好きです.

于 2008-10-17T03:17:08.333 に答える
4

Terracotta は「階層型」モデルに近く、すべてのクライアント アプリケーションが Terracotta Server Array と通信します (さらに重要なことに、スケールのために、それらは互いに通信しません)。Terracotta Server Array は、スケールと可用性の両方のためにクラスター化することができます (可用性のためにミラーリングし、スケールのためにストライプ化します)。

いずれにせよ、おそらくご存じのとおり、Terracotta を使用すると、POJO 同期/待機/通知を使用するか、ReentrantReadWriteLock などの java.util.concurrent プリミティブを使用して、単一の JVM で行うのと同じ方法で、クラスター全体で同時実行性を表現できます。 、CyclicBarrier、AtomicLong、FutureTask など。

Terracotta Cookbookには、これらのプリミティブの使用を示す簡単なレシピがたくさんあります。

例として、ReentrantReadWriteLock の例を投稿します (「Terracotta」バージョンのロックはありません。通常の Java ReentrantReadWriteLock を使用するだけです)。

import java.util.concurrent.locks.*;

public class Main
{
    public static final Main instance = new Main();
    private int counter = 0;
    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(true);

    public void read()
    {
        while (true) {
            rwl.readLock().lock();
                try {
                System.out.println("Counter is " + counter);
            } finally {
                rwl.readLock().unlock();
            }
            try { Thread.currentThread().sleep(1000); } catch (InterruptedException ie) {  }
        }
    }

    public void write()
    {
        while (true) {
            rwl.writeLock().lock();
            try {
               counter++;
               System.out.println("Incrementing counter.  Counter is " + counter);
            } finally {
                 rwl.writeLock().unlock();
            }
            try { Thread.currentThread().sleep(3000); } catch (InterruptedException ie) {  }
        }
    }

    public static void main(String[] args)
    {
        if (args.length > 0)  {
            // args --> Writer
            instance.write();
        } else {
            // no args --> Reader
            instance.read();
        }
    }
}
于 2008-09-19T16:19:03.113 に答える
3

Redissonの使用をお勧めします。を含む 30 を超える分散データ構造とサービスを実装していますjava.util.Lock。使用例:

Config config = new Config();
config.addAddress("some.server.com:8291");
Redisson redisson = Redisson.create(config);

Lock lock = redisson.getLock("anyLock");
lock.lock();
try {
    ...
} finally {
   lock.unlock();
}

redisson.shutdown();
于 2014-01-12T10:16:33.080 に答える
2

ログを保持するための非常に高速な分散 RAM ストレージとして memcached を使用するようアドバイスするつもりでした。しかし、EHCache は同様のプロジェクトですが、より Java 中心のようです。

アトミック更新を使用することが確実である限り、どちらかが進むべき道です (memcached はそれらをサポートしていますが、EHCache については知りません)。これは、最もスケーラブルなソリューションです。

関連するデータポイントとして、Google は BigTable を含むいくつかのシステムのルートとして、RAM ベースの高速な分散ロック ストレージである「Chubby」を使用しています。

于 2008-10-17T03:36:17.060 に答える
1

コンテキスト全体を理解しているかどうかはわかりませんが、これを裏付ける単一のデータベースがあるようですね? データベースのロックを利用しない理由: 顧客の作成が単一の INSERT である場合、データベースは制約の 1 つに違反する 2 番目の INSERT を拒否するため、このステートメントだけがロックとして機能します (たとえば、顧客名がたとえばユニークです)。

「顧客の挿入」操作がアトミックではなく、ステートメントのバッチである場合、最初の INSERT を導入 (または使用) して、顧客を識別する単純な基本レコードを (必要な UNIQUEness 制約を使用して) 作成し、すべての操作を行います。同じトランザクション内の他の挿入/更新。繰り返しますが、データベースは一貫性を維持し、同時に変更が行われると、そのうちの 1 つが失敗します。

于 2008-09-18T13:50:31.083 に答える
1

私は Coherence で多くの作業を行ってきました。これにより、分散ロックを実装するためのいくつかのアプローチが可能になりました。単純なアプローチは、参加しているすべてのノードで同じ論理オブジェクトをロックするように要求することでした。Coherence の用語では、これはレプリケートされたキャッシュでキーをロックしていました。このアプローチは、ノードを追加するとネットワーク トラフィックが直線的に増加するため、あまり拡張できません。よりスマートな方法は、分散キャッシュを使用することでした。この場合、クラスター内の各ノードがキー空間の一部を自然に担当するため、そのようなキャッシュ内のキーをロックするには、常に最大 1 つのノードとの通信が必要でした。このアイデアに基づいて独自のアプローチを展開することもできますが、Coherence を取得することをお勧めします。それは本当にあなたの夢のスケーラビリティ ツールキットです。

ネットワーク障害が発生した場合に正しく動作するように、半分まともなマルチノード ネットワーク ベースのロック メカニズムは、かなり洗練されたものでなければならないことを付け加えておきます。

于 2008-09-18T13:42:39.823 に答える
0

分散ロック用にCacheonixを検討することもできます。ここで言及されている他のものとは異なり、Cacheonix は、必要に応じて読み取りから書き込みへのロックエスカレーションを使用して ReadWrite ロックをサポートします。

ReadWriteLock rwLock = Cacheonix.getInstance().getCluster().getReadWriteLock();
Lock lock = rwLock.getWriteLock();
try {
  ...
} finally {
  lock.unlock();
}

完全開示: 私は Cacheonix 開発者です。

于 2011-08-26T16:54:37.720 に答える
0

lock と release の 2 つのメソッドを持つ単純な RMI サービスを作成しました。どちらの方法もキーを取ります (私のデータ モデルは UUID を pk として使用していたため、ロック キーでもありました)。

RMI は一元化されているため、これに適したソリューションです。EJB でこれを行うことはできません (特にクラスタでは、呼び出しがどのマシンに到達するかわからないため)。さらに、簡単です。

それは私のために働いた。

于 2008-09-18T13:33:44.527 に答える
0

すでにデータベースに接続しているので、別のインフラピースを追加する前に、JdbcSemaphoreを見てください。使い方は簡単です。

JdbcSemaphore semaphore = new JdbcSemaphore(ds, semName, maxReservations);
boolean acq = semaphore.acquire(acquire, 1, TimeUnit.MINUTES);
if (acq) {
 // do stuff
 semaphore.release();
} else {
  throw new TimeoutException();
}

spf4jライブラリの一部です。

于 2016-08-23T01:01:11.047 に答える
0

単一の顧客の要求が常に同じサーバーにマップされるように負荷分散を設定できる場合は、ローカル同期を介してこれを処理できます。たとえば、顧客 ID mod 10 を使用して、10 個のノードのどれを使用するかを見つけます。

一般的なケースでこれを行いたくない場合でも、ノードはこの特定のタイプのリクエストに対して互いにプロキシすることができます。

ユーザーが十分に均一であると仮定すると (つまり、大量のユーザーがいる場合)、1 つのノードが過負荷になる場所にホット スポットが発生することはないと想定しても、これはかなりうまくスケーリングするはずです。

于 2008-11-16T07:27:11.247 に答える
-1

昔は、これを処理するためにネットワーク上の特定の「ロック サーバー」を使用していました。ブレ。

データベース サーバーには、このようなことを行うためのリソースが用意されている場合があります。MS-SQL Server には、sp_getapplock / sp_releaseapplockプロシージャを通じて使用できるアプリケーション ロックがあります。

于 2008-09-18T13:28:14.400 に答える
-5

オープン ソースの分散同期フレームワークを開発しており、現在 DistributedReentrantLock と DistributedReentrantReadWrite ロックが実装されていますが、まだテストとリファクタリングの段階にあります。私たちのアーキテクチャでは、ロックキーはバケットに分割され、各ノードは特定の数のバケットに対応しています。したがって、効果的にロック要求が成功した場合、ネットワーク要求は 1 つだけです。また、AbstractQueuedSynchronizer クラスをローカル ロック状態として使用しているため、失敗したロック リクエストはすべてローカルで処理され、ネットワーク トラフィックが大幅に削減されます。グループ通信には JGroups ( http://jgroups.org ) を使用し、シリアル化には Hessian を使用しています。

詳細については、 http://code.google.com/p/vitrit/をご覧ください。

貴重なご意見をお寄せください。

カムラン

于 2010-02-08T08:45:35.023 に答える