记录java中zookeeper客户端ZkClient一个小坑
项目中使用org.I0Itec.zkclient.ZkClient库作为zookeeper的连接工具,一直很稳定。不过有个奇怪的问题,从ZooInspetor中连接Zookeeper,看NodeData,会发现数据像图中这样,字符串前面有一段奇怪的字符:
一直不清楚"t%"这些像乱码一样的字符是什么东西。因为项目运行的比较稳定,也没报错,就一直没管。
最近涉及到跨语言,要使用Golang去连接相同的zookeeper,就有问题了。去研究了一下,倒是比较容易找到原因。下面是示例代码:
import org.I0Itec.zkclient.IZkDataListener; import org.I0Itec.zkclient.ZkClient; import org.I0Itec.zkclient.serialize.SerializableSerializer; public class ZooKeeperClient { private static final String ZOOKEEPER_SERVER = "localhost:2181"; private static final String NODE_PATH = "/example_node"; public static void main(String[] args) { // 创建一个 ZkClient 实例 ZkClient zkClient = new ZkClient(ZOOKEEPER_SERVER);
// 默认数据编码为 SerializableSerializer
// zkClient.setZkSerializer(new BytesPushThroughSerializer());
// 写入节点数据 zkClient.writeData(NODE_PATH, "Hello, ZooKeeper!"); // 读取节点数据 String nodeData = zkClient.readData(NODE_PATH); System.out.println("节点数据:" + nodeData); // 注册节点数据监听器 zkClient.subscribeDataChanges(NODE_PATH, new IZkDataListener() { @Override public void handleDataChange(String dataPath, Object data) throws Exception { System.out.println("节点数据变化:" + data); } @Override public void handleDataDeleted(String dataPath) throws Exception { System.out.println("节点数据被删除"); } }); // 修改节点数据,触发数据变化事件 zkClient.writeData(NODE_PATH, "Updated data"); // 等待一段时间,观察数据变化事件 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } // 删除节点 zkClient.delete(NODE_PATH); // 关闭 ZkClient zkClient.close(); } }
问题就出在"默认数据编码为 SerializableSerializer"这里了。查看ZkCLient构造方法的源码:
new ZkClient(ZOOKEEPER_SERVER)构造的zk客户端,默认的使用的序列化策略为SerializableSerializer,它用于将节点数据以 Java 的序列化方式进行编码和解码。所以才导致了使用工具查看节点时,发现节点数据前面带有一段意义不明的字符串。
我的解决方法是:
1.zkClient.setZkSerializer(new BytesPushThroughSerializer());
2.zkClient.writeData(NODE_PATH, "Hello, ZooKeeper!".getBytes("UTF-8"));
3.String nodeData = new String(zkClient.readData(NODE_PATH), "UTF-8");
BytesPushThroughSerializer的
实现也很简单,它直接将字节数组作为节点数据进行写入和读取,不做任何序列化和反序列化操作。如何有自定义的要求也可以自定义实现自己的 ZkSerializer
接口,根据具体需求选择适合的编码方式。至此问题解决