1. 분산 잠금 장치 소개
분산 잠금 장치는 주로 분산 환경의 프로세스, 호스트 및 네트워크 전반에 걸쳐 공유 리소스를 보호하여 데이터 일관성을 보장하기 위해 상호 배타적 인 액세스를 달성하는 데 사용됩니다.
2. 건축 소개
Zookeeper를 사용하여 분산 잠금 장치를 구현하기 전에 먼저 현재 시스템 아키텍처 다이어그램을 살펴보십시오.
설명 : 왼쪽의 전체 영역은 동물원 키퍼 클러스터를 나타냅니다. 사물함은 Zookeeper의 지속적인 노드 이며 Node_1, Node_2 및 Node_3은 사물함의 지속적인 노드 아래의 임시 순차 노드 입니다. Client_1, Client_2, Client_n은 여러 클라이언트를 의미하며 서비스는 상호 배타적 인 액세스가 필요한 공유 리소스를 의미합니다.
분산 잠금 장치 획득을위한 아이디어
1. 분산 잠금 장치를 얻는 전반적인 아이디어
분산 잠금을 얻을 때, 사물함 노드 아래에 임시 순차 노드를 만들고 잠금을 출시 할 때 임시 노드를 삭제하십시오. 클라이언트는 CreateNode 메소드를 호출하여 사물함 아래에 임시 순차 노드를 생성 한 다음 GetChildren ( "Locker")을 호출하여 모든 어린이 노드를 사물함 아래로 가져옵니다. 현재 시청자는 필요하지 않습니다. 클라이언트가 모든 하위 노드 경로를 얻은 후에, 이전에 만든 자식 노드 번호가 가장 작다는 것을 알게되면 클라이언트가 잠금을 얻은 것으로 간주됩니다. 당신이 만든 노드가 사물함의 모든 아이들 중에서 가장 작지 않다는 것을 알게되면 잠금을 얻지 못했다는 것을 의미합니다. 현재 클라이언트는 노드보다 작은 노드를 찾은 다음 ENDESS () 메소드를 호출하고 이벤트 리스너를 등록해야합니다. 그 후, 당신이 관련된 노드를 삭제하면 클라이언트의 감시자는 해당 알림을받습니다. 이 시점에서, 당신은 당신이 만든 노드가 사물함 자식 노드 중에서 가장 작은 일련 번호인지 다시 결정할 것입니다. Rugao는 자물쇠를 얻었습니다. 그렇지 않은 경우 위의 단계를 반복하여 귀하보다 작은 노드를 계속 얻고 듣기 위해 등록하십시오. 현재 프로세스에는 여전히 많은 논리적 판단이 필요합니다.
2. 분산 잠금을 얻기위한 핵심 알고리즘 프로세스
다음은 다음과 같이 분산 잠금 잠금을 획득하기위한 완전한 알고리즘을 분석하는 것과 동일한 유량 차트입니다.
설명 : 클라이언트 A가 분산 잠금 잠금 장치를 얻으려면 먼저 사물함 아래에 임시 순차 노드 (Node_n)를 작성한 다음 즉시 사물함 아래에서 모든 (1 단계) 하위 노드를 얻습니다.
이 시점에서 여러 클라이언트가 동시에 잠금 장치와 경쟁하기 때문에 사물함의 자식 노드 수는 1보다 클 것입니다. 순차적 노드의 경우, 특성은 노드 이름 뒤에 숫자 숫자가 있다는 것입니다. 먼저 생성 된 노드의 수는 나중에 생성 된 것보다 작습니다. 따라서 하위 노드는 노드 이름의 접미사 순서대로 작고 큰 것으로 정렬 할 수 있습니다. 이런 식으로 첫 번째는 먼저 생성 된 순차 노드입니다. 현재로서는 자물쇠를 위해 먼저 노력하는 클라이언트를 나타냅니다! 현재 가장 작은 노드가 클라이언트 A에서 생성 한 node_n인지 확인하십시오. 그렇다면 클라이언트 A가 자물쇠를 획득했음을 의미합니다. 그렇지 않은 경우, 자물쇠가 다른 클라이언트가 인수했음을 의미합니다. 따라서 클라이언트 A는 잠금을 해제 할 때까지 기다려야합니다. 즉, 잠금을 얻은 클라이언트 B는 생성 된 노드를 삭제합니다.
현재 Client B가 Node_n Times보다 작은 순차 노드의 삭제 이벤트를 들음으로써 클라이언트 B가 잠금을 출시했는지 여부를 알게 될 것입니다. 그렇다면 클라이언트 A는 사물함 아래의 모든 어린이를 다시 획득하고 자체적으로 생성 된 node_n이 사물함의 모든 어린이들 사이에서 가장 작은 시퀀스 번호가 될 때까지 자체적으로 생성 된 node_n 노드와 비교합니다.
4. Zookeeper를 기반으로 분산 잠금 장치의 코드 구현
1. 분산 잠금 인터페이스를 정의합니다
정의 된 분산 잠금 인터페이스는 다음과 같습니다.
공개 인터페이스 분산 락 { / ** 잠금을 얻지 못하면 잠금을 얻지 못하면 대기* / public void arcire () 예외; / *** 타임 아웃까지 잠금을 획득* @param 시간 시간 초과 시간* @param 단위 단위 장치 시간 매개 변수 단위* @return* @throws 예외*/ public boolean arcire (긴 시간, 시간 유닛)는 예외를 던졌습니다. / *** 잠금 해제* @Throws Exception*/ public void release () throws Exception;}2. 간단한 뮤텍스를 정의하십시오
Mutex Lock 클래스를 정의하고, 위에서 정의 된 잠금 인터페이스를 구현하고, 기본 클래스를 기반으로 분산 된 분산을 상속합니다. 이 기본 클래스는 주로 잠금 장치와 릴리스 잠금을 얻는 방법을 포함하여 Zookeeper와 상호 작용하는 데 사용됩니다.
/** 잠금 인터페이스의 특정 구현은 주로 상속 된 상위 부모 클래스 기반 분산 록에 의해 달성됩니다. 부모 클래스는 Zookeeper의 특정 세부 사항을 기반으로 분산 잠금 장치를 구현하기위한 Zookeeper의 특정 세부 사항을 기반으로 구현됩니다.* /public class simplededpratedlockmutex는 DistributedLock 기반 분산 록 { /*이름이 사물함에 분산 잠금 장치를 구현하는 노드를 저장하는 데 사용됩니다.*이 노드는 인원 노드가되어야합니다. 이 노드 아래에서 임시 순차 노드를 생성하여 분산 잠금을 구현*/ 개인 최종 문자열 Basepath; /*잠금 이름 이름 접두사. 예를 들어, 사물함 아래에서 생성 된 순차 노드는 잠금으로 시작합니다. /* 후속 관련 작업 (예 : 판단)*/ private String ourLockPath; /*** 잠금 리소스를 획득하고 부모 클래스의 잠금 획득 방법을 통해 잠금을 얻는 데 사용되었습니다.* @param 시간의 시간 초과 시간을 얻기위한 시간* @param 단위 시간 단위 시간* @return* @throws 예외*/private boolean internallock (오랜 시간, 시간 단위)은 예외를 던졌습니다. 자세한 내용은 시도 록의 구현을 참조하십시오. ourlockpath = ritchlock (시간, 단위); ourlockpath! = null을 반환합니다. } /*** Zookeeper Client Connection Object를 통과하고 BasePath* @Param Client Zookeeper Client Connection Object* @Param BasePath BasePath는 영구적 인 노드* /public simplededpressedLockMutex (ZKClientExt Client, String BasePath) { /* 부모 클래스의 구성 자녀를 부르는 기저부의 구조물을 부릅니다. 노드 *Basepath의 참조를 현재 클래스 속성 */ super (client, basepath, lock_name)에 저장합니다. this.basepath = Basepath; } /** 타임 아웃까지 잠금을 획득하고 시간 초과 후 예외가 발생합니다.* /public void arcire ()는 예외를 {//-1으로 제외하고 시간 초과가 설정되지 않았 음을 의미하며, 시간 초과가 Zookeeper에 의해 결정됩니다. }} / *** 타임 아웃을 사용하여 잠금을 취득* / public boolean arcuire (긴 시간, TimeUnit Unit) 예외 {return InternAllock (Time, Unit); } / ** 잠금 해제* / public void release ()는 예외 {reeleaselock (ourlockpath); }}3. 분산 잠금의 구현에 대한 세부 사항
분산 잠금 잠금 장치를 획득하기위한 핵심 논리는 Basiver ProtentedLock이며, 동물원을 기반으로 분산 잠금 장치 구현의 세부 사항을 구현합니다.
공개 클래스 기반 DistributeDlock {Private Final Zkclientext Client; 개인 최종 문자열 경로; 개인 최종 문자열 Basepath; 개인 최종 문자열 LockName; 개인 정적 최종 정수 max_retry_count = 10; Public Based ProterbitedLock (zkclientext 클라이언트, 문자열 경로, String Lockname) {this.client = client; this.basepath = 경로; this.path = path.concat ( "/"). concat (lockname); this.lockname = lockname; } private void deleteourpath (String ourpath) 예외 {client.delete (ourpath); } private String createlockNode (zkclient client, String path)는 예외를 던집니다. } / ** * 잠금을 얻는 핵심 방법 * @param startmillis * @param millistowait * @param ourpath * @Throws Exception * / private boolean waittolock (long startmillis, long millistowait, string) {boolean havethelock = 거짓; 부울 dodelete = 거짓; try {while (! havethelock) {//이 메소드는 사물함 노드 아래의 모든 순차 노드의 획득을 구현하고 작은 목록에서 큰 목록에서 children = getSortedChildren (); 문자열 sequencenodename = ourpath.substring (basepath.length ()+1); // 사물함의 모든 자식 노드에서 클라이언트가 작성한 순서 노드의 정렬 위치를 계산합니다. 정렬이 0이면 잠금이 얻어 졌음을 의미합니다. int ourindex = children.indexof (Sequencenodename); /*이전에 만든 [임시] 주문 노드가 GetSortedChildren에서 찾을 수없는 경우, 이는 네트워크 플래시 브레이크로 인해 우리가 만든 노드가 삭제 될 수 있음을 의미합니다. 예외를 던져야합니다. 이전 레벨이 *를 처리하도록하십시오. *이전 레벨은 예외를 포착하고 지정된 레트리 수를 실행하는 것입니다. 후속 시도 록 메소드*/ if (ourIndex <0) {throw new zknonodeexception ( "찾을 수 없음 :" + sequencenodeName); } // Locker Child 노드 목록에서 현재 클라이언트가 생성 한 노드가 0보다 큰 경우 다른 클라이언트가 잠금을 획득했음을 의미합니다. // 현재 클라이언트는 다른 클라이언트가 잠금을 해제 할 때까지 기다려야합니다. Boolean isgetThelock = ourIndex == 0; // 다른 클라이언트가 잠금을 출시했는지 여부를 결정하는 방법은 무엇입니까? 하위 노드 목록에서 노드를 더 작게 가져 와서 문자열 pathtowatch = isgetThelock에 대한 청취 세션을 설정 하시겠습니까? NULL : children.get (ourindex -1); if (isgetThelock) {havethelock = true; } else {// 작은 노드가 삭제되면 현재 클라이언트의 노드가 가장 작아야하므로 CountdownLatch를 사용하여 대기 문자열을 실현하여 previousectionpath = basepath .concat ( "/") .concat (pathtowatch); Final CountdownLatch Latch = New CountdownLatch (1); 최종 izkdatalistener previousListener = new IZKDATALISTERE () {// 작은 노드 삭제 이벤트가 발생하면 CountdownLatch가 끝나고 기다릴 때 // 이시기에는 프로그램이 다시 돌아와서 새로운 판단을 내려야합니다! public void handledatadeleted (String Datapath)는 예외 {latch.countdown (); } public void handledAtachange (문자열 datapath, 객체 데이터) 예외 {// ingore}}; 시도 {// 노드가 존재하지 않는 경우 client.subscribedatachanges (previous everatecencepath, previouslistener); if (millistowait! = null) {millistowait- = (System.CurrentTimeMillis () - StartMillis); startMillis = System.CurrentTimeMillis (); if (millistowait <= 0) {dodelete = true; // 시간 초과 - 노드 브레이크를 삭제합니다. } latch.await (millistowait, timeUnit.microseconds); } else {latch.await (); }} catch (zknonodeexception e) {// ingore} 마침내 {client.unsubscribedAtachanges (previousectionpath, previousListener); }}}}} catch (예외 e) {// 예외가 삭제되어야합니다. dodelete = true; e 던지기; } 마지막으로 {// if (dodelete) {deleteourpath (ourpath); }} return havethelock; } private String getLockNodEnumber (String str, String LockName) {int index = str.lastIndexOf (LockName); if (index> = 0) {index += lockname.length (); return index <= str.length ()? str.substring (index) : ""; } return str; } private list <string> getSortedChildren ()은 예외를 던져 {try {list <string> children = client.getchildren (basepath); collections.sort (children, new comparator <string> () {public int compare (String LHS, String RHS) {return getLockNodenumber (lhs, lockname) .compareto (getLockNodenumber (RHS, LockName));}}); 아이들을 돌려주십시오. } catch (zknonodeexception e) {client.createPersistent (Basepath, true); return getSortedChildren (); }} Protected void releaselock (String Lockpath) 예외 {deleteourpath (lockpath); } 보호 된 문자열 시도 lock (Long Time, TimeUnit Unit)은 예외를 던집니다. {Final Long StartMillis = System.CurrentTimeMillis (); 최종 Long Millistowait = (단위! = null)? init.tomillis (시간) : null; String ourpath = null; 부울 hasthelock = false; 부울 isdone = 거짓; int retrycount = 0; // net flash break는 (! isdone) {isdone = true; try {// createlocknode는 클라이언트가 Locker (Basepath Persistent Node) 아래 잠금을 얻을 수 있도록 [임시] 주문 노드를 작성하는 데 사용됩니다. ourpath = createlocknode (클라이언트, 경로); / ***이 방법은 잠금 장치가 얻어 졌는지, 즉 직접 생성 된 순서 노드가 로커의 모든 어린이 노드 중에서 가장 작은 지 여부를 결정하는 데 사용됩니다.* 잠금이 획득되지 않으면 잠금이 해제 될 때까지 기다렸다가 잠금이 획득되거나 시간이 오래 걸릴 때까지 다시 시도하십시오 (startMillis, millistowait, our purpate); } catch (zknonodeexception e) {if (retrycount ++ <max_retry_count) {isdone = false; } else {throw e; }}}} if (hasthelock) {return ourpath; } return null; }위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.