文档章节

Zookeeper的服务发现与注册原理解析

星逝流
 星逝流
发布于 2016/01/03 16:17
字数 1631
阅读 2582
收藏 16

Zookeeper是什么?按照Apache官网的描述是:

ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.

参照官网的定义,它能够做:

1. 作为配置信息的存储的中心服务器

2. 命名服务

3. 分布式的协调

4. Mater选举等

在定义中特别提到了命名服务。在调研之后,Zookeeper作为服务注册与发现的解决方案,它有如下优点:

1. 它提供的简单API

2. 已有互联网公司(例如:Pinterest,Airbnb)使用它来进行服务注册与发现

3. 支持多语言的客户端

4. 通过Watcher机制实现Push模型,服务注册信息的变更能够及时通知服务消费方

缺点是:

1. 引入新的Zookeeper组件,带来新的复杂性和运维问题

2. 需自己通过它提供的API来实现服务注册与发现逻辑(包含Python与Java版本)

我们对上述几个方案的优缺点权衡之后,决定采用了基于Zookeeper实现自己的服务注册与发现。

基于Zookeeper的服务注册与发现架构

在此架构中有三类角色:服务提供者,服务注册中心,服务消费者。

服务提供者

服务提供者作为服务的提供方将自身的服务信息注册到服务注册中心中。服务信息包含:

▪ 隶属于哪个系统

▪ 服务的IP,端口

▪ 服务的请求URL

▪ 服务的权重等等

服务注册中心

服务注册中心主要提供所有服务注册信息的中心存储,同时负责将服务注册信息的更新通知实时的Push给服务消费者(主要是通过Zookeeper的Watcher机制来实现的)。

服务消费者

服务消费者主要职责如下:

1. 服务消费者在启动时从服务注册中心获取需要的服务注册信息

2. 将服务注册信息缓存在本地

3. 监听服务注册信息的变更,如接收到服务注册中心的服务变更通知,则在本地缓存中更新服务的注册信息

4. 根据本地缓存中的服务注册信息构建服务调用请求,并根据负载均衡策略(随机负载均衡,Round-Robin负载均衡等)来转发请求

5. 对服务提供方的存活进行检测,如果出现服务不可用的服务提供方,将从本地缓存中剔除

服务消费者只在自己初始化以及服务变更时会依赖服务注册中心,在此阶段的单点故障通过Zookeeper集群来进行保障。在整个服务调用过程中,服务消费者不依赖于任何第三方服务。

实现机制介绍

Zookeeper数据模型介绍

在整个服务注册与发现的设计中,最重要是如何来存储服务的注册信息。

在设计基于Zookeeper的服务注册结构之前,我们先来看一下Zookeeper的数据模型。Zookeeper的数据模型如下图所示:

Zookeeper数据模型结构与Unix文件系统很类似,是一个树状层次结构。每个节点叫做Znode,节点可以拥有子节点,同时允许将少量数据存储在该节点下。客户端可以通过监听节点的数据变更和子节点变更来实时获取Znode的变更(Wather机制)。

服务注册结构

服务注册结构如上图所示。

▪ /dada来标示公司名称dada,同时能方便与其它应用的目录区分开(例如:Kafka的brokers注册信息放置在/brokers下)

▪ /dada/services将所有服务提供者都放置该目录下

▪ /dada/services/category1目录定义具体的服务提供者的id:category1,同时该Znode节点中允许存放该服务提供者的一些元数据信息,例如:名称,服务提供者的Owner,上下文路径(Java Web项目),健康检查路径等。该信息可以根据实际需要进行自由扩展。

▪ /dada/services/category1/helloworld节点定义了服务提供者category1下的一个服务:helloworld。其中helloworld为该服务的ID,同时允许将该服务的元数据信息存储在该Znode下,例如图中标示的:服务名称,服务描述,服务路径,服务的调用的schema,服务的调用的HTTP METHOD等。该信息可以根据实际需要进行自由扩展。

▪ /dada/services/category1/helloworld/providers节点定义了服务提供者的父节点。在这里其实可以将服务提供者的IP和端口直接放置在helloworld节点下,在这里单独放一个节点,是为了将来可以将服务消费者的消息挂载在helloworld节点下,进行一些扩展,例如命名为:/dada/services/category1/helloworld/consumers。

▪ /dada/services/category__1/helloworld/providers/192.168.1.1:8080该节点定义了服务提供者的IP和端口,同时在节点中定义了该服务提供者的权重。


下面着重介绍一下服务发现是如何工作的:

在上述类图中,类ServiceDiscovery主要通过Zookeeper的API(Python/Java版本)来获取服务信息,同时对服务注册结构中的每个服务的providers节点增加Watcher,来监控节点变化。获取的服务注册信息保存在变量service_repos中。通过在初始化时设置LoadBalanceStrategy的实现(Round-Robin算法,Radmon算法)来实现服务提供者的负载均衡。主要方法:

1. init获取Zookeeper的服务注册信息,并缓存在service_repos

2. get_service_repos方法获取实例变量service_repos

3. get_service_endpoint根据init构建好的service_repos,以及lb_strategy提供的负载均衡策略返回某个服务的URL地址

4. update_service_repos通过Zookeeper的Watcher机制来实时更新本地缓存service_repos

5. heartbeat_monitor是一个心跳检测线程,用来进行服务提供者的健康存活检测,如果出现问题,将该服务提供者从该服务的提供者列表中移除;反之,则加入到服务的提供者列表中

LoadBalanceStrategy定义了根据服务提供者的信息返回对应的服务Host和IP,即决定由那台主机+端口来提供服务。

RoundRobinStrategy和RandomStrategy分别实现了Round-Robin和随机的负载均衡算法


© 著作权归作者所有

共有 人打赏支持
星逝流
粉丝 11
博文 52
码字总数 82710
作品 0
昌平
高级程序员
加载中

评论(1)

张忠友
多谢作者,写的很棒,
基于zookeeper的远程方法调用(RMI)的实现

采用zookeeper的命令服务,采用不同的目录结构存储不同模块不同服务的rmi的url,使用key来对应不同的服务。同时采用zookeeper解决了单点问题。 当有两个相同的服务注册时,因为采用的是临时有...

蔡少东
2015/04/02
0
0
Spring Cloud(三) zookeeper实现服务治理

1.安装ZooKeeper 我这里直接使用docker安装zookeeper,docker是个好东西,推荐大家使用,安装docker和常用命令的使用可以去找找资料学习下 2. 服务注册和发现 1.1 Maven依赖 <dependencies>...

lemonLove
08/14
0
0
阿里巴巴为什么不用 ZooKeeper 做服务发现?

站在未来的路口,回望历史的迷途,常常会很有意思,因为我们会不经意地兴起疯狂的念头,例如如果当年某事提前发生了,而另外一件事又没有发生会怎样?一如当年的奥匈帝国皇位继承人斐迪南大公...

阿里云头条
06/06
0
0
SkyWalking 源码分析系列 —— Collector Cluster 集群管理

name="小幸运" singer="田馥甄 - 湘江音乐节" playlength="250" src="/cgi-bin/readtemplate?t=tmpl/qqmusictmpl&singer=%E7%94%B0%E9%A6%A5%E7%94%84%20-%20%E6%B9%98%E6%B1%9F%E9%9F%B3%E......

工匠小猪猪的技术世界
06/28
0
0
ZooKeeper学习笔记十三 分布式系统中基于ZooKeeper的服务注册中心设计

本文学习资源来自《分布式服务框架原理与实践》中国工信出版信息、电子工业出版社 一、服务注册中心 对于服务提供者,它需要发布服务;由于应用系统的复杂性,服务的数量、类型不断膨胀;对于...

xundh
05/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Akka的Actor生命周期《Eight》译

Actor在创建时出现,然后在用户请求时停止。每当一个Actor停止时,它的所有孩子也会被递归停止。此行为极大地简化了资源清理,并有助于避免资源泄漏,例如由打开的套接字和文件引起的资源泄漏...

woshixin
7分钟前
0
0
Python 线程 条件锁 生产者消费者模型

创建多个生产者和消费者,并且加上条件锁,避免线程冲突 import threadingfrom threading import Threadfrom threading import Conditionimport timeimport randomc = Conditi...

阿豪boy
23分钟前
0
0
【七】组合Action

本章描述了常用定义Action的方法。 自定义action builders 我们在action一章已经看过如何声明一个action——有request parameter、无request parameter、有body parser等等。你可以在 asynch...

Landas
40分钟前
0
0
Spring Boot实战之基础回顾

本文作者: 吴伟祥 本文链接: https://wuweixiang.cn/2018/08/21/Spring-Boot实战之基础回顾/ 版权声明: 本博客所有文章除特别声明外均为原创,采用CC BY-NC-SA 4.0 许可协议。转载请在文章开...

吴伟祥
40分钟前
0
0
OAuth认证开发

提示: 以下测试是基于项目安装成功,初始化数据库(initial_db.ddl, oauth.ddl, initial_data.ddl)后的测试, 也可在页面上点击"client_details"菜单里进行测试 方式1:基于浏览器 (grant_type=...

舒文joven
48分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部