
上个月,我们替一家港股电商承接 618 预热流量,凌晨 0 点首批请求瞬间涌入,原本 4000 RPS 的 Memcached 集群被击穿,后端 MySQL QPS 直飙 15 万,负载拉满。那一夜我站在将军澳机房震耳欲聋的风扇旁,用手里的星巴克把 CPU 散热片压了半度,却还是眼睁睁看着订单网关超时。
1. 事后复盘发现:
- 缓存穿透——大量不存在的商品 ID 被恶意刷入,Memcached 无命中 → 每次都打到 DB
- 单点故障——一致性哈希槽不均导致一台节点热度过高
- 连接数瓶颈——内核 somaxconn/tcp_backlog 过小
这篇笔记记录了我如何在 48 小时内重构缓存层,最终把缓存命中率从 45 % 拉到 99.6 %、P99 延迟降到 3.1 ms,并且保证 再来十倍流量也打不穿。
2. 集群拓扑与核心组件
┌────────┐ ┌────────────┐ ┌────────┐
│ 客户端 │──┐ │ Twemproxy │──┐ │ Node A │
└────────┘ │ └────────────┘ │ └────────┘
│ │
│ │ ┌────────┐
│ └─│ Node B │
│ └────────┘
│ ┌────────────┐
└──▶│ BloomFilter │ (Go micro-svc, 本地内存)
└────────────┘
- Twemproxy 做一致性哈希、自动摘除故障节点
- Memcached 1.6.38 开启多线程 (‐t 16) 与 extstore(SSD → NVMe)
- Bloom Filter 将 6 亿合法 ID bitset 常驻内存,拦截无效 Key
- 边缘 WAF + 黑洞清洗,避免 DDoS 导致的链路拥塞(此处略)
3. 环境准备
| 角色 | 规格 (A5 数据) | OS | 备注 |
|---|---|---|---|
| Node A/B | 32 vCPU | 128 GB RAM | Ubuntu 24.04 LTS |
| Twemproxy | 16 vCPU | 32 GB | 同机部署 |
| Prometheus | 8 vCPU | 16 GB | 监控 |
内核调优(/etc/sysctl.d/99-memcached.conf)
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 400000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 10
vm.overcommit_memory = 1
4. Memcached 1.6.38 编译安装(支持 TLS + extstore)
apt update && apt install -y build-essential libevent-dev zlib1g-dev \
libsasl2-dev openssl libssl-dev
wget http://www.memcached.org/files/memcached-1.6.38.tar.gz
tar xf memcached-1.6.38.tar.gz && cd memcached-1.6.38
./configure --enable-extstore --enable-sasl --enable-tls
make -j && make install
为何不是 apt 安装?
- Ubuntu 24.04 默认仓库仍停留在 1.6.24——缺少 extstore 多个崩溃补丁与 proxy 漏洞修复。
systemd 单元 /etc/systemd/system/memcached.service:
[Service]
ExecStart=/usr/local/bin/memcached -m 64000 -u memcache \
-c 65535 -t 16 -R 400 -o hashpower=23,modern \
-o slab_reassign,slab_automove,extstore_file=/data/extstore/1.ext,\
extstore_wbuf_size=16m,extstore_page_size=64m \
-Z -o ssl_chain_cert=/etc/ssl/certs/mc.pem,ssl_key=/etc/ssl/private/mc.key \
-S -vv
LimitNOFILE=1000000
- -Z 启用 TLS,防止内部服务账号密码被抓包
- -S 启用 SASL,结合 Vault 动态下发只读/读写角色
- -R 400 提高任何单连接连续命令数,弱化 Nagle 粘包对 RTT 的影响
5. Twemproxy 一致性哈希
/etc/nutcracker/nutcracker.yml
cache_flash_sale:
listen: 0.0.0.0:22121
hash: fnv1a_64
distribution: ketama
auto_eject_hosts: true
server_retry_timeout: 10000
server_failure_limit: 2
servers:
- 10.0.8.11:11211:1
- 10.0.8.12:11211:1
timeout: 300
preconnect: true
- ketama 算法 (160 points) 降低水平扩容时的槽漂移
- auto_eject_hosts 10 秒摘除挂掉的节点,避免全局超时扩散
6. 缓存穿透 360° 防护
| 层级 | 策略 | 关键点 |
|---|---|---|
| 入口网关 | 简易规则 + 限流 | 同一 IP 空 key 超 120 次/分钟 → 403 |
| Bloom Filter | 判断合法 ID | Golang 版 5 GB bitset,FP≈1e-9 |
| Memcached | Null-Object 模式 | 数据不存在时写入 NIL:<id> TTL = 60 s |
| 后端 DB | 队列异步补偿 | 异步批量刷新穿透键,降低瞬时压力 |
6.1 Bloom Filter 微服务
bloom := bloomfilter.NewOptimal(6e8, 1e-9) // 误判率 0.000000001
if !bloom.Test(id) {
return ErrInvalidID
}
误判率 1e-9 意味着十亿次查询才可能有一次误杀,远低于业务容错线。
6.2 Null-Object 写入脚本(PHP 示例)
if (!$mc->get($k)) {
$mc->set("NIL:$k", 1, 60); // 写入占位,防止并发穿透
$db->asyncFetch($k);
}
7. 性能压测与调优
memtier_benchmark -s 10.0.8.10 -p 22121 --protocol=memcache_text \
--key-prefix=prod_ --key-minimum=1 --key-maximum=200000000 \
--threads=16 --clients=512 --ratio=9:1 -d 32 \
--data-size-range=32-256 -n allkeys --hide-histogram
| 优化前 (1.6.24) | 优化后 (1.6.38 + extstore) |
|---|---|
| QPS 175 k | 322 k |
| P99 18.4 ms | 3.1 ms |
| miss rate 55 % | 0.4 % |
8. 监控与告警
- Prometheus memcached_exporter 抓取 cmd_get_rate, get_miss_rate, evictions, curr_connections
- 自研 Bloom miss_rate 指标,10 分钟窗口 > 0.1 % 自动升级限流等级
- Grafana 告警模版:
expr: rate(memcached_get_misses_total[1m]) / rate(memcached_cmd_get_total[1m]) > 0.02
for: 2m
labels:
severity: critical
9. 常见故障案例与排查
| 现象 | Root Cause | 快速定位 |
|---|---|---|
| 节点 CPU 100 % 且 evictions 飙升 | 压测导致小对象写入,extstore page_size 过大,淘汰循环 | stats extstore 观察 page evicted |
| 全链路 TLS 握手延迟 | ssl_chain_cert 文件权限错,走回退路径 |
`journalctl -u memcached |
客户端偶发 SERVER_ERROR socket: Broken pipe |
net.core.somaxconn 没调高,队列溢满 |
ss -nl sport = :11211 state=listen backlog |
10. 收获与总结
- “先拦截,再加速”——Bloom Filter + Null-Object 让无效流量死在最前线。
- 正确的版本很关键——1.6.38 修复了 extstore 内存泄漏与代理死锁,稳定性肉眼可见提升。
- 链路全 TLS 不只是安全合规,也是抵御中间人流量篡改导致的穿透利器。
- 横向扩容≠随便加机器——一致性哈希 + 自动摘除,才能让调度成本在峰值也保持 O(1)。
如果你也在香港做高并发业务,强烈建议照着本文的“三板斧”——核调优、Bloom Filter、防穿透复合缓存——完整走一遍;命中率不过 99 %,别跟我说稳定性。











