读书笔记二——第一章《面向服务的体系架构SOA》下

1      服务器的路由和负载均衡

1.1    服务化的演变

分布式应用架构体系对于业务逻辑服用的需求十分强烈,公共业务被拆分出来,形成可共用的服务,最大程度的保障了代码和逻辑的复用,这种设计称为SOA Service-Oriented Architecture 。SOA架构中,服务消费者通过服务名称,在众多服务中找到要调用的服务的地址列表,称为服务的路由。


对于负载较高的服务来说,往往对应着多台服务器组成的集群,为了将请求均衡的分配到后端服务器,负载均衡程序将从服务对应的地址列表中通过负载均衡算法和规则,选取一台服务器进行访问,这个过程称为服务的负载均衡。


当服务规模较小时,可以采用硬编码的方式将服务地址和配置写在代码中,通过编码方式解决服务的路由和负载均衡的问题,也可以通过硬件设备如F5等,或者采用LVS或Nginx等软件解决方案。

当服务越来越多规模越来越大时,单靠人工来管理和维护服务及地址的配置信息越来越困难,并且依赖单一的硬件负载均衡设备或者LVS、Nginx等软件进行路由和负载均衡调度,单点故障的问题也开始凸显,一旦服务器或者负载均衡服务器宕机,依赖它的所有服务均将失效。此时需要一个能够动态注册和获取服务信息的地方,来统一管理服务名称和其对应的服务器列表信息,称之为服务配置中心。

基于ZooKeeper的持久和非持久节点,能近乎实时的感知后端服务器的状态,通过集群间的zab协议,使得服务器配置信息保持一致。ZooKeeper本身容错特性和leader选举机制,能保障我们方便的进行扩容,容错性好,且无中心化结构能解决使用负载均衡设备所带来的单点故障问题。


 

1.2    负载均衡算法

1.2.1 轮询法 Round Robin

将请求按顺序轮流的分配到后端服务器上,而不关心服务器实际的连接数和当前的系统负载。

这里通过初始化一个serverWeightMap变量来表示服务器地址和权重的映射。


轮训策略的目的在于,希望做到请求转移的绝对均衡,但付出的性能代价也是相当大的。

 

1.2.2 随机法 Random

通过系统的随机函数,随机选择一台服务器进行访问。

 

1.2.3 源地址哈希法Hash

通过获取客户端访问的IP地址值,通过哈希函数计算得到一个数值,用该数值对服务器列表大小进行取模运算,得到的结果是要访问的服务器序号。


该算法保证了同一个客户端IP地址将会被哈希到同一台后台服务器,根据此特性可以在服务消费者和服务提供者之间建立有状态的session会话。

 

 

1.2.4 加权轮询法 Weight Round Robin

不同的后端服务器配置,负载能力并不相同,因此给配置高、负载低的机器配置更高的权重,让其处理更多的请求。


 

1.2.5 加权随机法 Weight Random

 

1.2.6 最小连接数法 Least Connections

根据后端服务器当前的连接情况,动态的选取其中积压连接数最少的一台服务器来处理当前请求。

 

1.3    动态配置规则

由于Groovy脚本语言能直接编译成JAVA class字节码,运行在JAVA虚拟机上,通过Groovy语言,来实现负载均衡规则的动态配置。


对应的规则其实就是一个Groovy的class,可以看出一段文本,配置在相关的配置文件上,或是通过ZooKeeper的 watcher机制,配置在ZooKeeper服务器上,达到不重启应用配置即可生效的效果。

Groovy 的随机算法:


1.4    ZooKeeper 介绍与环境搭建

ZooKeeper是 Hadoop下的一个子项目,它是针对大型分布式系统的可靠的协调系统,提供的功能包括配置维护、名字服务、分布式同步、组服务等。ZooKeeper是可以集群复制的,通过ZAB协议来保持数据的一致性。该协议像Paxos协议的变形,包括两个阶段:leader election阶段和Atomic broadcas 阶段。集群选择一个leader ,其它机器则为followe,所有的写操作都被传送给leader,并通过broadcas将所有更新告诉follower。当leader 崩溃或者失去大多数的follower时,需要重新选举出一个新的leader,让所有的服务器恢复正确的状态。当leader被选举出来,且大多数服务器完成了和leader的状态同步后,leader election的过程就结束了,进入Atomic broadcas过程。Atomic broadcas同步leader和follower之间的信息,保证leader和follower具有相同的系统状态。


ZooKeeper的安装步骤:


1.5    ZooKeeper API使用简介

ZooKeeper实现了一个层次命名空间的数据模型,也可以认为它是一个小型的、精简的文件系统。它的每个节点称为znode,znode除了本身能够包含一部分数据外,还能够拥有子节点,当节点上的数据发生变化,或者子节点发生变化时,基于watcher机制,会发出相应的通知给订阅其状态变化的客户端。

首先,实例化一个ZooKeeper对象指定其三个参数。url为ZooKeeper服务器地址。sessionTimeOut为会话超时时间,ZooKeeper的会话超时时间由客户端确定,但是ZooKeeper的Server端会有两个配置,minSessionTimeout 和maxSessionTimeout,minSessionTimeout的默认值为2倍tickTime,maxSessionTimeout的默认值为20倍tickTime,单位都为ms。tickTime也是服务端的一个配置项,是Server内部控制时间逻辑的最小时间单位,如果客户端发来的sessionTimeout超过minSessionTimeout~maxSessionTimeout这个范围,Server会自动取minSessionTimeout或maxSessionTimeout作为sessionTimeout,然后为这个client新建一个session对象。最后一个参数为默认的watcher。如果包含booleanwatch的读方法中传入true,则将默认watcher注册为所关注事件的watcher,如果传入false,则不注册任何watcher,这里暂且定位空。


1.5.1 创建节点

通过ZooKeeper 的API新增一个znode节点,节点在被创建时,需要指定节点的路径(此处为/root)包含的字节数据(这里指定的是“root data”这个字符串)、访问权限(如果不想设置权限,则指定为Ids.OPEN_ACL_UNSAFE),以及创建的节点类型,节点类型如下:


1.5.2 删除节点

当不需要某个节点或者节点上的信息失效时,使用delete方法可以将该节点删除。删除时需要指定节点的版本号version,如果为-1,则匹配所有版本,ZooKeeper会比较删除节点版本是否和服务器版本一致,不一致则抛出异常。

删除节点示例:


1.5.3 设置和获取节点内容

如果想在已有的节点中保存数据,可以通过ZooKeeper的setData方法,将数据保存到节点,也可以通过ZooKeeper的 getData方法来获取该节点保存的数据,一个znode中最多能保存1MB数据。

设置和获取节点内容示例:


getData方法取得root节点上保存的字节数组,false表示不实用默认的watcher,stat表示该节点的状态,是一个传出参数,返回该节点当前的状态信息。

 

1.5.4 添加子节点

ZooKeeper 支持在已有的节点下添加子节点,父节点必须存在,否则会抛出异常。

创建子节点示例:


1.5.5 判断节点是否存在


判断/root/child1节点是否存在,存在则不为Null,否则为null。

 

1.5.6 watcher 的实现

当节点的状态发送变化,通过watcher机制,可以让客户端得到通知,watcher需要实现 org.apache.ZooKeeper.Watcher接口。节点的状态变化主要包含如下几种情况:


watcher的实现示例:


ZooKeeper的watcher机制是一次性的,每次处理完状态变化事件后,要重新注册watcher,这个特性也使得在处理事件和重新加上watcher这段时间发生的节点状态变化无法被感知。

ZooKeeper常常发生下面两种系统异常:

org.apache.ZooKeeper.KeeperException.ConnectionLossException,客户端与其中的一台服务器socket连接出现异常,连接丢失;

org.apache.ZooKeeper.KeeperException.SessionExpiredException,客户端的session已经超过sessionTimeout,未进行任何操作。

ConnectionLossException异常可以通过重试进行处理,客户端会根据初始化ZooKeeper时传递的服务列表,自动尝试下一个服务点,在这个时间段内,服务端节点的变更事件会丢失。

SessionExpiredException异常不能通过重试进行解决,需要重新创建一个新的客户端(new ZooKeeper()),这时所有的watcher和EPHEMERAL节点都将失效。

 

1.6    zkClient的使用

zkClient解决了watcher的一次性注册问题,将znode事件重新定义为子节点的变化、数据的变化、连接及状态的变化三类,由zkClient 统一将watcher 的 WatchedEvent转换到以上三种情况中去处理,watcher执行后重新读取数据的同时,再注册相同的watcher。

zkClient是GitHub上的开源项目,可以根据需要将源码构建可依靠的jar文件。

 

构建步骤如下

(1) 下载工程源码。


(2)在eclipse中新建一个zkclient的JAVA 工程


(3)在zkclient 目录下的src和lib目录导入eclipse。

 

(4) 通过eclipse的Export选项导出JAR文件。

 

在使用zkClient之前,需要实例化一个zkClient对象,指定ZooKeeper服务器的地址列表:


zkClient将ZooKeeper的watcher机制转换成为一种更加容易理解的订阅形式,并且这种关系是可以保持的。节点有三种状态提供订阅,一类是子节点的变化,一类是数据的变化,一类是状态的变化。

订阅子节点状态变化的示例:


订阅节点数据变化的示例:

 

订阅节点连接及状态的变化情况示例:


当发生session expire异常进行重连时,由于原来的所有watcher和EPHEMERAL节点都已失效,可以在handleNewSession方法中进行相应的容错处理。

 

1.7    路由和负载均衡的实现

使用LVS或Nginx的单点故障问题开始凸显。


ZooKeeper上所形成的节点树如下图所示,服务提供者在启动时,将其提供的服务名称、服务地址,以节点的形式注册到服务配置中心,消费者通过服务配置中心来获得需要调用的服务名称节点下机器列表节点。通过负载均衡算法,选取其中一台服务器进行调用。当服务器宕机下线时,由于znode非持久节点的特性,相应的机器可以动态的从服务配置中心移除,并触发消费者的watcher。在这个过程中消费者只有在第一次调用服务时需要查询服务配置中心,然后将查询到的服务信息缓存到本地,后面的调用直接使用本地缓存的服务地址列表信息,直到服务的地址列表有变更,变更行为触发消费者注册的相应watcher进行服务地址的重新查询。这种无中心化的结构,解决了之前负载均衡方案所导致的单点故障问题。


根节点用来聚集服务节点,通过它查询所有的服务,服务名称节点挂载的是服务提供者的服务器地址,服务消费者通过负载均衡算法来选择其中一个地址发起远程调用。根节点和服务名称节点采用的是ZooKeeper的持久节点,即persistent节点,而服务提供者的地址节点,则采用非持久节点,即ephemeral节点,一旦服务器宕机或者下线,节点也将消失。

服务规模增大,服务之间的依赖变得十分复杂时,人力已经很难理清楚谁调用了谁,谁被调用,为了更好的监控服务消费者的信息,对上图结构增加了一层。


每个服务包含了两种节点类型,即consumer和provider。当服务消费者启动时,即在服务注册中心里,在其所调用的所有服务的consumer节点下增加自己的机器地址。这样,只需要后台监控程序解析出对应服务的consumer节点的子节点,便能清楚的知道某一服务被哪些机器消费了。

基于ZooKeeper所实现的服务消费者获取服务提供者地址列表的示例:


这段代码首先实例化了一个zkClient对象,判断服务名称节点是否已经注册,如果没有则抛出RuntimeException。如果存在则取得其上所有注册的包含服务提供者地址的子节点。获得服务提供者地址列表后,根据负载均衡算法选取出一台服务器发起远程调用。服务器地址列表可以缓存在本地,需要在服务名称对应的节点上,注册一个IZKChildListener监听器,一旦有服务器上线、下线或宕机,发生节点的新增或删除动作。此时IZKChildListener的handleChildChange方法会被执行,在该方法中取得其所注册的最新子节点,赋值给当前的serverList。

服务提供者向ZooKeeper集群注册服务的示例:


利用ZooKeeper自带的zkCli.sh 小工具,我们能够清楚的看到服务提供者所创建的节点。


通过ZooKeeper来实现服务的动态注册、机器上线下线的动态感知,扩容方便,容错性好,无中心化结构能解决负载均衡的单点故障问题。

 

1.8    HTTP服务网关

相同的功能,相同的数据,在不同的平台下,没有必要重复开发,可以利用SOA体系,达成公共部分逻辑的复用。考虑到HTTP协议所包含的信息都是未经过加密的明文,因此,必须建立一个强大的安全体系来保障相关数据和接口的安全。这时网关(gateway)的作用凸显出来。


gateway接收外部各种APP请求,完成相应的权限与安全校验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值