Redis学习笔记
一、NoSQL数据库简介
二、redis6概述和安装
与memcache的不同点
- memcache支持单一数据类型 redis支持多种数据类型
- memcache不支持持久化 redis支持持久化
- memcache采取多线程+锁的机制 redis采用单线程+io多路复用
三、常用五大数据类型
1. Redis 字符串
String是Redis最基本的类型 是二进制安全的 value最多512M
incrby decrby 命令具有原子性,不会被线程调度机制打断。(将val增加或减少某值)
- 数据结构:String的数据结构为简单动态字符串。是可以修改的字符串,内部结构实现上类似于Java中的ArrayList,采用与分配冗余空间的方式来减少内存的频繁分配 如果字符串小于1M时,扩容都是加倍现有的空间,超过1M,每次只扩容1M的空间。最大的长度不允许超过512M
2. Redis 列表
Redis列表时简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部或者尾部
它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差
lpush/rpush lpop/rpop
- 数据结构:quickList 首先在列表元素较少的情况下使用一块连续的内存存储,这个结构时ziplist,也就是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存;当数据链比较多的时候次才会改成quickList。因为普通的链表需要的附加指针空间太大,会比较浪费空间。结构上还需要两个额外的指针prev和next
- redis将链表和ziplist结合起来组成了quickList。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余
3. Redis 集合
Redis set是string类型的无序集合。它底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)
sadd/smembers/sismember/scard(长度)/srem(删除)/spop(随机取)/srandmember(随机取,不会删除)/smove/sinter(交集)/sunion(并集)/sdiff(差集)
4. Redis 哈希
Redis hash是一个String类型的field和value的映射表,hash特别适合用户存储对象。类似Map<String, Object>
hset/hget/hmset/hmget/hexists/hkeys/hvals/
- 数据结构:hash类型对应的数据结构时两种,ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable
5. Redis 有序集合
Redis 有序集合zset与普通集合set,是一个没有重复元素的字符串集合。每个成员都关联了一个评分,集合的成员是唯一的,得分可以重复。
zadd()/zrange(
- 数据结构:
- hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value的唯一性,可以通过元素value找到相应的score值
- 跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表
四、Redis配置文件详解
- units —> 单位,只支持bytes,大小写不敏感
- include
- network
- bind:接受某个IP访问
- Protected-mode 是否支持远程访问
- Port 端口号
- Tcp-backlog 正在进行三次握手包括已经完成的队列总和
- Timeout 多长时间超时(0为永不超时)
- Tcp-keepalive (每隔300s检测连接是否活着)
- daemonize 是否支持后台启动
- pidfile 保存进程号的文件路径
- loglevel (日志级别)
- debug
- verbose
- notice
- warning
- Logfile 日志文件在哪
- databases 几号库
五、发布和订阅
Redis 发布订阅是一种消息通信模式:发送者发送消息,订阅者接受消息
Redis客户端可以订阅任意数量的频道
六、Redis新数据类型
1. Bitmaps(类似 编程之美中用二进制数来存储象棋状态)
- Bitmaps 本身不是一种数据类型,实际上它就是字符串,但是它可以对字符串的位进行操作
- Bitmaps 单独提供了一套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太相同,可以把Bitmaps想象成一个以位为单位的数组,数组的每个单元只能存储0和1,数组的下标在Bitmaps中叫做偏移量
2. HyperLogLog(占用内存小,类似set去重)
- 是用来做基数统计的算法,优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的
3. Geospatial
- 地理信息
七、Jedis操作Redis
自己看文档去!!!
八、Redis与Spring Boot整合
同上!!!
九、Redis的事务操作
1. Redis的事务定义
Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程汇总,不会被其他客户端发送来的命令请求所打断。
Redis事务的主要作用就是串联多个命令防止别的命令插队
2. Multi、Exec、discard
从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis才会将之前的命令队列中的命令依次执行。
组队的过程中可以通过discard来放弃组队。
3. 事务的错误处理
- 如果在命令队列中有一个语法错误,那么这个队列将被全部放弃(编译时错误)
- 单独隔离,若语句语法正确但是执行错误,例如让字符串+1,该语句报错(运行时错误)
4. 事务冲突的问题
- 例子:类似超卖现象
- 悲观锁:阻塞
- 乐观锁:增加版本号 类似java(CAS)
- Watch key (类似CAS,监视这个key有没有被操作,被操作则执行失败)
- unwatch (不监视了)
十、Redis持久化之RDB
1. 是什么?
- 在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里
2. 备份是如何执行的?
- Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能,如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
3. Fork
- Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据数值和原进程一致,但是是一个全新的进程,并作为原进程的子进程
- 在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后都会exec系统调用,处于效率考虑,Linux中引入了“写时复制技术”
- 一般情况父进程和子进程会共用同一个段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。
4. dump.rdb文件
- 在redis.conf中配置文件名称,默认为dump.rdb
5. 如何触发RDB快照;保持策略
-
rdbchecksum会增加10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能
-
rdb的备份
-
优点:
- 适合大规模的数据恢复
- 对数据完整性和一致性要求不高更适合使用
- 节省磁盘空间
- 恢复速度快
-
缺点:
- fork的时候需要内存两倍的空间
- 虽然使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能
- 在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改
十一、Redis持久化之AOF
1. 是什么?
- 以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来,只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
2. AOF持久化流程
- 客户端的请求命令会被append追加到AOF缓冲区内
- AOF缓冲区根据AOF持久化策略将操作sync同步到磁盘的AOF文件中
- AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量
- Redis服务重启后,会重新load加载AOF文件中的写操作达到数据恢复的目的;
3. 重写原理
- AOF文件持续增长而过大时,会fork出一条新进程来将文件重写,redis4.0版本后的重写,实际上就是把rdb的快照,以二进制的形式附在新的aof文件头部,作为已有的历史数据,替换掉原来的流水账操作。
4. 优劣势
- 优势:
- 备份机制更文件,丢失数据概率更低
- 可读的日志文本,通过操作AOF文件,可以处理误操作
- 劣势:
- 比起RDB占用更多的磁盘空间
- 恢复备份速度要慢
- 每次读写都同步的话,有一定的性能压力
- 存在个别bug,造成不能恢复
5. 总结
- 用哪个
- 官方推荐两个都启用,如果对数据不敏感,可以选RDB,不建议单独用AOF,因为可能会出现bug。如果知识做纯内存缓存,可以都不用
- 官网建议
- RDB持久化方式能够在指定的时间间隔内对你的数据进行快照存储
- AOF持久化方式记录每次对服务器写的操作,当服务秋重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾
- Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大
- 只做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式
- 同时开启两种持久化方式
- 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常的情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整
- RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?
- 建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的bug,留着座位一个万一的手段
- 性能建议
- 因为RDB文件只用作后背用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则
- 如果使用AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单,只load自己的AOF文件就可以了
- 代价,一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的
- 只要硬盘许可,应该尽量减少AOFrewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上
- 默认超过原大小100%大小时重写可以改到适当的数值。十二、Redis主从复制
十二、Redis主从复制和集群
自己看文档!!!
十三、Redis应用问题解决
1. 缓存穿透
- key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会压到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。
- 解决方案:
- 对空值缓存:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果进行缓存,设置空结果的过期时间会很短,最长不超过五分钟
- 设置可访问的名单:使用bitmaps类型定义一个可以访问的名单,名单id座位bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。
- 采用布隆过滤器,布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定个不存在的数据会被这个bitmaps拦截掉,从而避免了对底层存储系统的查询压力。
- 进行实时监控:当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务。
2. 缓存击穿
- key对应的数据存在,但在redis中国企,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮
- 解决方案:
- 预先设置热门数据:在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长
- 实时调整:现场监控哪些数据热门,实时调整key的过期时长
- 使用锁:
- 就是在缓存失效的时候,不是立即去load db
- 先使用缓存工具的某些带成功操作返回值的操作
3. 缓存雪崩
- key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。缓存雪崩与缓存击穿的区别在于这里针对很多key缓存,前者则是某一个key。
- 解决方案:
- 构建多级缓存架构:nginx缓存 + redis缓存 + 其他缓存(ehcache等)
- 使用锁或队列:
- 用加锁或者队列的方式来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况。
- 设置过期标志更新缓存:
- 记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际key的缓存
- 将缓存失效时间分散开
- 比如我们可以在原有的实效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的国企时间的重复率就会降低,就很难引发集体失效的事件。
4. 分布式锁
- 实现方式
- 基于数据库实现分布式锁
- 基于缓存(Redis等)
- 基于Zookeeper
- 对比
- 性能:redis最高
- 可靠性:zookeeper最高
十四、Redis6.0新功能
- ACL:对用户进行更细粒度的权限控制
- 接入权限:用户名和密码
- 可以执行的命令
- 可以操作的KEY
- IO多线程:其实是指客户端交互部分的网络IO交互处理模块多线程,而非执行命令多线程。Redis6执行命令依然是单线程
- 原理架构:Redis6加入多线程,但跟Memcached这种从IO处理到数据访问多线程的实现模式有些差异。Redis的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程。之所以这么设计是不想因为多线程而变得复杂,需要去控制key、lua、事务,LPUSH/LPOP等等的并发问题。# Redis学习笔记
一、NoSQL数据库简介
二、redis6概述和安装
与memcache的不同点
- memcache支持单一数据类型 redis支持多种数据类型
- memcache不支持持久化 redis支持持久化
- memcache采取多线程+锁的机制 redis采用单线程+io多路复用
三、常用五大数据类型
1. Redis 字符串
String是Redis最基本的类型 是二进制安全的 value最多512M
incrby decrby 命令具有原子性,不会被线程调度机制打断。(将val增加或减少某值)
- 数据结构:String的数据结构为简单动态字符串。是可以修改的字符串,内部结构实现上类似于Java中的ArrayList,采用与分配冗余空间的方式来减少内存的频繁分配 如果字符串小于1M时,扩容都是加倍现有的空间,超过1M,每次只扩容1M的空间。最大的长度不允许超过512M
2. Redis 列表
Redis列表时简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部或者尾部
它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差
lpush/rpush lpop/rpop
- 数据结构:quickList 首先在列表元素较少的情况下使用一块连续的内存存储,这个结构时ziplist,也就是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存;当数据链比较多的时候次才会改成quickList。因为普通的链表需要的附加指针空间太大,会比较浪费空间。结构上还需要两个额外的指针prev和next
- redis将链表和ziplist结合起来组成了quickList。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余
3. Redis 集合
Redis set是string类型的无序集合。它底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)
sadd/smembers/sismember/scard(长度)/srem(删除)/spop(随机取)/srandmember(随机取,不会删除)/smove/sinter(交集)/sunion(并集)/sdiff(差集)
4. Redis 哈希
Redis hash是一个String类型的field和value的映射表,hash特别适合用户存储对象。类似Map<String, Object>
hset/hget/hmset/hmget/hexists/hkeys/hvals/
- 数据结构:hash类型对应的数据结构时两种,ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable
5. Redis 有序集合
Redis 有序集合zset与普通集合set,是一个没有重复元素的字符串集合。每个成员都关联了一个评分,集合的成员是唯一的,得分可以重复。
zadd()/zrange(
- 数据结构:
- hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value的唯一性,可以通过元素value找到相应的score值
- 跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表
四、Redis配置文件详解
- units —> 单位,只支持bytes,大小写不敏感
- include
- network
- bind:接受某个IP访问
- Protected-mode 是否支持远程访问
- Port 端口号
- Tcp-backlog 正在进行三次握手包括已经完成的队列总和
- Timeout 多长时间超时(0为永不超时)
- Tcp-keepalive (每隔300s检测连接是否活着)
- daemonize 是否支持后台启动
- pidfile 保存进程号的文件路径
- loglevel (日志级别)
- debug
- verbose
- notice
- warning
- Logfile 日志文件在哪
- databases 几号库
五、发布和订阅
Redis 发布订阅是一种消息通信模式:发送者发送消息,订阅者接受消息
Redis客户端可以订阅任意数量的频道
六、Redis新数据类型
1. Bitmaps(类似 编程之美中用二进制数来存储象棋状态)
- Bitmaps 本身不是一种数据类型,实际上它就是字符串,但是它可以对字符串的位进行操作
- Bitmaps 单独提供了一套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太相同,可以把Bitmaps想象成一个以位为单位的数组,数组的每个单元只能存储0和1,数组的下标在Bitmaps中叫做偏移量
2. HyperLogLog(占用内存小,类似set去重)
- 是用来做基数统计的算法,优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的
3. Geospatial
- 地理信息
七、Jedis操作Redis
自己看文档去!!!
八、Redis与Spring Boot整合
同上!!!
九、Redis的事务操作
1. Redis的事务定义
Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程汇总,不会被其他客户端发送来的命令请求所打断。
Redis事务的主要作用就是串联多个命令防止别的命令插队
2. Multi、Exec、discard
从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis才会将之前的命令队列中的命令依次执行。
组队的过程中可以通过discard来放弃组队。
3. 事务的错误处理
- 如果在命令队列中有一个语法错误,那么这个队列将被全部放弃(编译时错误)
- 单独隔离,若语句语法正确但是执行错误,例如让字符串+1,该语句报错(运行时错误)
4. 事务冲突的问题
- 例子:类似超卖现象
- 悲观锁:阻塞
- 乐观锁:增加版本号 类似java(CAS)
- Watch key (类似CAS,监视这个key有没有被操作,被操作则执行失败)
- unwatch (不监视了)
十、Redis持久化之RDB
1. 是什么?
- 在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里
2. 备份是如何执行的?
- Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能,如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
3. Fork
- Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据数值和原进程一致,但是是一个全新的进程,并作为原进程的子进程
- 在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后都会exec系统调用,处于效率考虑,Linux中引入了“写时复制技术”
- 一般情况父进程和子进程会共用同一个段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。
4. dump.rdb文件
- 在redis.conf中配置文件名称,默认为dump.rdb
5. 如何触发RDB快照;保持策略
-
rdbchecksum会增加10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能
-
rdb的备份
-
优点:
- 适合大规模的数据恢复
- 对数据完整性和一致性要求不高更适合使用
- 节省磁盘空间
- 恢复速度快
-
缺点:
- fork的时候需要内存两倍的空间
- 虽然使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能
- 在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改
十一、Redis持久化之AOF
1. 是什么?
- 以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来,只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
2. AOF持久化流程
- 客户端的请求命令会被append追加到AOF缓冲区内
- AOF缓冲区根据AOF持久化策略将操作sync同步到磁盘的AOF文件中
- AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量
- Redis服务重启后,会重新load加载AOF文件中的写操作达到数据恢复的目的;
3. 重写原理
- AOF文件持续增长而过大时,会fork出一条新进程来将文件重写,redis4.0版本后的重写,实际上就是把rdb的快照,以二进制的形式附在新的aof文件头部,作为已有的历史数据,替换掉原来的流水账操作。
4. 优劣势
- 优势:
- 备份机制更文件,丢失数据概率更低
- 可读的日志文本,通过操作AOF文件,可以处理误操作
- 劣势:
- 比起RDB占用更多的磁盘空间
- 恢复备份速度要慢
- 每次读写都同步的话,有一定的性能压力
- 存在个别bug,造成不能恢复
5. 总结
- 用哪个
- 官方推荐两个都启用,如果对数据不敏感,可以选RDB,不建议单独用AOF,因为可能会出现bug。如果知识做纯内存缓存,可以都不用
- 官网建议
- RDB持久化方式能够在指定的时间间隔内对你的数据进行快照存储
- AOF持久化方式记录每次对服务器写的操作,当服务秋重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾
- Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大
- 只做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式
- 同时开启两种持久化方式
- 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常的情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整
- RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?
- 建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的bug,留着座位一个万一的手段
- 性能建议
- 因为RDB文件只用作后背用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则
- 如果使用AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单,只load自己的AOF文件就可以了
- 代价,一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的
- 只要硬盘许可,应该尽量减少AOFrewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上
- 默认超过原大小100%大小时重写可以改到适当的数值。十二、Redis主从复制
十二、Redis主从复制和集群
自己看文档!!!
十三、Redis应用问题解决
1. 缓存穿透
- key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会压到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。
- 解决方案:
- 对空值缓存:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果进行缓存,设置空结果的过期时间会很短,最长不超过五分钟
- 设置可访问的名单:使用bitmaps类型定义一个可以访问的名单,名单id座位bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。
- 采用布隆过滤器,布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定个不存在的数据会被这个bitmaps拦截掉,从而避免了对底层存储系统的查询压力。
- 进行实时监控:当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务。
2. 缓存击穿
- key对应的数据存在,但在redis中国企,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮
- 解决方案:
- 预先设置热门数据:在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长
- 实时调整:现场监控哪些数据热门,实时调整key的过期时长
- 使用锁:
- 就是在缓存失效的时候,不是立即去load db
- 先使用缓存工具的某些带成功操作返回值的操作
3. 缓存雪崩
- key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。缓存雪崩与缓存击穿的区别在于这里针对很多key缓存,前者则是某一个key。
- 解决方案:
- 构建多级缓存架构:nginx缓存 + redis缓存 + 其他缓存(ehcache等)
- 使用锁或队列:
- 用加锁或者队列的方式来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况。
- 设置过期标志更新缓存:
- 记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际key的缓存
- 将缓存失效时间分散开
- 比如我们可以在原有的实效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的国企时间的重复率就会降低,就很难引发集体失效的事件。
4. 分布式锁
- 实现方式
- 基于数据库实现分布式锁
- 基于缓存(Redis等)
- 基于Zookeeper
- 对比
- 性能:redis最高
- 可靠性:zookeeper最高
十四、Redis6.0新功能
- ACL:对用户进行更细粒度的权限控制
- 接入权限:用户名和密码
- 可以执行的命令
- 可以操作的KEY
- IO多线程:其实是指客户端交互部分的网络IO交互处理模块多线程,而非执行命令多线程。Redis6执行命令依然是单线程
- 原理架构:Redis6加入多线程,但跟Memcached这种从IO处理到数据访问多线程的实现模式有些差异。Redis的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程。之所以这么设计是不想因为多线程而变得复杂,需要去控制key、lua、事务,LPUSH/LPOP等等的并发问题。