zookeeper 분포 식 자물쇠 의 실현
본 고 는 주로 ZooKeeper 를 사용 하여 분포 식 자 물 쇠 를 실현 하 는 과정 에서 '양 떼 효과 (herdeffect)' 의 등장 을 어떻게 효과적으로 피 하 는 지 설명 한다.
마지막 으로 실현 코드 가 있 으 니 참고 하 시기 바 랍 니 다.
본 고 는 과 다음 과 같은 홈 페이지 내용 을 참고 하여 실현 했다.
http://aliapp.blog.51cto.com/8192229/1328018
실현 과정 은 다음 과 같다.
일반적인 분포 식 잠 금 실현
일반적인 분포 식 자물쇠 가 어떻게 실현 되 는 지 간단하게 말씀 드 리 겠 습 니 다.구체 적 인 코드 실현 은 여기 서 볼 수 있다. https://svn.apache.org/repos/asf/zookeeper/trunk/src/recipes/lock/
앞에서 언급 한 바 와 같이 zookeeper 에서 노드 의 생 성 유형 은 4 가지 가 있 는데 여기 서 우 리 는 임시 순서 노드 에 중심 을 두 었 다.이런 유형의 노드 는 몇 가지 특성 이 있다.
노드 의 생명주기 와 클 라 이언 트 세 션 이 연결 되 어 있 습 니 다. 즉, 노드 를 만 드 는 클 라 이언 트 세 션 이 효력 을 잃 으 면 이 노드 도 삭 제 됩 니 다.
모든 부모 노드 는 하위 노드 가 만 든 선후 순 서 를 유지 하고 순서 노드 (SEQUENTIAL) 를 만 들 면 부모 노드 는 자동 으로 이 노드 에 성형 수 치 를 분배 하고 접미사 형식 으로 노드 이름 에 자동 으로 추가 하여 이 노드 의 최종 노드 이름 으로 한다.
위의 두 가지 특성 을 이용 하여 분포 식 잠 금 을 실현 하 는 기본 논 리 를 살 펴 보 자.
클 라 이언 트 가 create () 방법 을 호출 하여 " locknode / guid - lock -" 라 는 노드 를 만 듭 니 다. 주의해 야 할 것 은 이 노드 의 생 성 유형 을 EPHEMERAL 로 설정 해 야 합 니 다.SEQUENTIAL。
클 라 이언 트 는 getChildren (" locknode") 방법 을 호출 하여 만 든 모든 하위 노드 를 가 져 오고 이 노드 에 하위 노드 변경 알림 을 등록 하 는 Watcher 입 니 다.
클 라 이언 트 가 모든 하위 노드 path 를 가 져 온 후에 자신 이 단계 1 에서 만 든 노드 가 모든 노드 에서 번호 가 가장 작은 것 을 발견 하면 이 클 라 이언 트 가 자 물 쇠 를 얻 었 다 고 생각 합 니 다.
3 단계 에서 자신 이 모든 하위 노드 에서 가장 작은 것 이 아니 라 는 것 을 발견 하면 자신 이 자 물 쇠 를 얻 지 못 했다 는 것 을 설명 하고 다음 하위 노드 가 알림 을 변경 할 때 까지 기 다 렸 다가 하위 노드 를 가 져 와 자 물 쇠 를 가 져 올 지 여 부 를 판단 한다.
자 물 쇠 를 풀 어 주 는 과정 은 상대 적 으로 간단 하 다. 바로 자신 이 만 든 하위 노드 를 삭제 하면 된다.
문제 의 소재
위의 이 분포 식 자물쇠 의 실현 에서 대체적으로 일반적인 분포 식 클 러 스 터 경쟁 자물쇠 의 수 요 를 만족 시 킬 수 있다.여기 서 말 하 는 일반적인 장면 은 군집 규모 가 크 지 않 고 보통 10 대의 기계 안에 있다 는 것 을 말한다.
그러나 위의 실현 논 리 를 곰 곰 이 생각해 보면 우 리 는 쉽게 문 제 를 발견 할 수 있다. 절차 4. '즉, 모든 하위 점 을 얻 고 자신 이 만 든 노드 가 번호 가 가장 작은 노드 인지 판단 하 는 것' 이다. 이 과정 은 전체 분포 식 자물쇠 의 경쟁 과정 에서 대량의 재 운행 을 하고 대부분 운행 결 과 는 자신 이 번호 가 가장 작은 노드 가 아니 라 는 것 을 판단 한다.다음 통 지 를 계속 기다 리 는 것 은 분명 과학적 으로 보이 지 않 는 다.클 라 이언 트 는 자신 과 관련 이 없 는 사건 통 지 를 이유 없 이 많이 받 습 니 다. 이것 은 클 라 이언 트 규모 가 클 때 서버 에 큰 성능 영향 을 줄 수 있 습 니 다. 그리고 같은 시간 에 여러 노드 의 클 라 이언 트 가 연결 을 끊 으 면 서버 는 다른 클 라 이언 트 처럼 대량의 사건 통 지 를 보 냅 니 다. 이것 이 바로 양 떼 효과 입 니 다.이 문제 의 근원 은 클 라 이언 트 의 진정한 관심 사 를 제대로 찾 지 못 한 데 있다.
우 리 는 위의 분포 식 자물쇠 경쟁 과정 을 다시 한 번 살 펴 보 자. 그의 핵심 논 리 는 자신 이 모든 노드 에서 번호 가 가장 작은 지 판단 하 는 것 이다.그래서 쉽게 연상 할 수 있 는 것 은 모든 노드 의 창조 자 는 자신의 번호 보다 작은 노드 에 만 관심 을 가 져 야 한 다 는 것 이다.
개 선 된 분포 식 잠 금 실현
다음은 개 선 된 분포 식 자물쇠 실현 입 니 다. 이전의 실현 방식 과 유일 하 게 다른 점 은 모든 자물쇠 경쟁자 로 설계 되 었 습 니 다. 관심 만 가 져 야 합 니 다. "locknode_”노드 아래 번호 가 자신 보다 작은 노드 가 존재 하 는 지 확인 하면 됩 니 다.다음 과 같이 구현:
클 라 이언 트 가 create () 방법 을 호출 하여 " locknode / guid - lock -" 라 는 노드 를 만 듭 니 다. 주의해 야 할 것 은 이 노드 의 생 성 유형 을 EPHEMERAL 로 설정 해 야 합 니 다.SEQUENTIAL。
클 라 이언 트 는 getChildren (" locknode") 방법 으로 만 든 모든 하위 노드 를 가 져 옵 니 다. 여 기 는 Watcher 를 등록 하지 않 습 니 다.
클 라 이언 트 가 모든 하위 노드 path 를 가 져 온 후에 자신 이 단계 1 에서 만 든 노드 번호 가 가장 작은 것 을 발견 하면 이 클 라 이언 트 가 자 물 쇠 를 얻 었 다 고 생각 합 니 다.
3 단계 에서 자신 이 모든 하위 노드 에서 가장 작은 것 이 아니 라 는 것 을 발견 하면 자신 이 아직 자 물 쇠 를 얻 지 못 했다 는 것 을 의미한다.이 때 클 라 이언 트 는 자신 보다 작은 노드 를 찾 은 다음 에 exist () 방법 을 호출 하고 이벤트 감청 을 등록 해 야 합 니 다.
그 후에 이 주 목 받 는 노드 가 제거 되면 클 라 이언 트 는 해당 하 는 통 지 를 받 을 것 이다.이 럴 때 클 라 이언 트 는 getChildren (" locknode") 방법 을 다시 호출 하여 만 든 모든 하위 노드 를 가 져 와 서 자신 이 가장 작은 노드 임 을 확인 한 다음 에 3 단계 에 들 어가 야 합 니 다.
코드 구현:
package cn.liu.zookeeper.ch14;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.KeeperState;
public class ConnectionWatcher implements Watcher {
private static final int SESSION_TIMEOUT = 5000;
protected ZooKeeper zk;
private CountDownLatch connectedSignal = new CountDownLatch(1);
public void connect(String hosts) throws IOException, InterruptedException {
zk = new ZooKeeper(hosts, SESSION_TIMEOUT, this);
connectedSignal.await();
}
@Override
public void process(WatchedEvent event) {
if (event.getState() == KeeperState.SyncConnected) {
connectedSignal.countDown();
}
}
public void close() throws InterruptedException {
zk.close();
}
}
package cn.liu.zookeeper.project;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.data.Stat;
import cn.liu.zookeeper.ch14.ConnectionWatcher;
/**
*
*
*
* zookeeper ; ,
* , ,
*
*
* (Herd Effect),
*
*
*
*
* @author Liu Dengtao
*
* 2014-2-28
*/
public class DistributedLock extends ConnectionWatcher {
public String join(String groupPath)
throws KeeperException, InterruptedException {
String path = groupPath + "/lock-" + zk.getSessionId() + "-";
//
String createdPath = zk.create(path, null/* data */,
Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println("Created " + createdPath);
return createdPath;
}
/**
*
* @param groupPath
* @param myName
* @return
* @throws KeeperException
* @throws InterruptedException
*/
public boolean checkState(String groupPath,String myName) throws KeeperException, InterruptedException{
List<String> childList = zk.getChildren(groupPath, false);
String[] myStr = myName.split("-");
long myId = Long.parseLong(myStr[2]);
boolean minId = true;
for (String childName : childList) {
String[] str = childName.split("-");
long id = Long.parseLong(str[2]);
if (id < myId) {
minId = false;
break;
}
}
if (minId) {
System.out.println(new Date() + " , ! myId:" + myId);
return true;
}else {
System.out.println(new Date() + " , myId:" + myId);
return false;
}
}
/**
* , ( )
* @param groupPath
* @param myName
* @throws KeeperException
* @throws InterruptedException
*/
public void listenNode(final String groupPath, final String myName) throws KeeperException, InterruptedException{
List<String> childList = zk.getChildren(groupPath, false);
String[] myStr = myName.split("-");
long myId = Long.parseLong(myStr[2]);
List<Long> idList = new ArrayList<Long>();
Map<Long, String> sessionMap = new HashMap<Long, String>();
for (String childName : childList) {
String[] str = childName.split("-");
long id = Long.parseLong(str[2]);
idList.add(id);
sessionMap.put(id, str[1]+"-"+str[2]);
}
Collections.sort(idList);
int i = idList.indexOf(myId);
if (i <=0) {
throw new IllegalArgumentException(" !");
}
//
long headId = idList.get(i-1);
String headPath = groupPath + "/lock-" + sessionMap.get(headId);
System.out.println(" :" + headPath);
Stat stat = zk.exists(headPath, new Watcher(){
@Override
public void process(WatchedEvent event) {
System.out.println(" " + event.getType() + " !");
try {
while(true){
if (checkState(groupPath,myName)) {
Thread.sleep(3000);
System.out.println(new Date() + " !");
System.exit(0);
}
Thread.sleep(3000);
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
System.out.println(stat);
}
public static void main(String[] args) throws Exception {
DistributedLock joinGroup = new DistributedLock();
joinGroup.connect("localhost:" + "2181");
//zookeeper ; ,
String groupName = "zkRoot";
String memberName = "_locknode_";
String path = "/" + groupName + "/" + memberName;
String myName = joinGroup.join(path);
if (!joinGroup.checkState(path, myName)) {
joinGroup.listenNode(path, myName);
}
Thread.sleep(Integer.MAX_VALUE);
joinGroup.close();
}
}
// ^^ JoinGroup
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.