假设此时,重新上线一个实例,其ip为192.168.1.5,那么此时zookeeper树形结构如下图所示:
服务上线服务消费者会去监听相应路径(/services),一旦路径上的数据有任务变化(增加或减少),zookeeper都会通知服务消费方服务提供者地址列表已经发生改变,从而进行更新。
实现下面是服务提供者在zookeeper注册中心注册时候的核心代码:
int ZKClient::Init(const std::string& host, int timeout,int retry_times) {
host_ = host;
timeout_ = timeout;
retry_times_ = retry_times;
hthandle_ = zookeeper_init(host_.c_str(), GlobalWatcher, timeout_,
NULL, this, 0);
return (hthandle_ != NULL) ? 0 : -1;
}
int ZKClient::CreateNode(const std::string& path,
const std::string& value,
int type) {
int flags;
if (type == Normal) {
flags = 0;
} else if (type == Ephemeral) {
flags = ZOO_EPHEMERAL;
} else {
return -1;
}
int ret = zoo_exists(hthandle_, path.c_str(), 0, NULL);
if (ret == ZOK) {
return -1;
}
if (ret != ZNONODE) {
return -1;
}
ret = zoo_create(hthandle_, path.c_str(), value.c_str(), value.length(),
&ZOO_OPEN_ACL_UNSAFE, flags, NULL, 0);
return ret == ZOK ? 0 : -1;
}
int main() {
std::string ip; // 当前服务ip
int port; // 当前服务的端口
std::string path = "/services/" + ip + ":" + std::to_string(port);
ZKClient zk;
zk.init(...);
//初始化zk客户端
zk.CreateNode(path, "", Ephemeral);
...
return 0
}
上面是服务提供者所做的一些操作,其核心功能就是:
在服务启动的时候,使用zookeeper的客户端,创建一个临时(Ephemeral)节点
从代码中可以看出,创建znode的时候,指定了其node类型为Ephemeral,这块非常重要,在zookeeper中,如果znode类型为Ephemeral,表明,在服务提供者跟注册中心断开连接的时候,这个节点会自动小时,进而注册中心会通知服务消费者重新获取服务提供者列表。
下面是服务消费者的核心代码:
int ZKClient::Init(const std::string& host, int timeout,int retry_times) {
host_ = host;
timeout_ = timeout;
retry_times_ = retry_times;
hthandle_ = zookeeper_init(host_.c_str(), GlobalWatcher, timeout_,
NULL, this, 0);
return (hthandle_ != NULL) ? 0 : -1;
}
int ZKClient::GetChildren(const std::string& path,
const std::function<int(const std::vector<std::tuple<std::string, std::string>>)>& on_change,
std::vector<std::tuple<std::string, std::string>>* children) {
std::lock_guard<std::recursive_mutex> lk(mutex_);
int ret = zoo_get_children(handle, path, 1, children); // 通过来获取子节点
if (ret == ZOK) {
node2children_[path] = std::make_tuple(on_change, *children); // 注册事件
}
return ret;
}
int main() {
ZKClient zk;
zk.Init(...);
std::vector children
// 设置回调通知,即在某个path下子节点发生变化时,进行通知
zk.GetChildren("/services", callback, children);
...
return 0;
}
对于服务消费者来说,其需要有两个功能:
获取服务提供者列表