zl程序教程

您现在的位置是:首页 >  后端

当前栏目

分布式缓存

2023-06-13 09:17:14 时间

缓存基础

存储在计算机上的一个原始数据复制集,以便于访问。

缓存和缓冲

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节点彼此互联,客户端连接集群上任何一个可用节点即可