redis的所有数据结构都以唯一的key作为名称,然后通过key获取对应的value数据,不同类型的数据结构的差异就在于value的结构不一样。
字符串String是redis中最简单的数据结构,也是我们最常用的。它的内部结构就是一个字符数组,底层是由SDS,即"simple dynamic string"来实现的,SDS结构入下:
stryct SDS<T>{
T capacity; //数组容量
T len; //数组长度
byte flags;
byte[] cotent; //数组内容
}
也可以通过下图来更好理解:
SDS是动态字符串,内部实现类似与ArrayLisk,采用预分配空间的方式来减少内存的频繁分配,所以一般字符容量capacity
要高于实际字符长度len
。
当字符串长度小于1MB,扩容是加倍现有空间,
当字符串长度大于1MB,扩容时一次只会多扩1MB,
字符串长度最大为512MB。
redis的list结构是个链表,相当于LinkedList,但是底层其实是由ziplist
+quicklist
实现的。
ziplist
在元素个数较少时使用,采用压缩列表,是一块连续的内存空间,元素之间紧挨着存储,没有任何冗余空间,不像SDS。
由于ziplist
是没有冗余空间的,所以每次新增元素都需要扩容,如果ziplist
占据内存太大,重新分配内存和拷贝内存就会有很大消耗,所以它不适合存储大型字符串,数量也不宜过多。
quicklist
在元素个数较多时使用,它就是把ziplist
当作元素,多个ziplist之间使用双向指针串起来。
struct quicklistNode{
prev;
next;
ziplist*zl; //指向压缩列表
int32 size; //ziplist的字节总数
int16 count; //ziplist中的元素数量
...
}
redis的hash字典相当于hashMap
,都是数组+链表结构,不同的是,redis的字典只能是字符串,并且rehash方式不一样。
java的HashMap在字典很大的时候,是个很耗时的操作,因为需要一次性全部rehash。 redis为了追求高性能,采用渐进式rehash。它会保留新旧2个hash结构,查询时会同时查询2个hash,然后在定时任务中循序渐进的将旧的hash迁移到新的hash中。
redis的set类似于java的hashtable
zset类似于SortedSet和HashMap的结合体,技能保证元素唯一,又可以排序。 它的内部实现是跳表。
不支持回滚
单线程不会浪费CPU吗?官网说:cpu不是redis的瓶颈,内存和网络才是,单核已经够用了
redis慢的原因?
建议:
redis会把设置过期时间的key单独放到一个字典中去处理,它的过期策略有如下三种:
LRU原理推荐阅读这篇文章:LRU原理
redis的持久化机制有2种:
RDB 是redis默认的持久化方案。
它指的是只要满足一定条件,redis会把内存中的所有数据生成快照文件dump.rdb
,保存在磁盘上。
save (seconds) (changes)
save 900 1 #900秒内如果超过1个key被修改,则发起快照保存
save 300 10 #300秒内容如超过10个key被修改,则发起快照保存
这几个规则是叠加相互作用的。
save
命令,但是会阻塞
bgsave
命令会异步执行 fork一个子进程进行持久化,主进程继续接收客户端请求 但是bgsave执行之后的数据不会被保存
AOF就是将redis执行过的命令保存到appendonly.aof
文件中,后续恢复的时候执行AOF中的命令。
appendonly yes //启用aof持久化方式
# appendfsync always //每次收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用
appendfsync everysec //每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,默认是这个
# appendfsync no //完全依赖os,性能最好,持久化没保证
AOF的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test
命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100就够了。
redis会fork一个子进程,从redis数据中重建一个AOF临时文件,最后用临时文件替换旧文件。
触发机制: 达到上次重写的100% 超过AOF指定大小
重写AOF时有新的命令进来了怎么办? 有一个AOF重写缓存,主进程把新进来的命令写到缓存中,当子进程重新完毕,最后把缓存并入AOF中。
RDB: 恢复速度快 会造成数据丢失 如果bgsave时数据量庞大,会影响性能,造成卡顿
AOF: 数据完整性更好 但是文件会比较大
AOF和RDB是可以一起配合使用的
面试: 如果同一时间有大量的key过期,会有什么后果?