Redis缓存
Redis 5种基本数据类型
String
string可以做数字运算
string单个字符串最大存储512M(2^32-1)
set key value --设置key以及对应的value值
get key --获取key对应的value值
append key value --在末尾追加字符串
strlen key --字符串长度
setnx key value --键不存在才设置,nx--not exsits
incr key --递增,原子操作
decr key --递减,原子操作
msetnx key value key value ... --所有的键都不存在才设置,有任意一个键存在全部都失败
getrange key start end --截取字符串,包含start和end
setrange key start value --替换子串,从start位置开始进行替换
expire key seconds --设置key的过期时间
ttl key --查看key的过期时间
setex key seconds value --添加数据,同时指定过期时间 (set+expire)
getset key value --返回旧值,设置新值
List
lpush/rpush key value value .. --左侧添加/右侧添加
lrange key start end --从左侧按范围取数据 -1表示末尾
lpop/rpop key [count] --从左侧或右侧弹出值
rpoplpush from_key to_key --右侧弹出,再加入左侧
lindex key index --按下标取数据
llen --列表长度
linsert key before/after value new_value --在指定的值的前后添加数据
lrem key n value --从左侧找到n个给定的值删掉,n是0表示删除全部指定的值
lset key index new_value --替换index位置
Set
sadd key value value ... --设置值
smembers key --取所有值
sismember key value --值是否在Set中存在
scard key --元素数量
srem key value value ... --删除值
spop key [count] --随机弹出
srandmember key n --随机访问n个值(不会删除)
smove from to value --把值从一个集合移动到另一个集合
sinter key key ... --多个Set集合的交集
sunion key key ... --并集
sdiff key key ... --差集
Hash
多数情况下直接使用redis存放兼职数据
如果多个属性的对象中,有的属性要频繁修改,可以考虑使用Hash
hset key field value field value ...
hget key field
hkeys key --列出所有field
hvals key --列出所有value
hincrby key field increment --在数字上加一个值
hsetnx key field value --不存在才添加
Zset
zadd key score value score value ...
zrange key start end --取数据,end用 -1表示末尾
zrange key start end withscores --取数据时同时返回得分
zrevrange key start end [withscores] --按得分从高到低排序
zrangebyscore key min max [withscores] [limit start count] --按分值范围取数据
zrevrangebyscore key min max [withscores] [limit start count] --按得分从高到低排序
zincrby key increment member --增加积分
zrem key member member ... --删除
zcount key min max --统计分数区间内的数据量
zrank key member --该数据的排名(从小到大)
zrevrank key member --该数据的排名(从大到小)
Redis事务
1、功能弱
2、Multi组队命令序列,类似mysql的begin multi后可以执行多步数据操作
3、Exec执行multi的命令序列,相当于mysql的commit
4、Discard放弃执行命令序列,相当于回滚
Redis持久化
redis内存的数据,持久化存储到磁盘,当redis重启时,可以从持久化的数据快速回复内存数据
RDB -Redis Database
1、内存数据镜像,把内存所有数据拍一个快照,把数据全部保存到一个磁盘文件:dump.rdb
2、默认在达到一定条件时才会自动保存,或者可以手动调用:save 同步保存,bgsave 异步保存
3、可以设置redis自动保存快照,redis.conf中添加配置,例如:
save 3600 1: 1小时内,有一条数据改动
save 300 100:5分钟内,有100条数据改动
save 60 10000:1分钟,有10000条数据改动
RDB的优缺点:
优点:恢复数据快
缺点:持久化时存储数据效率低,不能实时存储,可能丢失新数据
写时复制:保存快照时,先写到临时文件,完成后删除dump.rdb,把临时文件改名成dump.rdb 临时文件写入失败数据损坏,也不会影响dump.rdb
dump.rdb文件修复:docker exec -it redis bash redis-check-rdb dump.rdb
AOF-Append Only File
1、记录数据操作指令,每执行一条增删改的命令,都会实时地追加到aof日志文件
2、默认不开启AOF,需要在配置文件中开启AOF:appendonly yes #默认是no
AOF的优缺点:
优点:持久化效率高,实时持久化,不会丢失数据
缺点:恢复数据时效率低,aof中记录的所有命令进行重放,效率低
修复AOF文件:redis-check-aof --fix appendonly.aof
rewrite压缩:对文件中记录的指令,能合并的指令合并成一条执行
文件大小达到min-size时触发,每增长100%时再次触发
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
官方建议使用RDB+AOF混合模式
存储:RDB完整存储内存数据 RDB之后的增量数据,使用AOF来记录增量数据
恢复:从RDB恢复绝大多数数据 重放AOF,恢复少量增量数据
默认已经开启了混合模式:aof-use-rdb-preamble yes
需要手动打开AOF:appendonly yes #默认是no
高可用
主从
1、主从复制
2、读写分离
3、从服务器重启,可以自动从主服务器同步数据
4、主服务器宕机,从服务器会等待主服务器重启
5、主从复制原理,从服务器上线,全量复制,从服务器发送请求,主服务器rdb,将rdb文件发送给从服务器导入数据,主服务器更改数据时,自动向从服务器同步数据,增量复制
6、主-从-从结构,从服务器的从服务器,减轻主服务器数据同步的压力
7、命令slaveof ip port 作为制定服务器的从服务器 slaveof no one 从服务器转为主服务器
哨兵
1、监听主从集群,自动主从切换
2、选举依据:优先级replica-priority 偏移量 获取主机的数据数量 runid 随机的40位id的值
Redis Cluster 集群
1、去中心化
2、配置 cluster-enable yes cluster-config-file node.conf cluster-node-timeout 15000 #失联时间
3、集群规划原则,主服务器不在相同ip,从服务器不在他的主服务ip
4、哈希槽
cluster keyslot key 计算哈希槽值
cluster keyslot key{group}哈希槽中的数据量
cluster countkeysinslot slot 只能查看当前服务器哈希槽
clustetr getkeysinslot slot count 获得哈希槽中存储的键 count 指定获取的数量
5、数据操作
set key value 使用key计算哈希槽
set key{group} value 使用group计算哈希值
mset key{group} value key{group} value .... 添加多个数据必须指定组,且是相同的组
get key{group} 添加时有组名,获取数据时也必须有组名
6、故障恢复
主从切换,一台主机宕机,他的从服务器自动成为主机,之前的主机重启之后成为从机,一组主从全部宕机,哈希槽覆盖不全,整个集群不可用
cluster-require-full-coverage yes 默认
cluster-require-full-coverage no 哈希槽覆盖不全,其他服务器扔提供服务
7、缺点:不支持多键操作,不支持lua脚本,旧的集群内cluster迁移不方便
击穿、穿透和雪崩
击穿:热门数据,突然过期,访问被打到数据库上 击穿redis,打到数据库上
可能的场景:突发热门访问一个key正被大量访问,这个key过期
解决方案:预选设置热门数据,实时调整过期时间,自动续期使用锁、限流、缓存数据不存在,先把数据存入redis
穿透:Redis中没有数据,数据库中也没有数据
可能的场景:访问的数据在redis中数据不存在,大量访问非正常数据,数据在数据库中也不存在,非正常访问(黑客攻击)
解决方案:使用布隆过滤器
雪崩:大量的key集中过期,数据库访问短时激增
解决方案:多级缓存架构、自动续期、自动更新数据、即将过期的数据提前更新数据、对过期时间使用随机值,分散过期时间、锁 | 队列
布隆过滤器(二进制数组)
如果是0,表示不存在,如果是1,表示存在
当需要存入一个数据时,会通过几个哈希函数运算,将计算结果对应的哈希值的0改为1
当进行查询时,如果通过几个哈希函数计算出来的结果都是1,布隆过滤器就认为这个数据存在,只要有一个值为0就证明这个数据不存在。布隆过滤器很难去做删除操作,因为一个哈希值可能会代表多个数据。
优点:占用空间小,插入和查询速度快,保密性好,时间复杂度是O(K)
缺点:很难做删除操作,存在误判
哈希函数算法越多,误判率就会越小,占用空间就越大,性能也就越差。
Redis持久化
redis内存的数据,持久化存储到磁盘,当redis重启时,可以从持久化的数据快速恢复内存数据。
save命令和bgsave命令的区别?
save命令会阻塞redis,去生成rdb文件,直到完成文件,在此过程中,所有的客户端都被拒绝。
bgsave命令会fork一个子进程去生成rdb文件。
RDB:内存数据镜像,把内存所有数据拍一个快照,把数据全部保存到一个磁盘文件:dump.rdb
默认在达到一定条件时才会自动保存,或者可以手动调节
优点:恢复数据速度快
缺点:持久化时存储数据效率低,不能实时存储,可能丢失少量新数据
写时赋值:保存快照时,先写到临时文件,完成后删除dump.rdb,把临时文件改名为dump.rdb,临时文件写入失败数据损坏,也不会影响dump.rdb
AOF:记录数据操作指令,每执行一条增删改的命令,都会实时地追加到aof日志文件(默认不开启AOF,需要在配置文件中开启)
优点:持久化效率高,实时持久化,不会丢失数据
缺点:恢复数据时效率低,aof中记录的所有命令进行重放,效率低
官方建议使用RDB+AOF混合模式(默认开启)
存储:RDB完整存储内存数据,RDB之后的增量数据,使用AOF来记录增量数据
恢复:从RDB恢复绝大多数数据,重放AOF,恢复少量增量数据
Redis分布式锁
1.分布式锁和JAVA自带的锁的区别?
Java自带锁是进程锁,只能锁住当前服务
Redis由于资源在公共的地方,所以可以用它锁住所有订单服务
2.为什么需要分布式锁?
在微服务架构中,一个应用可能会部署多个线程,多个线程如果同时操作数据库中的一行记录,为了避出现脏数据,就要使用分布式锁了。
3.分布式锁如何实现?
想要实现分布式锁,必须要求Redis有互斥的能力,可以使用SET IF NOT EXIST,即如果key不存在,才会设置他的值,否则什么也不做,两个客户端进程可以执行这个命令,达到互斥,就可以实现一个分布式锁。加锁操作完成后,加锁成功的客户端,就可以去操作共享资源,操作完成后还要及时释放锁,直接使用DEL命令删除这个key即可。以上实现存在一个很大的问题,就是容易发生死锁。
死锁(已经获得锁的客户端一直占用锁,其他客户端永远无法获取到锁)
原因:程序处理业务逻辑异常,没及时释放锁。进程挂了,没机会释放锁
4.如何避免死锁?
在申请锁的同时,加一个锁的过期时间,在SET的同时指定EXPIRE时间,这条操作时原子的。这样又会出现新的问题,锁过期(加锁时,先设置一个预估的过期时间,然后开启一个守护线程,定时去检测这个锁的失效时间,如果锁快要过期了,操作共享资源还未完成,那么就自动对锁进行续期)| 释放了别人的锁(设置一个只有自己知道的唯一标识进去,例如自己的线程ID,如果是redis实现,要先判断这把锁是否归自己持有,只有是自己的才能释放他。释放的时候又出现了GET+DEL原子性操作,又不能同时进行了,这里使用Lua脚本,然后再让redis执行,因为Redis处理每个请求是单线程执行的,在执行一个Lua脚本时,其他请求必须等待,直到这个脚本处理完。
在Redis官网上发现了一个框架Redisson,他为Redis分布式锁提供了更好的实现和封装。
5.Redis的部署方式对锁的影响?
一般采用主从集群+哨兵的模式部署,哨兵的作用就是监测redis节点的运行状态,普通的主从模式,当master宕机哨兵实现自动切换,来保证可用性,此时就会出现分布式锁安全问题。集群模式+RedLock实现高可靠的分布式锁,RedLock算法的基本思路是:让客户端和多个独立的Redis实例依次请求加锁,如果客户端能够和半数以上的实例成功地完成加锁操作,那么我们就认为,客户端成功地获得分布式锁了,否则加锁失败。客户端只有在满足两个条件时,才能认为是加锁成功,一是客户端超过半数从redis实例上成功获取到了锁,二是客户端获取锁的总耗时没有超过锁的有效时间。
6.Redis实现高并发理由
基于内存的高速读写:Redis将数据存放在内存中,读写速度非常快,可以满足高并发的读写需求。同时,Redis还支持持久化机制,可以将内存中的数据异步地写入到磁盘上,以保证数据的持久性。
单线程模型:Redis采用单线程模型,通过事件轮询方式来处理多个客户端请求,从而避免了线程切换和锁等问题,保证了高并发下的稳定性和效率。
内部优化:Redis内部采用了多种优化技术,比如数据结构的优化、网络通信的优化、异步IO等技术,可以提升Redis的性能和并发能力。
分布式架构:Redis可以通过分布式方式,将数据分散到多个节点上,从而提高了整个系统的并发能力和可扩展性。
集群模式:Redis支持集群模式,可以将数据分散到多个节点上,从而实现负载均衡和容错性,保证了高并发下的稳定性。
7.过期数据删除策略
定性删除:将所有设置了过期时间的key放入一个独立的内部字典中,每段时间进行扫描判断是否过期(随机选20个key,删除20个key中过期的,如果超过1/4就重复上面的步骤)
惰性删除:在访问Redis获取数据时判断这个key是否过期,如果过期就立即删除
8.淘汰策略
random:随机删除数据
ttl:删除剩余有效时间最少的数据
lru:删除上次时间距离现在最久的数据
lfu:删除使用频率最少的
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端