服务发现-从原理到实现 (4)

服务下线

服务下线

假设此时,重新上线一个实例,其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;
}

对于服务消费者来说,其需要有两个功能:

获取服务提供者列表

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwwdsd.html