redis
2020-09-10 14:44:47 1 举报
AI智能生成
redis 大汇总
作者其他创作
大纲/内容
redis 数据结构
字符串 (Simple Dynamic Strings)
页面数据缓存
数字计算与统计
共享 Session 信息
使用方法
单个键值对操作
set k1 val1
多个键值对操作
mset k2 v2 k3 v3
数字统计
incr k1 2,decr k1 2,incrbyfloat k3 4.9
源码分析
int、embstr 和 raw
哈希类型
基本操作
插入单个元素
hset key field value
当某键不存在时,插入数据
hsetnx key field value
查询单个元素
hget key field
删除 key 中的一个或多个元素
hdel myhash field
某个整数值累加计算
hincrby key field increment
rehash 和哈希冲突
rehash
在进行渐进式 rehash 时,会同时保留两个 hash 结构,新键值对加入时会直接插入到新的 hash 结构中,并会把旧 hash 结构中的元素一点一点的移动到新的 hash 结构中,当移除完最后一个元素时,清空旧 hash 结构,主要的执行流程如下:
扩容或者缩容时把字典中的字段 rehashidx 标识为 0;
在执行定时任务或者执行客户端的 hset、hdel 等操作指令时,判断是否需要触发 rehash 操作(通过 rehashidx 标识判断),如果需要触发 rehash 操作,也就是调用 dictRehash 函数,dictRehash 函数会把 ht[0] 中的元素依次添加到新的 Hash 表 ht[1] 中;
rehash 操作完成之后,清空 Hash 表 ht[0],然后对调 ht[1] 和 ht[0] 的值,把新的数据表 ht[1] 更改为 ht[0],然后把字典中的 rehashidx 标识为 -1,表示不需要执行 rehash 操作。
扩容或者缩容时把字典中的字段 rehashidx 标识为 0;
在执行定时任务或者执行客户端的 hset、hdel 等操作指令时,判断是否需要触发 rehash 操作(通过 rehashidx 标识判断),如果需要触发 rehash 操作,也就是调用 dictRehash 函数,dictRehash 函数会把 ht[0] 中的元素依次添加到新的 Hash 表 ht[1] 中;
rehash 操作完成之后,清空 Hash 表 ht[0],然后对调 ht[1] 和 ht[0] 的值,把新的数据表 ht[1] 更改为 ht[0],然后把字典中的 rehashidx 标识为 -1,表示不需要执行 rehash 操作。
哈希冲突
通过算法 (Hash,计算和取余等) 操作获得数组的索引值,根据索引值找到对应的元素;
判断元素和查找的键值是否相等,相等则成功返回数据,否则需要查看 next 指针是否还有对应其他元素,如果没有,则返回 null,如果有的话,重复此步骤。
判断元素和查找的键值是否相等,相等则成功返回数据,否则需要查看 next 指针是否还有对应其他元素,如果没有,则返回 null,如果有的话,重复此步骤。
使用场景
1:商品购物车,购物车非常适合用哈希字典表示,使用人员唯一编号作为字典的 key,value 值可以存储商品的 id 和数量等信息;
2:存储用户的属性信息,使用人员唯一编号作为字典的 key,value 值为属性字段和对应的值;
3:存储文章详情页信息等。
2:存储用户的属性信息,使用人员唯一编号作为字典的 key,value 值为属性字段和对应的值;
3:存储文章详情页信息等。
列表(List)
简介
列表类型 (List) 是一个使用链表结构存储的有序结构,它的元素插入会按照先后顺序存储到链表结构中,因此它的元素操作 (插入\删除) 时间复杂度为 O(1),所以相对来说速度还是比较快的,但它的查询时间复杂度为 O(n),因此查询可能会比较慢
基础操作
给列表添加一个或多个元素
lpush key value
给列表尾部添加一个或多个元素
rpush key value
返回列表指定区间内的元素
lrang key statr stop
获取并删除列表的第一个元素
lpop key
获取并删除列表最好一个元素
rpop key
根据下标获取对应元素
lindex key index
在某值之前/之后添加某个元素
linsert key before|after pivot value
根据下标修改元素
lset key index value
根据下标删除元素
ltrim key start stop
查询列表的长度
llen key
删除指定个数的元素
lrem key count value
数据结构
quicklist(快速列表)
ziplist(压缩列表)
使用场景
消息队列
列表类型可以使用 rpush 实现先进先出的功能,同时使用 lpop(查询并删除)弹出
文章列表
博客站点,当用户文章读越来越多的时候,加快响应速度,可以把用户自己的文章存入到List中,因为List有序结构,可以实现分页功能
集合(Set)
简介
是一个无序并唯一的键值集合
基础使用
添加一个或多个元素
sadd key member
查询集合所有元素
smembers key
查询集合所有的元素
scard key
查询集合中是否包含某个元素
sismember key member
从一个集合移动一个元素到另一个集合
smove source destination member
移除集合中一个或多个元素
srem key member
移除并返回集合中的一个随机元素
spop key [count]
随机返回集合中指定数量的元素列表
srandmember mset 2
返回一个集合或多个集合的交集
sinter key eg:sinter myset myset2
把集合的交集复制到新的集合中
sinterstore destination key eg:sinterstore myset3 myset myset2
查询一个或对个集合的并集
sunion key [key …] eg: sunion group1 group2
把一个或多个集合的并集复制到新集合中
sunionstore group3 group1 group2
查询一个或多个集合的错集
sdiff group1 group2
把一个或多个集合的错集复制到新集合
sdiffstore group3 group1 group2
数据结构
intset 或 哈希表
1: 当所有元素为整数的时候,集合以intset 结构存储
2:hash 表的key 存储要插入的值,value 为null
2:hash 表的key 存储要插入的值,value 为null
使用场景
微博关注我的人和我关注的人 都适合用集合存储,可以保证人员不重复
中奖信息也适合用结合类型存储,这样可以保证一个人不会重复中奖
有序集合(Sort Set)
简介
有序集合类型 (Sorted Set) 相比于集合类型多了一个排序属性 score(分值),对于有序集合 ZSet 来说,每个存储元素相当于有两个值组成的,一个是有序结合的元素值,一个是排序值。有序集合的存储元素值也是不能重复的,但分值是可以重复的
基本操作
添加一个或多个元素
zadd key eg: zadd zset1 10 java、zadd zset1 3 golang 4 sql 1 redis
查询所有列表元素
zrang key start stop zrang zet 0 -1
删除一个或多个元素(根据元素值)
zrem key membe
查询某元素的 score 值
zscore key member
查询 score 区间内元素
zrangebyscore zset1 3 10
查询某元素排名
zrank key member
数据结构
ziplist \ skipList
zipList
1: 有序集合保存的元素个数要小于 128 个;
2:有序集合保存的所有元素成员的长度都必须小于 64 字节。
2:有序集合保存的所有元素成员的长度都必须小于 64 字节。
skiplist
使用场景
学生成绩排名
粉丝列表,根据关注的先后时间排序
redis 事务
事务指的是提供一种将多个命令打包,一次性按顺序地执行的机制,并且保证服务器只有在执行完事务中的所有命令后,才会继续处理此客户端的其他命令。
事务的基本使用
开启事务——Begin Transaction
执行业务代码,提交事务——Commit Transaction
业务处理中出现异常,回滚事务——Rollback Transaction
执行业务代码,提交事务——Commit Transaction
业务处理中出现异常,回滚事务——Rollback Transaction
开启事务
multi
可以让客户端从非事务模式状态更新为事务状态
multi 并不能嵌套使用
multi 并不能嵌套使用
命令入列
QUEUED
执行事务/ 放弃事务
执行事务
exec
放弃事务
discard
watch
引入watch 原因
watch 命令用于客户端并发情况下,为事务提供一个乐观锁(CAS,Check And Set),也就是可以用 watch 命令来监控一个或多个变量,如果在事务的过程中,某个监控项被修改了,那么整个事务就会终止执行。
为事务提供乐观锁实现
watch 只有在multi 之前执行,如果在multi中执行会报错
执行流程
1: watch 命令
2: multi 开启事务
3: 命令入列
4:exec 执行事务
5:判断监控的值是否修改
6:如果修改,终止事务;如果没有修改;执行并返回结果
2: multi 开启事务
3: 命令入列
4:exec 执行事务
5:判断监控的值是否修改
6:如果修改,终止事务;如果没有修改;执行并返回结果
unwatch
用于清除所有之前的监控对象
Redis 事务并不支持运行时错误的事务回滚,但在某些入列错误,如 set key 或者是 watch 监控项被修改时,提供整个事务回滚的功能
redis 是如何执行的?
1: 用户输入一条指令
2:客户端先将命令转换成Redis(Redis Serialization Protocol) 协议,然后在通过socket 发送给服务端
a: 保证服务器可以最快速度立即命令,如果没有这个协议,redis 要遍历所有的空格以确认此命令的含义
b: 采用的是I/O 多路复用功能监听socket 链接,一个线程处理多个请求,减少线程之间的开销,同时也避免了I/O 阻塞操作
3: 服务端接收命令
a: 服务端会先去输入缓冲中读取数据,然后判断数据大小是否超过了系统设置的值,如果大于此值,就关闭客户端;
4: 执行前准备
a: 判断是否为退出命令,如果是则直接返回;
b: 非null 判断,检查client 对象存储是否为nul,如果是则直接返回;
c: 获取执行命令,根据 client 对象存储的属性信息去 redisCommand 结构中查询执行命令;
d:用户权限效验,未通过身份验证的客户端只能执行 AUTH(授权) 命令,未通过身份验证的客户端执行了 AUTH 之外的命令则返回错误信息;
e: 如果是集群相关操作,如果是集群模式,把命令重定向到目标节点,如果是master 主节点 则不需要重新定向
f: 检查服务器端最大内存限制,如果服务器端超过了最大内存限制, 会先检查内存大小;
g: 持久化检查,如果开启了持久化检查,持久化写入失败也会禁止执行命令
h:集群模式最少节点slave 验证,如果是集群模式并且配置了replminslavetowrite(最小从节点写入) 当从节点的数量少于配置项,禁止执行命令
i: 只读从节点验证,当此服务器为只读节点,只接受master 的写命令;
j: 当客户端正在订阅频道时,只会执行部分命令(只会执行 SUBSCRIBE、PSUBSCRIBE、UNSUBSCRIBE、PUNSUBSCRIBE,其他命令都会被拒绝)
k:从节点状态效验,当服务器为 slave 并且没有连接 master 时,只会执行状态查询相关的命令,如 info 等;
l: 服务器初始化效验,当服务器正在启动时,只会执行 loading 标志的命令,其他的命令都会被拒绝;
m:lua 脚本阻塞效验,当服务器因为执行 lua 脚本阻塞时,只会执行部分命令;
n: 事务命令效验,如果执行的是事务命令,则开启事务把命令放入等待队列;
o:监视器 (monitor) 判断,如果服务器打开了监视器功能,那么服务器也会把执行命令和相关参数发送给监视器 (监视器是用于监控服务器运行状态的)。
5: 执行最终命令,调用redisCommand 中的proc 函数执行命令
6: 执行完后相关记录和统计
a: 检查慢查询是否开启,如果开启会记录慢查询日志;
b: 检查统计信息是否开启,如果开启会记录一些统计信息,例如执行命令所耗费时长和计数器(calls)加1;
c: 检查持久化功能是否开启,如果开启则会记录持久化信息;
d: 如果有其它从服务器正在复制当前服务器,则会将刚刚执行的命令传播给其他从服务器。
7: 返回结果给客户端
2:客户端先将命令转换成Redis(Redis Serialization Protocol) 协议,然后在通过socket 发送给服务端
a: 保证服务器可以最快速度立即命令,如果没有这个协议,redis 要遍历所有的空格以确认此命令的含义
b: 采用的是I/O 多路复用功能监听socket 链接,一个线程处理多个请求,减少线程之间的开销,同时也避免了I/O 阻塞操作
3: 服务端接收命令
a: 服务端会先去输入缓冲中读取数据,然后判断数据大小是否超过了系统设置的值,如果大于此值,就关闭客户端;
4: 执行前准备
a: 判断是否为退出命令,如果是则直接返回;
b: 非null 判断,检查client 对象存储是否为nul,如果是则直接返回;
c: 获取执行命令,根据 client 对象存储的属性信息去 redisCommand 结构中查询执行命令;
d:用户权限效验,未通过身份验证的客户端只能执行 AUTH(授权) 命令,未通过身份验证的客户端执行了 AUTH 之外的命令则返回错误信息;
e: 如果是集群相关操作,如果是集群模式,把命令重定向到目标节点,如果是master 主节点 则不需要重新定向
f: 检查服务器端最大内存限制,如果服务器端超过了最大内存限制, 会先检查内存大小;
g: 持久化检查,如果开启了持久化检查,持久化写入失败也会禁止执行命令
h:集群模式最少节点slave 验证,如果是集群模式并且配置了replminslavetowrite(最小从节点写入) 当从节点的数量少于配置项,禁止执行命令
i: 只读从节点验证,当此服务器为只读节点,只接受master 的写命令;
j: 当客户端正在订阅频道时,只会执行部分命令(只会执行 SUBSCRIBE、PSUBSCRIBE、UNSUBSCRIBE、PUNSUBSCRIBE,其他命令都会被拒绝)
k:从节点状态效验,当服务器为 slave 并且没有连接 master 时,只会执行状态查询相关的命令,如 info 等;
l: 服务器初始化效验,当服务器正在启动时,只会执行 loading 标志的命令,其他的命令都会被拒绝;
m:lua 脚本阻塞效验,当服务器因为执行 lua 脚本阻塞时,只会执行部分命令;
n: 事务命令效验,如果执行的是事务命令,则开启事务把命令放入等待队列;
o:监视器 (monitor) 判断,如果服务器打开了监视器功能,那么服务器也会把执行命令和相关参数发送给监视器 (监视器是用于监控服务器运行状态的)。
5: 执行最终命令,调用redisCommand 中的proc 函数执行命令
6: 执行完后相关记录和统计
a: 检查慢查询是否开启,如果开启会记录慢查询日志;
b: 检查统计信息是否开启,如果开启会记录一些统计信息,例如执行命令所耗费时长和计数器(calls)加1;
c: 检查持久化功能是否开启,如果开启则会记录持久化信息;
d: 如果有其它从服务器正在复制当前服务器,则会将刚刚执行的命令传播给其他从服务器。
7: 返回结果给客户端
redis 持久化
1:RDB(Redis DataBase) 将某一个时刻的内存数据,以二进制的方式写入磁盘
2:AOF (Append Only File) 记录所有的操作命令,并以文本的形式追加到文件中
3: 混合持久化方式,Redis 4.0 之后新增的方式,混合持久是结合RDB 和AOF 的优势,
先把当前数据以RDB的形式写入文件的开头,在将后续命令以AOF 的格式存入文件,
既能保证Redis 重启的速度,又能降低数据丢失的风险
2:AOF (Append Only File) 记录所有的操作命令,并以文本的形式追加到文件中
3: 混合持久化方式,Redis 4.0 之后新增的方式,混合持久是结合RDB 和AOF 的优势,
先把当前数据以RDB的形式写入文件的开头,在将后续命令以AOF 的格式存入文件,
既能保证Redis 重启的速度,又能降低数据丢失的风险
分析触发方式
1: RDB 持久化两种触发方式: a:手动触发 (save bgsave),b自动触发(save m n , flushall,主从同步)
a:save 和 bgsave 两个命令,save 是阻塞的,bgsave 是fork 出一个子线程,来备份数据
b: save m n 自动触发取决于这个命令,redis.conf 中可以配置多个,当满足其中一条,执行持久化
c: flushall 清空redis 数据库,使用之后自动触发持久化,把rdb 文件清空
e: 主从复制,当从节点执行全量复制操作,主节点执行bgsave ,并将rdb 文件传送给子节点
2:AOF 持久化两种触发方式: a:手动触发 bgrewriteaof, b 自动触发(满足 AOF 设置的策略触发和满足 AOF 重写触发)
a: bgrewriteaof 命令可以手动触发
b:自动触发
持久化策略:
always 每条redis 操作命令写入磁盘,最多丢失一条数据;
everysec 每秒钟写入一次磁盘,最多丢失1秒
no 不设置写入磁盘规则,根据当前操作系统决定何时写入磁盘,linux 默认30秒
重写实现:
a: auto-aof-rewrite-min-size : 允许 AOF 重写的最小文件容量,默认是 64mb 。
b: auto-aof-rewrite-percentage:AOF 文件重写的大小比例,默认值是 100,表示 100%,也就是只有当前 AOF 文件,比最后一次(上次)的 AOF 文件大一倍时,才会启动 AOF 文件重写。
a:save 和 bgsave 两个命令,save 是阻塞的,bgsave 是fork 出一个子线程,来备份数据
b: save m n 自动触发取决于这个命令,redis.conf 中可以配置多个,当满足其中一条,执行持久化
c: flushall 清空redis 数据库,使用之后自动触发持久化,把rdb 文件清空
e: 主从复制,当从节点执行全量复制操作,主节点执行bgsave ,并将rdb 文件传送给子节点
2:AOF 持久化两种触发方式: a:手动触发 bgrewriteaof, b 自动触发(满足 AOF 设置的策略触发和满足 AOF 重写触发)
a: bgrewriteaof 命令可以手动触发
b:自动触发
持久化策略:
always 每条redis 操作命令写入磁盘,最多丢失一条数据;
everysec 每秒钟写入一次磁盘,最多丢失1秒
no 不设置写入磁盘规则,根据当前操作系统决定何时写入磁盘,linux 默认30秒
重写实现:
a: auto-aof-rewrite-min-size : 允许 AOF 重写的最小文件容量,默认是 64mb 。
b: auto-aof-rewrite-percentage:AOF 文件重写的大小比例,默认值是 100,表示 100%,也就是只有当前 AOF 文件,比最后一次(上次)的 AOF 文件大一倍时,才会启动 AOF 文件重写。
优缺点
优点
RDB:
1:RDB 内容为二进制数据,内容紧凑,更适合备份文件
2:对于灾难恢复非常有用
3: RDB 可以提高redis 执行速度,持久化会fork()出子进程
4:相比aof 重启速度更快
2: AOF:
1:AOF 持久化保存的数据更加完整,AOF 提供了三种保存策略:每次操作保存、每秒钟保存一次、跟随系统的持久化策略保存,其中每秒保存一次,从数据 的安全性和性能两方面考虑是一个不错的选择,也是 AOF 默认的策略,即使发生了意外情况,最多只会丢失 1s 钟的数据;
2:AOF 采用的是命令追加的写入方式,所以不会出现文件损坏的问题,即使由于某些意外原因,导致了最后操作的持久化数据写入了一半,也可以通过 redis -check-aof 工具轻松的修复;
3:AOF 持久化文件,非常容易理解和解析,它是把所有 Redis 键值操作命令,以文件的方式存入了磁盘。即使不小心使用 flushall 命令删除了所有键值信息,只要使用 AOF 文件,删除最后的 flushall 命令,重启 Redis 即可恢复之前误删的数据。
混合持久化优点:
混合持久化结合了 RDB 和 AOF 持久化的优点,开头为 RDB 的格式,使得 Redis 可以更快的启动,同时结合 AOF 的优点,有减低了大量数据丢失的风险。
1:RDB 内容为二进制数据,内容紧凑,更适合备份文件
2:对于灾难恢复非常有用
3: RDB 可以提高redis 执行速度,持久化会fork()出子进程
4:相比aof 重启速度更快
2: AOF:
1:AOF 持久化保存的数据更加完整,AOF 提供了三种保存策略:每次操作保存、每秒钟保存一次、跟随系统的持久化策略保存,其中每秒保存一次,从数据 的安全性和性能两方面考虑是一个不错的选择,也是 AOF 默认的策略,即使发生了意外情况,最多只会丢失 1s 钟的数据;
2:AOF 采用的是命令追加的写入方式,所以不会出现文件损坏的问题,即使由于某些意外原因,导致了最后操作的持久化数据写入了一半,也可以通过 redis -check-aof 工具轻松的修复;
3:AOF 持久化文件,非常容易理解和解析,它是把所有 Redis 键值操作命令,以文件的方式存入了磁盘。即使不小心使用 flushall 命令删除了所有键值信息,只要使用 AOF 文件,删除最后的 flushall 命令,重启 Redis 即可恢复之前误删的数据。
混合持久化优点:
混合持久化结合了 RDB 和 AOF 持久化的优点,开头为 RDB 的格式,使得 Redis 可以更快的启动,同时结合 AOF 的优点,有减低了大量数据丢失的风险。
缺点
RDB:
1: 因为RDB 只能保存某个时间段的数据,中途redis 意外挂掉,则会丢失一部分数据
2: RDB 需要经常fork() 才能使用子进程将其持久化到磁盘上,如果数据集很大,fork() 可能很耗时,如果cpu 性能不佳,可能导致redis 停止服务几毫秒到1秒
AOF 缺点
对于相同的数据集来说,AOF 文件要大于 RDB 文件;
在 Redis 负载比较高的情况下,RDB 比 AOF 性能更好;
RDB 使用快照的形式来持久化整个 Redis 数据,而 AOF 只是将每次执行的命令追加到 AOF 文件中,因此从理论上说,RDB 比 AOF 更健壮。
redis-check-aof --fix
混合持久化缺点:
AOF 文件中添加了 RDB 格式的内容,使得 AOF 文件的可读性变得很差;
兼容性差,如果开启混合持久化,那么此混合持久化 AOF 文件,就不能用在 Redis 4.0 之前版本了
1: 因为RDB 只能保存某个时间段的数据,中途redis 意外挂掉,则会丢失一部分数据
2: RDB 需要经常fork() 才能使用子进程将其持久化到磁盘上,如果数据集很大,fork() 可能很耗时,如果cpu 性能不佳,可能导致redis 停止服务几毫秒到1秒
AOF 缺点
对于相同的数据集来说,AOF 文件要大于 RDB 文件;
在 Redis 负载比较高的情况下,RDB 比 AOF 性能更好;
RDB 使用快照的形式来持久化整个 Redis 数据,而 AOF 只是将每次执行的命令追加到 AOF 文件中,因此从理论上说,RDB 比 AOF 更健壮。
redis-check-aof --fix
混合持久化缺点:
AOF 文件中添加了 RDB 格式的内容,使得 AOF 文件的可读性变得很差;
兼容性差,如果开启混合持久化,那么此混合持久化 AOF 文件,就不能用在 Redis 4.0 之前版本了
redis 键值过期操作
过期设置的方式
expire key seconds 设置key 在n 秒之后过期
pexpire key milliseconds 设置key 在n 毫秒之后过期
expireat key timestamp 设置key 在某个时间戳 (精确到秒)之后过期
pexpireat key millisecondsTimestamp 设置 key 在某个时间戳(精确到毫秒)之后过期;
移除过期时间
persist key
持久化中的过期键
RDB 中的过期键
RDB 文件生成阶段
从内存状态持久化成 RDB(文件)的时候,会对 key 进行过期检查,过期的键不会被保存到新的 RDB 文件中,因此 Redis 中的过期键不会对生成新 RDB 文件产生任何影响。
RDB 加载阶段
主服务器运行模式
在载入 RDB 文件时,程序会对文件中保存的键进行检查,过期键不会被载入到数据库中。所以过期键不会对载入 RDB 文件的主服务器造成影响
从服务器运行模式
在载入 RDB 文件时,不论键是否过期都会被载入到数据库中。但由于主从服务器在进行数据同步时,从服务器的数据会被清空。所以一般来说,过期键对载入 RDB 文件的从服务器也不会造成影响
AOF 中的过期键
AOF 文件写入
当 Redis 以 AOF 模式持久化时,如果数据库某个过期键还没被删除,那么 AOF 文件会保留此过期键,当此过期键被删除后,Redis 会向 AOF 文件追加一条 DEL 命令来显式地删除该键值。
AOF 文件重写
执行 AOF 重写时,会对 Redis 中的键值对进行检查已过期的键不会被保存到重写后的 AOF 文件中,因此不会对 AOF 重写造成任何影响。
主从库的过期键
主库
删除过期键 同步到所有的从库
从库
没有过期键的概念,不会处理过期键
过期策略
定时删除
优点
保证内存尽快的释放
缺点
在redis 高负载的清空下,会造成redis 服务器卡顿
简介
在设置键值过期时,创建一个定时事件,当过期时间到达是时,由事件处理器自动执行的删除操作
惰性删除
简介
不主动删除,在访问key 的时候,判断是否过期,如果过期返null
优点
因为每次访问,才会判断是否过期,占用系统资源较少
缺点
系统占用空删除不几十,导致空间利用率降低,造成一定的空间浪费
定期删除
简介
每隔一段时间检查一次数据库,随机删除一些过期键
优点
通过限制操作的时长和频率,来减少删除操作对redis 对主业务的影响,同时也能删除一部分过期数据,减少来过期键对空间的占用
缺点
内存清理方面没有 定时删除好,也没有惰醒删除占用资源少
流程
并不是遍历所有过期的key,而是采用随机抽取并删除过期键
1:从过期键中抽取20 个
2:删除这20个键
3: 判断过期key 的比例超过25% ,重复步骤1
2:删除这20个键
3: 判断过期key 的比例超过25% ,重复步骤1
限制
为了保证出现循环过度,导致出现的线程卡死,算法还增加扫描时间的上限,默认不会超过25ms
总结
redis 使用的是惰性删除和定期删除策略
redis 高级操作
管道技术 Pipeline
优点
如果命令较多,可以使用pipline 一次执行多次,减少网络请求耗时,提高程序运行效率
注意
避免在管道内发送很多命令,管道内数据太多会导致网络阻塞
查询附件的人 Geo
使用场景
查询附近的人 ,附近的地点
计算相关距离
基本操作
geoadd
添加地理位置
geoadd key longitude latitude member
geopos
查询位置信息
geodist
距离统计
geodist key member1 member2 [unit]
georadius
查询某位置的其他成员信息
WITHCOORD
返回满足条件位置的经纬度信息
WITHDIST
返回满足条件位置与查询位置的直线距离。
WITHHASH
返回满足条件位置的哈希信息
COUNT
指定返回满足条件位置的个数
ASC|DESC
从近到远|从远到近排序返回
geohash
查询位置的哈希值
geohash key member [member ...]
zrem
删除地理位置
zrem key member [member ...]
游标迭代器 Scan
Scan 的好处
在没有scan 的时候,只能使用keys 来查找我们想要的信息,如果数据量巨大,那么查询就是o(n),会导致redis 假死
Scan 用法
scan 两个参数
count
查询的总数
match
匹配的规则(user_token_9999*)
规则
它可以完整返回开始到结束检索集合中出现的所有元素,也就是在整个查询过程中如果这些元素没有被删除,且符合检索条件,则一定会被查询出来
它可以保证不会查询出,在开始检索之前删除的那些元素
缺点
一个元素可能被返回多次,需要客户端来实现去重
在迭代过程中如果有元素被修改,那么修改的元素能不能被遍历到不确定
HScan
简介
遍历字典游标迭代器
hscan key cursor [MATCH pattern] [COUNT count]
SScan
简介
遍历集合的游标迭代器
sscan key cursor [MATCH pattern] [COUNT count]
ZScan
简介
ZScan 遍历有序集合的游标迭代器
zscan key cursor [MATCH pattern] [COUNT count]
基数统计算法-HyperLogLog
优点
能够使用极少的内存来统计巨量的数据,只需要12k 空间就可以统计 2^64 的数据
误差可以被设置辅助计算因子进行降低
缺点
统计存在一定的误差,误差率整体较低,标准误差在0.81%
基本操作
添加元素
pfadd key element [element ...]
统计不重复元素
pfcount key [key ...]
合并一个或多个 HLL 至新结构
pfmerge destkey sourcekey [sourcekey ...]
内存淘汰机制
简介
只有在 Redis 的运行内存达到了某个阀值,才会触发内存淘汰机制,这个阀值就是我们设置的最大运行内存,此值在 Redis 的配置文件中可以找到,配置项为 maxmemory
基本命令
查询内存大小
config get maxmemory
查看 Redis 内存淘汰策略
config get maxmemory-policy
修改内存淘汰策略
config set maxmemory-policy
不需要重启,但是重启之后,设置的就会失效
修改配置文件,需要重启redis
淘汰策略类型
noeviction
不淘汰任何数据,当内存不足的时候,新增会报错,Redis 默认淘汰策略
allkeys-lru
淘汰整个键值中最近未使用的值
allkeys-random
随机淘汰任意键值
volatile-lru
淘汰所有设置来过期时间的键值中最近未使用的键值
volatile-random
随机淘汰设置来过期时间的任意键值
volatile-ttl
优先淘汰更早过期的键值
volatile-lfu
淘汰设置来过期时间最少使用的键
allkeys-lfu
淘汰整个键值最少使用的键值
LRU 算法
简介
LRU 全称是 Least Recently Used 译为最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰
算法实现
基于链表结构,链表中的元素按照操作顺序从前忘后排列,最新操作的键会移动到比表头,当需要内存淘汰 只需要删除链表尾部的元素,
缺点
LRU 算法有一个缺点,比如说很久没有使用的一个键值,如果最近被访问了一次,那么它就不会被淘汰,即使它是使用次数最少的缓存,那它也不会被淘汰
LFU算法
简介
LFU 全称是 Least Frequently Used 翻译为最不常用的,最不常用的算法是根据总访问次数来淘汰数据的,它的核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”
实现原理
在redis 中每个对象头中记录来LFU 的信息
LFU 存储
16 bit ldt(last decrement time)
用来存储上一次logc 的更新时间
8 bit logc(logistic counter)
用来存储访问的频次,8bit 表示的最大整数是255 ,他的值越小表示使用的频率越低,越容易淘汰
消息队列
发布订阅模式
Publisher(发布者)
基本命令
publish channel "message"
channel (通道)
Subscriber (订阅者)
基本命令
subscribe channel
主题订阅
Pattern Subscribe
psubscribe
可以使用* 来定义多个channel
缺点
无法持久化保存消息,redis宕机或重启,所有的消息全部丢失
发后即往的模式,如果由订阅者离线重新连之后不能消费之前的历史消息
当消费端由一定的消息积压是时候,超过32M 或者60s 保持在8M 以上,消费端会被强行端口
client-output-buffer-limit pubsub 32mb 8mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
List 版本消息队列
基本命令
rpop
lpush
优点
解决了发布订阅不能持久化消息问题
消息可以积压,不会因为消息太多,导致消费这断开消息
缺点
不能重复消费,一个消息消费删除就完成了
没有主题订阅功能
Zset 版本消息队列
基本命令
zadd
zrangebyscore
可以实现延长队列
借助score 存储一个时间戳
优点
支持消息持久化
相比于List 查询更方便,ZSet 可以利用score 属性很方便完成检索,而List 则需要遍历整个元素才能完成检索
缺点
Zset 不能存储相同的元素
Zset 根据score 的值进行排序,不能像List 一样,按照插入的顺序来排序
Zset 没有向List 的brpop 那样阻塞弹出的功能
Stream 消息 队列
简介
在redis 5.0 之后新增类型 用于完美的实现消息队列
之前的发布订阅、list、zset 队列 存储的value 都只能是字符串,如果要存对象必须转JSON字符串,读取之后还有反序列化
基本操作
xadd
添加消息
xadd key ID field string [field string ...]
ID 可以自己指定也可以换成* * 代表时间戳+ 序号的方式自动生成ID
xlen
查询消息的长度
xlen key
xdel
根据消息ID 删除消息
del
删除整个stream
xrange
读取区间消息
xrange mq - +
- 代表第一个消息, + 代表最好一个消息
xread
读取某个消息之后的消息
此命令提供了阻塞读的参数 block,我们可以使用它读取从当前数据以后新增数据
xread [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
其中 block 0 表示一直阻塞,$ 表示从最后开始读取,这个时候新开一个命令行插入一条数据
xinfo
xinfo stream key
查询流信息
xinfo groups key
查询组信息
xinfo consumers mq group1
查询消费组成员信息
xgroup
xgroup delconsumer stream-key group-key consumer-key
删除消费者
xgroup destory stream-key group-key
删除消费组
消息分组
基本操作
xgroup create stream-key group-key ID
mq 为 Stream 的 key;
group1 为分组的名称;
0-0 表示从第一条消息开始读取
$ 当前最后一条消息向后读取
group1 为分组的名称;
0-0 表示从第一条消息开始读取
$ 当前最后一条消息向后读取
xreadgroup group group-key consumer-key streams stream-key
xreadgroup group group1 c1 count 1 streams mq >
> 表示读取下一条消息;
group1 表示分组名称;
c1 表示 consumer(消费者)名称。
group1 表示分组名称;
c1 表示 consumer(消费者)名称。
消息消费确认
消息确认命令
xack key group-key ID [ID ...]
查询未确认消息队列
xpending key group-key
分布式锁
常见的实现方式
Memcached 分布式锁
使用add 命令,添加成功的情况,表示创建分布式锁成功
zookeeper 实现的分布式锁
使用Zookeeper 顺序临时节点实现分布式锁
Redis 实现的分布式锁
Redis 分布式锁的实现思路是使用 setnx(set if not exists)
Redis 实现的分布式锁
缺点
setnx 虽然可以成功地创建分布式锁,但存在一个问题,如果此程序在创建了锁之后,程序异常退出了,那么这个锁将永远不会被释放,就造成了死锁的问题。
带参数的set
set lock true ex 30 nx
ex n 为设置超时时间,nx 为元素非空判断,用来判断是否能正常使用锁的
分布式锁超时问题
把执行比较耗时的任务不要放到加锁的方法内,锁内的方法尽量控制执行时长;
把最大超时时间可以适当的设置长一点,正常情况下锁用完之后会被手动的删除掉,因此适当的把最大超时时间设置的长一点,也是可行的
锁被误删
给每个锁加一个表示,删除之前判断是否属于当前人
判断和删除两个操作非原子操作,所以需要借助 Lua 脚本来执行判断和删除的操作
延迟队列
使用场景
超过30 分钟 未支付订单,将会被取消
外卖商家超过 5分钟 未接单,将会取消
在平台注册但30天内未登录的用户,发短信提醒
.......
常用实现方式
通过程序实现,jdk 自带 DelayQueue
需要实现Delayed 接口,重写 getDelay、comparrTo 方法
优点
开发比较简单,可以在代码中直接使用
代码实现比较简单
缺点
不支持持久化保存
不支持分布式系统
通过MQ框架实现
优点
支持分布式
支持持久化
缺点
框架比较重,需要搭建 和配置MQ
通过Redis 的方式实现延迟队列
借助Zset 有序集合
优点
灵活方便,redis 基本是标配,无须额外搭建环境
支持消息持久化,提高来延迟队列的可靠性
分布式支持
高可用,依赖Redis 本身的高可用方案
缺点
需要使无线循环方式执行任务检查,消耗少量系统资源
实现方式
第一种是利用 zrangebyscore 查询符合条件的所有待处理任务,循环执行队列任务
第二种实现方式是每次查询最早的一条消息,判断这条信息的执行时间是否小于等于此刻的时间,如果是则执行此任务,否则继续循环检测
定时任务案例
简介
定时任务指的是指定一个时间来执行某个任务,就叫做定时任务。
使用场景
线预约看病的患者,距离预约时间的前一天发送一条提醒推送,以防止患者错过看病的时间
实现方式
开启空间通知
命令设置方式
config set notify-keyspace-events Ex
配置文件设置方式
设置配置项 notify-keyspace-events Ex,然后重启 Redis 服务器。
配置项说明
K:键空间通知,所有通知以 __keyspace@<db>__ 为前缀
E:键事件通知,所有通知以 __keyevent@<db>__ 为前缀
g:DEL、EXPIRE、RENAME 等类型无关的通用命令的通知
$:字符串命令的通知
l:列表命令的通知
s:集合命令的通知
h:哈希命令的通知
z:有序集合命令的通知
x:过期事件,每当有过期键被删除时发送
e:驱逐(evict)事件,每当有键因为 maxmemory 政策而被删除时发送
A:参数 g$lshzxe 的别名
实现思路
定时任务需要使用 Pub/Sub 订阅者和发布者的功能,使用订阅者订阅元素的过期事件,然后再执行固定的任务,这就是定时任务的实现思路
redis 慢查询
配置项
用于设置慢查询的评定时间
slowlog-log-slower-than
用来配置慢查询日志的最大记录数
slowlog-max-len
慢查询命令
查询指定条数慢日志
slowlog get n
查询指定条数慢日志
slowlog len
清空慢查询日志
slowlog reset
redis 性能优化
缩短键值对的存储长度
在 key 不变的情况下,value 值越大操作效率越慢
内容越大需要的持久化时间就越长,需要挂起的时间越长,Redis 的性能就会越低
内容越大在网络上传输的内容就越多,需要的时间就越长,整体的运行速度就越低;
内容越大占用的内存就越多,就会更频繁地触发内存淘汰机制,从而给 Redis 带来了更多的运行负担
使用lazy free(延迟删除) 特性
lazyfree-lazy-eviction
表示当 Redis 运行内存超过 maxmeory 时,是否开启 lazy free 机制删除
lazyfree-lazy-expire
表示设置了过期时间的键值,当过期之后是否开启 lazy free 机制删除;
lazyfree-lazy-server-del
有些指令在处理已存在的键时,会带有一个隐式的 del 键的操作,比如 rename 命令,当目标键已存在,Redis 会先删除目标键,如果这些目标键是一个 big key,就会造成阻塞删除的问题,此配置表示在这种场景中是否开启 lazy free 机制删除;
slave-lazy-flush
针对 slave(从节点)进行全量数据同步,slave 在加载 master 的 RDB 文件前,会运行 flushall 来清理自己的数据,它表示此时是否开启 lazy free 机制删除。
设置键值的过期时间
禁用耗时长的查询命令
避免O(N) 命令对redis 造成的影响
禁止使用 keys 命令
避免一次查询所有的成员,要使用 scan 命令进行分批的,游标式的遍历
通过机制严格控制 Hash、Set、Sorted Set 等结构的数据大小
将排序、并集、交集等操作放在客户端执行,以减少 Redis 服务器运行压力
删除(del)一个大数据的时候,可能会需要很长时间,所以建议用异步删除的方式 unlink,它会启动一个新的线程来删除目标数据,而不阻塞 Redis 的主线程。
使用slowlog 优化耗时命令
使用pipeline 批量操作数据
避免大量数据同时失效
在过期时间的基础上添加一个指定范围的随机数
限制redis 内存大小
检查物理机而非虚拟机安装redis
检查数据持久化策略
使用分布式架构增加读写速度
主从同步
哨兵模式
Redis Cluster 集群
主从同步
主节点 master
一个主节点可以拥有多个从节点
从节点 slave
优点
有了主从同步之后,可以把查询任务分配给从服务器,用主服务器来执行写操作,这样极大的提高了程序运行的效率,把所有压力分摊到各个服务器了;
有了主从同步之后,当主服务器节点宕机之后,可以很迅速的把从节点提升为主节点,为 Redis 服务器的宕机恢复节省了宝贵的时间
当主服务器磁盘坏掉之后,其他从服务器还保留着相关的数据,不至于数据全部丢失。
开启主从同步
设置为目标IP从服务器
replicaof host port
设置主服务器密码
config set masterauth password
启动时设置从服务器
eg: redis-server --port 6380 --replicaof 127.0.0.1 6379
数据同步
完整数据同步
当有新的从服务器连接时,为来保障多个数据的一致性,主服务区会执行bgsave 命令生成一个RDB 文件,然后再以socket 的方式发送给从服务器,从服务区收到RDB 文件之后再把所有的数据加载到自己的程序中,完成一次全量的数据同步
部分数据同步
当从服务器离线后在上线
redis 2.8 之前
主服务器会进行一次完整的数据同步
redis 2.8 之后
主服务器会把离线之后的写入命令,存储在一个特定大小的队列中,队列可以保证先进先出的执行顺序,当从服务器恢复上线之后,主服务会判断离线这段时间命令是否在队列中,如果在直接将队列中的数据发送给从服务区,避免来完整同步的资源浪费
离线存储默认是1Mb 可以修改 repl-backlog-size 来改变大小
无盘数据同步
开启命令
repl-diskless-sync yes
执行过程
如果从服务器是非SSD 硬盘,那么系统IO 操作是很慢的,新增无盘复制
1:无盘复制不会在本地场景RDB 文件,而是会派生出一个子进程,然后由子进程通过Socket 的方式,直接将RDB 文件写入从服务器,这个主服务器可以不创建RDB 文件的情况下,完成数据同步
1:无盘复制不会在本地场景RDB 文件,而是会派生出一个子进程,然后由子进程通过Socket 的方式,直接将RDB 文件写入从服务器,这个主服务器可以不创建RDB 文件的情况下,完成数据同步
查询服务区角色命令
role
关闭主从同步
replicaof no one
主从同步带来的相关问题
数据一致性问题
当从服务器已经完成和主服务的数据同步之后,再新增的命令会以异步的方式发送至从服务器,在这个过程中主从同步会有短暂的数据不一致,如在这个异步同步发生之前主服务器宕机了,会造成数据不一致。
服务器只读性
开启从服务区可写功能
在从服务器上写的数据不会同步到主服务器
当键值相同时主服务器上的数据可以覆盖从服务器;
在进行完整数据同步时,从服务器数据会被清空。
复制命令的变化
redis 5.0之前
slaveof
redis 5.0之后
replicaof
Redis 哨兵模式(Redis Sentinel)
引入哨兵模式的必要
主从同步,当主从同步之前 ,主服务器挂掉之后,会造成主从数据不一样
启动方式
在redis src 目录下 执行./src/redis-sentinel sentinel.conf
sentinel.conf 内容解析
包含监听的主节点信息
sentinel monitor master-name ip port quorum
master-name 表示给监视的主节点起一个名字
ip 表示主节点的Ip
port 表示主节点的端口
quorunm 表示确认主节点下线的Sentinel 数量 如果 quorum 设置为 1 表示只要有一台 Sentinel 判断它下线了,就可以确认它真的下线了
授权主节点密码
sentinel auth-pass master-name password
sentinel 集群
主观下线
当又一个sentinel 标记主服务器为下线,那么主服务器会 标记为主观下线,然后询问其他从服务器
客观下线
当其他从服务器认为该主服务器下线来,达到quorum 参数指定的数量,开始进行故障转移
主服务区竞争规则
优先级
设置replica-priority 选项来设置竞选主节点的优先级,默认值是100,最大值是100 ,值越小权重越高
竞选规则
排除所有已经下线以及长时间没有回复心跳检测的疑似已下线从服务器
排除所有长时间没有与主服务器通信,数据状态过时的从服务器
排除所有优先级(replica-priority)为 0 的服务器
竞选顺序
优先级最高的从节点将会作为新主节点;
优先级相等则判断复制偏移量,偏移量最大的从节点获胜
如果以上两个条件都相同,选择 Redis 运行时随机生成 ID 最小那个为新的主服务器。
工作原理
1:首先每个 Sentinel 会以每秒钟 1 次的频率,向已知的主服务器、从服务器和以及其他 Sentinel 实例,发送一个 PING 命令
如果最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 所配置的值(默认 30s),那么这个实例会被 Sentinel 标记为主观下线
2:主服务器被标记为主观下线那么正在监视这个主服务器的所有 Sentinel 节点,要以每秒 1 次的频率确认 主服务器的确进入了主观下线状态。
如果有足够数量(quorum 配置值)的 Sentinel 在指定的时间范围内同意这一判断,那么这个主服务器被标记为客观下线。此时所有的 Sentinel 会按照规则协商自动选出新的主节点
如果最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 所配置的值(默认 30s),那么这个实例会被 Sentinel 标记为主观下线
2:主服务器被标记为主观下线那么正在监视这个主服务器的所有 Sentinel 节点,要以每秒 1 次的频率确认 主服务器的确进入了主观下线状态。
如果有足够数量(quorum 配置值)的 Sentinel 在指定的时间范围内同意这一判断,那么这个主服务器被标记为客观下线。此时所有的 Sentinel 会按照规则协商自动选出新的主节点
实战命令
查询所有被监控的主服务器信息
sentinel masters
查询某个主节点的信息
sentinel master master-name
查看某个主节点的 IP 和端口
sentinel get-master-addr-by-name master-name
查询从节点的信息
sentinel replicas master-name
查询 Sentinel 集群中的其他 Sentinel 信息
sentinel sentinels master-name
检查可用 Sentinel 的数量
sentinel ckquorum master-name
强制故障转移
sentinel failover master-name
增加监视主节点
sentinel monitor mymaster IP Port Quorum
移除主节点的监视
sentinel remove master-name
修改 quorum 参数
sentinel set master-name quorum n
Redis 集群模式(Redis Cluster )
简介
Redis Cluster 是无代理模式去中心化的运行模式,客户端发送的绝大数命令会直接交给相关节点执行,这样大部分情况请求命令无需转发,或仅转发一次的情况下就能完成请求与响应,所以集群单个节点的性能与单机 Redis 服务器的性能是非常接近的,因此在理论情况下,当水平扩展一倍的主节点就相当于请求处理的性能也提高了一倍,所以 Redis Cluster 的性能是非常高的。
搭建方式
源码中提供的工具
utils/create-cluster
./create-cluster start
手动搭建 Redis Cluster
redis.conf 文件,设置 cluster-enabled yes
启动6个 不同端口的redis
启动6个 不同端口的redis
redis-cli --cluster create 127.0.0.1:30001 127.0.0.1:30002 127.0.0.1:30003 127.0.0.1:30004 127.0.0.1:30005 127.0.0.1:30006 --cluster-replicas 1
cluster-replicas 表示给集群中的主节点指定从节点的数量,1 表示为每个主节点设置一个从节点
动态增删节点
增加主节点
cluster meet ip:port
使用 redis-cli --cluster add-node 添加节点ip:port 集群某节点ip:port
redis-cli --cluster add-node 127.0.0.1:30008 127.0.0.1:30001
添加从节点
cluster replicate nodeId
删除节点
cluster forget nodeId
重新分片
reshard
redis-cli --cluster reshard ip:port
负载均衡
rebalance
redis-cli --cluster rebalance ip:port
故障发现
疑似下线(PFAIL-Possibly Fail)
一个节点发现某个节点疑似下线,它会将这条信息向整个集群广播,其它节点就会收到这个消息,并且通过 PING 的方式监测某节点是否真的下线了。如果一个节点收到某个节点疑似下线的数量超过集群数量的一半以上,就可以标记该节点为确定下线状态
确定下线(Fail)
一个节点发现某个节点疑似下线,它会将这条信息向整个集群广播,其它节点就会收到这个消息,并且通过 PING 的方式监测某节点是否真的下线了。如果一个节点收到某个节点疑似下线的数量超过集群数量的一半以上,就可以标记该节点为确定下线状态
故障转移
从下线的主节点的所有从节点中
从节点会执行 SLAVEOF NO ONE 命令,关闭这个从节点的复制功能,并从从节点转变回主节点,原来同步所得的数据集不会被丢弃
新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽全部指派给自己
新的主节点向集群广播一条 PONG 消息,这条 PONG 消息是让集群中的其他节点知道此节点已经由从节点变成了主节点,并且这个主节点已经接管了原本由已下线节点负责处理的槽位信息
新的主节点开始处理相关的命令请求,此故障转移过程完成
新主节点选举原则
集群的纪元(epoch)是一个自增计数器,初始值为0
而每个主节点都有一次投票的机会,主节点会把这一票投给第一个要求投票的从节点
当从节点发现自己正在复制的主节点确认下线之后,就会向集群广播一条消息,要求所有有投票权的主节点给此从节点投票
如果有投票权的主节点还没有给其他人投票的情况下,它会向第一个要求投票的从节点发送一条消息,表示把这一票投给这个从节点
当从节点收到投票数量大于集群数量的半数以上时,这个从节点就会当选为新的主节点
槽位定位算法
Redis 集群总共的槽位数是 16384 个,每一个主节点负责维护一部分槽以及槽所映射的键值数据,Redis 集群默认会对要存储的 key 值使用 CRC16 算法进行 hash 得到一个整数值,然后用这个整数值对 16384 进行取模来得到具体槽位
slot = CRC16(key) & 16383
slot = CRC16(key) & 16383
redis 解决方案
缓存雪崩
简介
缓存雪崩是指在短时间内,有大量缓存同时过期,导致大量的请求直接查询数据库,从而对数据库造成了巨大的压力,严重情况下可能会导致数据库宕机的情况叫做缓存雪崩。
解决方案
加锁排队
缺点
锁排队可以起到缓冲的作用,防止大量的请求同时操作数据库,但它的缺点是增加了系统的响应时间,降低了系统的吞吐量,牺牲了一部分用户体验。
随机化过期时间
缺点
过期时间不准确
设置二级缓存
二级缓存指的是除了 Redis 本身的缓存,再设置一层缓存,当 Redis 失效之后,先去查询二级缓存。
缓存穿透
简介
缓存穿透是指查询数据库和缓存都无数据,因为数据库查询无数据,出于容错考虑,不会将结果保存到缓存中,因此每次请求都会去查询数据库,这种情况就叫做缓存穿透
解决方案
使用过滤器
布隆过滤器,它的原理是将数据库的数据哈希到 bitmap 中,每次查询之前,先使用布隆过滤器过滤掉一定不存在的无效请求,从而避免了无效请求给数据库带来的查询压力
缓存空结果
缓存击穿
简介
缓存击穿指的是某个热点缓存,在某一时刻恰好失效了,然后此时刚好有大量的并发请求,此时这些请求将会给数据库造成巨大的压力,这种情况就叫做缓存击穿
解决方案
加锁排队
设置永不过期
缓存预热
简介
用缓存时的一个优化方案,它可以提高前台用户的使用体验。
解决方案
缓存预热指的是在系统启动的时候,先把查询结果预存到缓存中,以便用户后面查询时可以直接从缓存中读取,以节约用户的等待时间
把需要缓存的方法挂载到某个页面或后端接口上,手动触发缓存预热
设置定时任务,定时自动进行缓存预热
0 条评论
下一页