为了提升系统的稳定性,没想到运维这么拼~

为了提升系统的稳定性,没想到运维这么拼~

为了提升系统的稳定性,没想到运维这么拼~

本文为携程刘芽老师在 GOPS 全球运维大会 2021 · 上海站的分享,更多精彩干货文章,请关注高效运维公众号。

作者简介
刘芽,2015 年加入携程,先后参与了携程构建平台、发布系统以及镜像管理平台的开发工作,参与携程 GitlabCI 落地以及推进,目前主要参与携程云平台稳定性建设相关工作。

随着应用云原生的推广及业务增长,携程云平台规模逐步扩大,宿主机规模达到万级别,云平台作为业务的基座,其稳定性直接影响了业务的可用性。

本文介绍了携程云平台团队在 Kubernetes 运维优化、宿主机精细化监控、网络及内核底层调优、容器镜像仓库管理等多个方向的一些实践。

1、携程容器云简介

云平台规模

为了提升系统的稳定性,没想到运维这么拼~

携程云平台是以私有云为主的混合云架构。私有云是一个同城双活的架构,主要分布在上海,此外在南通有一个测试环境的 IDC。目前生产 node 数在 1 万以上,pod 数在 20 万以上。

云平台架构:
  • 应用层:在线应用、DB、Kafka、ES;
  • PaaS平台:提供了应用 CI/CD 的能力,也提供了 Web Console 可以方便与实例进行交互,同时提供了HPA、Serverless 等一些云原生能力
  • 镜像管理:私有云通过 Harbor 管理;公有云节点通过 ECR(Amazon)和 ACR(阿里云)来存储镜像。镜像平台负责镜像的同步,并提供海外加速功能
  • K8S集群:每个IDC有若干个 K8s 集群,集群通过 Meta 集群进行统一管控,IDC 之间通过专线互访;Meta 集群除了能管理私有集群,还可以管理公有集群
  • IaaS:提供基础设施的能力,比如内核、CNI、CSI、CRI 等
  • 日志、监控等能力贯穿在所有层

为了提升系统的稳定性,没想到运维这么拼~

基础组件

  • 生产环境的 K8s 版本为 1.19,多集群管理目前从 Kubefed 逐渐过渡至 Karmada
  • 网络虚拟化经历了从 OpenStack + Neutron 到 Cilium + BGP 的技术演进,生产环境已完成 60%,预计 2021 年会完成 80%
  • 内核经历了从 4.14 到 4.19 再到 5.10 的升级,目前生产环境 5.10 的内核占 10% 的比例

为了提升系统的稳定性,没想到运维这么拼~

2、Kubernetes 控制平面稳定性建设

通过架构图可以发现上层应用的可用性直接依赖底层基础设施的稳定性。随着业务的扩张,云平台规模也随之快速增大,对云平台团队维护集群的稳定性也产生了更大的挑战,接下来介绍云团队对控制平台稳定性建设的一些工作。

案例

在某天凌晨,由于 etcd 一个 lead 节点,执行 defrag 导致切主,引起很多组件的重启,导致整个集群不可用。

主要现象表现:

  1. etcd 不停切主

  2. apiserver 不停重启

  3. 控制平面所在宿主机 OOM

  4. 集群雪崩

分析

首先 etcd 切主是 defrag 导致的,etcd 做磁盘碎片整理时 block IO,造成 etcd 切主。当 etcd 不可用时,客户端 lease 失效,组件重启时会拉取所有的元数据,数据量巨大。例如 cilium agent 需要拉取所有 endpoints 信息,当时集群 node 数 1000+,意味着有 1000+ Cilium 重启,造成 apiserver 内存暴增,也造成 etcd 内存暴增,很不巧的是 apiserver 和 etcd 部署在一台机器上,导致宿主机 OOM,最终结果导致整个集群不可用。

为了提升系统的稳定性,没想到运维这么拼~

改进

1、监控告警体系

  • 对接监控告警中台,梳理优先级,比如 p0 (etcd连续切主,核心组件多节点不可用等)、p1 (核心组件单节点故障等),也可引入 kuberhealthy 等一些开源组件对 k8s 集群核心组件可用性进行监控与度量

  • 应急预案 SOP,明确集群故障时恢复先后顺序,在集群故障时,可快速恢复

2、部署架构
  • 核心组件独立部署,减少相互影响

  • etcd 是对磁盘性能要求十分高的组件,所以需要选用磁盘性能较好的机器(最起码使用 SSD,有条件的可使用 nvme)。同时需要对每一个节点压测,尽量使用批次不同的机器(之前遇到某特性型号的机器 raid 卡组件 bug 导致机器 IO latency 非常高)

  • apiserver 分流:针对之前的故障,已经明确知道有两个比较大的请求源:cilium agentkubelet,所以可以将 apiserver 进行分组多入口部署,每个入口对应一个比较大的请求源

3、业务整改

  • 很多资源放到一个 namespace 下时,无法用到 namespace 索引,所以要尽可能避免在一个 namespace 下放太多资源

  • 没有使用 go-reflector 机制,频繁list数据

  • 避免滥用 CRD,减少控制平面的压力

为了提升系统的稳定性,没想到运维这么拼~

具体到每个组件,我们做了以下优化:

apiserver 问题定位及优化

为了提升系统的稳定性,没想到运维这么拼~

  • 节点监控 (IO/CPU/内存) 等一些必要的监控,除此之外由于客户端与 apiserver 通信采用长连接,很容易造成负载不均衡,通过增加连接数可以很直观看到负载不均衡的问题

  • 审计日志和 Trace 日志很方便在 apiserver 出问题的时候,定位到时哪些请求导致的,甚至可以定位到是哪些用户导致的

  • 调整 max-requests-inflightmax-mutating-requests-inflight,这两个参数是 apiserver 为了流量过大时做的自我保护,当集群大的时候,需要将这两个值调大,防止出现 429。在流量过大时,以上两个值也不能保证重要请求访问到服务器,所以需要开启 APIPriorityAndFairness 特性
  • 大集群可以开启 goaway 特性,使客户端尽可能平均分布在 apiserver 上

etcd 稳定性建设

  • 版本问题:在低版本的 etcd 可能会遇到死锁/数据不一致/内存泄漏等bug,节点升级到 3.4.9+ 后,这些问题基本被社区解决
  • OOM:最容易导致 OOM 的就是 expensive request,可以打开 zap 特性记录慢请求,推动客户端优化
  • 节点性能:为了避免采坑,对每个节点进行磁盘的压测
  • 运维治理:
    • etcd 默认的心跳超时和选举超时是比较低的
    • 禁止 defrag,只需要讲周期性 compact 打开,DB size 会处于一个稳定的状态
    • 拆分 events etcd
    • 可以在另外一个 IDC 里起一个 learner 节点来备份 etcd 数据,实现灾备
    • 使用 etcd opearator 备份上传至网络存储,支持标准 s3 协议,减少本地磁盘IO

通过以上整改后,etcd 集群稳定性得到了提升,切主现象基本没有发生。

为了提升系统的稳定性,没想到运维这么拼~

Kube-controller-manager 调优

  • Kube-controller-manger 包含了非常多的 controller,可以禁用不需要的 controller,减少不必要的开销。同时针对 Kube-controller-manager 主节点不可用时,备用节点启动慢的问题可参考社区优化的方案

  • 根据集群规模适当调大 kube-api-burstkube-api-qps 等一些影响并发的参数

  • 除此之外,通过调整 node-eviction-rate 避免集群故障时大量 pod 被驱逐从而影响到业务

3、宿主机巡检

除了控制平台的稳定性影响业务可用性外,由于业务是直接运行在 node 上,node 层面的稳定性更加直接地影响到运行的业务,所以故障 node 的快速发现和处理变得十分重要。

可以把 node 问题简单地归结为以下两类:

  1. 故障宿主机包括硬件故障、组件故障

    • 从浴盆曲线可以看出,一个硬件的生命周期在初期和末期的故障率是非常高的,而且硬件故障无法避免

    • 组件故障:docker / cilium / kubelet 等一些基础组件故障

  2. 热点宿主机由于 CPU 超卖等原因,在一些场景下会出现宿主机 CPU 和 LOAD 非常高的情况,导致一些实例没办法获取所需的 CPU 资源,从而会影响业务

为了提升系统的稳定性,没想到运维这么拼~

虽然宿主机故障不能避免,但可以尽可能提早发现,出现问题时及时补救,以减少对业务的影响。基于此,引入了节点探测器(NPD),以 DaemonSet 方式来运行到每个节点上,主要用来探测和上报节点的运行状况。

NPD 除了可以收集默认的 OOM、死锁等 metric,还支持自定义脚本按需定制所需要的 metric。我们可以通过 Prometheus exporter 将异常对接至告警中台,在告警中台配置相应的告警规则

为了提升系统的稳定性,没想到运维这么拼~

目前基于 NPD 实现的故障发现场景有:

  • 检测 kubelet / docker/ cilium agent 等基础组件的异常状态

  • 磁盘、内存、CPU、LOAD 异常状态

  • 从 dmesg 和 kmesg 日志中解析的异常事件

为了提升系统的稳定性,没想到运维这么拼~

热点宿主机治理

除了宿主机故障之外,热点宿主机也是比较常见的问题,可以通过多个维度去治理:

  • 调度策略

首先是调度策略,之前为了减少资源碎片,采用集中调度策略,优先将一个 node 的 requests 值用完。目前希望通过基于真实负载和集中调度相结合的方式,在一次调度时尽可能将宿主机负载均衡,减少热点宿主机出现的概率,同时减少资源碎片。

  • 重调度

重调度可以在宿主机 CPU 使用率和 LOAD 比较高的时候,通过驱逐宿主机上的 pod 来解决宿主机负载比极高的问题,这种方式对无状态应用比较适用。

  • 监控告警

除此之外,对宿主机的监控告警也可以实时地发现热点宿主机,同时对热点宿主机处理流程自动化,以此减少热点宿主机对业务的影响。

异常 pods 巡检
基于 kube-state-metrics 实现了 pod 层面巡检,对 Pod 按照 namespace 维度聚合了监控告警,比如 Pod pendingTermingtingImageError 等异常场景。

4、网络可观测性建设

为了提升系统的稳定性,没想到运维这么拼~

多维度监控体系:覆盖了置顶交换机、宿主机、单实例。

宿主机网络精细化监控

宿主机网络精细化监控:包括网卡错误、网卡状态、内核丢包、TCP 状态聚合等。

同宿主机实例聚合监控

相信很多做基础设施的同学有同感,经常会被丢锅。比如一个简单的场景,某个同学的若干实例中,突然某个时间点的一个实例 API 响应变慢,就会来报障询问是不是宿主机网络有问题?大多数时候虽然很无奈但是也没有办法拒绝。基于此实现了一个同宿主机的所有实例的聚合监控,通过聚合的监控可以很明显地反映出是不是宿主机网络问题导致的应用 API 响应变慢,以此来“自证清白”。

Cilium TCP Flow

此外也基于 Clilum 收集了所有的 TCP FLow,这个数据量比较大(每秒大概几十万条)主要含了源 IP、源 Port、目的 IP 和目的 Port。通过这个数据可以很容易筛选出生产集群(比如 Redis 集群)被哪些客户端访问,这个数据也是对安全审计非常重要,可以筛选出现访问不正常的现象。

为了提升系统的稳定性,没想到运维这么拼~

以上就是在网络可观测性上做的工作。

5、镜像管理工作

为了提升系统的稳定性,没想到运维这么拼~

私有云镜像通过 Harbor 管理,存储使用 ceph。随着 Gitlab-ci 全面推广,目前每天新增镜像数量在万级,但是 Harbor 自带的 gc 薄弱无法清理脏数据,随着集群规模的增长,集群性能变得越来越差。此外一些大应用在发布时一个批次可能要发布数百个实例,这个并发 pull 也会对 ceph 造成压力,从而影响集群性能。

Ceph性能提升

针对 ceph 性能问题,目前可以通过升级内核和 ceph 版本解决,对比实验:
  • 老内核 + filestore
  • 新内核 + bluestore
  • 数据表明,使用 bluestore + 新内核,相对于之前集群延时降低了20-30%

为了提升系统的稳定性,没想到运维这么拼~

除此之外,在 Kernel 5.X 上 开启 io_uring 特性测试, 通过对比实验可以发现吞吐量能提升20-30%。

为了提升系统的稳定性,没想到运维这么拼~

Image分层

为了提升系统的稳定性,没想到运维这么拼~

基础镜像的分层治理:

  1. 操作系统层(CentOS 7)
  2. 调试工具,包含了用户在容器中的一些基本调试工具
  3. 业务基础环境,按业务区分:Java、Redis、MySQL
  4. 业务组件版本,例如 tomcat7/8、redis4/6
  5. 应用层,包含了用户打包后的产物、代码等
  6. 同时为了满足用户定制化需求,也为用户提供了自定义层的能力。
通过分层治理后,使得用户每次发布只有镜像最后一层不一样,如果事先将基础层下发到 node 节点,应用每次发布需要下载的镜像只是最后一层,pull 请求数据量大大降低。

Harbor 高可用及 mirror

  • 在同城双活的情况下,每个 IDC 里各有一个 Harbor 集群,主集群提供写入口,用户 push 完镜像后,主集群会将 push 完的镜像会同步到另外一个 Standby 集群

  • 两个集群使用同一个 DB,这样可以使得集群切换时,用户数据不会丢失,在故障场景下可以做到用户无感知切换 DR

  • 用户下载的时候用了 registry-mirror 的特性,mirror 可以将下载的镜像缓存到本地来。

    在一个应用副本数比较多的场景下,在金丝雀发布之后该应用的镜像就被缓存在 mirror 的 cache 中,在批次大的滚动发布时镜像可以直接从 cache 来读,大大降低了 ceph 的压力

  • 同时提供了就近访问的能力

为了提升系统的稳定性,没想到运维这么拼~

Harbor sharding 和清理方案

为了解决 Harbor GC 问题,针对社区的方案做了改进。之前的 Habor gc 的缺点是需要扫描 harbor 所有的 blob(单线程扫描),blob 数在几千万左右场景下单线程扫描是灾难级的,通过可以提升线程数可以提升扫描效率,但是如果把线程数提高到非常大时就会导致 Ceph 集群出现性能瓶颈。在把线程数提高了100 倍时,实验结果表明仍然无法满足清理脏数据的需求。

针对此,提出了 Harbor sharding 的方案:
  • 镜像增长比较快的都是应用镜像,基于此可以把应用镜像和基础镜像拆分对应不同的 harbor 集群
  • 在应用镜像所在的 harbor 到达一定规模之后,可以直接废弃掉,只要去同步当前应用在线上的版本和若干历史版本

为了提升系统的稳定性,没想到运维这么拼~

6、容量管理

私有云的容量管理基于 kube-state-metric 实现。同时每个 IDC 中的 K8s 集群共享 node 节点缓存池,如果某个集群资源不足,可以将缓存池的机器接入到资源不足的 K8s 集群中,实现多个集群 node 资源相互借调。

为了提升系统的稳定性,没想到运维这么拼~

节假日扩容准备

在节假日来之前,首先基于历史订单去做流量峰值预测,然后再做 N 倍流量全链路压测。通过历史数据发现机票、火车票、酒店一些比较大的业务是错峰的,资源可以相互借调。基于以上数据可以提前采购一些资源来应对节假日高峰,同时历史数据表明提前采购的资源是可以被业务正常增长正常消耗,并不会造成资源浪费。但是从成本的角度考虑,私有云不会提前储备特别多的资源来应对流量洪峰,基于此我们也逐步地将核心应用部分流量迁移至公有云,在预期之外的流量来之后,在混合云的能力下可以很方便地将流量 offload 到公有云。

为了提升系统的稳定性,没想到运维这么拼~

还不过瘾?还想了解更多云原生下的稳定性提升实战?GOPS 全球运维大会 2022 · 深圳站等你来~

为了提升系统的稳定性,没想到运维这么拼~
长按图片二维码
抢先看精彩内容▲

推荐阅读

新鲜出炉!DevOps 能力成熟度模型持续交付第十七批及系统和工具第四批评估结果公布

“高效运维”公众号诚邀广大技术人员投稿,

投稿邮箱:jiachen@greatops.net,或添加联系人微信:greatops1118.
为了提升系统的稳定性,没想到运维这么拼~
点个“在看”,一年不宕机

文章来源于网络,投诉文章请联系:zhangyunfei@anqiangkj.com

主题测试文章,只做测试使用。发布者:2915,转转请注明出处:https://community.anqiangkj.com/archives/14448

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年4月28日 上午7:18
下一篇 2022年5月5日 上午7:10

相关推荐