1.概览
缓存命中率 = 命中缓存的请求数 / 总请求数(99%以上)
同时部署多个节点,让节点互为备份
- 客户端方案
- 客户端配置多个缓存节点,通过缓存写入和读取算法策略实现分布式
- 中间代理层方案
- 在应用代码和缓存节点间增加代理层,
- 服务端方案
- redis2.4以后的Redis Sentinel 方案
2.客户端(业务代码)方案(代码层面)
缓存的写和读两个方面
- 写入数据,写入缓存节点分散到多个节点中
- 读数据,利用多组缓存做容错,提升系统可用性
- 主从和副本策略
2.1缓存数据如何分片
- 要求
- 单机存储有限
- 同时保证一定的可用性
- Hash分片算法
- 算法思想:对缓存key进行hash计算,对总缓存节点个数取余
- 优点:算法简单
- 缺点:缓存节点发生变化,导致节点发生变化,造成缓存失效
- 适用场景:对缓存命中率不敏感
- 一致性Hash分片算法
- 算法思想:hash值空间组成一个虚拟的圆环,将特征hash后在放置环中,每次找一个最近的节点
- 优点:增加和删除节点,只有少量的key会漂移到其他节点
- 缺点:
- 分布不均匀会造成缓存节点压力较大
- 一个节点发生故障,导致后面节点造成更大压力
- 存在脏数据问题
- 适用场景:分号解决增加和删减节点,命中率下降的问题
增加节点后
为了解决一个节点的crash导致后续一系列节点crash的情况:
可以在在hash环上引入虚拟节点,避免一个节点crash导致所有节点的crash
为了解决节点的脏数据问题:
一定要设置缓存的过期时间,通过过期时间减少脏数据的几率
批量获取,单个节点的访问量没有减少(遍历所有节点)(尽量不要使用批量查询)
因为根据木桶原则,SLA 取决于最慢、最坏的节点的情况,节点数过多也会增加出问题的概率,因此推荐 4 到 6 个节点为佳。
2.2Memcached的主从机制
- 为每一组 Master 配置一组 Slave,更新数据时主从同步更新
- 优先从 Slave 中读数据,如果读取不到数据就穿透到 Master 读取,并且将数据回种到 Slave 中以保持 Slave 数据的热度
- 当某一个 Slave 宕机时,还会有 Master 作为兜底,不会有大量请求穿透到数据库的情况发生,提升了缓存系统的高可用性
2.3多副本
- 在副本中存储最热的数据
- 在 Master/Slave 之前增加一层副本层
- 请求首先会先从多个副本组中选取一个副本组发起查询,如果查询失败,就继续查询 Master/Slave,并且将查询的结果回种到所有副本组中,避免副本组中脏数据的存在
3.中间代理层方案
- 客户端方案会在切换语言后不可使用
- 可以通过缓存代理层将客户端高可用逻辑封装在代码里面,不再需要依赖客户端代码
- 业界方案
- Facebook 的Mcrouter github.com/facebook/mc…
- Twitter 的Twemproxy github.com/twitter/twe…
- 豌豆荚的Codis github.com/CodisLabs/c…
- 所有读写请求经过代理层完成,代理层是无状态的
- 主要负责读写请求的路由功能,高可用逻辑
4.服务端方案
- Redis 在 2.4 版本中提出了 Redis Sentinel 模式来解决主从 Redis 部署时的高可用问题
- 主节点挂了以后自动将从节点提升为主节点,保证整体集群的可用性
- Sentinel也有主备,同时是无状态的
- 所有的读写请求不会经过Sentinel
5.总结
需要根据实际情况进行自研