为了账号安全,请及时绑定邮箱和手机立即绑定

【架构探讨】没有银弹!如何针对具体业务采用合适的负载均衡策略

标签:
Java

大家好,我是姚半仙,慕课网《Java架构师成长直通车》课程架构师讲师团成员之一。话说条条大路通罗马,Ribbon提供了这么多的策略,我该用哪个策略才好呢?都说原配的才是最合适的,那我干脆就用默认的负载均衡策略好了。

事情真的这么简单吗?让我们从一个远古神话说起。

人月神话

图片描述

《人月神话》是FrederickP.Brooks的著作,被称为软件工程四大名著之一。Brooks结合了大量软件工程实践,向大家阐释了大型项目中普遍存在的难题,以及解决问题的方法和思路。

在这本书中引入了一个观点叫“没有银弹”(No Silver Bullet),「银弹」就是指白银做的子弹,在欧洲民间传说中,银色子弹往往被描绘成具有驱魔功效的武器,是针对狼人等超自然怪物的特效武器。在《人月神话》中“没有银弹”的意思是:没有任何技术或管理上的解决方案,能够独立地许诺十年内使软件系统项目生产率、 可靠性或简洁性获得数量级上的进步。简单来说就是没有万能方案。

人类从古到今一直都在各种问题中寻找一个万能方案,比如永动机,最初起源于1200年前的印度,经伊斯兰世界传入西方,过去几百年引得几代人苦苦研究,连跨界小能手达芬奇也掺和了一脚。可现实告诉我们,没有一劳永逸解决问题的方法,还是要靠人类的智慧对具体问题做具体分析。

那么在负载均衡领域中也有银弹吗?当然是没有的,否则Ribbon只提供一个万能负载均衡策略就好了。那针对具体业务我们都有哪些需要注意的呢?且听我一一道来。

Retry - 有多少爱可以重来

图片描述

正所谓有的爱一旦过去就过去了,有些人你永远不必等。比如说,我们开发了一个库存补货接口,每次调用后就自动补货上架100个商品。假如这个接口发生了超时,调用方收到timeout异常,但实际上库存服务在后台还在执行,只不过最终结果无法通知到调用方。也就是说实际补货成功,但调用方那边却超时了。

在上面这种情况下,如果一次次不停重试,可能你马上就要爆仓了。之所以类似的服务不能进行retry的原因,在于接口没有实现幂等性。

番外篇 - 关于幂等性

刚工作不久的时候,有次晚上加班和老大讨论技术需求,他对我说:“你需要幂等”,我以为他要我「眯瞪」一会儿,让我补一觉再回来,我应了一声起身就走。然后,然后就是觉没补成,倒被叫住补了一脚。从那以后我就学会了什么是幂等性。

幂等性往往针对的是执行“update”操作的接口,也就是常说的“写”操作。简单理解就是对一个具备幂等性的接口进行一次请求调用,和多次请求调用(每次调用的参数也相同),在执行结果上没有区别,接口并不会因为多调用了几次就产生不同结果。因此就需要从业务层面和代码层面做资源检查或锁定,来保证幂等性,这也是目前常用的分布式事务TCC方案的核心知识点。

用时间换空间?

图片描述

在魔都买房子就得采取“用时间换空间”的策略,甭管老破小先上车再说,过个几年再换个大house。在Ribbon这里,时间和空间经常要被换来换去,时间代表着接口响应时间(下文简称RT:Response Time),空间表示服务器的可用连接数。

在Ribbon里有两个和时间与空间密切相关的负载均衡策略,BestAvailableRule(简称BA)和WeightedResponseTimeRule(简称WRT)。他们都有同一个梦想,那就是希望世界和平,那就是选择压力较小的服务节点,但这两个策略努力的方向不同。BA会根据服务节点过去一段时间的请求数,选择并发量最小的机器(选择空间);WRT则是根据响应时间的统计结果,选择响应时间最快的服务(选择时间)。

我们知道服务的RT受很多因素制约,服务本身响应时间,网络连接时间,容器状态甚至JVM的full GC等等都会影响最终的RT。我们来设想这样一个场景,现在有一个非常轻量级的微服务,他的业务代码耗时大概在2ms范围内,只占整个接口响应时间的20%,而剩下80%基本都用在了网络连接的开销上。

在上面这个例子中,如果我们以RT作为指标,其实并不能客观获取服务节点当前的性能数据,因为接口本身的处理时间在RT分布中只占有很小的比例,甚至短时间的网络抖动都会对RT采样造成很大影响。而由于接口响应时间较短,因此性能瓶颈更容易被连接线程数卡住。线程数量达到上限会延长新请求的等待时间,从而增加RT,但这种情况下active的线程数量有更灵敏的指示作用,因为等到RT显著增加的时候,线程池可能早已被吃满了。对待这类问题,我们的实践经验是:

  • 连接数敏感模型 对响应时间较短,或RT和业务复杂度是非线性相关关系的接口,采用基于可用连接数的负载均衡策略更加合适

同样的,假设某个接口比较重量级,接口的处理时间与接收到的参数强相关。打个比方,订单导出服务,如果发起10个请求,每个请求都需要导出当前用户过去一整年的订单数据,那么这10个请求都会耗费大量的系统资源(CPU,内存)参与业务,同时RT时间也会相应拉长。在另一台机子上,同样是10个请求,但是只需要导出1个月的数据,相比较第一台机器,连接数相等的情况下,系统资源的占用率却大大不同。在这样的场景下,基于RT的指标具有更高的敏感度,我们的实践经验是:

  • RT敏感模型 对重量级接口,尤其是根据参数不同会导致系统资源使用率浮动较大的接口(RT与业务复杂度线性相关),建议采用基于响应时间的负载均衡策略。

当断则断

假如集成了Hystrix熔断器,而当前服务正处于熔断状态,你还想往火坑里跳吗?这时我们就需要根据熔断状态做过滤,使用AvailabilityFilteringRule便是极好的。

I Don’t Care

那还说啥,默认负载均衡策略走起不就不行了。Who cares.

小结

在这里想跟大家分享一个学习的经验。我们学习技术,不是简单的记忆+堆砌知识点,更重要的是建立在自己理解之上的进一步思考。比如课程前面提到的7种负载均衡策略,如果没有进一步的思考理解,你对Ribbon的理解就会停留在“Ribbon有7种策略,他们分别是xxxx”这种表面知识之上。技术只是工具,工具就是为了解决问题,我们要多思考几个“为什么”,比如“为什么Ribbon的负载均衡策略侧重不同,他们都可以解决哪类问题?”。提炼知识,多思考,几年之后,你就会发现与自己周围的人拉开了很大的差距。

点击查看更多内容
19人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消