redis的所有数据结构都以唯一的key作为名称,然后通过key获取对应的value数据,不同类型的数据结构的差异就在于value的结构不一样。
Sting list hash set zset 1.1、string1.1.1、结构字符串String是redis中最简单的数据结构,也是我们最常用的。它的内部结构就是一个字符数组,底层是由SDS,即"simple dynamic string"来实现的,SDS结构入下:
stryct SDS<T>{ T capacity; //数组容量 T len; //数组长度 byte flags; byte[] cotent; //数组内容 }也可以通过下图来更好理解:
1.1.2、特点SDS是动态字符串,内部实现类似与ArrayLisk,采用预分配空间的方式来减少内存的频繁分配,所以一般字符容量capacity要高于实际字符长度len。 当字符串长度小于1MB,扩容是加倍现有空间, 当字符串长度大于1MB,扩容时一次只会多扩1MB, 字符串长度最大为512MB。
1.2、listredis的list结构是个链表,相当于LinkedList,但是底层其实是由ziplist+quicklist实现的。 ziplist在元素个数较少时使用,采用压缩列表,是一块连续的内存空间,元素之间紧挨着存储,没有任何冗余空间,不像SDS。 由于ziplist是没有冗余空间的,所以每次新增元素都需要扩容,如果ziplist占据内存太大,重新分配内存和拷贝内存就会有很大消耗,所以它不适合存储大型字符串,数量也不宜过多。
quicklist在元素个数较多时使用,它就是把ziplist当作元素,多个ziplist之间使用双向指针串起来。
struct quicklistNode{ prev; next; ziplist*zl; //指向压缩列表 int32 size; //ziplist的字节总数 int16 count; //ziplist中的元素数量 ... } 1.3、hashredis的hash字典相当于hashMap,都是数组+链表结构,不同的是,redis的字典只能是字符串,并且rehash方式不一样。
java的HashMap在字典很大的时候,是个很耗时的操作,因为需要一次性全部rehash。 redis为了追求高性能,采用渐进式rehash。它会保留新旧2个hash结构,查询时会同时查询2个hash,然后在定时任务中循序渐进的将旧的hash迁移到新的hash中。
1.4、setredis的set类似于java的hashtable
1.5、zsetzset类似于SortedSet和HashMap的结合体,技能保证元素唯一,又可以排序。 它的内部实现是跳表。
二、redis事务不支持回滚
三、redis单线程 优点: 快、避免创建销毁线程的消耗、避免CPU上下午切换、避免资源竞争(加锁、死锁) 缺点: 执行lua有死循环风险,整个redis服务端都会被阻塞,busy redis 解决: 设置lua超时时间,script kill、shutdown nosave 钩子函数单线程不会浪费CPU吗?官网说:cpu不是redis的瓶颈,内存和网络才是,单核已经够用了
四、redis为什么快? 读取内存 KY数据结构,数据复杂度是O1 单线程 异步非阻塞IOredis慢的原因?
检查RDB配置,是否每隔900s同步一次。 改为凌晨1点同步,因为RDB是全量的,磁盘IO操作建议:
主节点:AOF,不影响使用 从节点:RDB 五、过期策略redis会把设置过期时间的key单独放到一个字典中去处理,它的过期策略有如下三种:
定时扫描 redis默认每秒进行10次过期扫描,但不是扫面全部,而是采用一种简单的贪心策略: 从过期字典中随机选出20个key; 删除这20中过期的key; 如果过期的key超过1/4,就重复步骤; 同时为了避免循环过度,算法增加了扫面时间限制,默认不会超过25ms。 懒惰过期 只在用到这个key的时候,进行判断,然后删除 优点:不占用cpu 缺点:占用内存 定期过期: 达到最大内存阈值的时候,扫描一定数量进行删除 从节点过期策略 从节点不会进行过期扫描,当主节点删除过期key时,会同步del指令到aof文件,同步给所有从节点。 六、内存淘汰策略 volatile-LRU :只对设置了过期时间的key进行LRU淘汰 allkeys-LRU: 对所有key进行LRU volatile-LFU: 访问频率少的淘汰掉 allkeys-LFU: volatile-random:随机 allkeys-random: volatile-ttl:把最近要过期的key淘汰掉LRU原理推荐阅读这篇文章:LRU原理
七、持久化机制redis的持久化机制有2种:
RDBAOF7.1 RDB7.1.1、什么是RDBRDB 是redis默认的持久化方案。 它指的是只要满足一定条件,redis会把内存中的所有数据生成快照文件dump.rdb,保存在磁盘上。
7.1.2、RDB的触发机制: 满足配置条件时 redis有以下几个默认配置: save (seconds) (changes) save 900 1 #900秒内如果超过1个key被修改,则发起快照保存 save 300 10 #300秒内容如超过10个key被修改,则发起快照保存 这几个规则是叠加相互作用的。 停机的时候 shutdown flushall 手动触发 save命令,但是会阻塞 bgsave命令会异步执行 fork一个子进程进行持久化,主进程继续接收客户端请求 但是bgsave执行之后的数据不会被保存 7.2 AOF7.2.1、什么是AOFAOF就是将redis执行过的命令保存到appendonly.aof文件中,后续恢复的时候执行AOF中的命令。
7.2.2、触发机制appendonly yes //启用aof持久化方式 # appendfsync always //每次收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用 appendfsync everysec //每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,默认是这个 # appendfsync no //完全依赖os,性能最好,持久化没保证 7.2.3、重写机制AOF的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100就够了。
redis会fork一个子进程,从redis数据中重建一个AOF临时文件,最后用临时文件替换旧文件。
触发机制: 达到上次重写的100% 超过AOF指定大小
重写AOF时有新的命令进来了怎么办? 有一个AOF重写缓存,主进程把新进来的命令写到缓存中,当子进程重新完毕,最后把缓存并入AOF中。
7.3 AOF于RDB比较RDB: 恢复速度快 会造成数据丢失 如果bgsave时数据量庞大,会影响性能,造成卡顿
AOF: 数据完整性更好 但是文件会比较大
AOF和RDB是可以一起配合使用的
面试: 如果同一时间有大量的key过期,会有什么后果?
---来自腾讯云社区的---大王叫下
微信扫一扫打赏
支付宝扫一扫打赏