REDIS 云原生实战
摘要
本次以Redis为范例,论述了有道基础架构团队在基础设施容器化路线上的实际,次要将从申明式治理,Operator工作原理,容器编排,主从模式,集群模式,高可用策略,集群扩缩容等方面开展。目录
- 背景
- 面临的挑战
- 申明式治理
Operator工作原理
- 容器编排
- 主从模式
• 主从拓扑图
• 和谐原理- 集群模式
• 集群拓扑图
• 和谐原理- 高可用策略
• Kubernetes保障的高可用
• Redis集群的高可用- 监控观测
- 集群扩缩容
- 总结与瞻望
背景
Redis 是业务零碎中较为罕用的缓存服务,罕用于流量顶峰、数据分析、积分排序等场景,并且通过中间件能够实现零碎之间的解耦,晋升零碎的可扩展性。
传统物理机部署中间件,须要运维人员手动搭建,启动工夫较长,也不利于前期保护,无奈满足业务疾速倒退的需要。
云原生相较于传统IT,能够助力业务平滑迁徙、疾速开发、稳固运维,大幅升高技术老本,节约硬件资源。
云原生中间件是指依靠容器化、服务网格、微服务、Serverless等技术,构建可扩大的基础设施,继续交付用于生产零碎的根底软件,在性能不变的前提下,进步了利用的可用性与稳定性。
在这种大趋势下,有道基础架构团队开始了云原生中间件的实际,除了本文介绍的 Redis,还包含 Elasticsearch、ZooKeeper 等。
面临的挑战
利用云原生技术能够解决以后Redis部署迟缓,资源利用率低等问题,同时容器化 Redis 集群也面临着一些挑战:
• Kubernetes 如何部署 Redis 有状态服务
• 容器 Crash 后如何不影响服务可用性;
• 容器重启后如何保障Redis 内存中的数据不丢;
• 节点程度扩容时如何做到 slots 迁徙时不影响业务;
• pod ip变动后集群的状态如何解决。
申明式治理
对于一个 Redis 集群,咱们的冀望是可能 7x24 小时无间断提供服务,遇故障可自行修复。这与Kubernetes API的申明式特点一模一样。
所谓“申明式”, 指的就是咱们只须要提交一个定义好的 API 对象来“申明”我所冀望的状态是什么样子,Kubernetes中的资源对象可在无外界烦扰的状况下,实现以后状态到冀望状态的转换,这个过程就是Reconcile过程。例如,咱们通过yaml创立了一个Deployment ,Kubernetes将“主动的”依据yaml中的配置,为其创立好Pod,并拉取指定存储卷进行挂载,以及其余一系列简单要求。
因而,咱们的Redis集群是否能够应用一个相似的服务去实现这个过程呢?即咱们须要定义这样的对象,定义服务Reconcile的过程。Kubernetes的Operator刚好能够满足这个需要,能够简略的了解Operator由资源定义和资源控制器形成,在充沛解读集群和Operator的关系后,咱们将整体架构图设计如下
Operator集群自身采纳Deployment部署,由ETCD 实现选主,下层与Kubernetes的Api Server 、Controller Manager等组件进行通信,上层继续和谐Redis集群状态。
哨兵模式中Redis服务用一套哨兵集群,应用StatefulSet部署,长久化配置文件。Redis server也采纳 StatefulSet部署, 哨兵模式的实例为一主多从。
集群模式中的每个分片应用StatefulSet部署,代理采纳Deployment部署。原生Pod、StatefulSet、Service、调度策略等由Kubernetes自身负责。
Redis的资源定义在ETCD中存储一份即可,咱们只须要事后提交自定义资源的 yaml配置。如下所示为创立三个正本的Redis主从集群:
apiVersion: Redis.io/v1beta1kind: RedisClustermetadata: name: my-releasespec: size: 3 imagePullPolicy: IfNotPresent resources: limits: cpu: 1000m memory: 1Gi requests: cpu: 1000m memory: 1Gi config: maxclients: "10000"
其中,kind定义应用的CR名称,size为正本数,resources定义资源配额,config对应Redis Server的config,该定义存储在Kubernetes的ETCD数据库中,后续的具体资源申请与应用由Operator的Controller实现。
Operator工作原理
Operator 是 Kubernetes 的扩大模式,由CRD、Controller形成。它利用定制资源管理特定利用及其组件,Operator 遵循 Kubernetes 的理念。
Operator 无需任何批改,即可从 Kubernetes 外围中取得许多内置的自动化性能,如应用 Kubernetes 自动化部署和运行工作负载, 甚至能够自动化 Kubernetes 本身。
Kubernetes 的 Operator 模式可在不批改 Kubernetes 本身的代码根底上,通过控制器关联到一个以上的定制资源,即能够扩大集群的行为。Operator 是 Kubernetes API 的客户端,外围性能是充当定制资源的控制器。
CRD: Custom Resource Definition, 在Kubernetes中所有皆是资源,资源就是CRD,用户自定义的Kubernetes资源是一个类型 ,比方默认自带的由Deployment,Pod ,Service等。
CR: Custom Resource 是实现CRD的具体实例。
用户创立一个CRD自定义资源,ApiServer把CRD转发给webhook,webhook 进行缺省值配置 验证配置和批改配置,webhook解决实现后的的配置会存入ETCD中 ,返回给用户是否创立胜利信息。Controller 会监测到CRD,依照事后写的业务逻辑,解决这个CRD,比方创立Pod、解决新节点与旧集群关系等,保障运行的状态与冀望的统一。
容器编排
Redis 集群在 Kubernetes 中的最小部署单位为 Pod,因而在架构设计之前,需事后思考Redis个性、资源限度、部署状态、数据存储、状态保护等内容,为不同类型的Redis集群配置适合的部署形式。
资源限度:
Kubernetes 采纳 request 和 limit 两种限度类型来对资源进行调配。
• request(资源需要):即运行Pod的节点必须满足运行Pod的最根本需要能力启动。
\
• limit(资源限度):即运行Pod期间,可能内存使用量会减少,那最多能应用多少内存,这就是资源限额。
Redis 根本不会滥用 cpu,因而配置1-2个核即可。内存依据具体业务应用调配,思考到局部场景下会fork较多的内存,例如 aof 频繁刷写,aof 重写过程中,Redis 主程序称仍旧能够接管写操作,这时会采纳 copy on write (写时复制)的办法操作内存数据,若业务应用特点为“写多读少”,那么刷写期间将产生大量的内存拷贝,从而导致 OOM,服务重启。
一个无效的解决形式为缩小刷写次数,将刷写操作放在夜间低流量时段进行。缩小刷写次数的办法为适当减少auto-aof-rewrite-min-size的大小,可配置应用内存的5倍甚至更大的最小刷写量;其次能够被动触发刷写,判断内存应用达到的配额两倍时进行刷写,理论部署时个别也会预留50%的内存避免OOM。
部署的根本状态:
根据数据是否须要长久化或是否须要惟一标识辨别服务为无状态和有状态的服务,Redis集群须要明确主从、分片标识,大部分场景也须要数据长久化,Kubernetes应用StatefulSet来满足这一类需要。StatefulSet的程序部署、逆序主动滚动更新更能进步Redis集群的可用性。
具体的:
• Redis Server 应用 StatefulSet 启动,为标识为{StatefulSetName}-0的Pod设置Master角色,给其余Pod设置为该Master的从节点。
• Proxy无需存储任何数据,应用Deployment部署,便于动静扩大。
配置文件:
Redis Server 启动时须要一些配置文件,外面波及到用户名和明码,咱们应用 Configmap 和 Secret 来存储的。Configmap 是 Kubernetes的Api 对象,罕用于存储小于1MB的非秘密键值对。而 Secret 能够用于存储蕴含敏感信息的明码、令牌、密钥等数据的对象。
两种资源均能够在 Pod 运行的时候通过 Volume 机制挂载到 Pod 外部。
存储:
存储应用的是 PVC(PersistentVolumeClaim) 加 PV (Persistent Volumes),PV为Kubernetes集群中的资源,由存储类StorageClass来动静供给,PV反对多种拜访模式:ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany,通过PV定义存储资源,PVC申请应用该存储资源。另外通过依据存储的 StorageClass 字段 可形象不同的存储后端,如Cephfs、Cephrbd、Openebs、LocalStorage 等。
主从模式
主从拓扑图
Redis容器化后建设的每个 CR 示意一个残缺的Redis服务,具体的服务模式包含哨兵模式和集群模式两种,在进行容器化过程中,除笼罩裸服务器部署构造外,也对架构进行了肯定水平的优化。
原生哨兵模式
原生哨兵模式为每套实例配一组哨兵。
共用哨兵模式
所有实例共用一组哨兵将进一步提高实例启动速度,并在肯定水平上可进步硬件资源利用率,实测单组哨兵可轻松应答百规模的主从集群。
和谐原理
Reconcile 实现继续监测并对主从集群进行修复的性能。
- 查看是否依照预期启动了全副的Pod,比方创立3个Server,那么须要依照预期启动三个能力持续进行前面的操作。
- 查看Master的数量,确保该实例仅有一个主节点(数量为0被动选一个;数量大于1手动修复)。
查看哨兵:
(1)所有的哨兵是否监控了正确的Master;
(2)所有的哨兵均晓得雷同的Slave;
(3)再次查看哨兵的数量,确保哨兵均可用。
- 查看 Service,使Service 的Endpoints指向正确的Master。
- 查看Redis config是否有做批改,有则对所有节点重写config参数。
集群模式
集群拓扑图
Redis Cluster + Proxy模式
通过在传统Redis Cluster架构中引入代理性能,实现动静路由散发,并基于Kubernetes原生动静扩缩容个性,更易应答突发流量,正当调配应用资源。
代理根底转发规定如下
代理根底转发规定如下:
• 对于操作单个Key的命令,Proxy会依据Key所属的Slot(槽)将申请发送给所属的数据分片。
• 对于操作多个Key的命令,如果这些Key是贮存在不同的数据分片,Proxy会将命令拆分成多个命令别离发送给对应的分片。
服务部署前,也对代理的局部性能进行了补充,例如移除不可用节点等。
和谐原理
reconcile实现继续监测并对Redis Cluster进行修复性能。
确保集群衰弱的步骤:
- 期待所有 Pod 状态变为 Ready 且每个节点互相辨认后,Operator 会在每个 StatefulSet 的 Pod 中筛选一个作为 Master 节点,其余节点为该 Master 的 Slave。
- 获取实例集群所有Pod的ip、所有Pod的cluster info(蕴含nodeIP,主从关系等)。
进入复原流程
(1)解决失败节点, 对局部节点重启后的有效ip、状态为noaddr的僵尸节点进行forget操作;
(2)解决不可信节点 (所有handshake状态的节点),产生于某一个节点被移除(由forget node触发),但试图退出集群时,即该Pod在Operator角度下存在,但理论集群节点并不需要该节点,解决形式为删掉这个Pod,并再次做forget操作直到Pod被删除。
- 任选一个节点,应用CLUSTER MEET给该节点退出所有已知节点。
- 为StatefulSet中的Pod建设主从关系,同时给其调配Slots。若以后Master数量同预期不统一,则对应扩缩容操作,具体见’集群扩缩容’的横向扩缩容大节。
- 查看Redis config是否有做批改,有则对所有节点重写config参数。
确保代理衰弱的步骤:
- 获取所有Running状态代理的Pod ip。
- 从代理获取Redis Server信息,将集群信息同步到所有的代理上,代理中不存在的Server ip做移除操作。
- 若代理中无可用Redis Server, 示意被全副移除,则增加一个,代理可主动发现集群其余Redis节点。
高可用策略
Kubernetes保障的高可用
(1) 容器部署保障高可用:
Redis部署最小资源对象为Pod,Pod是Kubernetes创立或部署的最小/最简略的根本单位。
当启动出错,例如呈现“CrashLoopBackOff”时,Kubernetes将主动在该节点上重启该Pod,当呈现物理节点故障时,Kubernetes将主动在其余节点上从新拉起一个。
Pod未出问题,但程序不可用时,依靠于健康检查策略,Kubernetes也将重启该Redis节点。
(2) 滚动降级:
节点纵向扩容时,应用StatefulSet的滚动降级机制,Kubernetes将逆序重启更新每个Pod,进步了服务的可用性。
(3) 调度的高可用:
Kubernetes自身不解决Redis 多个Pod组建的集群之间的部署关系,但提供了部署策略,为保障特定场景下的高可用,如因物理节点导致所有Redis节点均宕机,CRD在设计中退出了亲和与反亲和字段。
默认应用 podAntiAffinity 做节点打散,如下所示实例instance1的所有 Pod 将被尽可能调度到不同的节点上。
spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchLabels: Redis.io/name: instance1 topologyKey: Kubernetes.io/hostname weight: 1
Redis集群的高可用
Redis 服务运行期间不可避免的呈现各种非凡状况,如节点宕机、网络抖动等,如何继续监测这类故障并进行修复,实现 Redis 集群的高可用,也是 Operator 需解决的问题,上面以哨兵模式模式为例形容集群如何进行故障复原。
主节点宕机:因物理节点驱赶、节点重启、过程异样完结等导致的Redis主节点宕机状况,哨兵会进行切主操作,而后Kubernetes会在可用物理节点上从新拉起一个Pod。
从节点宕机:哨兵模式的Redis集群未开启读写拆散,从节点宕机对服务无影响,后续Kubernetes会重启拉起一个Pod,Operator会将该Pod设置为新主节点的从节点。
集群全副节点宕机:产生概率极小,但基于长久化可将服务影响降至最低,集群复原后可持续提供服务。
节点网络故障:主从模式下配置了三个哨兵用于集群选主操作,哨兵集群的每一个节点会定时对 Redis 集群的所有节点发心跳包检测节点是否失常。如果一个节点在down-after-milliseconds工夫内没有回复Sentinel节点的心跳包,则该Redis节点被该Sentinel节点主观下线。
当节点被一个 Sentinel 节点记为主观下线时,并不意味着该节点必定故障了,还须要Sentinel集群的其余Sentinel节点独特判断为主观下线才行。
该 Sentinel 节点会询问其余Sentinel节点,如果 Sentinel 集群中超过 quorum 数量的 Sentinel 节点认为该 Redis 节点主观下线,则该 Redis 主观下线。
如果主观下线的 Redis 节点是从节点或者是Sentinel节点,则操作到此为止,没有后续的操作了;如果主观下线的Redis节点为主节点,则开始故障转移,从从节点中选举一个节点降级为主节点。
集群模式故障转移与上述相似,不过不须要哨兵干涉,而是由节点之间通过PING/PONG实现。
监控观测
Redis 的监控采纳经典的 Exporter+Promethus 的计划,Exporter 用于指标采集,数据存储在 Prometheus 或其余数据库中,最终 Grafana 前端将服务状态可视化。
集群扩缩容
(1)纵向扩缩容
纵向扩缩容次要指Pod的CPU、内存资源的调整,基于Kubernetes的个性,只需批改实例对应的spec字段,Operator的和谐机制将继续监测参数变动,并对实例做出调整 。当批改cpu 、内存等参数时,Operator同步更新StatefulSet的limit、request信息,Kubernetes将逆序滚动更新Pod,滚动更新时,若停掉的是主节点,主节点的preStop性能会先告诉哨兵或者集群进行数据保留,而后做主从切换操作,从而将服务的影响降至最低。更新后的主从关系建设以及哨兵monitor主节点性能也由Operator一并处理,全过程对客户端无感知。主从版、集群版在该场景下均反对秒级断闪。
(2)横向扩缩容
横向扩缩容次要指正本数或节点数的调整,得益于 Kubernetes 的申明式 API,能够通过更改申明的资源规模对集群进行无损弹性扩容和缩容。
Redis Server扩容操作时,主从版本中Operator将获取新节点ip, 新启动节点将在下一轮和谐时触发slaveof 主节点操作,且同步过程中,哨兵不会将该节点选为主节点。集群版本中Operator将在同步节点信息后进行分片迁徙,保障所有节点上的Slots尽可能均匀分布。
Redis Server缩容操作时,主从版本中Operator将逆序销毁Pod,销毁时会先询问哨兵,本人是否为主节点,若为主节点则进行先failover操作再退出。集群版本中Operator中会先进行分片迁徙,再对该节点做删除操作。
代理的扩缩容,更易实现,依据流量波峰波谷法则,可手动定期在波峰到来时对 Proxy 进行扩容,波峰过后对 Proxy 进行缩容;也可依据HPA实现动静扩缩容,HPA也是Kubernetes的一种资源,能够根据Kubernetes 的Metrics API的数据,实现基于CPU使用率、内存使用率、流量的动静扩缩容。
总结与瞻望
本次以 Redis 为范例,论述了有道基础架构团队在基础设施容器化路线上的实际,Redis上云后将大幅缩短集群部署工夫,反对秒级部署、分钟级启动、启动后的集群反对秒级自愈,集群依靠于哨兵和代理的个性,故障切换对用户无感知。
有道架构团队最终以云平台的模式提供中间件能力,用户无需关注基础设施的资源调度与运维,重点关注具体业务场景,助力业务增长。将来,将进一步围绕Redis实例动静扩缩容、故障剖析诊断、在线迁徙、混合部署等内容开展摸索。
Redis 容器化后有哪些劣势?
Kubernetes 是一个容器编排零碎,能够自动化容器利用的部署、扩大和治理。Kubernetes 提供了一些根底个性:
部署:部署更快,集群建设无需人工干预。容器部署后可保障每个的Redis节点服务失常,节点启动后将由Operator继续监测和谐Redis集群状态,包含主从关系、集群关系、哨兵监控、故障转移等。
资源隔离:如果所有服务都用同一个集群,批改了Redis集群配置的话,很可能会影响到其余的服务。但如果你是每个零碎独立用一个Redis群的话,彼此之间互不影响,也不会呈现某一个利用不小心把集群给打挂了,而后造成连锁反应的状况。
故障复原:
(1) 实例的重启:容器化后的健康检查能够实现服务主动重启性能;
(2) 网络故障:因宿主机网络故障带来的实例提早高,哨兵可进行主从切换,而为了保障集群的衰弱,将由Operator负责同步集群信息。扩缩容:容器部署可依据limit和request限度实例的cpu和内存,也能够进行扩缩容操作,扩容后的故障复原由Operator解决。
节点调整:基于Operator对CRD资源的继续和谐,可在Operator的Controller中为每个Redis实例进行状态保护,因而,节点调整后带来的主副关系建设、集群Slots迁徙等均可主动实现。
数据存储:容器化可挂载Cephfs、LocalStorage等多种存储卷。
监控与保护:实例隔离后搭配Exporter、Prometheus等监控工具更容易发现问题。
-- END --