分布式缓存
缓存基础
存储在计算机上的一个原始数据复制集,以便于访问。
缓存和缓冲
Cache
是介于数据访问者和数据源之间的高速存储,当数据需要多次读取的时候用于加快读取速度。
读缓存
Buffer
是介于数据访问者和数据源之间的高速存储,进行高速介质(cpu、内存)到低速介质(硬盘、网卡)的匹配。
写缓冲
无处不在的缓存
- 操作系统缓存
- CPU缓存
- JVM缓存
- 数据库缓存
- CDN缓存
- 反向代理缓存
- 前端缓存
- 应用程序缓存
- 分布式对象缓存
缓存本身的数据结构
- tree
- hash
缓存命中率
缓存是否有效依赖于能多少次重用同一个缓存来响应业务请求
命中率是缓存的关键指标
如果查询一个缓存,十次查询九次能够得到正确结果,那么他的命中率就是90%
影响命中率的主要指标:
- 缓存键集合大小
读取缓存数据时通过缓存键进行精准匹配,缓存键越少,效率越高
- 可用内存空间
可使用内存空间直接决定了缓存对象的平均大小和数量,空间越大,命中率越高
- 对象生存时间
TimeToLive,TTL越长,被重用的可能性越高
常见分类
通读缓存
read-through,通读缓存给客户端返回缓存资源,并在请求未命中时请求原始服务器
客户端连接的是通读缓存而不是生成响应的原始服务器
代理缓存
反向代理缓存
多层反向代理缓存
内容分发网络CDN
CDN同时配置静态和动态请求
旁路缓存
cache-aside,对象缓存是一种旁路缓存,旁路缓存通常是一个独立的键值对存储。
应用代码通常首先询问需要的对象是否存在,如果存在则获取后直接返回,不存在则请求原始服务器获得响应后也会缓存到旁路缓存。
浏览器对象缓存
var preferences = { /* data object to be stored */};
localStorage.setItem('preferences',JSON.stringify(preferences));
// 访问
var cachedData = localStorage.getItem('preferences');
var preferences = JSON.parse(cachedData);
本地对象缓存
- 对象直接缓存在应用程序内存中
- 对象存储在共享内存,同一台机器的多个进程可访问
- 缓存服务作为独立应用和应用程序部署在同一个服务器上,通过localhost访问
分布式对象缓存
分布式寻址算法是分布式对象缓存的关键,即缓存键如何分布到不同服务器,集群增加节点时如何处理
均匀hash算法
- 针对一个key,计算hashcode,然后在对节点数量取模,完成寻址。
- 当新增节点或某个节点故障时,会有大量key的缓存失效,给数据库带来压力。
一致性hash算法
- 解决分布式缓存集群扩容时数据访问不一致问题的算法,防止缓存雪崩。
- 实现步骤
- 构建一个一致性hash环(0-(232-1),也是hashcode的范围即4个字节的范围)
- 首先根据node的hashcode把node加入到环上
- 再根据key的hashcode把key加入到环上
- 最后沿着环按顺时针找到最近的node完成寻址
- 当新增节点或某个节点故障时,仅有少量的key的缓存失效,把压力降到最低。
- 但此算法的缺点就是node的hashcode可能分布不均匀导致负载不均衡,需要基于虚拟节点的一致性hash
基于虚拟节点的一致性hash算法
- 把node拆分成M个虚拟节点(nodeN_0......nodeN_M)
- 然后把虚拟节点按hashcode放入hash环,解决均衡问题
- 虚拟节点越多,对增减节点时缓存失效的概率越低,同时算法的效率也会降低,综合起来M应该在150-200
缓存特性
各种介质数据访问延迟
操作类型 | 粗略时间 |
---|---|
访问本地内存 | 100ns |
SSD磁盘搜索 | 100,000ns |
网络数据包在同一个数据中心来回一次的时间 | 500,000ns |
非SSD磁盘搜索 | 10,000,000ns |
按顺序从网络读取1MB数据 | 10,000,000ns |
按顺序从非SSD磁盘读取1MB数据 | 30,000,000ns |
跨大西洋网络数据包来回一次的时间 | 150,000,000ns |
跨太平洋网络数据包来回一次的时间 | 300,000,000ns |
每秒等于多少 | 1,000,000,000ns |
- 美国访问中国的数据中心网络延迟就有300ms
- redis/memcached一次请求(1-2k)大概耗时0.5ms
- 加索引的数据库的一次请求(1-2k)大概耗时50ms,是缓存的100倍
技术栈各个层次的缓存
缓存为什么显著提升性能
- 缓存数据通常来自内存,比磁盘等其他介质有更快的访问速度
- 缓存的数据通常是终态,不需要中间计算,节省了CPU资源消耗
- 缓存降低了数据库、磁盘、网络的负载压力,使得这些IO设备能获得更好的响应特性,提升系统整体性能
缓存是系统性能优化的大杀器
- 技术简单
- 性能提升显著
- 应用场景多
缓存不适宜场景
- 频繁修改的数据
此类型数据应用还来不及读取就失效了徒增系统负担,一般数据的读写比在2:1以上,缓存才有意义。
- 没有热点的访问
缓存使用内存存储,内存资源有限且宝贵,如果数据没有二八定律即大部分访问集中在小部分数据上,则缓存效果不会明显
- 数据不一致与脏读不允许
一般会对缓存数据设置过期时间,过期时间内可能会和数据库不一致,如果业务容忍则也可以使用,如果业务不能容忍,则需要数据在数据库变更时也要清除缓存。
缓存使用问题
- 缓存预热
缓存中存放的是热点数据,热点数据通过LRU算法筛选出来的,整个过程时间比较长,过程内性能一般,需要在缓存系统启动时就把热点数据加载好就是缓存预热warm up,
- 缓存穿透
如果不恰当的业务或恶意请求持续高并发的请求某个不存在的缓存,如果缓存没有相应的对策,那所有的查询请求都落到数据库上,带来很大的压力,甚至崩溃。一个简单的对策是将不存在的数据也缓存起来值为null,并设置较短的过期时间
- 缓存雪崩
当缓存服务器崩溃时,请求压力全部打倒数据库,导致数据库也宕机,进而整个服务失效。发生这种问题时甚至不能简单的重启缓存服务器和数据库服务器来恢复。
Redis简介
Redis VS Memcached
- Redis支持复杂的数据结构,Memcached只支持字符串
- Redis支持多路复用、异步IO保证高性能
- Redis支持主从复制保证高可用
- Redis原生支持集群模式
Redis集群
- 集群预分好16384个slot,根据CRC16(key) mod 16384的值决定key放入哪个slot,结果是均匀的
- Redis-cluster把所有物理节点映射到[0-16383]slot上,并负责维护slot与服务器的映射关系
- slot使得增/删节点变得非常简单,可以像磁盘分区一样自由分配slot,在配置文件里可显示指定也可默认
- 管理员可以根据机器的配置和负载情况进行slot的动态调整,基本上解决了最开始的负载均衡问题
- 当新增节点时,各节点会分一些slot到新节点。当删除节点时,该节点上的slot也会分给其他节点
- 所有的Redis节点彼此互联,客户端连接集群上任何一个可用节点即可
相关文章
- 【说站】mysql查询缓存的使用
- .NET WebAPI 采用 IDistributedCache 实现分布式缓存过滤器 Redis 模式
- 什么是缓存击穿、缓存穿透、缓存雪崩?如何解决?
- 12 张图看懂 CPU 缓存一致性与 MESI 协议,真的一致吗?
- Nginx反代理加速,打造自己的Gravatar头像缓存服务器
- aching令Redis让你的缓存加速(redis-c)
- 缓存Linux删除Nginx缓存:轻松解决一个困难(linux删除nginx)
- 应用『Java应用程序中Redis缓存的使用』(redis缓存与java)
- Redis缓存:了解生命周期的关键(redis缓存生命周期)
- Redis:高性能缓存和数据存储解决方案(redis是用来干嘛的)
- 与优势深入浅出:Redis缓存的原理与助力优势(redis缓存的原理)
- Redis如何实现加节点的分布式缓存扩展(redis加节点)
- 缓存若依搭建Redis缓存实现极致性能加速(若依搭建redis)
- 缓存重置客户端本地Redis清空缓存(本地redis清空客户端)
- 动态增多Redis集群节点实现可伸缩的分布式缓存(动态增加redis节点)
- 缓解服务器压力使用Redis进行分布式缓存刷新(刷redis缓存)
- 分布式环境下更高效地更新Redis缓存(分布式更新redis)
- 分布式Redis缓存更新优化表现(分布式redis缓存更新)
- 为了改善公务效率,引入Redis缓存系统(公务 设置redis)
- 商品抢购快人一步利用Redis管理商品库存(商品库存缓存redis)
- Redis高可用实践实现健壮的分布式缓存(redis高可用实战)
- Redis集群挂载优化分布式缓存管理(redis集群挂载)
- 红色梅森实现读者分离的分布式缓存(redis读者分离)