1. 背景
Redis 是各大业务系统中常用的缓存中间件,以解决巨大的网络流量和数据访问场景,并且通过中间件可以实现系统之间的解耦,并提升系统的可扩展性。
对于传统的 IT 资源,中间件的运维一般是需要运维人员全手动搭建和维护,自动化程度低,无法满足业务快速发展需求。
云计算时代的到来为企业灵活多变的业务和僵化的 IT 基础设施之间的尖锐矛盾提供了完美的解决方案。弹性的云计算资源根据业务流量进行扩缩,提高资源利用率;平台化的资源托管,解决了传统集群的运维繁琐问题;云计算重构了企业 IT 基础设施,在业务系统逐渐迁移到云上的过程中,中间件起到了至关重要的作用。
在云计算发展初期,大部分的中间件架设于物理机或者采用 OpenStack 搭建的虚拟云主机之上,通过 OpenStack 对资源的管理和虚拟化,加上具体中间件的运维逻辑实现的管控服务,实现中间件的运维和高可用管理。这种方式缺乏灵活性,无法满足用户多云、混合云等需求,并且由于 OpenStack 的虚拟化复杂性,管控服务的维护成本高。
云原生时代的应用轻量化,将与核心业务无关的能力剥离出去。这些能力将以中间件的形式下沉到基础设施中,成为云的一部分,从而加强和改善应用的运行环境,实现应用轻量化。
云原生赋于中间件新的内涵,即云原生中间件下沉到云基础设施,保持功能不变的情况下与应用解耦,在运行时为应用动态赋能,支撑上层应用系统。
云原生中间件是指在公有云、私有云和混合云等动态环境中,用于构建和运行可弹性扩展的应用,持续交付部署业务生产系统的分布式中间件。在这种大趋势下,网易数帆开始了轻舟云原生中间件的实践,除了本文介绍的 Redis,还包括 MySQL、Elasticsearch、Kafka、RocketMQ、RabbitMQ、ZooKeeper 等。
2. Redis 的云原生化
网易数帆基于云原生强大编排能力和 Kubernetes 的通用接口,通过自定义 Operator 实现状态中间件的云原生化,云原生化的 Redis 相对云主机虚拟化有更好的性能、更低的 IT 成本、更轻量级的资源管理、更灵活的调度策略、更快速的故障恢复和更强的系统自愈能力。
2.1 容器原生
采用容器技术对 Redis 进行服务部署,可以实现 Iaas 底层资源差异的隔离,利用灵活的容器编排技术,实现服务高可用部署。相比于云主机方案,容器方案可以做到采用更小的镜像,更快的启动速度和更轻量级的资源隔离方案,实现更小的性能损耗。
K8s 中 pod 通过 Request 和 Limit 对 CPU 和 Memory 进行资源控制,其中 Request 表示请求资源,主要用于 K8s 的调度,而 Limit 则是对 Node 资源的限制和保护,用户限制 Pod 自身占用资源,保护其他 Pod 的资源占用。
对于 Redis 服务,由于 Redis 服务的特殊性,Redis 为单服务进程模式,并且在特殊场景下会 fork 进程做一些备份或 aof 重写操作,并且会占用额外一部分内存 buffer,所以,
对于 CPU 资源来说,对于 Redis 的 Pod,Request 采用 1 core,Limit 选择 2 core 或不限制
对于内存资源,Request 是用户实际申请的容量,limit 设置为两倍的实际申请容量
这样既可以限制单个 pod 内存占用,又可以满足 Redis 本身在特定场景下对内存资源的额外占用,防止进程被 OOM。但是对于 cpu limit 的设定,经过线上验证,最终选择了不设置。下面是 Pod 中 cpu limit 的工作原理。
上面的图说明了 CPU limit 的工作原理,场景 1 中通过cfs_quota_us
配置的单个容器的 limit 时间片是 200ms,在两个线程的情况下不会发生产生 throttle;场景 2 中,如果是 10 线程的应用,则在相同的 quota 配置下,会出现 10 个线程先同时调度运行 20ms,再触发 cpu throttle 被调度强制回收 cpu 使用权。
可以通过上述的工作原理,配置 cpu limit 会在某些场景下触发 cpu throttle,产生慢查询,通过slowlog get
命令甚至可能看到普通的INFO
命令统计耗时可能会超过 10ms。
并且在 Linux kernel 4.18 之前,由于存在调度 bug,该问题更加严重。所以对于 Redis 服务,本来为单进程服务,不会对 cpu 资源无限制滥用,应尽量避免配置容器的 cpu limit。
上面nr_throttled
统计的含义是 cpu 被限制运行的次数。
2.2 服务状态
对于 Redis 中间件,本身就是状态服务,而 K8s 起初是为无状态服务设计。好在 K8s 可以通过自定义资源 CRD 来自定义 Controller 完成状态服务的控制。
对于有状态的 Redis 而言,需要考虑到数据分布、pod 的异常、副本的复制、状态的恢复等。
通过自定义 Controller 来完成像 Redis 有状态服务的自动化管理,Controller 具有状态服务的数据分布、pod 的异常、副本的复制、状态的恢复等专业运维技能,对用户而言,当机器宕机,用户也不需要介入运维,Redis 似乎完成了从有状态服务向无状态服务转变。
高可用调度
K8s 的原生调度器无法实现对 Redis 对高可用的调度限制,增加了对于 node 节点、az 可用域和多机房的调度控制。
支持单 node 节点集群调度的 pod 数量上限,防止单个 Redis 集群的 pod 集中调度到单个 node 节点,存在宕机风险。
支持单机房调度 Pod 数量上限,防止在多可用域部署场景下,单个可用域可调度的 pod 数量过大,无法容忍单个可用域故障导致的服务不可用风险。
支持多机房选择,支持在多可用域基础设施环境下,通过机房的调度定义,可以灵活对 Redis 集群定义可用域部署策略。
状态管理
Redis 单集群规模能达到上百分片,所以采用单个 Statefulset 管理灵活性差,并且无法快速定位资源对应的数据分片,所以我们采用了单个 Statefulset 管理单个 Redis 集群分片的方式,单个 Redis 集群可能有上百个 Statefulset 组成。使用更细粒度的控制,可以做到运维粒度更小,对资源的控制并发度更加可控。
反亲和配置。对于单可用域的集群,保证单个分片的 pod 调度到不同的 node 节点;对于多可用域的集群,保证单个分片的 pod 调度到不同的可用域。
滚动升级。滚动升级是指的对实例的资源规格变更或者 Redis 版本的升级,Operator 可以通过对 Statefulset 和 Redis cluster 的状态控制,实现无缝的资源重建,整个过程可以通过并发度调整来调整整个滚动升级的速度。
实例重启、重建。Pod 异常后会删除重新创建,创建的新 Pod 的 IP 会发生变化,所以在新 Pod 创建后,Operator 会首先清理旧的实例信息,然后将新启动的 Pod 作为新的 Redis 实例节点加入集群,通过数据复制重建 Redis 集群分片的数据高可用。
2.3 状态声明和事件通知
集群的状态通过 Reconcile 完成,Reconcile 时,通过对集群当前状态的计算和声明的状态进行对比,如果不满足声明的状态,则进行对应的操作,如:
集群停服状态。
调度 configmap 状态。
service 状态。
规格和版本变更状态。
主动运维操作状态。
集群状态异常修复。
集群资源和配置状态。
proxy 资源资源。
定时任务检查。
由于 Reconcile 过程成本较高,并且默认情况下,如果没有订阅的事件发生 Reconcile 的周期性触发时间 30s,时间较长,需要通过一定的手段加快异常发现的速度和状态异常告警。
通过增加 Healthy checker,周期性的对每个 Redis 集群进行状态检查,如果检查到集群本身存在异常,首先进行事件告警,然后将对应的 Custom resource 加入 Reconcile 队列,触发一次全量 Reconcile,使集群状态调整到正常状态。
2.4 观测性
可观测性包含了监控、告警、日志聚合、分布式跟踪和依赖分析等部分,通过收集处理数据来定位问题,并简化信息的访问,实时深入的观察整个应用系统的健康状态,从业务资源计量等多个维度进行度量。日志、指标和请求跟踪是可观测性的基础。
Redis 的监控采用的经典的 Exporter+Promethus 的方案,搜集的监控数据通过自定义的 Grafana 前端将服务状态可视化。
服务的告警分为两类,其中一类就是 Promethus 的监控指标状态监控告警,另一类的 Operator 主动发出的 Event 事件告警。状态监控告警主要负责的是集群本身运行指标的一些异常监控,如:连接数、内存使用率、CPU 使用率、数据淘汰、网络带宽等;事件告警主要是 Operator 发现的一些集群异常、Operator 进行的一些变更操作失败或者事件通知。
Operator 本身的日志和 Redis 的日志也会通过 filebeat 收集到 Elasticsearch 中,用于实时搜索异常。
2.5 弹性伸缩
得益于 K8s 的声明式 API,可以通过更改声明的资源规模可以对集群进行无损弹性扩容和缩容。
如根据流量波峰波谷规律,可定期在波峰到来时对 Proxy 进行扩容,波峰过后对 Proxy 进行缩容;
根据业务的数据容量规律,可一键对 Redis cluster 分片扩容缩容和数据均衡。
2.6 服务形态
轻舟中间件 Redis 包含了常用的 Redis 服务形态,有哨兵模式和集群模式,并且服务接入方式也有多种:
原生 redis cluster 模式,兼容原生使用方式
redis cluster + proxy 模式,屏蔽集群细节
redis cluster + istio 模式,配合微服务的云原生使用方式
原生 sentinel 模式,兼容哨兵使用方式
VIP 模式,固定 IP,客户端采用单节点使用方式,仍然保留高可用
3. 平台化
以云平台(Cloud Planform)的形式提供服务将中间件功能下沉到基础设施,以云平台的形式对外输出能力,提供中间件的接口供用户按需调用,并且通过平台可以实现多云和混合云的部署管控能力,用户无需关注中间件服务的下层资源调度与运维,更加聚焦轻量级的业务应用。
轻舟平台提供了完善的认、用户管理、角色权限、操作审计、监控、OpenAPI 等完善的平台能力,使得中间件和业务联系更加紧密,实现全栈云原生化。
4. 落地场景
轻舟中间件 Redis 已经实现大规模落地,包括在网易集团内部网易云音乐、网易传媒和网易严选生产环境大规模落地,使得集团内部的 Redis 运维效率和服务可用性大幅提升,同时也通过网易数帆商业化平台在金融领域落地,将诞生于互联网公司的云原生中间件能力输送到传统行业数字化业务中。
评论 2 条评论