看字节跳动容器化场景下,如何实现性能优化?
cac55 2024-09-29 09:30 40 浏览 0 评论
大规模用户容器的快速发展,字节跳动研发工程师教你稳准狠节约成本,优化性能。
如今在字节跳动的私有云平台上,托管了抖音、今日头条等大量在线服务的容器。随着这些业务的快速发展,字节跳动的 Kubernetes 集群数量和规模也越来越大,与此同时,机器的负载也会越来越高,给日常的运维工作带来了巨大的挑战。
尤其是性能问题,经过大量系统问题排查后发现,归根结底在于内核本身的 Cgroups 隔离性和可观测性不足,不能提供所需的数据,这就给线上运维工作带来了困难,进而也阻碍了真正提升资源利用率的进程。那么在字节跳动大规模的容器化场景下,如何实现既提高机器的利用率又能兼顾服务稳定性问题呢?
传统的系统监控,治标不治本
很多人第一时间想到利用传统的系统监控去处理,但是并不能。一个很重要的原因,我们常用到的系统监控,包括像 cAdvisor、Atop 等等,这些系统监控的一个弊端是,只能看到内核暴露出来的数据,也就是说,如果内核没有提供这块数据,我们就没有办法看到。如果我们希望通过修改内核,去支持一些问题的排查和新的特性,但内核的上线过程,又是一个非常痛苦和长期的过程。
我们的思路是,通过提升系统的可见性,去了解服务之间的相互影响,提升系统问题的排查效率,进而去提升资源利用率。
基于eBPF的系统监控,提升系统可见性
Kubernetes 实际上是一个面向应用的技术架构,其设计目标是让业务只用关心资源,而不是机器,因此它的监控系统也应该是服务级别的,而不是机器级别的。基于这些考虑,我们引入了eBPF。
eBPF 是一个在内核中运行的虚拟机,它可以运行用户实现的 eBPF 程序,在内核以本地代码的形式和速度去执行,它可以跟内核的 Trace 系统相结合,给我们提供几乎无限的可观测性。
eBPF 的基本原理——它所有的接口都是通过 bpf 系统调用来跟内核进行交互,eBPF 程序通过Clang/LLVM 编译产生 eBPF 的字节码,通过 bpf 系统调用,加载入内核,由 Verifier 去验证代码的安全性,再通过 JIT 编译实时的转化成 native 的 X86 的指令。
准确识别用户程序在各资源维度的具体行为
如果这个程序是跟内核的 Kprobe 相结合的,当它执行到我们 hook 那个内核函数时,就会回调我们自定义的 eBPF 程序。同时它也提供了一些 Map,用来存 KV,再通过 bpf 这个系统调用,去读取数据。这一套机制,就给我们提供了几乎无限的可观测性。那么我们就基于 eBPF 这个内核机制,实现了一个叫做 SysProbe 的系统监控,在 CPU 和内存层面,我们同样延续使用了Cgroups 的一些数据,同时增加了 throttle、组线程数和状态,以及实例 Load 等更能反映实例负载真实情况的一些指标。
在 Block IO 这层,通过 hook VFS 层的关键函数和系统调用,实现准确识别实例的读写行为。在网络 IO 这一层也是类似的情况,我们可以去探测服务的 Socket 级别的连接状态,以及实时的 SLA,比如说 SRTT 的抖动。基于这种线程级别的数据,我们可以把它聚合到容器级别,再聚合到实例级别,这样我们就得到了一个更准确的实例级别的监控。它的核心的思想就是准确识别用户程序在各个资源纬度的系统行为。
合理提升资源利用率
基于 eBPF 的系统监控,给我们提供了更准确的应用行为描述,继而我们可以在调度层面去做更多的事情,比如说我们可以基于这些数据构建一个实时 pipeline 来实现动态超售,从管控层面去提升资源利用率。
在调度器的 Priority 阶段,对资源部署影响最大的是 MostRequestedPriority,它会把机器上的CPU 内存尽量部署的更满,去减少 CPU 和内存的碎片。在网络 IO 和磁盘 IO 等没有被抽象成为可分配资源的场景下,我们会去把这两个纬度的资源打散,才真正的尽量去避免实例之间的相互影响,对于一些冷服务(升级不太频繁的服务),我们会主动去触发它的一些滚动,让它去更新套餐。既然我们把机器部署的更满,那么意味着,它们可能出现更多资源被饿死和排队的情况。当出现服务过载时,我们有必要去做一些驱逐,去保证机器上的资源处于一个合理的水位。
关于驱逐的优化,主要保证在关键的资源维度上,包括 CPU、内存和磁盘空间等纬度,不出现排队和饿死的情况。对于在线服务来说,实例 Load 是一个非常重要的指标,因为它更能反映业务进程在内核调度器上的排队的情况,这对于我们在线服务来说非常的有用。同时我们也对Kubernetes 本身驱逐的机制做了一些优化,让它受到 pdb 约束,而不至于在一些极端情况下把一个服务的所有实例全部驱逐掉。
PCT99是影响终端用户体验的关键指标
基于 Kubernetes 管控层面调度上的优化,是否就能够把利用率提上去,同时业务也不受影响呢?这显然是不够的,对于在线服务来说,有一个很关键的指标——PCT99,在大型的后台的分布式系统里面,很有可能成为整个后台系统的一个瓶颈,最终影响到终端用户的体验。
这些问题是从 Kubernetes、Docker 这些层面是无法解释清楚的,我们必须要从更深层次去挖掘这个问题的原因。在此不得不提到 RPC 请求,探索一个完整的链路是怎样的一种形态,继而分析出来性能瓶颈究竟出在哪里。
Kubernetes QoS 的深层含义
上文提到,eBPF 是一个很好的内核性能分析利器,因此基于 eBPF 我们可以对一个 RPC 请求的完成链路的延迟进行拆解分析,并确定延迟主要发生在进程处理请求这个阶段,而 Kubernetes的 CPU QoS 配置是其最重要的一个影响因素。
Kubernetes 的资源模型主要包含两个维度,即 Request 和 Limit。Request 表现出来的是Cgroups 中的进程在 CFS 调度器上的 share,而 Limit 则是 CFS 上的带宽限制。带宽限制意味着,用户申请了两核,那么就只能使用两核的 CPU 时间。基于 Request 和 Limit 相互大小的差异,在 Kubernetes 管控层面,将 Pod 换分为三个 QoS 层级, 优先级由高到低依次是Guaranteed、Burstable 和 Besteffort。如果我们对服务进行了超售,那么 Request 就会小于Limit, 在我们的场景下,大部分业务 Pod 都被放置在 Burstable 层级。因此,超售在管控层面的表现是,机器上所有 Pod 的 Request 总和小于机器的可分配资源,进而小于机器上所有Pod 的 Limit 的总和。
Kubernetes 对于 Cgroups 进程的优先级配置,最终会反映到 CFS 调度器上,而调度延迟是引起响应延迟抖动的主要原因。这里需要简单介绍下 CFS 调度器的基本原理。CFS 设计初衷是保证运行中进程的公平性,它会给每一个进程赋予一个权重,同时还有一个 vruntime 的概念,用于表示每个进程的累计运行时间。CFS 保证当前运行的是拥有最小 vruntime 的进程,如果进程的优先级高,则 vruntime 累计速度慢,优先级低,则 vruntime 累计速度快。组调度就是在 CFS 的基础上添加了 task_group 的概念,表示一组进程。因此在引入组调度后,一个sched_entity 可能是一个进程,也可能是一个进程组。task_group 在每个核的队列上有一个自己 sched_entity 和一个 rbtree。基于这样一种设计,Cgroups 支持递归创建子 Cgroup。因此 QoS 的本质是 Pod 所在 Cgroup 在 CFS 上的 share 占总体的比例,并且逐层递归。
CFS 调度延迟分析
调度延迟的含义,不是进程的运行速度变慢了,而是因为调度算法导致进程本该去执行的时候没有办法分配到 CPU 时间。产生调度延迟主要包含两个方面。第一个方面是上文提到的Kubernetes 管控层面的超售,它本质上使 Cgroup 内进程在 CFS 队列上的 share 变小了,所以在一个调度周期内运行时间相对变小。另一方面,实际上也是影响最大的一个方面,即 CFS 的唤醒抢占。其含义是,进程等待的资源就绪时,进程状态被置为 running,并被加入到调度队列等待执行,内核认为刚唤醒的进程有要事要做,会给它一些 vruntime 的补偿,将它的vruntime置为当前队列中所有处于运行状态的进程的vruntime的最小值减去 L,L 默认12毫秒。例如,现在有两个进程 A 和 B,A 为 running 状态而 B 为 sleeping 状态。当 B 唤醒时,其 vruntime 被置为 A 的 runtime 减去 L,并很快抢占 A 的 CPU 时间。因此在 B 的运行过程中,就给 A 带来了调度延迟。
早期在我们场景下,很多业务设置的套餐过小,比如 2C4G,他们利用率不高,但是调用下游超时的情况缺非常频繁。在当时无法从系统层面解释的情况下,业务只能通过扩容去解决,所有早期我们上容器的时候,没有节省资源,反而增加了资源的浪费。其次,对于延迟极其敏感的服务,我们在 Kubernetes 加入了一些特性,支持 share 和 Request 的计算解耦,给予业务进程一些 share 的补偿。
CFS 带宽限制和调优方法
CPU share 保证的是进程可用 CPU 时间的下限,但无法阻止进程使用超过其 quota 的 CPU 时间,因此还需要 Limit,也就是带宽限制来严格控制上限。对于 Limit,通常有两种调节技术。一种是最直观的纵向调节,也就是加大套餐核数,比如有 2C 改为 6C。这样调节的不足之处是,在数据层面,其利用率也随之变低,而这通常是业务同学不愿意看到的地方,因为业务同学会认为这是你的内核隔离机制的不完善导致他们不得不承受一个低的 ROI 的后果。另一种方式,我们其实可以横向来调节带宽限制的 quota 回填周期,即 cfs_period_us,同时保证 cfs_quota_us与 cfs_period_us 的比值不变。如下图,矩形表示 quota 大小,曲线以下面积表示进程使用的CPU 时间。在 100ms 时,曲线以下面积大于矩形面积,但是在 300ms 的长度上来看,前者却比后者小。通过这种横向调节技术,基本可以彻底解决在线业务被 throttle 挂起导致 RPC 超时的问题。
另一方面,我们并不仅仅从系统层面去做调优,实际上业务层面可以一起来配合做这样一件事情。在我们的场景下,很多在线业务使用 golang 编写。在 golang 场景下,调度延迟的问题特别常见,其原因主要有两点,一是 golang 中常用的异步超时逻辑,即一个 select 下会有一个timer 的 channal 和一个请求处理完成的 channel,根据上文分析唤醒抢占,timer 的响应一定会比请求处理的响应时间快,因为 server 端的 reponse 数据已经达到了client 端,但是因为调度延时而拖慢了时间,因而出现超时。另一个原因是,golang 的 GC、work steal 协程调度算法,非常容易在短时间内产生大量并发线程而被 CFS 带宽限制给 throttle。因此我们会在微服务框架中默认限制并发度大小。对于 python 服务,我们则通过 lxcfs 给容器一个虚拟的 /proc和 /sys 视图,业务进程在启动时就会只启动所分配核数的 worker 进程数。
Cgroups 调优案例
第一个服务案例。我们的场景下,Service Mesh 的 Proxy 是跟业务进程是跑在同一个容器里面的。它增加了这个容器里面的线程数,开启 mesh 以后,这个黑色的曲线是开启的,蓝色是没有开启的,我们会发现黑色比蓝色要稍微差一点,开启了 mesh 以后,他们的早晚高峰的 PCT99 抖动问题都非常的严重。我们做了一件非常简单的事情,把多个套餐合并成了一个大套餐,但实际上它整体的利用率并没有改变,整体的资源的申请量也没有改变,但是可以看到效果非常的显著,它甚至比之前没有开启 mesh 的效果还要好。
第二个服务是一个典型的在短时间内有大量的 burst 请求的服务,它会出现大量的调用下游超时,于是我们就给它就做了 period 调整,把 period 时间拉长,同时配合用户态去限制它的线程并发度,而且 share 保持不变,这时可以看到调用下游超时的情况完全消失了。
第三个服务案例,效果与上一个类似。先给它做了一个 period 调整,我们可以看到5月31号到6月1号期间,效果相对于之前来说已经好了很多,这个时候我们只调整拉长了 period,但是并没有完全解决他们的性能问题。我们又把它的套餐也调了一下,结果就看到超时情况完全消失了,效果非常的理想。
写在最后
字节跳动经过近几年来高速发展,集结和掌握了一批优质的技术资源,出品了今日头条与抖音两大国民级App,想必其中运维与架构技术定是日趋成熟的,在容器化场景下,优化性能的优势也日益凸显。如果觉得本篇文章值得学习,欢迎继续关注Archsummit全球架构师峰会北京2019,点击「了解更多」即刻享有限时7折大力优惠名额,有任何问题欢迎联系票务小姐姐灰灰:15600537884 (微信同号)
相关推荐
- Linux :远程访问的 16 个最佳工具(一)
-
通过远程桌面协议(RDP)可以访问远程Linux桌面计算机,这是Microsoft开发的专有协议。它为用户提供了一个图形界面,可以通过网络连接连接到另一台/远程计算机。FreeRDP是...
- Guacamole安装部署_guacamole简单搭建
-
Guacamole安装部署Guacamole简介Guacamole是提供连接远程桌面的解决方案的开源项目(也可以说是一个远程桌面网关),通过浏览器就能远程操作服务器,适用于Chrome、Firefox...
- 1-FreeRTOS入门指南_freertos+lwip
-
本专栏是根据官方提供的文档进行FreeRTOS的各个功能函数的说明,以及函数的使用本专栏不涉及动手操作,只是对原理进行说明,FreeRTOS基础知识篇更新完成会对如何在开发板上进行上手实战操作。这里不...
- Windows暂停远程桌面,这些工具可替代
-
Windows暂停远程桌面,这些工具可替代近日,Windows官方宣布将于2025年5月27日起,在Windows10和Windows11应用商店中下架“Microsoft远程桌面”应用。这一消...
- 现在做 Web 全景合适吗?_前端全景
-
作者:前端藏经阁转发链接:https://www.yuque.com/xwifrr/uxqg5v/cgclx0前言Web全景在以前带宽有限的条件下常常用来作为街景和360°全景图片可查看。它可以...
- 网页直连,MSTSC远程控制Windows新姿势!
-
不用安装软件,打开浏览器就能远程办公?今天要聊的是一种颠覆传统的远程控制玩法,直接用网页连接Windows电脑,无需下载客户端,手机、平板、Mac甚至Linux都能轻松操作。这可不是吹牛,结合MSTS...
- QQ出现大面积盗号,原因已查明,请抓紧改密码
-
你没有看错,QQ又上了微博热搜,这次比较严重了,QQ出现大面积盗号,多个QQ群出现yellow信息,其次导致多位成员被踢出,并且还被封号处理,到底怎么回事?请继续往下看。在6月26日晚上10点左...
- 我在淘宝花10块钱,买到了能玩“宝可梦”的Q群机器人
-
十一月雨|文我是个没事喜欢逛淘宝的人,虽然是个不怎么好的习惯,但总是能够发现一些奇奇怪怪的东西,这次我发现的是一种Q群机器人。Q群机器人,大多是基于腾讯SmartQQ协议实现的一种能自动回复、自定...
- Metasploit最实用的攻击模块"Meterpreter"
-
Meterpreter命令详解Meterpreter是Metasploit渗透测试平台框架中功能最强大的攻击载荷模块,在最新的Metasploitv4.5.0版本中,攻击载荷模块已经达到了25...
- 手机QQ再更新,上线了一个想让人“无法回避”的新功能
-
近日,手机QQ更新了V8.2.6.700版本,苹果iOS版和安卓版手机QQ上线了一个新功能:可以实时显示对方的手机电量以及充电状态。开通电量显示也很简单,长按主页左上方的头像,在在线状态中选择我的电量...
- 「网络安全」常见攻击篇(20)——点击劫持
-
什么是点击劫持?点击劫持(Clickjacking)技术又称为界面伪装攻击(UIredressattack),是一种视觉上的欺骗手段。通常有两种方式:攻击者使用一个透明的iframe,覆盖...
- 曾利用驱动人生升级通道传播的木马下载器攻击方法再次升级
-
一、概述御见威胁情报中心1月25日再次监测到曾利用驱动人生升级通道传播的木马下载器攻击方法再升级。本次升级主要变化在于攻击模块,木马在之前的版本上,新增计划任务“DnsScan”,在其中将永恒之蓝攻击...
- QQ飞车手游:点券首个功能性宠物上架,实战稳定触发还不快入手?
-
随着版本的逐渐更新,点券宠物在道具模式发挥逐渐越来越小,曾经探讨点券宠物在道具是不是真的没有用?直到出现了波斯猫改变了,我对点券宠物在道具模式的看法,如今又一个强势点券宠物来袭,而且特性触发简单,还是...
- 工单系统设计实战(上):核心配置与效能提升
-
流程的标准化并非终点,而是研发效能持续革命的基石。当工单系统真正成为研发团队的“神经中枢”,每一次需求的精准流转、每一行代码的受控提交、每一次版本的可靠发布,都将汇聚成驱动产品持续进化的强大动力...
- 6个编辑PDF文档内容的工具(软件+网站)
-
在日常办公、学习和生活中,PDF文件因其格式稳定、跨平台兼容性强等特点,被广泛应用。但有时我们拿到PDF文件后,却发现需要修改其中的内容,总感觉有点难搞。其实PDF文档编辑修改也很简单,这里分享6个软...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 如何绘制折线图 (52)
- javaabstract (48)
- 新浪微博头像 (53)
- grub4dos (66)
- s扫描器 (51)
- httpfile dll (48)
- ps实例教程 (55)
- taskmgr (51)
- s spline (61)
- vnc远程控制 (47)
- 数据丢失 (47)
- wbem (57)
- flac文件 (72)
- 网页制作基础教程 (53)
- 镜像文件刻录 (61)
- ug5 0软件免费下载 (78)
- debian下载 (53)
- ubuntu10 04 (60)
- web qq登录 (59)
- 笔记本变成无线路由 (52)
- flash player 11 4 (50)
- 右键菜单清理 (78)
- cuteftp 注册码 (57)
- ospf协议 (53)
- ms17 010 下载 (60)