/**
* 创建节点
*/
@Test
public void createNodeTest() {
System.out.println("conneted ok!");
User user = new User();
user.setId("1");
user.setName("testUser");
/**
* testUserNode" :节点的地址
* user:数据的对象
* CreateMode.PERSISTENT:创建的节点类型
*/
String createPath = "/testUserNode" + new Date().getTime();
String path = zkClient.create(createPath, user, CreateMode.PERSISTENT_SEQUENTIAL);
//输出创建节点的路径
System.out.println("createPath:" + createPath);
System.out.println("created path:" + path);
}
跟踪代码进入zkClient.create:
进入到 ZooKeeper.java
public String create(String path, byte[] data, List<ACL> acl, CreateMode createMode) throws KeeperException, InterruptedException {
PathUtils.validatePath(path, createMode.isSequential());
EphemeralType.validateTTL(createMode, -1L);
String serverPath = this.prependChroot(path);
RequestHeader h = new RequestHeader();
h.setType(createMode.isContainer() ? 19 : 1);
CreateRequest request = new CreateRequest();
CreateResponse response = new CreateResponse();
request.setData(data);
request.setFlags(createMode.toFlag());
request.setPath(serverPath);
if (acl != null && acl.size() == 0) {
throw new InvalidACLException();
} else {
request.setAcl(acl);
ReplyHeader r = this.cnxn.submitRequest(h, request, response, (ZooKeeper.WatchRegistration)null);
if (r.getErr() != 0) {
throw KeeperException.create(Code.get(r.getErr()), path);
} else {
return this.cnxn.chrootPath == null ? response.getPath() : response.getPath().substring(this.cnxn.chrootPath.length());
}
}
}
继续跟踪代码,发现zk客户端和服务端的通信,比较依赖 ClientCnxn.java , 而在序列化时依赖于工具:ReplyHeader.java
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.jute.BinaryInputArchive;
import org.apache.jute.BinaryOutputArchive;
import org.apache.jute.CsvOutputArchive;
import org.apache.jute.InputArchive;
import org.apache.jute.OutputArchive;
import org.apache.jute.Record;
import org.apache.yetus.audience.InterfaceAudience.Public;
@Public
public class ReplyHeader implements Record {
private int xid;
private long zxid;
private int err;
public ReplyHeader() {
}
.............................
.............................
}
从导入的包可以看到,ReplyHeader 使用了org.apache.jute来进行序列化。由此可知,zookeeper使用了org.apache.jute来进行序列化。
接下来我们继续观察zookeeper实现nio的方式。
通过对服务端进行断点,发现了关键代码:NIOServerCnxnFactory.java
public void doWork() throws InterruptedException {
if (!key.isValid()) {
selectorThread.cleanupSelectionKey(key);
return;
}
if (key.isReadable() || key.isWritable()) {
cnxn.doIO(key);
// Check if we shutdown or doIO() closed this connection
if (stopped) {
cnxn.close();
return;
}
if (!key.isValid()) {
selectorThread.cleanupSelectionKey(key);
return;
}
touchCnxn(cnxn);
}
// Mark this connection as once again ready for selection
cnxn.enableSelectable();
// Push an update request on the queue to resume selecting
// on the current set of interest ops, which may have changed
// as a result of the I/O operations we just performed.
if (!selectorThread.addInterestOpsUpdateRequest(key)) {
cnxn.close();
}
}
通过观察NIOServerCnxnFactory的依赖包:
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Queue;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
可以得知,通信使用了java.nio包socket通信;
另外,可以看到源码中还存在netty的nio工厂类,故可猜测zookeeper是支持两种方式的nio;