0%

缓存

一、前言

1. 影响缓存命中率的因素

  • 缓存键集合
    • 键越少性能越高
  • 可以使用内存空间大小
    • 空间越大,缓存内容越多,命中率越高
  • 使用寿命

2. 缓存为什么可以提升性能

  • 缓存来自内存,比磁盘访问更快
  • 减少数据库、磁盘和网络的压力,减少cpu的io时间
  • 缓存最终结果,不需要再次计算

3. 各种介质数据访问延迟

操作类型大致时间
本地内存100ns
SSD磁盘搜索100000ns
网络数据包在同一个数据中心来回时间500000ns
非ssd磁盘搜索10000000ns
按顺序从网络读取1MB数据10000000ns
按顺序从非ssd磁盘读取1MB数据3000000ns
跨大西洋网络数据包来回时间150000000ns
每秒1000000000ns

二、缓存分类和添加原则

1. 使用场景分类

私有缓存

共享缓存

2. 存储位置分类

本地缓存

分布式缓存

3. 实现方式分类

代理缓存

  • 通过代理服务器进行缓存,一般是客户端侧的缓存

反向代理缓存

  • 反向代理是在数据中心侧缓存,用户连接数据中心先连接反向代理服务器进行缓存查找
  • 可以使用多层反向代理实现缓存

CDN缓存

  • 内容分发网络,为网络服务商提供的服务,不在客户端也不在数据中心
  • 第一个请求到数据中心,返回页面中的各项静态资源地址为cdn的服务器,客户端请求cdn的服务器获取资源
  • 由cdn请求数据中心然后缓存到cdn服务器上返回

4. 数据来源分类

通读缓存

  • 客户端只从缓存服务器获取数据,失效由缓存服务器进行请求后返回

旁路缓存

  • 客户端先从缓存服务器获取,失效直接请求数据中心,如对象缓存

三、缓存问题和解决

1. 缓存击穿

  • 缓存击穿是指缓存中没有但是数据库中有的数据,一般是缓存到期。由于并发用户特别多,同时读缓存没有读到数据,就到数据库进行查询而形成压力

1.1. 解决方案

  • 设置热点数据永远不过期
  • 互斥锁

2. 缓存雪崩

  • 缓存雪崩是指同一时间缓存大面积失效,所有请求都会落到数据库上,造成数据库短时间处理大量请求而崩掉

2.1. 解决方案

  • 缓存数据的过期时间要随机设置,防止同一时间大量数据过期
  • 给每个缓存数据添加缓存标记,记录缓存是否失效,标记失效立即更新,消耗较大,需要做监控
  • 缓存预热,系统刚启动时先不对外提供服务,先将数据存入缓存再对外提供数据
  • 互斥锁,对于某个key进行互斥,只让少量请求进行数据库操作,其余的进行排队,然后更新到缓存后就可以对缓存进行操作

3. 缓存穿透

  • 缓存穿透是指缓存和数据库中都没有数据,导致所有请求都落到数据库上
  • 一般是攻击数据库会造成

3.1. 解决方案

  • 接口层增加校验,用户鉴权、id格式校验等
  • 从缓存和数据库都取不到的数据,设置key-value为key-null,有效时间可以短一点,防止用户使用同一个key进行攻击
  • 使用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一定不存在的数据会被bitmap进行拦截,减少对底层数据库的查询

4. 热key问题的处理

4.1. 添加本地缓存

4.2. 热key探查

  • 集群环境下,所有流量会分布到不同设备上,在客户端进行探查会不够真实,所以一般是在客户端到redis之间添加proxy进行热key探查

1) 京东

  • 在客户端和redis之间添加一层proxy,proxy对所有key进行访问统计
  • 推送到客户端上,客户端对热key进行本地缓存

2) 阿里云

  • 同样是proxy,但是热key的缓存放到proxy上,不会推送给客户端

5. 不需要使用缓存的场景

  • 频繁修改的数据
  • 没有热点的数据

5. 缓存失效方式

  • 超时失效
  • 实时通知清除
  • LRU算法清理

四、分布式对象缓存

  • memcached

1. 查找缓存方式

  1. 使用客户端里面的路由算法来查找到哪个服务器
  2. 再通过通讯模块进行连接访问

2. 路由算法

2.1. 余数hash

  • 使用取余来查找服务器
  • 如果添加服务器,可能造成缓存雪崩,因为余数不一致

2.2. 一致性hash

  • 一般环取 $2^{32}-1$
  • 将节点计算hash放到环上,对key也计算hash在环上查找后面最近的节点,缓存就在此节点
  • 可以动态扩容服务器,不会影响原有的节点hash和分布,仅影响最近的一个节点,部分key会查找到此节点
  • 由于hash值不确定,可能会造成部分节点数据很多,部分很少,添加一个节点并不能分担大部分节点压力,仅能影响最近的节点

2.3. 一致性hash改进(虚拟节点)

  • 物理节点分为多个虚拟节点,将虚拟节点加到环上
  • 单个物理节点加入,由于虚拟节点很多,所以可以分担大部分节点压力