当前位置: 首页 > 科技观察

基于Zookeeper的服务注册和发现

时间:2023-03-14 09:52:54 科技观察

背景大多数系统都是从单系统开始的。随着公司业务的快速发展,这个单体系统变得越来越庞大,带来了几个问题:1、随着访问量的不断攀升,问题不能单纯通过提高机器的性能来解决,而系统无法有效横向扩展。2.维护这个单一的系统变得越来越复杂。3.同时,随着业务场景的不同和研发的大量招募,带来了不同技术背景的工程师,在原有达达Python技术栈的基础上引入了Java技术栈。如何解决这些问题?业务服务是解决大型系统性能瓶颈和复杂性的有效手段。通过系统拆分将原来单一的庞大系统拆分成小系统,带来以下好处:1.很好的分流了原有系统的压力,有效解决了原有系统的瓶颈,带来了更好的扩展性2.代码独立基础、业务逻辑少,系统可维护性得到极大增强。同时也带来了一系列的问题:?系统服务越来越多,如何管理这些服务??如何将请求分发给提供相同服务的多台主机(如何做负载均衡)?如果提供服务的Endpoint发生变化,如何通知服务的调用者?原创解决方案的创始人LinkedinReedHoffman曾说过:创办一家初创公司就像跳下悬崖,然后在下坠的途中组装一架飞机。初创公司达达也是如此,其业务正以火箭般的速度发展。技术在业务发展中的作用是保障业务稳定运行,快速“组装飞机”。所以在业务服务化初期,我们采用Nginx+本地hosts文件的方式来注册和发现内部服务。与Nginx的IP绑定信息,调用服务2.Nginx用于对服务提供者提供的服务进行存活检查和负载均衡3.服务提供者提供服务供服务消费者访问,分发请求通过Nginx。当内部系统比较小,访问量比较少的时候,解决服务注册、发现和负载均衡的问题。但是,随着内部服务越来越多,访问越来越多,这种架构的隐患也逐渐暴露出来:?最明显的问题是Nginx存在单点故障(SPOF)。改进将成为性能瓶颈。随着内部服务越来越多,不同的服务消费者需要配置不同的主机。新增主机时很容易忘记配置主机,造成服务调用问题,增加运维。负担?服务的配置信息分散在各个主机,难以保持一致性,不方便服务管理?服务主机的发布和下线需要手动修改Nginx上游配置,修改后的配置需要在线,不利于快速服务如何部署解决在谈如何解决之前,先梳理一下服务注册和发现的目标:?服务注册信息要统一保存,方便服务管理?通过服务名称自动发现服务,而无需知道服务提供的端点是哪台主机?支持服务负载平衡和故障转移?添加或删除服务端点对服务消费者来说是透明的?支持Python和Java备份选项1:DNSDNS是一种相对简单的服务注册和发现解决方案。只需在DNS服务上配置一个DNS名称到IP的对应关系即可。定位一个服务,只需要连接到DNS服务器,随机返回一个IP地址即可。由于有DNS缓存,DNS服务器本身不会成为瓶颈。这种拉取方式无法及时获取服务状态更新(例如:服务IP更新等)。如果服务的提供者失败,由于DNS缓存的存在,服务的调用者仍然会将请求转发给失败的服务提供者;反之亦然。备选方案2:DubboDubbo是阿里巴巴推出的分布式服务框架,致力于解决服务注册与发现、编排和治理。其优点如下:1.功能全面,易于扩展2.支持各种序列化协议(JSON、Hession、java序列化等)3.支持各种RPC协议(HTTP、JavaRMI、Dubbo自带的RPC协议等)4、支持多种负载均衡算法5、其他高级特性:服务编排、服务治理、服务监控等缺点如下:1、只支持Java,对Python没有相应的支持2、虽然是开放的source,没有成熟的社区来运维,以后升级可能会比较麻烦。3.重量级解决方案带来新的复杂性备选方案3:Zookeeper什么是Zookeeper?根据Apache官网的描述:ZooKeeper是一个维护配置信息、命名、提供分布式同步、提供群组服务的集中式服务。参考官网??的定义,它可以做到:1.作为存储配置信息的中心服务器2.命名服务3.分布式协调4.Mater选举等在命名服务的定义中特别提到。经过研究,Zookeeper作为服务注册和发现的解决方案,具有以下优点:1.提供的API简单2.互联网公司(如:Pinterest,Airbnb)已经使用它来进行服务注册和发现3.支持多种Languageclient4.通过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,节点可以有子节点,同时允许节点下存储少量数据。客户端可以通过监听节点的数据变化和子节点的变化(Wather机制)实时获取Znode的变化。服务注册结构服务注册结构如上图所示。?/dada标记公司名称dada,可以很容易的和其他应用目录区分开来(例如:Kafka的brokers注册信息放在/brokers下)?/dada/services把所有的服务提供者都放在这个目录下?/dada/services/category1目录定义了具体服务提供者的id:category1,同时Znode节点允许存储服务提供者的一些元数据信息,如:名称,服务提供者的所有者,上下文路径(JavaWebproject)、健康检查路径等,这些信息可以根据实际需要自由扩展。?/dada/services/category1/helloworld节点在服务提供者category1下定义了一个服务:helloworld。其中helloworld是服务的ID,同时允许在Znode下存放服务的元数据信息,例如图中标注:服务名称、服务描述、服务路径、服务调用模式、服务调用HTTPMETHOD等待。这些信息可以根据实际需要自由扩展。?/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和端口,定义了服务提供者在节点中的权重。实现机制由于服务注册目前是通过我们的服务注册中心UI进行注册的,所以这部分逻辑比较简单,就是通过UI接口构造上面定义的服务注册结构。下面重点介绍我们的服务发现是如何工作的:在上面的类图中,ServiceDiscovery类主要是通过ZookeeperAPI(Python/Java版)获取服务信息,同时提供服务中各个服务的providers节点注册结构添加Watcher,监听节点变化。获取到的服务注册信息保存在变量service_repos中。服务提供者的负载均衡是通过在初始化时设置LoadBalanceStrategy(Round-Robin算法,Radmon算法)的实现来实现的。主要方法:1.init获取Zookeeper的服务注册信息,缓存在service_repos2中。get_service_repos方法获取实例变量service_repos3。get_service_endpoint根据init构建的service_repos和lb_strategy4提供的负载均衡策略返回某个服务的URL地址。update_service_repos本地缓存service_repos5通过Zookeeper的Watcher机制实时更新。heartbeat_monitor是一个心跳检测线程,用于检测服务提供者的健康和存活情况。如有问题,该服务提供者将从服务提供者列表中移除;相反,它被添加到服务提供商列表中。LoadBalanceStrategy定义了根据服务提供者的信息返回对应的服务Host和IP,即决定在哪个主机+端口提供服务。RoundRobinStrategy和RandomStrategy分别实现了Round-Robin和随机负载均衡算法的集成,服务的监控等。当然,基于Zookeeper还可以做很多其他的事情,比如实时动态配置系统。目前我们已经实现了基于Zookeeper的实时动态配置系统。如果您想了解,请继续关注我们的博客。杨军达达CTO目前掌管着达达庞大的研发部门,负责产品、技术和数据。曾在谷歌和Facebook总部工作近7年。作为Facebook最早的华人工程师之一,他加入并领导了多个研发团队。负责好友推荐系统和多个广告产品及后台。他使用机器学习和大数据分析来优化广告。加入达达之前,曾在硅谷知名移动支付公司Square领导Growth团队,负责公司的用户增长战略和实施。毕业于浙江大学朱可桢学院,后获博士学位。来自卡耐基梅隆大学,从事机器学习和多媒体分析方向的研究。