redis-ha · Sentinel 主从加 HAProxy 的 Redis 高可用栈

redis-ha 是为了替换集群里那套单点 redis Deployment 而搭的 Sentinel 高可用栈:3 个 redis 节点做主从复制,3 个 sentinel 做仲裁与故障转移,2 个 HAProxy 把流量固定路由到当前 master。所有资源都以 redis-ha-* 命名,不与现存的单点 redis 冲突,可以并行部署、按 CUTOVER.md 无停机切换。它当前还没接进 bootstrap/,部署是一次有意的人工步骤,不是 ArgoCD 自动同步。

部署形态

整个栈由三类工作负载组成,全部落在 redis 命名空间,kustomization 设置了 commonLabels: app.kubernetes.io/part-of: redis-ha

  • Name
    命名空间
    Description
    redis
  • Name
    redis 节点
    Description
    StatefulSet redis-ha,replicas 3,podManagementPolicy: Parallel,镜像 redis:8.8-alpine,端口 6379
  • Name
    sentinel 节点
    Description
    StatefulSet redis-ha-sentinel,replicas 3,podManagementPolicy: Parallel,镜像 redis:8.8-alpine,端口 26379
  • Name
    HAProxy
    Description
    Deployment redis-ha-haproxy,replicas 2,镜像 haproxy:3.4-alpine,监听 6379
  • Name
    调度
    Description
    redis 与 sentinel 都用 requiredDuringSchedulingIgnoredDuringExecution 的 podAntiAffinity 按 kubernetes.io/hostname 强制分散到不同节点;HAProxy 用 preferred 软反亲和
  • Name
    存储
    Description
    redis 用 volumeClaimTemplates,local-path StorageClass,20Gi/节点;sentinel 同样 local-path,1Gi/节点(仅放可写的 sentinel.conf);HAProxy 无持久卷,仅 emptyDir 临时目录
  • Name
    资源
    Description
    redis 请求 100m/256Mi、上限 1 核/2Gi(对齐命名空间 LimitRange 上限与单点 redis 的 maxmemory 2gb 口径);sentinel 请求 50m/64Mi、上限 200m/128Mi;HAProxy 请求 50m/64Mi、上限 300m/128Mi

redis 节点的 2Gi 内存上限是按命名空间 LimitRange 每容器 2Gi 的上限设置的,与 maxmemory 2gb 一致。

配置与依赖

三个组件各有一个 ConfigMap,既放配置又放启动脚本 entrypoint.sh,启动时由脚本把密码等运行时值注入再 exec。

  • Name
    redis-ha-config
    Description
    redis.conf 从单点 redis 沿用(maxmemory 2gb、allkeys-lru、AOF appendfsync everysec、RDB save 规则等)。entrypoint.sh 做引导:先问任一 sentinel 谁是 master,已知且不是自己就 replicaof 它;无 master 时 ordinal 0 当 master、其余 replicaof redis-ha-0;并用稳定的 pod FQDN 做 replica-announce-iprequirepass/masterauth 由密码注入
  • Name
    redis-ha-sentinel-config
    Description
    sentinel.conf 启用 resolve-hostnames/announce-hostnames(按 k8s DNS 而非会变的 pod IP 跟踪节点),monitor mymaster ... 2(quorum 2/3),down-after 5000msfailover-timeout 60000msparallel-syncs 1。脚本把模板复制到可写的 /data/sentinel.conf 再追加 auth-pass/announce-ip
  • Name
    redis-ha-haproxy-config
    Description
    haproxy.cfg 用 tcp-check 依次 AUTH、PING、info replication 断言 role:master,只有当前 master 通过健康检查,replica 不接流量;后端三台 redis 按 FQDN 解析,配 resolvers k8s 指向 CoreDNS。__REDIS_PASSWORD__ 由脚本 sed 替换
  • Name
    密钥
    Description
    三类 pod 都从既有 Secret redis-secretREDIS_PASSWORD 注入密码(env valueFrom.secretKeyRef),本目录不含 ExternalSecret,复用单点 redis 的密钥

HAProxy 配置里的 CoreDNS ClusterIP 写死为 k3s 默认的 10.43.0.10:53,切换前需用 kubectl -n kube-system get svc kube-dns -o jsonpath='{.spec.clusterIP}' 核对。

访问与监控

栈内有三个 Service,没有 Ingress(纯内部访问),也没有 ServiceMonitor / PrometheusRule / HPA / VPA / PDB。

Service类型用途
redis-ha-headlessHeadless(clusterIP None,publishNotReadyAddresses给每个 redis-ha-N 一个稳定 DNS redis-ha-N.redis-ha-headless.redis.svc.cluster.local,供 sentinel 与 replica 做 announce/replicaof,不做负载均衡
redis-ha-sentinelHeadlesssentinel 的稳定寻址,端口 26379
redis-ha-haproxyClusterIPHAProxy 的稳定入口,端口 6379;切换时把现存 redis Service 的 selector 指向它,客户端继续用 redis.redis.svc.cluster.local:6379 不变

约 17 个 platform + app 命名空间的服务连接 redis.redis.svc.cluster.local:6379,切换以这个不变的 DNS 为前提,客户端不需要改任何配置。

注意事项

切换流程与设计取舍都记录在本目录的 CUTOVER.md,要点如下。

  • 为什么是 Sentinel 而不是 Redis Cluster:客户端用了编号 DB(0、1、7、10、15…),而 Cluster 模式只支持 db0,所以 Cluster 不可行,Sentinel 是唯一可行的 HA。Redis 保持 8.8(当前线上版本),HA 迁移不等于版本升级。
  • 切换前要先把 applications/data/redis/resourcequota.yamlredis-quota 调大:HA 栈加上仍在跑的单点 redis 装不进现配额,大致需要 req cpu ≥1500m、mem ≥3Gi,limit cpu ≥7、mem ≥13Gi,pods ≥15。
  • 数据播种:HA master 起来是空的,而线上 redis 持有真实队列状态(Sidekiq retry/schedule/dead、Celery unacked),不能丢。做法是临时让 redis-ha-0 replicaof 线上 redis 做全量同步,待 master_link_status:up 且 dbsize 一致后 replicaof no one 转正,redis-ha-1/2 已 replicate redis-ha-0 故自动继承。
  • 客户端可见的唯一一步是把现存 redis Service 的 selector 从 app: redis 改到 app: redis-ha-haproxy,并要把这一改动持久化进 git,否则 ArgoCD selfHeal 会还原。回滚就是把 selector 改回 app: redis,未动过的单点 redis 立刻恢复服务。
  • 已知坑:maxmemory-policy allkeys-lru 是从单点配置继承的,内存压力下可能连无 TTL 的队列 key 一起淘汰,若在意队列持久性需另行改成 volatile-lru;failover 窗口内短暂无 master 时写操作会失败(预期行为,客户端重试);手搓的 k8s 上 Sentinel 依赖 resolve-hostnames/announce-hostnames 加稳定 pod FQDN,建议在非生产环境先验证 failover 确实能让 HAProxy 重新指向新 master。

返回 data 服务总览

评论