Redis
2024-04-28 20:56:04 35 举报
AI智能生成
登录查看完整内容
Redis 2024年4月28日20:55:29:补充底层数据结构的实现(面试被问麻了)
作者其他创作
大纲/内容
批处理命令的优化措施,类似Redis的原生批命令(多条命令打包执行)
①命令集写到txt文件里
②通过管道符 | ,连接redis-cli 通过添加--pipe命令执行
使用
管道
基于内存读写快
数据结构优化的好,也快
单线程IO多路复用和非阻塞IO
为什么当年说它快
作者认为Reds的主要瓶颈是内存或者带宽,不是CPU
当年为什么是单线程
时代变了大人,硬件发展快
为什么又要加多线程
4以前是单线程
4开始有一点多线程
6开始完全支持多线程
版本
Redis单线程VS多线程
对于恶意攻击导致的缓存穿透,使用布隆过滤器
对于业务逻辑本身就不能避免的缓存穿透,将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
缓存和数据库中都没有的数据,而用户不断发起请求。
缓存穿透
设置热点数据永不过时
接口限流与熔断,降级
互斥加锁
缓存中可能过期了,没有,请求到数据库
缓存击穿
缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生
如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中。
数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
缓存雪崩
读数据时,先读缓存,缓存没有的话,再读数据源,然后将数据放入缓存,再响应请求
写数据时,先写数据源,然后失效(而不是更新)掉缓存
缓存污染多数是由开发者更新缓存不规范造成的
缓存污染是指缓存中的数据与真实数据源中的数据不一致的现象
缓存污染
缓存问题
只读缓存
写数据库后同步写redis
同步直写
容许数据库和redis之间的数据存在一定的延时
异步缓写
读写缓存
QPS<=1000可以用,高并发不行!
先读redis,没有再度数据库,读完回写redis
redis没有,加锁,再查一次redis,没有,从数据库查,查完回写redis,返回
双检加锁
高QPS怎么解决?
具体实现
先更数据库,再更缓存×
先更缓存,再更数据库×
但是也会引申出其他问题
进阶 延迟双删
先删缓存,在更数据库×
先更新数据库,在删除缓存(主流的,但是不100%权威)
四种更新策略
消息中间件实现最终一致性
引申
认清一个现实:缓存和数据库之间的数据是不可能永远维持在一致性状态的
缓存双写一致性
更进一步set NX PX + Lua
setNX(小公司够用)
WatchDog机制
上redisson
基于RedLock实现分布式锁
分布式锁实现
对cpu友好,对内存不友好
取出的时候才会去检查
惰性删除
对内存友好,对cpu不友好
字面意思,定期扫描
定期删除
缓存过期策略
最近最少使用
lru
最不经常使用
lfu
将要过期
ttl
随机
random
volatile(设置了过期时间)
allkeys(所有key)
不淘汰
noeviction
缓存淘汰机制
缓存过期淘汰策略
简单动态字符串SDS:Redis会根据不同的键值选择使用不同的编码格式
String
压缩链表ziplist(特殊编码的双向链表)
哈希表hashtable
7之前
listpack(紧凑列表,它的特点就是用一块连续的内存空间来紧凑地保存数据)
7之后
Hash
ziplist(特殊编码的双向链表)
List
intset整数集合
Set
skiplist(redis跳跃表并没有在单独的类(比如skplist.c)中定义,空间换时间)
ZSet
数据类型底层的数据结构
进阶
Redis是一款内存高速缓存数据库。Redis全称为:Remote Dictionary Server(远程数据服务),使用C语言编写,Redis是一个key-value存储系统(键值存储系统),支持丰富的数据类型,如:String、list、set、zset、hash
是什么
基于内存,读写优异
数据类型丰富,数据结构优化
持久化
为什么
工作中用的最多的就这个,而且主要是用String存token、权限信息、验证码这些
读取前,先去读Redis,如果没有数据,读取数据库,将数据拉入Redis
插入数据时,同时写入Redis
缓存的使用方式
缓存
要么是RedisUtil封一下setnx方法,要么直接用redisson
这个主要利用redis的setnx命令进行,setnx:\"set if not exists\"就是如果不存在则成功设置缓存同时返回1,否则返回0
分布式锁
没用过
计数器
消息队列
......
使用场景
keys * 查看当前库所有的key
exists key 判断某个key是否存在
type key 查看key的类型
del key 删除指定的key
unlink key 非阻塞删除
ttl key 查看还有多少秒过期 -1永不过期 -2已过期
expire key 设置过期时间
select dbindex 切换数据库
dbsize key数量
flushdb 清空当前库
flushall 通杀全部库
常用命令
基础和概念
介绍:String类型是二进制安全的,意思是 redis 的 string 可以包含任何数据。如数字,字符串,jpg图片或者序列化的对象
使用场景:缓存、计数器、Session
底层数据结构
介绍:Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。
使用场景:存储对象
介绍:Redis中的List其实就是链表
使用场景:排队功能、消息队列
介绍:Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
使用场景:标签、点赞、踩、收藏
使用场景:排行榜
ZSet(SortSet)
5种基础
可以非常省内存的去统计各种计数,比如注册 IP 数、每日访问 IP 数、页面实时UV、在线用户数,共同好友数等
基数统计
Hyperloglog
两个状态的,都可以使用 Bitmaps
位图数据结构,都是操作二进制位来进行记录,只有0 和 1 两个状态
bitmap
地理位置信息
geospatial
bitfield
3中特殊
Stream
数据结构
RDB持久化是把当前进程数据生成快照保存到磁盘上的过程,由于是某一时刻的快照,那么快照中的值要早于或者等于内存中的值
内存快照
阻塞当前Redis服务器,直到RDB过程完成为止,对于内存 比较大的实例会造成长时间阻塞,线上环境不建议使用
save
Redis进程执行fork操作创建子进程,RDB持久化过程由子 进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短
bgsave
手动触发
基于配置文件里设置的规则m时间内有n次修改 触发
主从复制会触发
flushdb/flushall会触发
shutdown命令,如果没有开启aof,会触发
Save m n
自动触发
配置文件里改成save \" \"
禁用rdb
触发方式
redis-check-rdb命令
rdb文件检查修复
关闭redis,把RDB文件复制到Redis的安装目录里,启动redis
恢复
RDB文件是某个时间节点的快照,默认使用LZF算法进行压缩,压缩后的文件体积远远小于内存大小,适用于备份、全量复制等场景
Redis加载RDB文件恢复数据要远远快于AOF方式
优点
无法做到秒级持久化
fork子进程属于重量级操作,开销大
RDB文件没有可读性,是二进制文件
实时性不够
缺点
RDB(默认)
针对RDB不适合实时持久化的问题,Redis提供了AOF持久化方式来解决
配置文件里 appendonly yes
AOF开启(默认关闭)
AOF日志记录Redis的每个写命令
同步写回
always
每秒写回
everysec(默认)
躺平,操作系统自己控制时机
no
AOF写回策略
和rdb一样
redis-check-aof --fix
AOF文件修改
实时性持久化,秒级
日志不易损坏,损坏了也能修复
满足配置文件的配置,默认是大于上一次的一倍且文件到达64M
自动
bgrewriteaof命令
手动
AOF重写触发机制
Redis通过创建一个新的AOF文件来替换现有的AOF,新旧两个AOF文件保存的数据相同,但新AOF文件没有了冗余命令
①主线程fork出子进程重写aof日志
②子进程重写日志完成后,主线程追加aof日志缓冲
③替换日志文件
重写原理
AOF文件过大的情况下有AOF重写机制进行瘦身
日志内容可读
优势
AOF文件比相同数据集的RDB文件更大
恢复速度慢于RDB
劣势
AOF
同时开启数据恢复只会加载aof文件,不会加载rdb
aof-use-rdb-preamble yes
开启
aof做增量,rdb做全量
特点
混合模式
同时关闭rdb和aof
纯缓存模式
持久化机制
Redis 可以通过 MULTI,EXEC,DISCARD 和 WATCH 等命令来实现事务(transaction)功能
1开始事务(MULTI)
2、命令入队(批量操作 Redis 的命令,先进先出(FIFO)的顺序执行)。
3执行事务(EXEC)
使用过程
你也可以通过 DISCARD (opens new window)命令取消一个事务,它会清空事务队列中保存的所有命令
WATCH是乐观锁,基于CAS
WATCH (opens new window)命令用于监听指定的键,当调用 EXEC 命令执行事务时,如果一个被 WATCH 命令监视的键被修改的话,整个事务都不会执行,直接返回失败。
UNWATCH:取消WATCH对所有key的监视。
Redis的事务是原子性的:所有的命令,要么全部执行,要么全部不执行。而不是完全成功。
redis事务可以保证命令失败的情况下得以回滚,数据能恢复到没有执行之前的样子,是保证一致性的,除非redis进程意外终结。
redis事务是严格遵守隔离性的,原因是redis是单进程单线程模式(v6.0之前),可以保证命令执行过程中不会被其他客户端命令打断。但是,Redis不像其它结构化数据库有隔离级别这种设计。
redis事务是不保证持久性的,这是因为redis持久化策略中不管是RDB还是AOF都是异步执行的,不保证持久性是出于对性能的考虑。
Redis事务的ACID
事务
消息队列,实现进程间消息通信
干嘛的
不推荐使用,专业的事交个专业的做,市面上有更好的消息中间件
subscribe channel:1
订阅
publish channel:1 hi
发布
基于频道(Channel)的发布/订阅
psubscribe c? b* d?*
publish c m1
publish c11 m1
基于模式(pattern)的发布/订阅
发布订阅(了解即可)
复制
哨兵
集群
高可用(TODO)
Redis
0 条评论
回复 删除
下一页