Redis-缓存相关QA

1. 为什么Redis性能这么强

支持数十万的并发(32G可以Set操作达到30W的QPS, Get操作40W的QPS),pipline则更高x2

  • 内存存储:Redis是使用内存(in-memeroy)存储,没有磁盘IO上的开销

  • 单线程实现:Redis使用单个线程处理请求,避免了多个线程之间线程切换和锁资源争用的开销

  • 非阻塞IO:Redis使用多路复用IO技术,在poll,epolll,kqueue选择最优IO实现(参考netty篇章)

  • 优化的数据结构:Redis有诸多可以直接应用的优化数据结构的实现,应用层可以直接使用原生的数据结构提升性能

2. 为什么用Redis

高性能:mysql数据存储磁盘,访问较慢。 redis存内存,访问快。50ms,10ms

大并发:mysql并发能力有限(8C32G的mysql,8000的最大连接数,可以达到3W的QPS,1.5K的TPS),在大并发情况下需要引入redis来缓冲数据访问(4 50W的QPS),避免击穿mysql。

3. Redis数据结构

  • String

  • List

  • Hash

  • Set

  • Sorted Set

  • Bitmap

    boomfilter

Redis为什么单线程

https://draveness.me/whys-the-design-redis-single-thread/

单线程模型,基于多路复用IO模型监听多个连接。

  1. 使用单线程模型能带来更好的可维护性,方便开发和调试;

    不需要引入锁之类机制来控制同步。(比如变量被并发读写了,那么需要加锁之类,不然访问结果无法确定)

  2. 使用单线程模型也能并发的处理客户端的请求;

    多路复用IO也能同时监听多个FD,当监听到有相关事件发生时就调用相应的事件处理器进行处理。https://draveness.me/redis-io-multiplexing/

  3. Redis 服务中运行的绝大多数操作的性能瓶颈都不是 CPU;

    Redis 并不是 CPU 密集型的服务,如果不开启 AOF 备份,所有 Redis 的操作都会在内存中完成不会涉及任何的 I/O 操作,这些数据的读写由于只发生在内存中,所以处理速度是非常快的。

    整个服务的瓶颈在于网络传输带来的延迟和等待客户端的数据传输,也就是网络 I/O。

    在普通的linux上,redis也可以在1S内处理100W的请求。 如果这种还不够的话就做集群。

Redis引入多线程

redis4.0之后引入了一些命令,例如 UNLINKFLUSHALL ASYNCFLUSHDB ASYNC 等非阻塞的删除操作,这些命令会使用主线程外的线程执行。

删除操作如果删除的KV对占用比较小,那么同步也没什么问题。但是如果是几十几百MB的那么会消耗较多时间,不能在几MS内处理完,影响Redis的可用性。UNLINK命令将键从元数据中删除,无法再被访问到,真正的删除操作会在后台异步执行。

Redis持久化机制

RDB 快照持久化

创建快照后获得某个时间点上完整的数据副本,快照可以用来复制到其他Redis从服务器来创建相同数据,或者用来重启服务时候进行恢复数据。

快照持久化是 Redis 默认采用的持久化方式,在 Redis.conf 配置文件中默认有此下配置:

save 900 1           #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 300 10          #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
AOF(append-only file)持久化

AOF模式实时性更强,默认没有开启,需要配置appendonly yes来开启。每执行一条修改数据的命令都会将命令写入硬盘的AOF文件。

appendfsync always    #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec  #每秒钟同步一次,显示地将多个写命令同步到硬盘 推荐
appendfsync no        #让操作系统决定何时进行同步

AOF重写:
执行BGREWRITEAOF会创建一个子进程进行AOF重写,但是其实不会读取当前的AOF文件,是通过读取现在数据库中KV数据生成新的AOF文件。新的AOF文件体积更加小。

Redis事务

Redis 过期机制

Redis集群模式

Redis pipeline、script、mass insertion

Redis配置修改

config set 可以不重启redis,实时生效配置

CONFIG SET protected-mode no

缓存相关

https://mp.weixin.qq.com/s/TBCEwLVAXdsTszRVpXhVug

https://segmentfault.com/a/1190000008931971

缓存穿透

指查询不存在的数据,缓存层没有命中,导致每次都查询数据库层,使得缓存层失去了保护存储层的意义,产生原因可能如下:

  1. 业务自身代码或者数据出现问题

  2. 一些恶意攻击、爬虫等造成大量空命中

可以进行分析统计方法调用次数,缓存命中次数,储存层命中次数,判断是否出现了缓存穿透的情况。

解决方案1. 缓存空对象

在存储层也返回空时,把空对象也保存到缓存,这样下次查询就会命中缓存。

问题:占用更多存储空间,而且如果是恶意攻击则会更加严重。

解决:

  1. 添加一个较小的TTL ,使其自动过期删除

2. 空对象缓存放到另外单独的一个缓存服务,避免空间不够回收时LRU算法剔除了正常的KV而没有过期空对象

问题: 数据不一致,如果缓存了空对象,然后业务操作导致存储层有把数据添加上了,那么在空对象缓存过期之前两边数据产生了不一致。

解决:

1. 如果是redis缓存,则更新数据后直接删除缓存

  1. 如果是本地缓存,则需要引入消息中间件之类通知机制,通知删除
解决方案2. 布隆过滤器

在访问缓存层之前,先访问布隆过滤器,如果miss,那就是不存在直接返回空对象。如果命中再继续查询缓存和存储层。

boomfilter命中可能误判,但是不命中必定是真的不命中。

缺点:需要额外维护boomfilter,删除数据时候需要重建,添加数据时候需要通知插入。如果是本地缓存构建的boomfilter那也还需要引入消息通知机制。如果是使用redis bitmap实现的那还简单点。

缓存雪崩

缓存正常起着承担大量请求,保护存储层的作用,但是由于某些情况导致缓存层无法提供服务,那么所有请求到达了存储层,导致存储层挂掉宕机。

产生的原因:

  1. 缓存层服务可用性不高,重启,或者网络等各种故障导致一段时间内无法提供服务
  2. 热点key,大量缓存同时失效过期

解决:

  1. 针对可用性问题可以构建集群+主备来提高可用性
  2. 大量缓存同时失效问题可以在存储层读写时候进行队列,加锁,信号量等控制并发数量。(hystrix对访问进行熔断限流)
  3. 大量缓存同时失效问题也可以对key设置分散的过期时间
  4. 针对热点key过期,可以设置永不过期,然后异步单独的线程来更新重建热点key数据
  5. 针对热点key过期,也可以在过期重建数据时候加锁,只允许一个线程进行重建,其他线程进行等待重建完成。分布式环境下可以用redis setnx锁。

你可能感兴趣的:(Redis-缓存相关QA)