中电金信:技术实践|Flink多线程实现异构集群的动态负载均衡
导语:Apache Flink是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。本文主要从实际案例入手并结合作者的实践经验,向各位读者分享当应用场景中异构集群无法做到负载均衡时,如何通过Flink的自定义多线程来实现异构集群的动态负载均衡。
● 1. 前言
● 2. 出现的问题与解决方案
● 2.1 出现问题
● 2.2 分析思路
● 2.3 解决方案
● 3. 技术架构
● 4. 建设成效
● 5. 结语
前言
在实时计算应用场景中经常会有对异构集群的实时调用需求,而当异构集群的服务由于机器配置、节点负载等原因无法做到负载均衡时,可以通过Flink的自定义多线程来实现对异构集群的动态负载均衡。
下面举个例子:
文本内容鉴别、图片内容鉴别、图片OCR等特征生产需求,都需要和基于GPU部署的异构集群来交互。如果GPU集群机器配置无法统一,那么就会产生负载不均的情况。即:一个GPU集群中某些节点处理的快,某些节点处理的慢,处理慢的节点往往会导致大量的超时异常,从而引起整个作业的反压。
其流程图如下:
我们借助Flink分布式的先天优势,在任务中通过Thrift RPC调用模型服务,实时获取结果后再写到特征工程,以此来构建特征生成整个链路。
出现的问题与解决方案
出现问题:
在模型服务中部署的若干个节点,节点和节点之间是完全独立的,每个节点上线/下线后都会将自己的状态更新到ZooKeeper。在Flink任务的每个subTask都会注册一个Watch,以便获取最新且可用的所有节点。对于流入到subTask的每条数据,都需要选择一个节点来完成数据的推理。
在前期,我们使用Random策略来选择节点,但是在使用过程中我们发现,如果服务端的一个模型节点性能变低,随之而来的就是数据推理的耗时变长,那么最终可能会导致Flink任务反压。而在服务端来看,很多模型节点并没有满负荷运行,但客户端反应出来的服务端性能却不够,处理完成的总QPS很低。
另外,在和模型服务通信的时候,我们采用的是同步策略,这对于一些推理耗时长、QPS高的任务来说,需要足够大的并发度才能完成数据请求。然而,这些任务的资源利用率较低,这也是生产环境的一大痛点。
分析思路:
基于上图,我们作出如下分析:
在理想情况下,我们假设服务端有节点1、节点2、节点3,且3个节点性能都一致,每个节点都开32个并行度处理。假设每条数据处理耗时都是800ms,那么每个节点的处理能力应该是40条/s,三个节点满载的情况下处理能力应该是120条/s。
而在实际生产环境下,服务端部署的机器各个节点之间处理能力是有差异的,导致其出现差异的原因主要有三点。
■ GPU物理机器有多种规格,性能之间差别较大,在进行部署时很难确保将节点部署在同一批机器上;
■ 一台机器上混部多种模型服务,相互之间会有影响;
■ 部分节点所在机器网络、磁盘等出现故障也会导致出现差异。
例如节点1和节点2部署在高性能机器上,节点并行度是32,单条数据处理耗时是800ms。节点3部署在低性能机器上,节点并行度是32,单条数据处理耗时2400ms,那么节点3的处理能力可以看作为13.3条/s。同样采用随机选择节点的策略,倘若一秒总共发送了40条数据,对于节点3来说就已经达到性能瓶颈了。假设这个时候有更多的数据选择到了节点3进行处理,就只能在服务端的队列进行排队,而如果这个队列满了就会拒绝连接。
随着任务的运行,节点3的等待队列数据会越来越多,客户端从发送请求到返回结果的耗时也会随之越来越大。这时一旦有subTask选择了这个节点,那么这个subTask就需要等待比较长的时间来完成这次的请求。在这个过程中,如果上游数据还在源源不断的流入,那么就会造成subTask的InputChannel慢慢被耗尽,随后公共Buffer Pool的空间也会被占满,进而导致subTask2卡死。又因为上游算子使用了Rebalance,最终会把整个Flink任务卡死。
这是一个典型的木桶效应,在实际应用场景中,一旦有个别节点性能差或者出现故障,就会影响整个任务的稳定性。
解决方案:
在分析事故出现的原因后,我们提出给每个节点配置一个权重,模型节点定期将权重数值上报到ZooKeeper,客户端再通过权重来给每个节点分配相应的流量。这个想法很好,也在实践过程中取得了一定的效果,但是它有一个小问题:这样做会导致每个节点的流量一直抖动,抖动的频次和上报权重的时间呈正相关的关系,而且从监控来看,这样做也会导致处理的总数据量不太稳定。
在问题初步得到缓解后,我们开始思考是不是还有其他更好的方式可以解决这个事情。已知模型节点慢了会卡死一个subTask,而这个subTask本质是一个Slot,也就是一个线程,那么我们是不是可以借用多线程的方式来解决这个问题?带着这个思考,我们又尝试了另外两种解决方式:Async I/O和多线程方案。
■ Async I/O方案
Flink 在1.2版本中引入Async I/O,其主要目的是为了解决与外部系统交互时网络延迟成为系统瓶颈的问题。通过暴露出来的API,我们可以设置最大的操作数,简单理解为Slot中异步请求的最大并发数量。测试的时候我们准备了三个节点,一个节点处理耗时2000ms,另外两个节点处理耗时500ms。
任务在刚启动的几分钟内运行还比较正常,之后处理速度较慢节点的服务端队列堆积长度开始变得越来越大,最后稳定在150左右,与此同时超时失败率也开始随之升高。我们可以看到,通过这种方式虽然可以很好的解决因为快慢节点导致反压卡死和资源利用率问题,但是仍然无法解决流量分配的问题。
■ 多线程方案
我们在每个Slot内部实现一个生产者-消费者模型,再创建和模型节点相同数量的线程,让每个线程固定的请求一个节点,就算这个节点卡死或者处理速度缓慢,也只会影响当前线程,对整个subTask的影响有限。
如上图所示,一个Slot内包含多个线程,个别线程对应的Service节点出现问题不会影响其它线程的消费。通过这种方式可以实现自适应的流量分发策略,每个线程对应一个服务端Pod,这种线程自适应阻塞的方式可以实现慢的节点少消费,快的节点多消费的目的。
在Flink以Slot为最小资源粒度情况下再进行细化,从Slot中开启若干个线程能够增大并发度,从而减少整体Slot数量,在降低资源的同时提高资源利用率。
技术架构
在Flink任务使用多线程的方案来解决RPC通信负载均衡的问题,编程模型需要做相应的改造,具体改造如下图:
建设成效
通过前后数据对比,我们发现在采用多线程方案后,效果还是很明显的。通过下图所示的服务端处理耗时这个指标我们可以看出以125.172结尾的节点处理耗时在1.7s左右,在流量分发数量指标可以看到分配给它的流量在5条/s左右;160.25的节点处理耗时在0.14s左右,分配的流量在58条/s左右,整体符合预期。
同时,为了保证整个服务的稳定性,我们增加了一些监控指标,如:缓存队列长度、模型失败率、链路耗时、写特征失败率等。
结语
本文主要介绍了Flink在异构集群调用的时候,如果出现服务端无法分发流量的情况,在客户端可以通过多线程的方式实现流量的动态负载均衡,这样做可以帮助服务端兼容高低配机型,提升机器利用效能。不过,需要特别指出的是本文中使用的多线程算子是Stateless(无状态)的,对于有状态的算子还需要酌情考虑。另外,如果服务端是可以自主分配节点的组件时,可以选择使用Async I/O方案。
中电金信:技术实践|Flink多线程实现异构集群的动态负载均衡的更多相关文章
- 【大型网站技术实践】初级篇:借助LVS+Keepalived实现负载均衡
一.负载均衡:必不可少的基础手段 1.1 找更多的牛来拉车吧 当前大多数的互联网系统都使用了服务器集群技术,集群即将相同服务部署在多台服务器上构成一个集群整体对外提供服务,这些集群可以是Web应用服务 ...
- CDN技术之--集群服务与负载均衡
Web集群是由多个同时运行同一个web应用的服务器组成,在外界看来就像一个服务器一样,这多台服务器共同来为客户提供更高性能的服务.集群更标准的定义是:一组相互独立的服务器在网络中表现为单一的系统,并以 ...
- Flink的高可用集群环境
Flink的高可用集群环境 Flink简介 Flink核心是一个流式的数据流执行引擎,其针对数据流的分布式计算提供了数据分布,数据通信以及容错机制等功能. 因现在主要Flink这一块做先关方面的学习, ...
- 基于开源Tars的动态负载均衡实践
一.背景 vivo 互联网领域的部分业务在微服务的实践过程当中基于很多综合因素的考虑选择了TARS微服务框架. 官方的描述是:TARS是一个支持多语言.内嵌服务治理功能,与Devops能很好协同的微服 ...
- K8s 实践 | 如何解决多租户集群的安全隔离问题?
作者 | 匡大虎 阿里巴巴技术专家 导读:如何解决多租户集群的安全隔离问题是企业上云的一个关键问题,本文主要介绍 Kubernetes 多租户集群的基本概念和常见应用形态,以及在企业内部共享集群的业 ...
- 从JAVA多线程理解到集群分布式和网络设计的浅析
对于JAVA多线程的应用非常广泛,现在的系统没有多线程几乎什么也做不了,很多时候我们在何种场合如何应用多线程成为一种首先需要选择的问题,另外关于java多线程的知识也是非常的多,本文中先介绍和说明一些 ...
- 关于java多线程理解到集群分布式和网络设计的浅析
对于JAVA多线程的应用非常广泛,现在的系统没有多线程几乎什么也做不了,很多时候我们在何种场合如何应用多线程成为一种首先需要选择的问题, 另外关于java多线程的知识也是非常的多,本文中先介绍和说明一 ...
- ZooKeeper场景实践:(6)集群监控和Master选举
1. 集群机器监控 这通经常使用于那种对集群中机器状态,机器在线率有较高要求的场景,可以高速对集群中机器变化作出响应.这种场景中,往往有一个监控系统,实时检測集群机器是否存活. 利用ZooKeeper ...
- VMware workstation虚拟集群实践(1)—— 配置集群多节点互信
一. 简述 节点互信,是集群管理的基本操作之一.节点互信是通过SSH协议的公钥密钥认证来代替密码认证来实现的.对于单点批量管理多个节点,多个节点之间相互通信来说,配置SSH单方向信任,或者互信十分必要 ...
- ElasticSearch实践系列(二):探索集群
前言 为了方便ELK的逐步搭建,我们本篇文章先安装Kibana,然后用Kibana的DevTols执行命令.也可以安装elasticsearch-head运行命令. 安装Kibana 参考Instal ...
随机推荐
- /proc/buddyinfo
在应用程序设计过程中,内存是很重要的资源,而计算机主机的内存资源时有限的.一般而言我们可以申请到的内存是有限的,并不是想申请多大就有多大就可以申请多大的./proc/buddyinfo文件里,就记录着 ...
- 2024年8月中国数据库排行榜:OceanBase攀升再夺冠,达梦跃入三甲关
在这个炽热的季节,随着巴黎奥运会的盛大开幕,全球将目光聚集在了体育的无限魅力和竞技的巅峰对决上.如同奥运赛场上的激烈角逐,中国数据库界也上演着一场技术与创新的较量,各个数据库产品正在中国乃至全球舞台上 ...
- iOS 数据持久化方案-Realm的使用小结
一.Realm介绍 1.1.Realm是一个跨平台移动数据库引擎,支持iOS.OS X(Objective-C和Swift)以及Android,核心数据引擎C++打造,并不是建立在SQLite之上的O ...
- 动态去读 dll 文件
// 反射动态读取 dll // Assembly assembly = Assembly.LoadFile(); 路径 // Assembly assembly = Assembly.LoadFro ...
- 74.数组map能干什么,会改变原数组吗
map是处理数据的方法,不会改变原数组,会返回一个新数组 : filter 也不会改变原数组,会返回新数组 : forEach 也不会改变原数组,不会返回新数组 : reduce不会改变原数组 : 是 ...
- Chirpy+Github
相关网址 Chirpy 示例:网页上有官方教程,我写的肯定不全 Chirpy 示例仓库:这个就是包含官方教程的那个示例的仓库 Chirpy 模板仓库:直接 fork 这个仓库,快速搭建,没有多余的东西 ...
- .NET 隐藏/自定义windows系统光标
本文介绍如何操作windows系统光标.正常我们设置/隐藏光标,只能改变当前窗体或者控件范围,无法全局操作windows光标.接到一个需求,想隐藏windows全局的鼠标光标显示,下面讲下如何操作 先 ...
- 洛谷 P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布
题目大意 小A和小B,要进行 \(N\) 次猜拳,每次按照一定周期出拳,胜负情况如下: 求出小A和小B分别赢了几次. 思路 枚举 \(N\) 次猜拳,每次比较 \(a[powera]\) 与 \(b[ ...
- Xor-FWT 的另一种理解方式
Xor-FWT 的另一种理解方式 学习 \(\text{Fennec's Algorithm}\) 的额外收获,顺手记录一下. 假设我们要求两个长度为 \(n\) 的数组的异或卷积,为方便起见令 \( ...
- 如何在离线的Linux服务器上部署 Ollama,并使用 Ollama 管理运行 Qwen 大模型
手动安装 Ollama 根据Linux的版本下载对应版本的 Ollama, 查看Linux CPU型号,使用下面的命令 #查看Linux版本号 cat /proc/version #查看cpu架构 l ...