一.简介:

Redis是一种键值对格式缓存非关系型数据库了(NoSql)

二.特点:

1.读写效率高,10WQPS
2.单线程单进程,线程安全
3.可以作为消息中间件,支持发布订阅消息
4.数据可持久化到本地
5.可作为分布式锁
6.支持五种数据类型(list,string,set,SortSet,Hash)

三.缓存对象的创建(Spring Boot)

1.通过Redistemplate使用
2.通过Spring Cache集成Redis

四.遇到的一些问题

1.数据一致性

分布式环境下,很容易出现数据的一致性问题,如果项目对于数据的要求需要强一致性,则不建议使用redis缓存,因为一致性只能通过策略来降低概率,无法保障强一致性,一般的策略包含缓存更新机制,数据库更新后及时更新缓存,并增加失败重试机制

2.缓存击穿,穿透,雪崩

雪崩:大量key过期失效(缓存服务器宕机),这时有大量的请求进来,直接访问数据库,造成数据库挂掉

(假设A系统需要每秒处理5000个请求,但是数据库每秒只能处理4000个请求,这个时候缓存服务器宕机了,挂了,这个时候请求就全部落到数据库上,数据库肯定承受不住,也挂掉,这个时候如果没有采取缓存措施,数据库又急着用,刚重启(有可能没重启完成),请求又来了,数据库又挂了,这就是redis最致命的雪崩事件)

redis 三个问题 redis解决的问题_服务器


解决方案:

  • 事故前:保证redis高可用,搭建redis集群,部署主从+哨兵,避免全盘崩溃
  • 事故中:降低数据库压力,使用Ehcache本地缓存+限流组件避免超过数据库的承受能力
  • 事故后:做redis持久化,一旦redis重启,可从磁盘中恢复数据

改造后流程:用户发送一个请求,系统先请求Ehcache本地缓存是否有数据,没有再去Redis请求数据,如果还没有就去数据库请求数据,获取到数据后先同步到Redis,再同步到Ehcache

redis 三个问题 redis解决的问题_redis_02


优点:

  • 数据库安全:在限流组件可用的情况下,数据库不会挂掉,限流根据确保了每秒多少请求能通过
  • 部分请求可以被处理:数据库没挂,就意味着至少2/5的请求可以被处理掉

缺点:

  • 高峰时期部分请求无法处理到,需要用户多次点击,因为只有2/5的请求被处理,剩下的请求,用户刷不出来界面,需要多点击几次
  • redis设置的缓存失效时间不是设置成同一个时间,可根据功能、业务、请求接口灵活设置缓存时间:setRedis(key, value, time+Math.random()*10000)

穿透:大量的请求不存在的key

(缓存中都没有对应的数据,但是用户不断发送请求,请求就会直接走数据库,这样的场景会直接是数据库挂掉,一般都是黑客攻击,恶意行为)

redis 三个问题 redis解决的问题_数据库_03


解决方案:

  • 设置白名单,在接口的请求层设置参数校验,比如说用户鉴权,参数校验,不符合要求的直接return
  • 对空值进行缓存, 对有效的id做认证或者拦截,不符合的id直接过滤掉或者保存到redis,下次不合法的id请求时,直接从缓存中获取数据
  • 使用redis中的高级接口Bloom Filter(布隆过滤器),通过算法可以判断出,请求的key在数据库中是否存在,不存在直接return,存在的话就查询数据库然后刷新同步redis的key再return

击穿:redis中一个热点key过期
(针对一个热点key导致redis异常,当这个key失效或者过期,大量的请求机会击穿缓存直接访问数据库)
解决方案:

  • 数据基本不变:设置某些热点key的过期时间,如果更新不频繁可以设置不过期
  • 数据更新不频繁:缓存的刷新流程较少时,利用redis,zookeeper分布式锁或本地互斥锁来保证少量请求能访问到数据库,并将请求到的数据同时更新到缓存,其他请求等锁释放后才能访问新缓存
  • 数据更新频繁:采用定时线程,在缓存过期前主动更新缓存或者延长过期时间,保证数据能被一直访问

五.Redis的淘汰策略

  1. volatile为前缀的策略都是已设置过期时间的数据集中进行淘汰
  2. allkeys为前缀的策略是面向所有key进行淘汰
  3. LRU:最近少用到的
  4. LFU:最不常用的
  • 他们的触发条件都是Redis内存达到阈值时

redis 三个问题 redis解决的问题_数据库_04

Redis的持久化

  • RDB:快照的形式,定时的将内存中的数据写入的dump文件中保存到硬盘上
    优点:因为是快照的形式,所以效率高且保存了某个时间点上的数据集,适合备份和大规模数据的恢复
    缺点:
    1.很难做到秒级持久化,因为bgsave每次执行都要重新执行fork调用一次子线程,频繁执行成本过高
    2.一段时间做一次快照,如果redis服务器宕机可能会丢失数据,安全性有所缺失
  • AOF:每次执行命令后将命令本身记录下来,每次执行命令都会将命令写入到aof文件中
    优点:可以做到秒级持久化
    缺点:AOF文件体积比RDB文件体积大,高并发情况下,RDB的性高还是要高于AOF

AOF拓展

Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写:重写后的新 AOF 文件包含了重写这一时刻之前数据集所需的最小命令集合

重写的流程是这样:
• 主进程会fork一个子进程出来进行AOF重写,并不是对原文件进行重新整理,而是直接读取redis服务内存中现有的键值对,然后用一条命令去代替每个键值对,写入到新的AOF文件中
• 在fork子进程这个过程中,服务端仍然可以对外提供服务,在子进程重写的这个时间段里面,主进程的数据更新操作,会缓存到aof_rewrite_buf中,也就是单独开辟一块缓存来存储重写期间收到的命令,当子进程重写完以后再把缓存中的数据追加到新的aof文件
• 当所有的数据全部追加到新的aof文件中后,会把旧的aof文件替换成新的aof文件,此后所有的操作都会被写入新的aof文件
• 如果在rewrite过程中出现故障,不会影响原来aof文件的正常工作,只有当rewrite完成后才会切换文件。因此这个rewrite过程是比较可靠的

Redis的主从复制

主从复制就是将一台Redis服务器上的数据同步到另外几台服务器,前者为master主节点,后者为slave从节点,由于数据的复制是单向的,所以只能从master向slave复制,master以写为主,slave以读为主

建立连接

  1. 从节点执行 slaveof[masterIP][masterPort],保存主节点信息
  2. 与主节点建立socket连接,从节点发出Ping,主节点响应pong,两者建立通信
  3. Slave 启动成功连接到 master 后会发送一个sync同步命令
    Master 接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。

全量复制: slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制: Master 继续将新的所有收集到的修改命令依次传给slave,完成同步,但是只要是重新连接master,一次完全同步(全量复制)将被自动执行! 主机的数据一定可以在从机中看到。

作用

  • 数据冗余:主从复制实现了数据的热备份
  • 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复
  • 负载均衡:主从复制的基础上配合读写分离,主节点负责写,从节点负责读(即写Redis数据的时候连接主节点,读Redis数据的时候连接从节点),分担服务器负载,使redis的并发量提高(特别是在读到写少的情况下,从多个节点分担读负载)
  • 读写分离:可以用于实现读写分离,主库写、从库读,读写分离不仅可以提高服务器的负载能力,同时可根据需求的变化,改变从库的数量;
  • 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础
Redis的哨兵模式

我们先说说主从复制会存在问题

  1. 一旦主节点宕机,从节点晋升为主节点,同时需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预。
  2. 主节点的写能力和存储能力受到单机的限制。
  3. 原生复制的弊端在早期的版本中也会比较突出,比如:Redis 复制中断后,从节点会发起 psync。
    此时如果同步不成功,则会进行全量同步,主库执行全量备份的同时,可能会造成毫秒或秒级的卡顿。
  4. redis 三个问题 redis解决的问题_redis 三个问题_05

  5. 该系统可以执行以下四个任务:
  • 监控:不断检查主服务器和从服务器是否正常运行。
  • 通知:当被监控的某个 Redis 服务器出现问题,Sentinel 通过 API 脚本向管理员或者其他应用程序发出通知。
  • 自动故障转移:当主节点不能正常工作时,Sentinel 会开始一次自动的故障转移操作,它会将与失效主节点是主从关系的其中一个从节点升级为新的主节点,并且将其他的从节点指向新的主节点,这样人工干预就可以免了。
  • 配置提供者:在 Redis Sentinel 模式下,客户端应用在初始化时连接的是 Sentinel 节点集合,从中获取主节点的信息。

哨兵原理是什么?

  • Sentinel 使用的算法核心是 Raft算法,主要用途就是用于分布式系统,系统容错,以及Leader选举,每个Sentinel都需要定期的执行以下任务:
  • 每个 Sentinel会自动发现其他 Sentinel 和从服务器,它以每秒钟一次的频率向它所知的主服务器、从服务器以及其他Sentinel实例发送一个 PING 命令。
  • 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds选项所指定的值, 那么这个实例会被Sentinel标记为主观下线。 有效回复可以是: +PONG 、 -LOADING 或者 -MASTERDOWN 。
  • 如果一个主服务器被标记为主观下线, 那么正在监视这个主服务器的所有Sentinel要以每秒一次的频率确认主服务器的确进入了主观下线状态。
  • 如果一个主服务器被标记为主观下线, 并且有足够数量的Sentinel(至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断,
    那么这个主服务器被标记为客观下线。
  • 在一般情况下, 每个Sentinel会以每 10 秒一次的频率向它已知的所有主服务器和从服务器发送 INFO 命令。当一个主服务器Sentinel标记为客观下线时,Sentinel向下线主服务器的所有从服务器发送 INFO 命令的频率会从 10秒一次改为每秒一次。
  • 当没有足够数量的Sentinel同意主服务器已经下线, 主服务器的客观下线状态就会被移除。 当主服务器重新向Sentinel的 PING命令返回有效回复时, 主服务器的主管下线状态就会被移除。