TL;DR

  • 场景: Java 服务接入 Memcached,需要搞清 Spymemcached 的线程模型、分片路由和序列化细节
  • 结论: Spymemcached 基于 NIO+回调实现异步 IO,通过 ketama 一致性哈希做 Sharding
  • 产出: 整体架构拆解、线程与 Sharding 机制说明、以及错误速查卡

Spymemcached 基本介绍

Spymemcached 是一个 memcached 的客户端,使用NIO实现。

协议支持:

  • Text 协议: 基于纯文本的协议,易于调试和阅读
  • Binary 协议: 二进制协议,传输效率更高

异步通信机制: 采用 NIO(Non-blocking I/O)实现高效网络通信,通过 callback(回调)机制处理响应。

集群与分片: 支持 Sharding(分片)机制,采用一致性哈希算法分配 key,支持动态增减节点。

整体设计架构

  1. API接口设计: 提供同步和异步两种调用方式
  2. 任务封装机制: 将请求封装为独立Task对象
  3. 路由分区策略: 采用一致性哈希算法确定目标节点
  4. 任务队列管理: 每个connection维护独立的任务队列
  5. 异步IO处理流程: Selector监控所有连接的IO事件
  6. 响应处理机制: 根据opaque字段匹配原始Task,执行回调

线程设计

Spymemcached 有两类线程:业务线程Selector线程

业务线程负责:

  • 请求封装
  • 对象序列化
  • 协议封装
  • 任务分发

Selector线程负责:

  • 发送处理:队列轮询、数据发送、流量控制
  • 接收处理:响应读取、结果通知
  • 连接管理:故障检测、自动恢复、负载均衡

Sharding机制

路由机制

两种哈希算法:

  1. arrayMod(数组取模哈希)

    • 计算方式:hash(key) % 节点数量 = 目标节点索引
    • 特点:节点增减时会导致大规模数据迁移
  2. ketama(一致性哈希)

    • 为每个物理节点生成160个虚拟节点
    • 构建哈希环,将虚拟节点均匀分布
    • 优势:节点增减时平均只需迁移1/N的数据

容错

三种Failover处理策略:

  1. Redistribute策略(推荐): 轮询/随机选择下一个可用节点
  2. Retry策略: 最大重试次数3次,线性增长重试间隔
  3. Cancel策略: 记录错误日志,抛出ConnectionException

序列化

对象以二进制形式存储在Memcached中。序列化后判断长度是否大于阈值的16384byte,如果是则进行GZip压缩。

错误速查

症状根因定位修复
高并发下大量 get 超时单节点压力过大,Selector 线程处理不过来降低单节点压力、调大超时配置
节点增减后缓存命中率跌到0使用 arrayMod 分片改用 ketama 一致性哈希
某个节点故障后大量报连接异常Failover 策略配置不当限制最大重试次数
QPS上去后Client进程内存持续增长任务队列、Future或回调里持有大对象引用给队列设置合理上限
某些 key 偶发 NOT_FOUND分片路由不一致固定节点列表顺序和权重
大对象写入时CPU飙高序列化+GZip压缩消耗大调整压缩阈值,避免超大对象进缓存