为了做到微服务的高可用,鬼知道我出了多少张牌( 四 )


这时候可以选择获取之前没有失败接口的缓存数据,如果没有则可以获取通用商品不用个性化推荐,如果也没有可以读取一些静态文字进行展示 。
由于我们架构进行了分层,分层 App,网关,业务逻辑层,数据访问层等等,在组织结构也进行了划分,与之对应的是前端组,后端业务逻辑组,甚至有中台组等等 。
既然有代码和人员架构的层级划分,那么每一层都必须有这样的思想:包容下一层的错误,为上一层提供尽可能无错的服务 。
举个例子:

为了做到微服务的高可用,鬼知道我出了多少张牌

文章插图
 
商品的美元售价假设要用商品人民币售价/汇率,这个时候错误发生在低层的数据层,上一层如果直接进行除,肯定就抛出 JAVA.lang.ArithmeticException: / by zero 。
本着我们对任何一层调用服务都不可信的原则,应该对其进行容错处理,不能让异常扩散,更要保证我们这一层对上一次尽可能的作出最大努力确定的服务 。
负载均衡
为了做到微服务的高可用,鬼知道我出了多少张牌

文章插图
 
相信负载均衡这个话题基本已经深入每个做微服务开发或设计者的人心,负载均衡的实现有硬件和软件 。
硬件有 F5,A10 等机器;软件有 LVS,Nginx,HAProxy 等等,负载均衡的算法有 Random,RoundRobin,ConsistentHash 等等 。
①Nginx 负载均衡故障转移
为了做到微服务的高可用,鬼知道我出了多少张牌

文章插图
 
转移流程:Nginx 根据给定好的负载均衡算法进行调度,当请求到 Tomcat1,Nginx 发现 Tomcat1 出现连接错误(节点失效),Nginx 会根据一定的机制将 Tomcat1 从调用的负载列表中清除 。
在下一次请求,Nginx 不会分配请求到有问题的 Tomcat1 上面,会将请求转移到其他的 Tomcat 之上 。
节点失效:Nginx 默认判断节点失效是以 connect refuse 和 timeout 为标准,在对某个节点进行 fails 累加,当 fails 大于 max_fails 时,该节点失效 。
节点恢复:当某个节点失败的次数大于 max_fails 时,但不超过 fail_timeout,Nginx 将不再对该节点进行探测,直到超过失效时间或者所有的节点都失效,Nginx 会对节点进行重新探测 。
②ZK 负载均衡故障转移
为了做到微服务的高可用,鬼知道我出了多少张牌

文章插图
 
在使用 ZK 作为注册中心时,故障的发现是由 ZK 去进行发现,业务逻辑层通过 Watch 的心跳机制将自己注册到 ZK 上,网关对 ZK 进行订阅就可以知道有多少可以调用的列表 。
当业务逻辑层在重启或者被关闭时就会跟 ZK 断了心跳,ZK 会更新可调用列表 。
使用 ZK 作为负载均衡的协调器,最大的问题是 ZK 对于服务是否可用是基于 Pingpong 的方式 。
只要服务心跳存在,ZK 就认为服务是处在可用状态,但是服务如果处在假死的状态,ZK 是无从得知的 。这个时候,业务逻辑服务是否真正可用只能够由网关知道 。
幂等设计:为何会牵出幂等设计的问题,主要是因为负载均衡的 Failover 策略,就是对失败的服务会进行重试 。
一般来说,如果是读操作的服务,重复执行也不会出问题,但想象一下,如果是一个创建订单减库存的操作,第一次调用也 Tomcat1 超时,再重新调用了 Tomcat2 。
这个时候我们都不能确认超时调用的 Tomcat1 是否真的被调用,有可能根本就调用不成功,有可能已经调用成功但是因为某些原因返回超时而已 。
所以,很大程度这个接口会被调用 2 次 。如果我们没有保证幂等性,就有可能一个订单导致了减少 2 次的库存 。
所谓的幂等性,就是得保证在同一个业务中,一个接口被调用了多次,其导致的结果都是一样的 。
服务限流降级熔断
为了做到微服务的高可用,鬼知道我出了多少张牌

文章插图
 
先来讲讲微服务中限流/熔断的目的是什么,微服务后,系统分布式部署,系统之间通过 RPC 框架通信,整个系统发生故障的概率随着系统规模的增长而增长,一个小的故障经过链路的传递放大,有可能会造成更大的故障 。
限流跟高可用的关系是什么?假定我们的系统最多只能承受 500 个人的并发访问,但某个时候突然增加到 1000 个人进来,一下子就把整个系统给压垮了 。
本来还有 500 个人能享受到我们系统的服务,突然间变成了所有人都无法得到服务 。
与其让 1000 人都无法得到服务,不如就让 500 个人得到服务,拒绝掉另外 500 个人 。限流是对访问的隔离,是保证了部门系统承受范围内用户的可用性 。


推荐阅读