4万字《腾讯云技术实践精选集 2021》发布,点击下载 了解详情
写点什么

计算密集型服务的负载均衡策略

  • 2020 年 2 月 19 日
  • 本文字数:1604 字

    阅读完需:约 5 分钟

计算密集型服务的负载均衡策略

一般情况下,在计算密集型服务中,即使处理单个请求也需要使用到服务器的所有 CPU。如果单台服务器连续接收到两个请求,要么两个请求互相争抢 CPU,要么后来的请求排在前面的后面等待处理。最终,会导致平均处理时间变长。常规的负载均衡策略(如轮询、随机等)下,负载均衡器不关心服务器的负载情况,这就很容易造成服务器同时收到多个请求,从而使服务器的服务质量下降。


一、背景

有一天,携程国际机票查询引擎经过一次改造后,虽然平均响应时间得到了提升,但是响应时间也有非常大的波动。从监控图上看,非常明显的尖刺持续存在。如下图:



经过分析,我们发现这次改造深度优化了服务的并行计算能力,使得引擎成为了一个完全的计算密集型服务,它的最大并发处理能力为 1。然而,我们却没有相应的修改负载均衡策略,而是继续使用的轮询策略。


对于计算密集型服务,如果使用轮询策略,有如下三种情况:


理想情况是连续两个请求之间无间隔、无重叠,既下一个请求刚好在上一个请求处理完成的时刻到达。这种情况下,后来的请求没有等待时间,服务器也没有空闲时间,得到了充分的利用。



通常情况下,由于请求的到达普遍服从泊松分布,如果使用轮询、随机等负载均衡策略,单机的请求也服从泊松分布,即连续两个请求间总会存在间隔或者重叠,导致服务器资源空闲或者请求响应时间上升。



在极端情况下,如果某个请求的处理时间特别长,后续的一大串请求将产生积压,最终导致这些请求的响应时间也变得特别长,甚至超时。



我们发现,引擎的响应时间尖刺是由极端情况的 case 造成的。引擎有一类请求 A,它 qps 不高,但是却需要 CPU 满负荷运转长达几秒甚至 10 秒才能算出结果。另有一类请求 B,它 qps 非常高,只需要 CPU 满负荷运转几十毫秒就能算出结果。


当一台服务器正在处理一个 A 类请求时,在接下来的几秒内,它将继续收到几十个 B 类请求,而且所有的 B 类请求都要排队,直到 A 类请求完成。这就导致大批 B 类请求的响应时间由应该的几十毫秒升高到几秒,从而造成了严重的尖刺。


二、pooling

为了解决这个问题,我们使用了一种新的负载均衡策略,在这种策略下,服务器不再被动的接收请求,而是主动的去获取请求,这种方式非常容易做到服务器同一时刻只处理一个请求。在我们内部,这种方式被称为 pooling(它和线程池类似,可以叫做服务器池)。


在 pooling 模式中,有三个主要角色:submitor、queue、worker。


  • submitor


submitor 一方面用于接收请求方的调用,它收到请求后,不直接处理请求,而是把这个请求提交给 queue。


另一方面,submitor 接收 worker 的回调,submitor 收到 worker 的结果后,直接把它转发给请求方。


  • queue


pooling 的关键是引入了一个 queue,queue 是一个全局唯一队列,用于暂时缓冲请求。


我们使用了 redis 的 list 结构来实现 queue。入队操作为 lpush,出队操作为 brpop。brpop 是阻塞式的操作,当队列为空时,brpop 会阻塞直到队列非空。队列非空时,如果有该队列有多个 brpop 操作阻塞,只有其中一个会被唤醒并且返回数据。


  • worker


worker 是实际的请求处理者。在旧的模式下,worker 是被动接收请求。在 pooling 模式下,worker 要主动去 queue 获取请求。worker 启动时,要创建一个线程,这个线程启动后,便进入一个无限循环,循环的主要内容为:


1)从 queue 获取一个请求,当 queue 没有请求时,worker 被阻塞。


2)worker 处理这个请求。


3)把结果返回给 submitor。


如此往复。可以看到,worker 要么正在处理一个请求,要么正在等待一个请求。


三、效果

国际机票查询引擎的负载均衡策略由轮询改为 pooling 后,效果非常好。系统的平均响应时间降低了大约 20%,并且完全消除了响应时间尖刺。


轮询方式:



pooling 方式:


作者介绍


罗茂林,携程国际机票后台研发总监,主要负责国际机票引擎的研发工作。致力于系统性能优化和研发效率提升。


本文转载自公众号携程技术(ID:ctriptech)。


原文链接


https://mp.weixin.qq.com/s/XsyXkaOIJ3m8sdCt8Pl5Ig


2020 年 2 月 19 日 20:30247

评论

发布
暂无评论
发现更多内容

入行架构师之前,这7项技能你要先了解一下

Java架构师迁哥

架构师训练营第 1 期第 4 周作业

好吃不贵

极客大学架构师训练营

极客时间架构 1 期:第 3 周代码重构 - 学习总结

Null

Python 为什么不支持 switch 语句?

Python猫

Python 编程

Malagu 框架介绍

木香丘

云计算 开源 Serverless 架构 框架

有这些要素,架构才完整

北风

架构 架构师之道 架构方法

架构师训练营第 1 期第 4 周学习总结

好吃不贵

基于 Spring Boot 的企业级快速开发框架 BDF3

木香丘

架构 Spring Boot 可视化 后台管理系统

Redis-技术专题-基础介绍

浩宇天尚

爆赞!这份《Java核心宝典》绝对是面试复习的最佳选择

Java架构之路

Java 程序员 面试 编程语言

架构师训练营第四周学习总结

尹斌

架构师1期-代码重构作业

ltl3884

极客大学架构师训练营

第四周作业

极客大学架构师训练营

架构师训练营第四周作业

尹斌

发几张国庆的照片

亨利笔记

容器 k8s Harbor 镜像

如何高质量学习与正确运用设计模式

木香丘

学习 设计模式 实战

Hazelcast IMDG 带你瞬间进入内存计算的时代

张磊

分布式计算 内存管理 分布式缓存 分布式内存网格

架构师训练营第三周课后作业

Gosling

极客大学架构师训练营

单例模式

魏小龙

深入剖析go中字符串的编码问题——特殊字符的string怎么转byte?

Gopher指北

后端 string utf-8 Go 语言

架构师训练营第三周作业(9.28-10.4)

zjzj2017

spring-boot-route(九)整合JPA操作数据库

Java旅途

Java Spring Boot jpa

实用威胁建模指南(一)

亚伦碎语

敏捷 安全设计 系统安全 #威胁建模

架构师训练营第三小结(9.28-10.4)

zjzj2017

java安全编码指南之:方法编写指南

程序那些事

java安全编码 java安全 java安全编码指南

使用 jsDelivr 免费加速 GitHub Pages 博客的静态资源(二)

mzlogin

jsDelivr CDN Jekyll GitHub Pages 个人博客

Serverless 多云解决方案 Malagu

木香丘

云计算 Serverless 架构 云原生 Malagu

缓存服务-技术专题-解决方案

浩宇天尚

LeetCode题解:226. 翻转二叉树,递归,JavaScript,详细注释

Lee Chen

大前端 LeetCode

Redis-技术专题- 热点Key如何解决

浩宇天尚

甲方日常 26

句子

生活 随笔杂谈 日常

计算密集型服务的负载均衡策略-InfoQ