deployment部署memcached会导致数据丢失、连接中断和缓存命中率暴跌,必须用statefulset——因其提供稳定网络标识、有序部署和headless service支持,配合显式servicename、严格label匹配、exec探针及正确启动参数(如-m 2048、-c 4096)才能保障生产可用。

直接用 Deployment 部署 Memcached 在 Kubernetes 中是错的——它会丢数据、扩缩容时连接中断、Pod 重启后缓存全失,而且无法保证客户端始终访问到同一节点(对分片场景尤其致命)。
为什么必须用 StatefulSet 而不是 Deployment
Memcached 本身无状态,但它的使用方式是有状态的:客户端通常依赖一致性哈希把 key 固定路由到某个实例;如果 Pod IP 变了、顺序乱了、或被随机调度,缓存命中率会断崖式下跌。
-
Deployment滚动更新时 Pod 名称和网络标识不固定,Headless Service无法提供稳定的 DNS 记录(如memcached-0.memcached.cache.svc.cluster.local) -
StatefulSet提供有序部署、稳定主机名、固定存储挂载点(即使你不用 PV,网络身份也必须稳定) - 官方 Helm chart 和生产实践都强制要求
serviceName字段指向一个Headless Service,否则客户端无法做服务发现
StatefulSet 清单里最关键的三处配置
很多 YAML 抄来就跑,但漏掉这几项会导致 probe 失败、启动卡住、或资源超限被 OOMKilled。
-
serviceName必须显式声明,且值要和Headless Service的metadata.name完全一致(不能省略,也不能写成clusterIP: None的 Service 名) -
selector.matchLabels和template.metadata.labels必须严格一致,否则 StatefulSet 控制器找不到自己的 Pod -
livenessProbe和readinessProbe不能只靠tcpSocket:Memcached 启动后可能卡在初始化阶段,nc能连上但没真正 ready,要用exec执行echo stats | nc 127.0.0.1 11211 | grep -q uptime确认服务已响应
容器启动参数必须避开的坑
镜像默认启动命令不带参数,直接跑起来会用极小内存和连接数,线上一压就崩。所有关键参数必须显式传入 args,不能靠 ConfigMap 注入环境变量再由 entrypoint 解析——Memcached 不读环境变量。
-
-m 2048:内存限制必须设,否则默认 64MB,limits.memory和这个值最好一致,避免 cgroup kill -
-c 4096:连接数上限必须调高,默认 1024,K8s 里多副本+sidecar 容易打满 -
-t 4:线程数建议设为 CPU request 的整数倍(比如 request 是cpu: "2",就设-t 2或-t 4),避免线程争抢 -
-o modern,slab_automove=1:必须启用 slab 自动迁移,否则长期运行后碎片率飙升,get_hits下跌
DaemonSet 模式只适用于低延迟敏感型场景
如果你的应用和 Memcached 必须同节点通信(比如 OpenStack 控制节点组件),才考虑 DaemonSet;否则别用——它牺牲了水平扩展能力,且每个节点都跑一份,资源利用率反而更低。
- 必须配
nodeAffinity+tolerations,否则可能调度到 master 节点或污点节点上 - 端口不能用
11211(会被其他 DaemonSet 冲突),得用宿主机端口映射,比如hostPort: 30213 - 没有
Headless Service,客户端只能靠hostNetwork: true或 NodePort 访问,失去服务发现能力
真正麻烦的不是部署,而是后续怎么让客户端正确分片——K8s DNS 返回的是全部 Pod A 记录,但多数 Memcached 客户端 SDK(如 Python 的 pylibmc、Go 的 gomemcache)需要你手动传入静态 IP 列表。这点没人提醒,但线上出问题八成栽在这儿。











