现如今,缓存系统的应用非常广泛,能够用来提高并发数、数据吞吐量,提高快速响应能力。那么当数据量达到一定程度,单机环境可能就显得有些力不从心了,就需要一个分布式缓存系统。分布式缓存能够处理大量的动态数据,因此比较适合应用在Web 2.0时代中的社交网站等需要由用户生成内容的场景。


CDN 缓存:CDN 即内容分发网络,CDN 边缘节点将数据缓存起来。
反向代理缓存:如 Nginx 的缓存。
本地缓存:代表的有 EhCache 和 Guava Cache。
分布式缓存:各缓存系统。
EvCache:是 Netflix 的基于 Memcached & SpyMemcached 的缓存方案。
Aerospike:是可基于 SSD 的 KV NoSQL 数据库。

Tair:阿里开源,跨机房、性能随结点添加线性上升、适用大数据量。Tair 还有三种引擎。
LDB:基于 Google LevelDB,支持 KV和类 HashMap 结构,性能稍低,持久化可靠性最高。
MDB:基于 Memcache,支持 KV 和类 HashMap,性能最优,不支持持久化存储。
RDB:基于 Redis。
Memcache:不支持数据同步、分布式支持较差。
Redis:社区活跃、使用最多。




Twemproxy:Twitter 开源,轻量级,不再维护,无法平滑地扩容/缩容,运维也不是很友好,性能一般。
Codis:豌豆荚开源,支持水平拓展,运维平台完善,性能较 Twemproxy 快。Codis 在国内使用的较多,同时代理分片的思路也有很多公司在此基础开发了自己的二次方案。不过 Codis 也不再维护。

数据一致性:由于Redis Cluster 使用异步复制, 在某些情况下如 Master 宕机但未同步至 Slave,可能会导致丢失写入。在绝对需要支持同步写入时,可通过 WAIT 命令实现,可使得丢失写入的可能性大大降低。
可用性:当集群中一部分节点故障后,集群整体能响应客户端读写请求。
节点间定时互 ping ,当超过一半 Master 判定某节点失败,则标记为 FAIL,且会向集群广播节点下线的消息。如下线节点是带有槽的主节点,则要从它的从节点选出一个替换。

高性能和拓展:操作某个 key 时,不会先找到节点再处理,而是直接直接重定向到该节点,同时相较代理分片也少了 proxy 的连接损耗。
但是在进行 multiple key 操作时需要 keys 位于同一个 slot 上,需要使用 hash tags,使用 {} 强制将某些 key 映射到每个 slot,以便进行 multiple。
在拓展方面,Redis Cluster 最大支持线性拓展 1000 个节点,将新节点加入集群后可以通过命令指定和平均的从已有节点分配 slot。


空 key:指对于不存在的数据也将 key 存空值入缓存系统,这样下次访问也会得到返回。但只适用于空数据 key 有限、key 重复请求概率高,如果量大且不重复,就会造成很多无用 key 的创建。
布隆过滤器:布隆过滤器是一个很长的二进制向量和一系列随机映射函数。可用于检索一个元素是否在一个集合中加一层对空值的过滤器,空间和时间效率都很高。但由于 hash 产生的碰撞可能存在误判,以及因不存储 key 导致的无法删除。适用于空数据 key 各不同、重复请求概率低。
互斥锁:在缓存失效的时候,不立即 load db,可以先用如 SETNX 等命令去 set 一个 mutex key,当操作返回成功时,说明拿到锁,此刻该线程进行 load db 的操作并更新缓存;否则未拿到锁就(可休眠一段)重试 get 缓存的方法。但要注意死锁风险。
不过期
这里的不过期有两个概念,一个指未设过期时间,那是真的不过期,那没事了。
另一个是指通过业务逻辑,将 key 的过期时间进行存储,请求是判断是否小于值,是则后台异步更新。
随机时间:在设置过期时间时,可以在基础时间上 + 一个随机的时间,等于实现了分批过期。
后台更新:将更新失效的工作交给后台定时线程。
限流 + 本地缓存:如 ehcache 本地缓存 + Hystrix 限流。
双缓存:类似于设置主从缓存,从 key 不过期。
Cache Aside:最常用的。失效时回源取数据,更新;命中时,返回缓存数据;更新时先数据源更新,再更新缓存。
Write Back:更新数据时,只更新缓存,不更新数据源。缓存异步批量更新数据库。
Read/Write Through
Write Through:当有数据更新时,如未命中缓存,直接更新数据库,并返回。如命中缓存,则更新缓存,再由 Cache 自己更新数据库。
Read Through:更新数据源由缓存系统操作,读取数据时如缓存失效,则取回源数据更新缓存。
拆分复杂结构:如二级数据结构,进行拆分,这样热点 key 就被拆为若干个的 key 分布到不同节点。
迁移热点:对于 Redis Cluster 而言可以将热点 key 所在的 slot 单独迁移到一个节点,降低其他节点压力。
多副本:复制多份缓存副本,将请求分散到多个节点上,减轻单台缓存服务器压力,适合多读少写。

redis-cli --cluster create IP1:port1 IP2:port2 IP3:port3 IP4:port4 IP5:port5 IP6:port6 ... --cluster-replicas 1
spring.redis.cluster.nodes=ip1:port1,ip2:port2,ip3:port3
compile("org.springframework.boot:spring-boot-starter-data-redis")
