분산 잠금 패턴 찾기


10

C #의 분산 시스템에 대한 사용자 지정 재귀 적 객체 잠금 메커니즘 \ 패턴을 만들어야합니다. 본질적으로 다중 노드 시스템이 있습니다. 각 노드에는 n 개의 상태 조각에 대해 독점적 인 쓰기 권한이 있습니다. 하나 이상의 다른 노드 에서 동일한 상태를 읽기 전용 형식으로 사용할 수도 있습니다 . 일부 쓰기 / 업데이트는 모든 노드에서 원자 적이어야하지만 다른 업데이트는 백그라운드 복제 프로세스, 큐 등을 통해 일관되게 유지됩니다.

원자 업데이트의 경우 객체를 쓰기에 대해 잠긴 것으로 효율적으로 표시하여 배포, 커밋, 롤백 등을 할 수 있는 패턴 또는 샘플을 찾고 있습니다. 시스템에 높은 수준의 동시성이 있으므로, 잠금이 해제되면 시간 초과되거나 풀릴 수있는 잠금을 쌓을 수 있어야한다고 가정합니다.

트랜잭션 또는 메시징 부분은이 질문의 초점이 아니지만 추가 컨텍스트를 제공했습니다. 그 말로, 원하는 경우 어떤 메시지가 필요하다고 생각하는지 자유롭게 표현하십시오.

완전히 새로운 제품을 구현하는 것 외에도 새로운 아이디어에 개방적이지만 내가 구상했던 것에 대한 모호한 샘플은 다음과 같습니다.

thing.AquireLock(LockLevel.Write);

//Do work

thing.ReleaseLock();

확장 방법을 사용하려고 생각했는데 다음과 같이 보일 수 있습니다.

public static void AquireLock(this IThing instance, TupleLockLevel lockLevel)
{ 
    //TODO: Add aquisition wait, retry, recursion count, timeout support, etc...  
    //TODO: Disallow read lock requests if the 'thing' is already write locked
    //TODO: Throw exception when aquisition fails
    instance.Lock = lockLevel;
}

public static void ReleaseLock(this IThing instance)
{
    instance.Lock = TupleLockLevel.None;
}

몇 가지 세부 사항을 명확히하려면 ...

  • 모든 통신은 이진 요청 / 응답 프로토콜을 사용하는 TCP / IP입니다.
  • 대기열 또는 데이터베이스와 같은 중개 기술이 없습니다
  • 중앙 마스터 노드가 없습니다. 이 경우 잠금 배열은 잠금의 시작 자와 해당 동작을 제어하기위한 시간 종료 형식으로 요청을 처리 할 파트너에 의해 정의됩니다.

누구든지 제안이 있습니까?


잠금은 일반적으로 대부분의 시스템에서 표준 기능입니다. C #에도있는 것 같습니다. (Google 검색 결과 : albahari.com/threading/part2.aspx ) 기본 Mutex 나 세마포어 이외의 것을 달성하려고하십니까?
Dipan Mehta

2
@DipanMehta 죄송합니다.이 문제를 더 명확하게 해결해야합니다. 노드 내가 언급은 네트워크에있는 기계입니다. Mutex와 Semaphores에 대한 나의 이해는 그것들이 기계 전체의 잠금 장치 ( 예 : 교차 프로세스 )이며 네트워크의 컴퓨터간에 확장 할 수있는 잠금 장치가 아니라는 것입니다.
JoeGeeky

@JoeGeeky 귀하의 질문은 여기서 주제이며 Stack Overflow에 대해 너무 이론적 일 것 입니다. 거기에 다시 묻고 싶다면 더 코드 중심의 문구를 원할 것입니다.
Adam Lear

답변:


4

설명을 주셔서 감사합니다.

이 경우 권장하는 것은 게시 / 구독 모델을 사용하는 것입니다. Google의 Chubby 분산 잠금 프로토콜 ( Paxos 구현 )

나는 Paxos (또는 풍만)를 사용하지 않는,하지만 오픈 소스 구현있을 것 같습니다 적이 여기 .

그래도 작동하지 않으면 메시징 라이브러리 측면에서 일반적인 용의자 중 하나 인 메시지 큐 라이브러리 0 , RabbitMQ 또는 ActiveMQ 등을 사용하여 자신의 Paxos 버전을 구현할 수 있습니다 .


이전 답변 :

SO ( [A] , [B] )에 대한 대부분의 제안은 시스템 간 잠금을 달성하기 위해 메시지 큐를 사용합니다.

귀하의 AcquireLock방법은 성공하기 전에 잠금의 이전 인스턴스에 대한 확인, 큐에 락 객체를 식별 뭔가를 밀어 것입니다. 귀하의 ReleaseLock방법은 큐에서 잠금 개체를 제거합니다.

SO 사용자 아틀란티스이 게시물 에서 Jeff Key의 게시물에 대해 자세히 설명합니다.


감사합니다. 그러나 중앙 마스터, 데이터베이스 또는 대기열이 없기 때문에 이러한 솔루션은 적합하지 않습니다. 이러한 세부 사항 중 일부를 명확하게하기 위해 몇 가지 추가 세부 사항으로 질문을 업데이트했습니다.
JoeGeeky

노드 간의 모든 통신에 사용해야하는 잘 정의 된 프로토콜이 이미 있기 때문에 이러한 제품을 직접 사용할 수는 없지만 Chubby와 Paxos에는 잘 정의 된 패턴이있을 수 있습니다. 내가 볼게
JoeGeeky

@JoeGeeky 그렇습니다. Paxos 링크 에는 선호하는 통신 링크를 사용하여이를 구현할 수있는 시퀀스 다이어그램이 있습니다.
Peter K.

직접적인 대답은 아니지만 모든 Chubby 및 Paxos 자료를 읽음으로써 내 솔루션을 정의하는 데 도움이되었습니다. 나는 그 도구를 사용하지 않았지만 그들의 개념 중 일부를 기반으로 합리적인 패턴을 정의 할 수있었습니다. 감사.
JoeGeeky

@JoeGeeky : 적어도 도움이되었다 니 다행입니다. 진드기에 감사합니다.
Peter K.

4

여기에 두 가지 혼합 기술이있는 것처럼 보입니다.

  • 커뮤니케이션 (당신은 본질적으로 100 % 신뢰할 수있는 것에 의존합니다 ... 치명적일 수 있습니다)

  • 잠금 / 상호 배제

  • 타임 아웃 (어떤 목적으로)?

경고 : 분산 시스템의 시간 초과는 위험과 어려움을 겪을 수 있습니다. 시간 초과를 무차별 적으로 사용한다고해서 문제가 해결되는 것은 아니기 때문에 재앙을 미룰 수 있기 때문에 매우 신중하게 설정하고 사용해야합니다. (시간 초과 어떻게 사용 되는지 보려면 HDLC 통신 프로토콜 설명서를 읽고 이해하십시오. 이것은 유휴 비트와 같은 것을 감지 할 수있는 영리한 비트 코딩 시스템과 함께 적합하고 영리한 사용의 좋은 예입니다) .

한동안 나는 통신 링크 (TCP가 아닌 다른 것)를 사용하여 연결된 다중 프로세서 분산 시스템에서 일했다. 내가 배운 것 중 하나는 대략적인 일반화로서 위험한 멀티 프로그래밍 장소가 있다는 것입니다.

  • 대기열에 대한 의존은 일반적으로 눈물로 끝납니다 (대기열이 가득 차면 문제가 있습니다. 절대 채워지지 않는 대기열 크기를 계산할 수있는 경우 대기열이없는 솔루션을 사용할 수 있습니다)

  • 잠금에 의존하는 것은 고통스럽고 다른 방법이 있는지 시도하고 생각하십시오 (잠금을 사용해야하는 경우 문헌을 참조하십시오. 멀티 프로세서 분산 잠금은 지난 2-3 년 동안 많은 천문 논문의 주제였습니다)

잠금을 사용하여 진행해야합니다.

마지막 수단을 복구하는 수단으로 만 시간 초과를 사용한다고 가정합니다. 즉, 기본 통신 시스템의 오류를 감지하기위한 것입니다. 또한 TCP / IP 통신 시스템의 대역폭이 높고 지연 시간이 낮은 것으로 생각할 수 있다고 가정합니다 (이상적으로는 0이지만 결코 발생하지 않음).

내가 제안하는 것은 모든 노드에 연결할 수있는 다른 노드의 연결 목록이 있다는 것입니다. (노드는 연결의 출처를 신경 쓰지 않습니다.) 노드가 연결할 수있는 노드의 테이블 채우기는 분리 할 별도의 항목으로 남겨 두므로 정적으로 설정되는지 그렇지 않은지에 대해서는 언급하지 않았습니다. 연결이 노드로 들어오는 IP 포트 번호 할당과 같은 것도 편리하게 무시됩니다. 단일 포트 또는 여러 포트에서 요청을 수락해야하는 이유가있을 수 있습니다. 이것은 신중하게 고려해야합니다. 암시 적 큐잉, 순서 지정, 리소스 사용, 운영 체제 유형 및 기능이 요소에 포함됩니다.

노드가 연결 한 사람을 알고 나면 해당 노드에 잠금 요청을 보낼 수 있으며 해당 원격 노드의 잠금 응답에서 다시 수신해야합니다. 이 두 가지 작업을 래퍼로 묶어 원자 모양으로 만들 수 있습니다. 그 결과 잠금을 획득하려는 노드는 다음과 같은 호출을합니다.

if (get_lock(remote_node) == timeout) then
  {
    take some failure action - the comms network is down
  }

/* Lock is now acquired - do work here */

if (release_lock(remote_node) == timeout) then
  {
    take some failure action - the comms network is down
  }

get_lock 및 release_lock 호출은 원칙적으로 다음과 같아야합니다.

send_to_remote_node(lock_request)
get_from_remote_node_or_timeout(lock_reply, time)
if (result was timeout) then
  return timeout
else
  return ok

잠금이 유지되는 동안 수행되는 작업 단위가 작고 빠르다는 분산 잠금 시스템에주의를 기울여야합니다. 잠금을 얻기 위해 대기중인 많은 원격 노드가있을 수 있기 때문입니다. 이것은 사실상 멈춤-대기 다중 프로세서 / 통신 시스템으로 강력하지만 가능한 최고 성능을 갖지 않습니다.

제안은 완전히 다른 접근법을 취하는 것입니다. 각 RPC 호출에 수신자가 처리 할 수있는 정보 패키지가 들어 있고 잠금이 필요없는 원격 프로 시저 호출을 사용할 수 있습니까?


질문을 다시 읽으면 실제로 사물의 통신 측면에 관심이없는 것처럼 보이며 잠금 문제를 해결하려고합니다.

따라서 내 대답은 약간 주제가 아닌 것처럼 보일 수 있지만 부품 아래에 부품을 넣지 않으면 잠금 문제를 해결할 수 없다고 생각합니다. 유추 : 나쁜 기초 위에 집을 짓면 결국 쓰러집니다.


1
타임 아웃 시맨틱은 네트워크에서 사라지는 노드를 처리하거나 잠금 스택에서 큰 백 로그를 처리하기 위해 주로 존재합니다. 이는 잠금을 기다리는 동안 차단 된 시간을 제한하고 잠금을 요청하는 사용자에게 기회를 제공합니다. 예상치 못한 지연, 실패 등의 상황에서 다른 프로세스를 시작하기 위해 ... 또한 이것은 무언가 실패하는 경우 무언가가 영원히 잠기지 못하게합니다. 이 시점에서 귀하의 우려에 감사드립니다. 그러나 결국에는 어떤 것이 실패 할 것이라는 대안을
찾지

다른 의견들과 이야기하기 위해, 나는 비동기식 통신 의미에서 대기열 자체를 사용하지 않고 있지만, FIFO 패턴을 사용하여 잠금이 쌓이고 해제 될 것으로 기대합니다. 나는 이것이 어떤 방식으로 차단하고 더 큰 악수의 일부가되어야하는 것 이외의 필요한 요청 / 응답 패턴과 관련하여 어떻게 작동하는지 잘 조정하지 못했습니다. 현재 단일 노드 내에서 스택 잠금 메커니즘을 사용하고 있으며 분산 시나리오를 통해 작동하는 방식을 연구하고 있습니다. 당신이 제안한대로 조금 더 읽을 것입니다. 감사합니다
JoeGeeky

@JoeGeeky-FIFO는 대기열입니다. 대기열을 조심하십시오. 그 측면을 매우 신중하게 생각하십시오. "선반에서"무언가를 얻지 않을 것 같지만 문제와 해결책을 신중하게 생각해야 할 것 같습니다.
quick_now

이해합니다 ... 비동기 프로세스에 사용되는 FIFO 대기열의 차이 ( 예 : 하나의 프로세스 큐에 넣은 다음 다른 큐에 넣는 것)를 명확히하려고했습니다 . 이 경우 사물을 순서대로 관리해야하지만 대기열에 들어가는 프로세스는 (a) 잠금을 얻거나 (b) 잠금이 거부되거나 (c) 시간 초과되어 라인을 떠날 때까지 떠나지 않습니다. ATM에 줄을서는 것과 같습니다. 이는 성공 사례에서 FIFO 패턴처럼 작동하지만 프로세스가 라인의 앞에 도달하기 전에 순서가 잘못 될 수 있습니다. 기성품은? 아니요, 그러나 이것은 새로운 문제가 아닙니다
JoeGeeky

0

NCache와 같은 분산 캐시를 사용하여 질문을 쉽게 구현할 수 있습니다. 필요한 것은 객체를 사용하여 잠금을 획득 할 수있는 비관적 잠금 메커니즘입니다. 그런 다음 작업 및 작업을 수행하고 나중에 다른 응용 프로그램에서 사용할 수 있도록 잠금을 해제하십시오.

다음 코드를 살펴보십시오.

여기에서 특정 키에 대한 잠금을 얻은 다음 작업을 수행하고 (하나 이상의 작업에서) 작업이 완료되면 잠금을 해제합니다.

// Instance of the object used to lock and unlock cache items in NCache
LockHandle lockHandle = new LockHandle();

// Specify time span of 10 sec for which the item remains locked
// NCache will auto release the lock after 10 seconds.
TimeSpan lockSpan = new TimeSpan(0, 0, 10); 

try
{
    // If item fetch is successful, lockHandle object will be populated
    // The lockHandle object will be used to unlock the cache item
    // acquireLock should be true if you want to acquire to the lock.
    // If item does not exists, account will be null
    BankAccount account = cache.Get(key, lockSpan, 
    ref lockHandle, acquireLock) as BankAccount;
    // Lock acquired otherwise it will throw LockingException exception

    if(account != null && account.IsActive)
    {
        // Withdraw money or Deposit
        account.Balance += withdrawAmount;
        // account.Balance -= depositAmount;

        // Insert the data in the cache and release the lock simultaneously 
        // LockHandle initially used to lock the item must be provided
        // releaseLock should be true to release the lock, otherwise false
        cache.Insert("Key", account, lockHandle, releaseLock); 
        //For your case you should use cache.Unlock("Key", lockHandle);
    }
    else
    {
        // Either does not exist or unable to cast
        // Explicitly release the lock in case of errors
        cache.Unlock("Key", lockHandle);
    } 
}
catch(LockingException lockException)
{
    // Lock couldn't be acquired
    // Wait and try again
}

링크에서 가져옴 : http://blogs.alachisoft.com/ncache/distributed-locking/

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.