张煜,15年加入腾讯并从事腾讯广告维护工做。20年开始引导腾讯广告技术团队接入公司的TKEx-teg,从业务的平常痛点并结合腾讯云原生特性来完善腾讯广告自有的容器化解决方案php
腾讯广告承载了整个腾讯的广告流量,而且接入了外部联盟的请求,在全部流量日益增大的场景下,流量突增后如何快速调配资源甚至自动调度,都成为了广告团队所须要考虑的问题。尤为是今年总体广告架构(投放、播放)的条带化容灾优化,对于按需分配资源、按区域分配资源等功能都有着更强的依赖。
在广告内部,播放流系统承载了整个广告播出的功能,这里的稳定性直接决定了整个腾讯广告的收入,如下为架构图:前端
业务特色:java
在20年腾讯广告已经在大规模上云,主要使用的是 AMD 的 SA2 cvm 云主机,而且已经完成了对网络、公司公共组件、广告自有组件等兼容和调试。在此基础上,基于 CVM 的 Node 云原生也开始进行调优和业务使用,弹性伸缩、Docker 化改造,大量使用各类 PAAS 服务,充分发挥云的高级功能。
如下为广告使用的 TKE 架构:node
困难一:通用性
(1)面对广告84个技术团队,如何实现全部业务的适配
(2)镜像管理:基础环境对于业务团队的透明化
(3)腾讯广告容器配置规范
困难二:CPU密集型检索
(1)广告订单数量:百万级
(2)绑核:各个应用之间的 CPU 绑核隔离
(3)关核:关闭超线程
困难三:有状态服务升级中的高可用
(1)广告资源在容器升级过程当中的持续可用
(2)在迭代、销毁重建过程当中的持续高可用python
广告运维侧提供了一套覆盖大部分应用场景的基础镜像,其中以 XXXXXXX-base:latest 为基础,这里集成了原先广告在物理机上面的各个环境配置、基础 agent、业务 agent 等。
而且基于这个基础镜像,提供了多个业务环境镜像,镜像列表以下:linux
mirrors.XXXXX.com/XXXXX/XXXXXXX-base:latest
mirrors.XXXXX.com/XXXXX/XXXXXXX-nodejs:latest
mirrors.XXXXX.com/XXXXX/XXXXXXX-konajdk:latest
mirrors.XXXXX.com/XXXXX/XXXXXXX-python:3
mirrors.XXXXX.com/XXXXX/XXXXXXX-python:2
mirrors.XXXXX.com/XXXXX/XXXXXXX-tnginx:latestnginx
具体镜像使用状况以下:git
在广告的基础镜像中,因为权限集设置未使用到 systemd,因此使用启动脚本做为1号 PID,而且在基础镜像中内置了一份通用的腾讯通用 Agent & 广告独有 Agent 的启动脚本,在业务镜像启动过程当中,能够在各自的启动脚本中选择是否调用。docker
原先大量使用了其余平台的 CD 部分,但如今使用 TKE 后,其余平台已经没法使用。而 TKEx-teg 上的持续化集成部分对于自动化流水线实现较弱,需手动参与,因此在广告内部引入的 CI/CD 方案是腾讯内部的持续化集成和持续化部署方案:蓝盾。微信
这里全程实现流水线发布,除了审核外无需人工参与,减小人为因素的问题影响。
stage1:主要使用手动触发、git 自动触发、定时触发、远程触发
stage2 & stage3:持续化集成,拉取 git 后进行自定义的编译
蓝盾提供了默认的CI镜像进行编译,不进行二进制编译的能够选择默认(例如 php、java、nodejs等),然后台业务腾讯广告内部大量使用 blade,一般使用 mirrors.XXXXXX.com/XXXXXX/tlinux2.2-XXXXXX-landun-ci:latest 做为构建镜像,此镜像由腾讯广告效能团队提供,内部集成了腾讯广告在持续化集成过程当中的各类环境和配置。
编译完成后经过镜像插件,依赖 git 库中的 dockerfile 进行镜像 build,而后推送至仓库中,同时保留一份在织云中。
stage4:线上灰度 set 发布,用于观察灰度流量下的数据表现。经过集群名、ns 名、workload 名来对某个工做负载进行镜像 tag 的迭代,而且使用一份 TKEx-teg 内部的 token 进行认证。
stage5:确认 stage4 没问题后,开始线上的全量,每次都通过审核确认。
stage6 & stage7:数据统计。
另外有一个蓝盾中机器人群通知的功能,能够自定义把须要告知的流程信息,推送到某个企业微信群中,以便你们进行确认并审核。
广告内部的母机都是用的腾讯云星星海 AMD(SA2),这里是90核超线程 cpu+192G 内存,磁盘使用的是高速云硬盘3T,在平常使用中这样的配置这个机型是腾讯云现阶段能提供的最大机型(已经开始测试SA3,最高机型配置会更大)。
若是是已经上线的 workload,则能够经过修改 yaml 来增长目录的挂载:
- mountPath: /data/log/adid_service name: adid-log volumes: - emptyDir: {} name: adid-log
因此在广告的 TKE 条带化使用过程当中,咱们会去经过 label 的方式来指定机房选择,腾讯云对各个机房的 CVM 都默认打了 label,能够直接调用。
存量的 workload 也能够修改 yaml 来进行强制的调度。
spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: failure-domain.beta.kubernetes.io/zone operator: In values: - "370004"
affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchExpressions: - key: k8s-app operator: In values: - proxy-tj topologyKey: kubernetes.io/hostname weight: 100
在容器化的使用过程当中,有两种方式能够面对业务流量的突增。
注:但这里的超卖并非万能的,他有两个问题也很是明显:
大部分的业务都是cpu的性能为瓶颈,因此通用方式能够针对cpu的request使用率来设置扩容
广告对于每一个流量都存在一个站点集的概念,每一个站点集分了不一样的 set,为了区分开各个流量之间的影响和不一样的耗时要求。在20年咱们对每一个模块都拆出了一个 set 进行了 CVM 的上云,在此基础上,21年咱们针对核心模块 sunfish 进行了容器化的上云。这个模块的特色就是 CPU 高度密集型的检索,因此他没法使用超线程(超线程的调度会致使耗时增长),而且内部的程序都进行了绑核处理(减小多进程之间的 CPU 调度)。
这里是广告最大的一个特性,并且也是 TKE 和 CVM/物理机的最大区别。
在 CVM/物理机的场景中,虚拟化技术是能够从 /proc/cpuinfo 中获取到正确的 cpu 单核信息,因此在原先的业务绑核过程当中,都是从 /proc/cpuinfo 中获取 cpu 的核数和信息,进行每一个程序的绑核操做。
但在容器中 cpu 信息产生了很大的误差,缘由是 /proc/cpuinfo 是根据容器自身的核数进行的排序,但这个顺序并非该容器在母机上的真实cpu序列,真实的 cpu 序列须要从 /sys/fs/cgroup/cpuset/cpuset.cpus 中获取,例以下图两个举例:
/proc/cpuinfo 中的 CPU 序号展现(虚假):
/sys/fs/cgroup/cpuset/cpuset.cpus 中的 CPU 序号展现(真实):
从上面两张图中能够看到,/proc/cpuinfo 中只是按照分配到的 cpu 核数进行了一个排序,但并非真正对应母机的核数序列,这样在绑核的过程当中,若是绑定了15号核,实际上是对母机的15号核进行绑定,但母机的第15个CPU并非分配给了该容器。
因此须要从 /sys/fs/cgroup/cpuset/cpuset.cpus 中获取在母机中真正对应的 cpu 序列,才能实现绑核,如上图2。而且能够经过在启动脚本中加入下面的命令,能够实现对 cpu 真实核数的格式转换,方便绑定。
cpuset_cpus=$(cat /sys/fs/cgroup/cpuset/cpuset.cpus) cpu_info=$(echo ${cpuset_cpus} | tr "," "\n") for cpu_core in ${cpu_info};do echo ${cpu_core} | grep "-" > /dev/null 2>&1 if [ $? -eq 0 ];then first_cpu=$(echo ${cpu_core} | awk -F"-" '{print $1}') last_cpu=$(echo ${cpu_core} | awk -F"-" '{print $2}') cpu_modify=$(seq -s "," ${first_cpu} ${last_cpu}) cpuset_cpus=$(echo ${cpuset_cpus} | sed "s/${first_cpu}-${last_cpu}/${cpu_modify}/g") fi done echo "export cpuset_cpus=${cpuset_cpus}" >> /etc/profile
source /etc/profile 调用环境变量,转换后的格式以下:
注意:绑核依赖 qos 配置(也就是 request 和 limit 必须设置成一致)
超线程在大部分场景下都是打开的,但在计算密集型的场景下须要关闭,此处的解决方法是在申请CVM的时候就选择关闭超线程。
而后对关核的母机作污点并打上 label,让普通的拉取不会拉到关核母机,在须要分配关核资源的时候,在 yaml 中打开容忍和设置 label,就能够获取到相应的关核资源。
yunti 资源申请时的关核配置:
无状态容器的升级最为简单,业务端口的可用即为容器的可用。
但有状态业务的启动较为复杂,须要在启动脚本中完成状态的前期准备工做。在广告这里主要涉及在广告订单资源的推送和加载。
容器的升级较于物理机最大的区别就在于容器会销毁原有的容器,而后重新的镜像中拉起新的容器提供服务,原有容器的磁盘、进程、资源都会被销毁。
但广告这里的广告订单资源都是百万级别,文件若是在每次升级都须要从新拉取,会直接致使启动过慢,因此咱们在容器中都加入了临时挂在目录。
<img src="https://main.qcloudimg.com/raw/a4579ab4826d06e19e688e283ed2fee3.png" style="zoom:67%;" />
<img src="https://main.qcloudimg.com/raw/6865d1b811ed0d3060083b65d22a5ee6.png" style="zoom:67%;" />
这样的挂载方式,可让容器在升级过程当中保留上述目录下的文件,不须要从新拉取。但 emptyDir 只能在升级场景下保留,销毁重建仍旧会销毁后从新拉取,如下为存量服务直接修改 yaml 的方法:
volumeMounts: - mountPath: /data/example/ name: example-bf volumes: - emptyDir: {} name: example-bf
在业务迭代的过程当中,其实有两个问题会致使业务提供了有损服务。
因此咱们这里的一个最主要的思路就是:
这里咱们引入业务的两个升级的概念:
后置脚本
1 )探针就绪
须要在workload建立的时候,选择针对端口进行作就绪探测,这样在业务端口启动后才会投入到关联好的负载均衡里。
<img src="https://main.qcloudimg.com/raw/15cdd81315a26cab80a6fb26eefe8700.png" style="zoom:67%;" />
也能够在存量的workload中修改yaml
readinessProbe: failureThreshold: 1 periodSeconds: 3 successThreshold: 1 tcpSocket: port: 8080 timeoutSeconds: 2
出现相似的unhealty,就是在容器启动后,等待业务端口的可用的过程
2 )后置脚本
后置脚本的核心功能就是在从关联的负载均衡中剔除后,到销毁容器之间,能够执行一系列业务自定义的动做。
执行顺序是:提交销毁重建/升级/缩容的操做 → 剔除北极星/L5/CLB/service → 执行后置脚本 → 销毁容器
最简单的一个功能就是在上游使用L5调用的时候,在剔除L5后sleep 60s,可让上游更新到该pods剔除后再进行销毁操做。
lifecycle: preStop: exec: command: - sleep - "60"
lifecycle: preStop: exec: command: - /data/scripts/stop.sh
长期的使用经验来看,主要问题在L5这方面,若是是大流量的服务,那sleep 60s 内就行,若是是请求量较小的,但愿一个报错都没的,须要 sleep 90s。
这里在相同配置下,对比了普通机器 CVM 和 TKE 容器之间的 CPU 和耗时,能够看到基本没太大差别,耗时也无变化。
CVM:
TKE:
不一样于其余从底层介绍云原生的分享,本文主要从业务角度,来介绍云原生在大型线上服务中的优点和使用方法,并结合腾讯广告自有的特色及策略,来实现腾讯广告在高并发、自动化等场景下的容器化实践。
对于业务团队来讲,任何的工做都是从质量、效率以及成本出发,而云原生则是能从这三个方面都有所提高,但愿将来能有更多来自于咱们腾讯广告的分享。
容器服务(Tencent Kubernetes Engine,TKE)是腾讯云提供的基于 Kubernetes,一站式云原生 PaaS 服务平台。为用户提供集成了容器集群调度、Helm 应用编排、Docker 镜像管理、Istio服务治理、自动化DevOps以及全套监控运维体系的企业级服务。
【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!
![]()