阿里妹导读:双十一的零点,整个电商系统的请求速率到达峰值。若是将这些请求流量只分配给少部分 server,这些机器接收到的请求速率会远超过处理速率,新来的任务来不及处理,就会产生请求任务堆积。算法
今年的中间件性能挑战赛就围绕“挑战双11零点流量洪峰”展开。自2015年开始,中间件性能挑战赛已经成功举办了四届,被历年大赛选手称为“中间件技术的风向标”。接下来,跟随阿里巴巴中间件团队的郭浩,一块儿来围观赛题,解读赛题。网络
在现代分布式应用中,服务请求是由物理机或虚拟机组成的 server 池进行处理的。 一般,server 池规模巨大且服务容量各不相同,受网络、内存、CPU、下游服务等各类因素影响,一个 server 的服务容量始终处于动态变更和趋于稳定的状态,如何设计和实现这种系统的负载均衡算法是一个极具挑战的难题。数据结构
负载均衡有两个主要目标:并发
自适应负载均衡是指不管系统处于空闲、稳定仍是繁忙状态,负载均衡算法都会自动评估系统的服务能力,进行合理的流量分配,使整个系统始终保持较好的性能,不产生饥饿或者过载、宕机。负载均衡
这种算法对于如今的电商系统、数据中心、云计算等领域都颇有必要,使用自适应负载均衡可以更合理的利用资源,提升性能。框架
对用户而言,一旦产生任务堆积,请求会变慢甚至超时,体验严重降低,甚至致使服务不可用。而处理请求的机器也会因为堆积的任务愈来愈多而发生严重过载,直到被打垮。剩余的还没有宕机的其它机器会逐渐重复这个过程,直至整个应用不可用,发生系统故障。dom
为了不这种状况发生,咱们可能会想到一种经常使用的办法:在服务上线前提早进行压测,使用压测的容量做为限流值,当线上服务的请求速率大于限流值的时候,服务拒绝新到的服务,从而保障服务始终可用。可是这种方式也存在问题:压测时测试的容量进行限流一般会趋于保守,不能充分发挥异构系统的所有性能;也没法智能地应对因为网络、下游服务变化而致使的容量降低等问题,系统仍然存在宕机风险。分布式
所以,咱们须要具有自适应能力的负载均衡算法,来更好地进行流量分配调度以及稳定性保障,追求极致性能,挑战大促等场景下的流量洪峰。ide
咱们结合「第五届中间件性能挑战赛」中的初赛场景,来一块儿探讨一下设计和实现一个自适应的负载均衡的基本思路。微服务
本次挑战赛的场景由施压程序(阿里云性能测试PTS)、服务调用方(Consumer)和三个规格不一样的服务提供方(Provider) 组成。在评测过程当中,每一个程序都部署在不一样的物理机上,以免因 CPU、网络资源的竞争,致使评测程序抖动,影响最终评测成绩。
Becnhmarker 负责请求 Consumer, Consumer 收到请求后,从三台物理规格不一样、服务响应时间和最大并发都不一样的 Provider 中选择一个进行调用并返回结果。选择哪个 Provider 进行调用的流程就是本次挑战赛须要实现的负载均衡算法。
为了简化环境部署和提高性能,本次挑战赛没有使用服务注册和发现机制。三个 Provider 对应的 URL 都已经被直接配置在了 Consumer 中,选手在开发和测试时可直接经过 Provider-small 等 hostname 访问相应的 Provider。
题目描述很简单,不考虑 Consumer 直接拒绝的状况下,场景能够简化为 3 选 1 的问题,但如何进行这个决策则是本次挑战赛考察的难点和重点。
官方题目组提供了 Random 算法做为默认实现:从 3 个 Provider 中随机取任意一个。对于单 dispatcher (在本次赛题中是 Consumer) 同构系统的场景,Random能够达到渐近负载均衡, 每一个 Provider 接收到的总请求数接近。可是对于多 dispatcher 或异构系统而言,Random 算法因为缺乏全局状态,没法保证全局随机,极端条件下,多个 dispatcher 可能将请求同时分配到一台 Provider 上,致使系统存在服务过载和宕机的风险;异构系统中,不一样 Provider 服务容量实际是不一样的,即便每一个 Provider 请求速率相同也会产生空闲、稳定、过载等不一样的服务状态,没法实现最优流量分配,更不能作到响应时间最小。显而易见,Random 并非符合赛题要求的自适应算法。
那么,如何实现自适应负载均衡呢?接下来咱们将利用题目给出的条件由浅入深的描述这个算法的设计过程。
自适应算法首先要解决如何对服务进行容量评估的问题。
本次比赛按照硬件规格不一样,Provider 被分为 small、medium、和 large 三种,CPU 和内存对应的比例为 1:2:3 。在评测过程当中,每一个 Provider 的处理能力都会动态变化,主要体如今单次响应时间的变化和容许的最大的并发数上。来自 Consumer 的请求速率过快时, Provider 端新到的请求会排队等待处理,当排队线程数和工做线程数量之和达到最大线程数时,Provider 返回线程池用尽异常。在算法的实现和调优过程当中,应该尽可能避免产生线程池异常,减小排队。如何结合好程序和硬件的限制,区分出不一样阶段的瓶颈,作出符合实际的容量评估是赛题的第一个难点。对于本次题目所采用的参数和变化过程,仅凭现有的理论和实践很难达到最优,因此须要选手充分理解题意和各参数配置,设计出更适合实际场景的算法。
第二个须要考虑的问题是如何应用容量评估结果,即如何维护表明 Provider 服务能力的状态,又如何在选择 Provider 阶段根据这些状态进行决策?
传统的单 Dispatcher 负载均衡模型由一个 Dispatcher 维护全部 Provider 的状态,在同构系统中,这种方式可以达到渐进最优负载均衡。可是它存在的问题也很明显:单 Dispatcher 性能存在自然瓶颈,可扩容性较差,当 Provider 数量成倍上升时,Dispatcher 须要维护的状态也在成倍上升,通讯成本也在上升。本次挑战赛中为了下降难度,没有基于多 Dispatcher 模型构建题目,但多 Dispatcher 、多 Provider 才是 Dubbo 等微服务框架在实际生产环境中最多见的状况。所以,若能实现高性能且可扩展性良好的均衡算法,会是一个不错的加分项。
第三点是辅助接口的使用。为了避免限制算法设计思路,赛题提供了多个可能用到的辅助接口,包括双向通讯、Provider 限流等支持。可是这些接口都是非必选项,是否使用这些接口取决于算法实现的须要。
在评测环境中,任意一个 Provider 服务处理速率都小于评测程序的请求速率。三个 Provider 总的处理速率会在请求速率上下浮动。最终成绩由请求成功数和最大 TPS 组成,失败的请求不计入成绩。对于这个限制,能够有两种解读方式,一是为了保证服务不严重过载,能够适当拒绝请求。第二点是须要充分利用每一个 Provider 的服务容量,保证性能最优的 Provider 请求数合理,适当的过载也是容许的。
以上仅做为一个主要的算法设计思路,优秀的负载均衡算法在工程上的实现也是很关键的一点,须要选取合适的数据结构,充分利用好内存和 CPU,压榨出比赛环境的每一点性能。固然,评测成绩并不表明一切,良好的代码结构、编码风格以及通用性,也在最终初赛成绩中占据很大比例。
关注“阿里技术”官方公众号,并在对话框内回复“中间件”,便可得到初赛赛题。
评测环境由 1 台 4 核 8G 的施压机,1 台 4 核 8G 的网关机和 3 台 4 核 8G 的 Provider组成。Consumer 和 Provider 程序都会限制 CPU 和内存使用,每一个评测任务都会独占五台机器。
本文结合第五届中间件性能挑战赛的赛题背景、题目场景、题目分析和评测环境与过程的角度,介绍了自适应负载均衡算法的基本设计思路,但愿对即将参加比赛的同窗们能有所帮助,也欢迎更多的技术同窗报名参加咱们的挑战赛,分享你在算法方面的思考和实践。
原文连接 本文为云栖社区原创内容,未经容许不得转载。