前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >超时错误码减少99.85%,QQ聊天图片自研上云的技术详解

超时错误码减少99.85%,QQ聊天图片自研上云的技术详解

作者头像
腾讯云开发者
发布2023-08-18 14:00:21
3570
发布2023-08-18 14:00:21
举报

# 关注并星标腾讯云开发者

# 每周3 | 谈谈我在腾讯的架构设计经验

# 第3期 | 陈经纶:QQ 聊天图片自研上云 TKE 实践

自研业务存储平台-是 QQ 的富媒体(图片、视频、语音、文件等)数据传输、存储、处理等全链路解决方案的平台。致力于为用户提供稳定快速的群聊 、单聊图片上传和下载服务。为了面对突发热点也能快速响应,作者团队决定对其进行上云处理。本文着重以 QQ 聊天图片(简称:QQ 图片)为例讲述整个上云的过程及调优。

上云初阶段我们将存量使用的 TVM 统一替换为腾讯云提供的 CVM,一并将老旧云下外网服务升级到腾讯云的公网 CLB。今年我们又进一步实现容器上云目标,使用的是 TKE 平台。我们将所有核心模块作为上云目标,从而实现业务全链路上云。

社交类业务有很强的早晚高峰以及节假日高峰特性

通常项目会遇到一些突发的问题,以除夕0点为例,上传、压缩和下载模块均需保障平日峰值的净增数倍流量,涉及模块多、机器数量大、扩容效率低;非节假日也非常容易受到热点图片带来的流量突增,曾经某视频网站晚上崩了,一时大量用户截图在 QQ 群里传播,导致瞬时下载流量突增1倍多。因此架构设计上非常考验我们平台侧的稳定性以及快速扩缩容的能力,这在以往使用 CVM 的方式上是肯定不具备的。

容器化部署分散在独立集群和复用集群,管理成本高

因历史原因,有部分压缩模块部署在基础架构部门的低价复用集群和一些自建独立集群上,虽然降了成本,但也牺牲了稳定性、提高了变更复杂性和运维成本,因此统一收敛到 TKE 是大势所趋。

图片模块的 CPU 平均利用率较低

图片与视频有个很大的区别就是,平均流量小,耗 CPU 资源低,以往我们使用的 CVM 多是 SA2.2XLARGE16 或同规格(8核16G 内存1.5G 出+入带宽)机型,根据节日压测结果,单机跑到流量安全值上限 1.4G 时 CPU 峰值也只有50%左右,平日的 CPU 利用率只有20%不到,所以上 TKE 后的利用率和成熟度提升也是 SRE 要着重优化的方向。

QPS

单机入流量 Mbps

单机出流量 Mbps

CPU%

210

151

167

14

571

456

402

35

874

505

587

50

970

593

702

55

1062

639

755

59

镜像统一

考虑到为了减少基础环境和各式各样 agent 对各个业务不同模块的影响,基于对部门设备验收流程、应用部署流程的分析,我们制作了通用基础镜像,具体以 tlinux 团队提供具备标准化的镜像为基准,在组内封装了各种通用 agent 后制作了统一镜像,并将启动脚本 docker_run.sh 写入 Dockerfile 最后执行,可以依次执行拉起各种 agent、拉配置文件和安装业务程序的步骤,并通过 tail -f /dev/null 来保持容器始终 Up 的状态,脚本如下:

代码语言:javascript
复制
#!/bin/bash

sh /usr/local/all-agent-start.sh
sh /etc/rainbow-agent/rainbow-agent-pull.sh

project_name="http"
project_path="/usr/local/storage/${project_name}"

chmod -R 755 ${project_path}
cd ${project_path}/tools/op && ./install.sh

printenv >> /etc/environment
tail -f /dev/null
配置 workload 和交付流

这里需要注意的是,在发布过一次变更后,yaml 会自动生成 templatePool 的配置,如果不做处理的话,这个配置会越来越多,使得 yaml 文件动辄几千行变得难以维护。在查阅 k8s 原生文档资料以及和交付流团队沟通后,建议所有应用都加上以下配置:

代码语言:javascript
复制
autoDeleteExceededMapping: true
autoDeleteUnusedTemplate: true

可以删除掉无用的模板映射。

镜像更新策略

这里大部分业务会配置为默认选项(Always 总是拉取),在某天镜像源不可用时,依赖 HPA 的业务频繁出现了扩容时拉取镜像超时的问题,本质原因就是不管母机上有没有镜像,都会去重新拉取一遍,而 QQ 图片全模块均修改了此项配置为“IfNotPresent”(母机镜像不存在时再拉取),然后第一时间将 HPA 的最小值全部调整为当前值(避免了缩容后扩容不上影响业务容量),最终在那几天未出现任何因镜像原因导致的异常。同时调整为此配置也能一定程度上节省母机的磁盘空间和下载流量,还可以提高扩容速度,在 HPA 频繁的业务场景下效果更明显。结论:对于版本名为 xx:lastest 的,建议使用 Always,对于版本名为指定版本号,如 xx:v_20230711 的,建议使用 IfNotPresent。

代码语言:javascript
复制
imagePullPolicy: IfNotPresent
存活探测和可用性探测

为了让 pod 在重建或者变更时能做到对业务无损,经过调研我们给 yaml 配置了多个健康探针,以如下配置为例,存活探测可以保证加入现网请求的新 pod 都是端口就绪的,可用性探测可以保证 pod 端口心跳失败指定次数时可以自动执行重建,同时从关联的 CLB 或者北极星里剔除,实现无人工干预自愈,提高了运维效率。对于初始化较慢或者需要较多预热步骤的业务,我们也建议配置上启动探测 startupProbe。

配置亲和性

初上云阶段,我们是没有配置亲和性的,哪里有资源就扩去哪里,同时早期母机资源也相对没那么充足,所以我们的 pod 会经常被调度到同一台母机上,终于有一天发现了问题。简单来说就是多组 TApp 绑定了同样的 CLB 提供外网服务,同时这几组 TApp 又有较多容器在同一台母机上,这种情况会引起 CLB 的串流问题。

因此,在和腾讯云团队沟通后,解决方案逐渐明朗,决定一次请求的四元组是:client_ip + client_port + pod_ip + pod_port,那么调整任意一个和上一次请求的值不同即可解决。在不影响客户端启用端口复用的情况下,我们需要将所有 pod 尽量分散到各个母机上,因此开始调研各种 pod 和 node 的亲和性配置,最终决定使用 pod 反亲和性 podAntiAffinity 配置:

代码语言:javascript
复制
affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - podAffinityTerm:
        labelSelector:
          matchExpressions:
          - key: k8s-app
            operator: In
            values:
            - http
        topologyKey: kubernetes.io/hostname
      weight: 100

从而保证了不同母机运行不同的 TApp,绑定不同的 CLB 来提供外网服务,将当时被串流问题引起的超时错误码减少了99.85%。

后来,也为了实现多可用区容灾,我们协同 TKE 团队将所有可用区打散,例如广州的调度到广州-4/5/6/7四个可用区,南京的调度到南京-1/2/3三个可用区,和以往找运管分配不同可用区的 CVM 来部署对比,极大地提升了运维效率和业务稳定性。

HPA 弹性扩缩容

在 CVM 切量上 TKE 完成之后,我们思考如何进一步降本。考虑到 TKE 的成本是按分钟核心数计算的,而社交类业务又有很明显的早晚高峰效应,因此配置合理的 HPA 迫在眉睫,既能在夜间缩小核心数减少成本,又能在业务突发时快速扩容应对。我们根据压测结果和现网实际负载经过多轮调整后针对性的将所有 TApp 都配置了合理的 HPA,有按照 CPU 负载配的,也有按单 pod 出入流量配的,从而保证了每天各 workload 的 CPU 峰值均能达到50%以上。

部分配置截图如上,这里还需要注意 HPA 能够实现 Pod 的水平扩缩容,但如果母机节点资源不足,则扩容出的 Pod 状态仍会 Pending,因此需要业务侧合理预留 Quota,并让 TKE 平台提前准备好支持伸缩的资源节点。摘取部分 TApp 现网利用率和扩缩容情况如下:

小核心适配

上了 TKE 共享集群,若各个业务都使用大核心(例如32核或更大)会产生非常多的碎片资源,不仅仅会降低节点装箱率,浪费很多资源,还会由于节点的碎片资源不满足大核心,导致无法及时扩容,影响业务的可用性,同时单价也会比使用小核心(8核心及以下)要贵一些。

我们的应用都是基于 MCP++框架开发的,为了适配小核心优化了部分核心数要求多的进程模型,既能满足业务需要,又能提高小核心占比。在改造完后我们发现当 CPU limits 大于 requests 且由于客观原因节点资源调度缺乏时,会触发 pod 的抢占逻辑,此时调度器会删除一个或多个低优先级的 pod 以释放资源给高优先级的 pod 使用,这样的“抢占+删除”模式会影响到业务可用性,因此我们将所有 TApp 均设置成 requests 值等于 limits 值,这样调整后的 pod 优先级变高,不容易被抢占。同时为了进一步提升 CPU 利用率,在保证业务质量的情况下我们仍继续探索缩核降配的可行性,将部分流量消耗型 TApp 降配到了6核、4核,甚至将一些信令转发模块降配到了1核,部分 resources 配置参考如下:

代码语言:javascript
复制
resources:
  limits:
    cpu: "4"
    memory: 8Gi
    networkbandwidth.tkex.woa.com/size: 1500Mi
    teg.tkex.oa.com/amd-cpu: 4k
    tke.cloud.tencent.com/eni-ip: "1"
  requests:
    cpu: "4"
    memory: 8Gi
    networkbandwidth.tkex.woa.com/size: 1500Mi
    teg.tkex.oa.com/amd-cpu: 4k
    tke.cloud.tencent.com/eni-ip: "1"

但我们仍不满足于现状,在所有接入模块均已实现上 TKE 并且适配小核心的前提下,思考能否在保持利用率不下降的同时继续提高小核心 workload 的整体核心数,来降低少部分降配较困难业务的成熟度占比影响,争取拿到小核心100%全适配 。机缘巧合,在降本增效的大背景下,我们 QQ 图片业务立了个新项,探索能否通过升级 AVIF 压缩格式,以类似空间换流量的方式,帮业务节省带宽成本。AVIF(AV1 Image Format)简要介绍就是基于新一代 AV1视频编码技术的图片格式,它的主要优点是压缩率更高:对比上一代 H265 格式图片,同等质量下压缩率可以高出20%~30%。同时对我们业务的优势就是能非常好的解决图片存储带宽成本高的问题,也能更好地支持未来大分辨率高清图片的需求,还能提升图片加载速度,利好 QQ 聊天斗图场景,最终提升用户体验。

然而升级压缩格式有一大痛点,即 AVIF 对比原有的 JPG 图片,格式转换(压缩)耗时涨到了6倍,也就是需要原本压缩资源的6倍,直接给我们带来了大量新增核心数的需求,一拍即合。在多轮测试和协调资源部署,最终切量上线后,原图落地的平均大小减少了一半以上,带来了同等的带宽节省收益,用昂贵的带宽成本换来了相对便宜的 CPU 成本,同时还提升了 QQ 图片小核心 workload 的整体核心数,实现双赢。后续我们目标是测试迁移去算力和 GPU 集群,使用它们闲时空余的 CPU 资源,将降本收益提高到最大化。通过降配小核心,提高了 CPU 利用率;利用业务的早晚高峰特性,充分使用 HPA 弹性扩缩容,最终提高了整体云原生成熟度。

可调度能力

上云了是否就解决了让每一个 SRE 都头疼的问题——异地容灾呢?可调度能力就是对业务上云的一大考验,要求业务可以复制、可以优雅终止,对此我的理解就是业务 workload 层面和 pod 层面都需要具备容灾能力,能自动化实现负载均衡。

workload 层面,还是以上述的 AVIF 压缩池为例,上千台实例 pod,如果全部配置在一个 workload、绑定同一个名字服务,怎么看都不是一种优雅的做法,也不具备当误操作 yaml 配置导致整个 workload 被批量重建时的容灾能力。对此我们想到的方案就是拷贝多个 workload,均匀拆分所有实例到三个不同的 workload,每个都创建在指定的不同可用区内,既能实现多 AZ 容灾,也能保证任一 workload 不可用时可以通过快速扩容其它可用 workload 来恢复业务。除了名字服务,下载 http 模块的 CLB 部署我们也是按照同样的方式实现了跨 workload 容灾,靠不同可用区的 workload 分组绑定不同城市的 CLB 资源,实现了 workload 层面的可任意调度能力。

pod 层面,由于不可避免的会偶现部分母机负载高影响到上面的 pod,造成一些主调业务的超时,因此单 pod 的重建、迁移、优雅终止也是我们要考虑的地方,毕竟业务稳定永远是第一位。我们在多个模块下进行了测试,发现原生默认的优雅等待配置(30秒)并不能满足全部业务均能按时剔除掉所有负载均衡,在测试了40秒、60秒等若干配置后,最终选择了75秒作为最佳实践,并形成了组内社交自研业务上云的规范配置之一。

代码语言:javascript
复制
terminationGracePeriodSeconds: 75

在配置了合理的优雅终止后,无论有状态还是无状态的业务,我们都具备了可调度的能力,因此将所有的 workload 都统一配置上了5%的 PDB 可调度性,既能满足单 pod 异常时健康探测自动发现剔除,也能满足母机 CVM 裁撤或需重启时的无感迁移,从而实现服务发现和业务自愈。

经过多团队的协作和努力,QQ 图片业务在整个上云过程中0故障,取得了不错的效果和业务满意度。

整体质量实现了统一基础镜像、规范上云流程,保障整个迁移过程0故障发生。TKE 实例版本、配置收敛一致,避免各种不一致带来的现网问题。多 AZ 多 workload 容灾,打散调度提高业务容灾能力。

成本方面降低了固定规格 CVM 置换为 CPU 与内存可精细化调整的容器,节省了26%的资源成本。容器异常自愈、资源自动弹性扩缩容等特性,释放了30%的人力投入。Quota 资源按需申请,降低闲置空/低负载浪费。

大大提高与交付流和运营 OSS 打通并优化,将扩缩容时间从原小时级别降低至分钟级。CLB 与北极星映射关系一次绑定,自动关联,无需人工频繁介入。支持所有应用可调度,提升故障实例迁移时效。

📢关于企业项目上云你有什么心得体验或犀利观点?欢迎点击腾讯云开发者公众号留言。我们将挑选一则最有趣的答案,为其留言者送出腾讯定制毛毯。8月23日中午12点开奖。

关注并星标腾讯云开发者

第一时间看鹅厂架构设计经验

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯云开发者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 容器化部署分散在独立集群和复用集群,管理成本高
  • 图片模块的 CPU 平均利用率较低
  • 配置 workload 和交付流
  • 存活探测和可用性探测
  • 配置亲和性
  • 小核心适配
  • 可调度能力
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档