Redis_V2023
2023-05-15 15:49:43 0 举报
AI智能生成
Redis
作者其他创作
大纲/内容
int:8个字节的long。用于存储整数。如果一个字符串对象保存的是整数值,并且这个整数值可以用long类型来表示,那么字符串对象会将整数值保存在字符串对象结构的ptr属性里面(将void*转换成 long),并将字符串对象的编码设置为int。
embstr(SDS):如果字符串对象保存的是一个字符串,并且这个字符申的长度小于等于 32 字节(redis 2.+版本),那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串,并将对象的编码设置为embstr, embstr编码是专门用于保存短字符串的一种优化编码方式。
raw(SDS):如果字符串对象保存的是一个字符串,并且这个字符串的长度大于 32 字节(redis 2.+版本),那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串,并将对象的编码设置为raw:
常见命令:incrby\\set\\get\\getrange\\strlen\\ttl\\del\\expire
应用场景:缓存、分布式锁、分布式session、计数器。
SDS相比C语言的字符串有什么好处?
好处:embstr会通过一次内存分配函数来分配一块连续的内存空间来保存redisObject和SDS,而raw编码会通过调用两次内存分配函数来分别分配两块空间来保存redisObject和SDS。
缺点:如果字符串的长度增加需要重新分配内存时,整个redisObject和sds都需要重新分配空间,所以embstr编码的字符串对象实际上是只读的,redis没有为embstr编码的字符串对象编写任何相应的修改程序。当我们对embstr编码的字符串对象执行任何修改命令(例如append)时,程序会先将对象的编码从embstr转换成raw,然后再执行修改命令
embstr和raw有什么区别?
面试题
string
当元素较少的时候,使用ziplist(压缩列表)。
当元素较多的时候,使用quicklist。
内部实现:类似双向链表linkedlist
常见命令:lpush\\lpop\push\pop\\llen\\lrange\\lindex\\lset\\lrem
1、如何满足消息保序需求?-- LPUSH + RPOP。RPOP是非阻塞的,需要不断轮询。为解决这个问题,Redis提供RBPOP(阻塞读取)。
2、如何处理重复的消息? -- 自己生成唯一性ID
3、如何保证消息可靠性?
4、List 作为消息队列有什么缺陷? --List 不支持多个消费者消费同一条消息,因为一旦消费者拉取一条消息后,这条消息就从 List 中删除了,无法被其它消费者再次消费。
消息队列:
应用场景:粉丝列表、文章评论、阻塞队列
list
field、value比较少时,使用ziplist
field、value比较多时,使用dict
配置项:hash-max-ziplist-entries 512hash-max-ziplist-value 64,满足以上一个条件,就会转dict
什么时候从ziplist转dict?
1. 插入和修改引发的realloc,大概率会引起内存拷贝
2. ziplist的查询需要O(N)的遍历
为什么这么设计?
内部实现:类似HashMap
常见命令:hset\\hmset\\hget\\hgetall\\hkeys\\hvals\\hdel\\hexist
应用场景:购物车
hash
intset:如果集合中的元素都是整数且元素个数小于 512 (默认值,set-maxintset-entries配置)个,Redis 会使用整数集合作为 Set 类型的底层数据结构;
dict
内部实现
set
当数据量比较少时,用ziplist
dict:hash存储value和score的唯一映射关系
实现排序功能
省市区例子
查找的时间复杂度O(N)
跳表skiplist用于排序
当数据量比较大时,内部使用2个数据结构
使用场景:排行榜、带权重的队列
常用命令:zadd\\zrem\\zrank\\zrange\\zrangbyscore
sorted set(zset)
统计页面访问UV
应用场景
HyperLogLog
setbit key offset value\\getbit key offset
布隆过滤器
用户签到
统计活跃用户
用户在线状态
Bitmap(V2.2新增)
Stream(V5.0新增)
Geo(V3.2新增)
其他数据结构
外部数据结构
为了解决算法中的查找问题
增量Hash
dictEntry
dictType
dictht
dict数据结构
redis中的key和value组成一个全局字典,zset中的value和score锁组成的映射关系也是通过dict实现。
可动态扩展内存
可存储任何二进制
与C语言兼容
特点
和C语言字符串相似,但是有长度字段
长度=最大容量+1
表示字符串真正长度(不含NULL字符串)
len
字符串最大容量
alloc
flags
一个header结构
一个字符数组
sds数据结构
当string存储数值时,内部存储还是sds吗?
浅谈sds和string的关系
sds
空间和时间的折中
quicklist的每个节点都是ziplist
quicklist
内存结构:<zlbytes><zltail><zllen><entry>...<entry><zlend>
每一项之间连续顺序存储,追求存储效率。能以O(1)的效率在两端存储
可以存储:字符串和整数,其中整数以二进制方式存储
ziplist
skiplist
内部数据结构
1. 可以改进内部编码,对外部数据结构没有影响
2. 多种内部编码在不同场景下发挥各自优势
为什么设计内外部数据结构?
robj是联接内外部数据结构的桥梁,通过不同的encoding来区分。
基础数据结构robj(RedisObject)
Hash数据结构可以给HKey设置过期时间吗?
一、数据结构
会有什么问题?(丢失数据)
为什么这么设计?(避免记录错误日志,避免阻塞当前线程)
写后日志(WAL先执行命令、后记录日志)
MySQL是写前日志
AOF日志是如何实现的? -- 主线程操作的
always 同步写回 -- 高可靠性
every sec 每秒写回
no 由操作系统决定何时写回磁盘 -- 高性能
三种写回策略?
实时性更好
优点?
因为日志文件记录的是命令,不是实际数据,所以回放恢复很缓慢;
OS无法保存过大的文件,再者大文件追加命令效率也会变低;
缺点?
为什么重写就可以减小日志文件呢?-- 重写可以合并多条命令
AOF重写会阻塞主线程吗? -- 重写是子进程bgwriteaof完成的,避免阻塞主进程;
重写过程是怎么样的? -- 一个拷贝,2处日志:fork子进程拷贝最新内存;
AOF日志文件太大怎么办? -- AOF重写机制
AOF追加
默认;数据快照;适用于备份
save: 在主线程中执行,会导致阻塞
bgsave: 创建子进程执行
redis提供2个命令生成rdb文件
对哪些数据做快照? -- 全量数据
可以,使用写时复制
快照时数据能修改吗?
在恢复大数据时,速度比AOF快;
bgsave和写时复制可以减少对主线程的影响
实时性不高
RDB快照
内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作
Redis4.0 支持RDB和AOF混合持久化
从节点:开启RDB,主节点什么都不做
CAOCAO采用的方案
二、持久化(如何避免数据丢失?)
惰性删除
定期删除
已经设置了TTL,为什么还需要过期策略?
为什么需要内存淘汰策略?
内存淘汰策略有哪些?
内存淘汰策略是如何工作的?
如何选择内存淘汰策略?
LRU和LFU的区别?
内存用完了会怎么样?
内存淘汰策略?
过期key的删除策略?
线程模型
三、功能
原子性:事务中的所有命令要么全部执行,要么全部回滚。
缺陷
不具备一致性(不支持回滚)
一致性【不具备】:Redis 的事务机制并不会自动保证数据的一致性。如果在事务执行过程中有其他客户端对事务中涉及的键进行修改,事务会继续执行而不会回滚。因此,一致性需要在应用层面进行处理。
隔离性【不具备】:Redis 的事务机制默认情况下是没有隔离级别的概念的,多个事务之间可以并发执行,彼此之间不会产生相互干扰。但是,在事务执行期间,如果有其他客户端修改了事务中的键,事务可能会受到影响。
持久性:Redis 的事务机制在 EXEC 命令执行后,事务中的修改会立即生效,不需要像普通命令一样显式地进行持久化操作。Redis 使用写时复制(copy-on-write)技术,将事务中的修改写入磁盘,保证了持久性。
特性
redis事务是怎么实现的 ?
四、事务
读写策略:主节点可读可写,从节点只读。从节点可以扩展主库节点的读能力,有效应对大并发量的读操作。
高可靠性:一方面,采用双机主备架构,能够在主库出现故障时自动进行主备切换,从库提升为主库提供服务,保证服务平稳运行;另一方面,开启数据持久化功能和配置合理的备份策略,能有效的解决数据误操作和数据异常丢失的问题;
优点:
故障恢复复杂:需要手动。主节点宕机后整个集群不可用。
主库的写能力受到单机的限制。
缺点:
主从:有且只有一个master
基于主从复制实现主从节点故障转移。社区版本推出的原生高可用解决方案,其部署架构主要包括两部分:Redis Sentinel集群和Redis数据集群。
特点:1、哨兵的任务是:监控、提醒、自动故障转移;2、过半机制
优点:能实现自动故障转移
读写策略:仍然只有一个master节点,不能缓解写压力。
缺点
每隔1s发送一次心跳。如果节点没有在规定时间内响应,哨兵就会标记主观下线。
主观下线:单个sentinel认为节点下线
客观下线(只适用于主节点):过半sentinel认为节点下线-- 为了降低误判
1. 哨兵判断节点是否正常的依据?
2. 由哨兵集群中的哪个节点进行主从故障转移呢?
3.主从故障转移的过程是怎样的?
哨兵进程的工作原理?(自动故障转移机制?)
0. ”筛选+打分“
1. 筛选:剔除主从网络不好的节点,判断依据是down-after-milliseconds*10
2.1 优先级高的从库得分高,判断依据是salve-prority配置项
2.2 和旧master同步最接近的从库得分高,判断依据是master_repl_offset和salve_repl_offset
2.3 ID号小的从库得分高
哨兵如何选定新主库?
哨兵Leader选主流程?
如果有哨兵实例出现故障,主从库还能正常切换吗?
主从切换过程中,client是否正常进行请求操作?
为什么哨兵节点至少要有 3 个?
哨兵集群是如何组成的?
哨兵集群会对「从节点」的运行状态进行监控,那哨兵集群如何知道「从节点」的信息?
哨兵sentinel
Master可读可写、Slave只写,最少6个节点(三主三从)
读写策略:多个master提供读写,去中心化。主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。
可扩展性:
高可用性:
资源浪费:Redis数据节点中slave节点作为备份节点不提供服务;
数据一致性:异步复制,不保证数据的强一致。
部分命令不支持。
工作原理是什么?如何处理数据分片和故障转移?
为什么cluster采用18324(2的14次)个槽?
什么情况下会产生数据丢失?
如何保证尽量少的数据丢失?
有哪些不支持的命令?为什么不支持?
为什么要传全量的slot状态?
集群redis-cluster
特点:集成了哨兵。
可展现:可以通过添加proxy做横向扩展
优点
缺点:1.不支持事务 2.不支持部分指令
为什么codis很多命令不支持?例如keys
ZK存储路由表,过半机制保证高可靠
Codis之间的槽位同步?
Codis扩容:新增节点之后,原来的key如何迁移和分配?
集群的扩容和数据迁移
主从+哨兵机制
怎么保证高可用?
为什么大厂都喜欢用 Codis 来管理分布式集群?
实践
codis
五、集群高可用
IO多路复用机制
单线程。只是IO是单线程。
Redis为什么能那么快?Redis真的只有单线程吗?为什么用单线程?Redis有哪些潜在的性能瓶颈?Redis6.0为什么引入多线程(换而言之: 6.0之前为什么不用多线程)?会引入并发控制问题吗?
Redis是单线程的,如何提高多核CPU的利用率?
你知道有哪些Redis分区实现方案?
基于内存实现
高效的数据结构
合理的数据编码
合理的线程模型
虚拟内存映射
Redis为什么那么快?
字符串:value值过大。一般认为超过10kb就是bigKey。
非字符串:hash\\set\\list\\zeset元素过多。
什么是BigKey?
内存空间不均匀。
超时阻塞。由于redis单线程,操作bigkey比较耗时,容易阻塞。
网络拥塞。获取bigkey产生较大网络流量。
危害?
BigKey问题:什么是BigKey?BigKey有哪些危害?如何解决BigKey问题?
为什么Lua脚本的执行可以保证原子性?Lua脚本如何某个命令失败了咋办?
Lua脚本和事务有什么区别?
如何实现一个LRU算法?
redis事务是怎么实现的?
Redis的哨兵机制和集群有什么区别?
用读写锁保障强一致性
强一致性
弱一致性
先删除缓存,再写DB
先写DB,再删除缓存
先更新DB,后删除Cache
先删除Cache,后更新DB
延迟双删
缓存更新策略有哪几种策略?分别有什么问题
最终一致性
DB和Cache双写一致性?
多级缓存(本地缓存)
缓存数据不失效
读写分离
热Key问题
BigKey问题?
如何使用Redis解决并发竞争Key问题?
加随机值
缓存预热
缓存雪崩(缓存同一时间大面积的失效,造成大量请求打到DB)
缓存穿透(访问一个不存在的key)
互斥锁
热点数据不失效
缓存击穿
缓存异常有哪些情况?
延迟队列
令牌桶
漏桶
滑动窗口
计数器
限流
批量拉取,本地缓存
作为分布式ID,如何保障可用性?
设计一个缓存系统,需要考虑哪些问题?
六、面试题
图解Redis
参考文献
Redis_V2023
0 条评论
回复 删除
下一页