服务化的演变
对于负载较高的服务来说,往往对应着由多台服务器组成的集群。在请求到来时,为了将请求均衡的分配到后端服务器,负载均衡程序将从服务对应的地址列表中,通过响应的负载均衡算法和规则(rount_robin、random、weight_random),选取一台服务器进行访问,这个过程称为服务的负载均衡。
当服务的规模较小时,可以采用硬编码的方式将服务地址和配置写在代码中,通过编码的方式来解决服务的路由和负载均衡问题,也可以通过传统的硬件负载均衡设备,如F5,或者采用LVC或Nginx等软件解决方案,通过相关的配置,来解决服务的路由和负载均衡问题。
当服务越来越多,规模越来越大,对应的机器数量也越来越庞大,单靠人工来管理和维护服务及地址的配置信息,变得困难。并且,依赖单一的硬件负载均衡设备或者使用LVS、Nginx等软件方案进行路由和负载均衡调度,单点故障的问题也开始凸显出来。
因此,需要一个能够动态注册和获取服务信息的地方,来统一管理服务名称和其对应的服务器列表信息,称之为服务配置中心。服务提供者在启动时,将其提供的服务名称、服务器地址注册到服务配置中心。服务消费者通过服务配置中心来获得需要调用的服务,通过相应的负载均衡算法,选择其中一台服务器开始调用。这种无中心化的结构解决了之前负载均衡设备导致的单点故障。
基于ZooKeeper的持久和非持久节点,我们能够近乎实时的感知后端服务器的状态(上线、下线、宕机)。通过zab协议,使得服务配置信息能够保持一致。而Zookeeper本身的容错特性和leader选举机制,能保障我们方便的进行扩容。通过ZooKeeper来实现服务动态注册、机器上线与下线的动态感知,扩容方便、容错性好,且无中心化结构能够解决之前使用负载均衡设备带来的单点故障问题,只有但配置信息更新才会去ZooKeeper上获取最新的服务地址列表,其他时候可采用本地缓存。
图例:
上图是传统方式的,假如我有四台服务器,每台服务器都提供相同的服务,如果我消费者去掉用的时候,肯定要在四个当中选择某一个去调用,可是选择哪一个就是一个难题,当然这就涉及到负载均衡问题了,需用到F5(其实我也没用过F5。。。)或者我们在消费者这边加代码逻辑判断达到负载均衡的效果,还有每次调用的时候都要查询当前有哪些服务提供者,这是很耗开销的。
方案都是一步一步进化的。
我们在消费者和服务提供者之间加了一层服务路由。服务路由提供F5功能同事还提供代理服务的地址,代理地址是稳定的,这样就算服务提供者地址改变了,消费者直接调用代理服务器地址给 服务器路由,让服务器路由自己去查询,减小开销
最终方案
我们利用zookeeper生成的节点树,服务器提供者在启动的时候,将提供的服务名称和地址以节点的方式注册都服务器zookeeper服务器配置中心,消费者通过服务器配置中心获取需要的服务名称节点下的服务地址。因为znode有非持久节点的特性,服务器可以动态的从服务配置中心一处,并且触发消费者的watcher方法!!!
消费者只有在第一次调用的时候直接本地缓存服务器列表信息,而不需哟重新发起请求到服务器配置中心区获取相应 的服务器列表,直到服务器地址列表有变化(机器下线或者上线),变更厨房消费者watcher进行服务地址的重新查询。正是因为赭红无中心化的结构,使得服务消费者在服务信息没变更时候,几乎不依赖配置中心,解决了负载均衡设备导致的单点故障的问题。