programing

분산 된 동시성 제어

sourcetip 2021. 1. 15. 20:27
반응형

분산 된 동시성 제어


저는이 작업을 며칠 동안 해왔고 몇 가지 솔루션을 찾았지만 믿을 수 없을 정도로 간단하거나 가벼운 솔루션은 없습니다. 문제는 기본적으로 다음과 같습니다. 10 대의 머신 클러스터가 있으며 각 머신은 다중 스레드 ESB 플랫폼에서 동일한 소프트웨어를 실행합니다. 동일한 시스템의 스레드 간의 동시성 문제를 상당히 쉽게 처리 할 수 ​​있지만 다른 시스템의 동일한 데이터에 대한 동시성은 어떻습니까?

기본적으로 소프트웨어는 웹 서비스를 통해 한 비즈니스에서 다른 비즈니스로 고객의 데이터를 공급하라는 요청을받습니다. 그러나 고객은 다른 시스템에 아직 존재하거나 존재하지 않을 수 있습니다. 그렇지 않은 경우 웹 서비스 방법을 통해 생성합니다. 따라서 일종의 테스트 및 설정이 필요하지만 다른 기계가 경쟁 조건을 유발하는 것을 차단하기 위해 일종의 세마포어가 필요합니다. 이전에 단일 로컬 고객에 대해 원격 고객이 두 번 생성 된 상황이 있었는데, 이는 실제로 바람직하지 않습니다.

내가 개념적으로 가지고 놀았 던 솔루션은 다음과 같습니다.

  1. 내결함성 공유 파일 시스템을 사용하여 고객에 따라 각 컴퓨터에서 확인할 "잠금"파일을 만듭니다.

  2. 데이터베이스의 특수 테이블을 사용하고 잠금 레코드에 대해 "테스트 및 설정"을 수행하기 위해 전체 테이블을 잠급니다.

  3. 확장을 지원하지만 허브 앤 스포크 모델을 사용하는 오픈 소스 서버 소프트웨어 인 Terracotta를 사용합니다.

  4. 메모리 내 "잠금"의 동기식 복제를 위해 EHCache를 사용합니다.

이런 종류의 문제를 겪은 사람이 나 뿐이라고 상상할 수 없습니다. 어떻게 해결 했나요? 사내에서 요리했거나 좋아하는 타사 제품이 있습니까?


Hazelcast 분산 잠금 사용을 고려할 수 있습니다 . 매우 가볍고 쉽습니다.

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

Hazelcast-분산 대기열,지도, 설정, 목록, 잠금


우리는 테라코타를 사용하므로 이에 투표하고 싶습니다.

나는 Hazelcast를 따라 왔고 다른 유망한 기술처럼 보이지만 사용하지 않았기 때문에 투표 할 수 없으며 들었을 때 P2P 기반 시스템을 사용한다는 것을 알기 때문에 실제로는 그것을 믿지 않을 것입니다 확장이 필요합니다.

하지만 야후에서 나온 사육사에 대해서도 들어 봤는데, 하둡 우산 아래로 움직이고있다. 새로운 기술을 시도하는 모험을 좋아한다면 조정에만 초점을 맞추고 매우 간결하고 의미가 있기 때문에 정말 많은 가능성이 있습니다. 여전히 너무 녹색 일 수 있지만 비전과 약속이 마음에 듭니다.


Terracotta는 "계층 형"모델에 더 가깝습니다. 모든 클라이언트 응용 프로그램은 Terracotta 서버 배열과 통신합니다 (더 중요하게는 규모 측면에서 서로 통신하지 않음). Terracotta 서버 어레이는 규모와 가용성 모두를 위해 클러스터링 할 수 있습니다 (가용성을 위해 미러링, 확장을 위해 스트라이프).

어떤 경우에도 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();
        }
    }
}

Redisson 을 사용하는 것이 좋습니다 . .NET을 포함한 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();

I was going to advice on using memcached as a very fast, distributed RAM storage for keeping logs; but it seems that EHCache is a similar project but more java-centric.

Either one is the way to go, as long as you're sure to use atomic updates (memcached supports them, don't know about EHCache). It's by far the most scalable solution.

As a related datapoint, Google uses 'Chubby', a fast, RAM-based distributed lock storage as the root of several systems, among them BigTable.


I have done a lot of work with Coherence, which allowed several approaches to implementing a distributed lock. The naive approach was to request to lock the same logical object on all participating nodes. In Coherence terms this was locking a key on a Replicated Cache. This approach doesn't scale that well because the network traffic increases linearly as you add nodes. A smarter way was to use a Distributed Cache, where each node in the cluster is naturally responsible for a portion of the key space, so locking a key in such a cache always involved communication with at most one node. You could roll your own approach based on this idea, or better still, get Coherence. It really is the scalability toolkit of your dreams.

I would add that any half decent multi-node network based locking mechanism would have to be reasonably sophisticated to act correctly in the event of any network failure.


Not sure if I understand the entire context but it sounds like you have 1 single database backing this? Why not make use of the database's locking: if creating the customer is a single INSERT then this statement alone can serve as a lock since the database will reject a second INSERT that would violate one of your constraints (e.g. the fact that the customer name is unique for example).

If the "inserting of a customer" operation is not atomic and is a batch of statements then I would introduce (or use) an initial INSERT that creates some simple basic record identifying your customer (with the necessary UNIQUEness constraints) and then do all the other inserts/updates in the same transaction. Again the database will take care of consistency and any concurrent modifications will result in one of them failing.


I made a simple RMI service with two methods: lock and release. both methods take a key (my data model used UUIDs as pk so that was also the locking key).

RMI is a good solution for this because it's centralized. you can't do this with EJBs (specialially in a cluster as you don't know on which machine your call will land). plus, it's easy.

it worked for me.


If you can set up your load balancing so that requests for a single customer always get mapped to the same server then you can handle this via local synchronization. For example, take your customer ID mod 10 to find which of the 10 nodes to use.

Even if you don't want to do this in the general case your nodes could proxy to each other for this specific type of request.

Assuming your users are uniform enough (i.e. if you have a ton of them) that you don't expect hot spots to pop up where one node gets overloaded, this should still scale pretty well.


You might also consider Cacheonix for distributed locks. Unlike anything else mentioned here Cacheonix support ReadWrite locks with lock escalation from read to write when needed:

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

Full disclosure: I am a Cacheonix developer.


Since you are already connecting to a database, before adding another infra piece, take a look at JdbcSemaphore, it is simple to use:

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();
}

It is part of spf4j library.


Back in the day, we'd use a specific "lock server" on the network to handle this. Bleh.

Your database server might have resources specifically for doing this kind of thing. MS-SQL Server has application locks usable through the sp_getapplock/sp_releaseapplock procedures.


We have been developing an open source, distributed synchronization framework, currently DistributedReentrantLock and DistributedReentrantReadWrite lock has been implemented, but still are in testing and refactoring phase. In our architecture lock keys are devided in buckets and each node is resonsible for certain number of buckets. So effectively for a successfull lock requests, there is only one network request. We are also using AbstractQueuedSynchronizer class as local lock state, so all the failed lock requests are handled locally, this drastically reduces network trafic. We are using JGroups (http://jgroups.org) for group communication and Hessian for serialization.

for details, please check out http://code.google.com/p/vitrit/.

Please send me your valuable feedback.

Kamran

ReferenceURL : https://stackoverflow.com/questions/92452/distributed-concurrency-control

반응형