Curator異步接口
Curator中引入了BackgroundCallback接口,用來處理異步接口調用之後服務端返回的結果信息,其接口定義如下。
public interface BackgroundCallback {
void processResult(CuratorFramework client, CuratorEvent event) throws Exception;
}
Backg roundCallback接口只有一一個processResult方法,該方法會在操作完成後被異步調用。該方法的參數說明如下:
CuratorEvent定義了Zookeeper服務端發送到客戶端的一系列事件參數,其中比較重要的有事件類型和響應碼兩個參數:
事件類型(CuratorEventType):
getType()會返回事件的類型,主要有:
- CREATE:對應方法
CuratorFramework#create()
- DELETE:對應方法
CuratorFramework#delete()
- EXISTS:對應方法
CuratorFramework#checkExists()
- GET_DATA:
CuratorFramework#getData()
- SET_DATA:
CuratorFramework#setData()
- CHILDREN:
CuratorFramework#getChildren()
- SYNC:
CuratorFramework#sync(String,Object)
- GET_ACL:
CuratorFramework#getACL()
- WATCHED:
Watchable#usingWatcher(Watcher)
和Watchable#watched()
- CLOSING:對應Zookeeper客戶端與服務度斷開連接事件
響應碼(int):
響應碼用於標識事件的結果狀態,所有響應碼都被定義在org . apache. zookeeper .KeeperException. Code類中
OK(0),//成功
SYSTEMERROR(-1),//服務端內部錯誤
RUNTIMEINCONSISTENCY(-2),
DATAINCONSISTENCY(-3),
CONNECTIONLOSS(-4),//斷開連接
MARSHALLINGERROR(-5),
UNIMPLEMENTED(-6),
OPERATIONTIMEOUT(-7),
BADARGUMENTS(-8),
APIERROR(-100),
NONODE(-101),
NOAUTH(-102),
BADVERSION(-103),
NOCHILDRENFOREPHEMERALS(-108),
NODEEXISTS(-110),//指定節點已存在
NOTEMPTY(-111),
SESSIONEXPIRED(-112),//會話過期
INVALIDCALLBACK(-113),
INVALIDACL(-114),
AUTHFAILED(-115),
SESSIONMOVED(-118),
NOTREADONLY(-119);
異步API:
Backgroundable<T>
-- public T inBackground();
-- public T inBackground(Object context);
-- public T inBackground(BackgroundCallback callback);
-- public T inBackground(BackgroundCallback callback, Object context);
-- public T inBackground(BackgroundCallback callback, Executor executor);
-- public T inBackground(BackgroundCallback callback, Object context, Executor executor);
在ZooKeeper中,所有異步通知事件處理都是由EventThread這個線程來處理的——EventThread 線程用於串行處理所有的事件通知。EventThread的“串行處理機制”在絕大部分應用場景下能夠保證對事件處理的順序性,但這個特性也有其弊端,就是一旦碰上一個複雜的處理單元,就會消耗過長的處理時間,從而影響對其他事件的處理。因此,在上面的inBackground接口中,允許用戶傳入一個Executor實例,這樣一來,就可以把那些比較複雜的事件處理放到一一個專門的線程池中去,如Executors. newFixedThreadPool( 2 )。
//使用Curator的異步接口
public class Create_Node_Background_Sample {
static String path = "/zk-book";
static CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("127.0.0.1:2181")
.sessionTimeoutMs(5000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.build();
static CountDownLatch semaphore = new CountDownLatch(2);
static ExecutorService tp = Executors.newFixedThreadPool(2);
public static void main(String[] args) throws Exception {
client.start();
System.out.println("main thread: " + Thread.currentThread().getName());
//此處傳入了自定的Executor
client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL)
.inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
System.out.println("event[code: ]" + curatorEvent.getResultCode() + ", type: " + curatorEvent.getType() + "}");
System.out.println("Thread of processResult: " + Thread.currentThread().getName());
semaphore.countDown();
}
}, tp).forPath(path, "init".getBytes());
//此處沒有傳入自定義的Executor
client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL)
.inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
System.out.println("event[code: ]" + curatorEvent.getResultCode() + ", type: " + curatorEvent.getType() + "}");
System.out.println("Thread of processResult: " + Thread.currentThread().getName());
semaphore.countDown();
}
}).forPath(path, "init".getBytes());
semaphore.await();
tp.shutdown();
}
}
main thread: main
event[code: ]-110, type: CREATE}
Thread of processResult: main-EventThread
event[code: ]0, type: CREATE}
Thread of processResult: pool-3-thread-1
上面這個程序使用了異步接口inBackground來創建節點,前後兩次調用,創建的節點名相同。從兩次返回的event中可以看出,第一次返回的響應碼是0,表明此次調用成功,即創建節點成功;而第二次返回的響應碼是-110,表明該節點已經存在,無法重複創建。這些響應碼和ZooKeeper原生的響應碼是一致的。
另外,我們再來看看前後兩次調用inBackground接口時傳入的Executor參數。第一次傳入了一個ExecutorService,這樣一來,Curator 的異步事件處理邏輯就會交由該線程池去做。而第二次調用時,沒有傳入任何Executor,因此會使用ZooKeeper默認的EventThread來處理。