Redis设计与实现,以及关于Redis使用的总结
Redis自己构建了简单动态字符串(Simple Dynamic String,SDS)来作为默认的字符串表示。 SDS的构造如下:
优势是:
Redis采用跳跃表作为有序集合键的底层数据结构,另:在集群节点中用作内部数据结构 跳跃表:一种有序数据结构,通过在一个节点维持多个指向其他节点的指针,从而达到快速访问节点的目的。支持平均O(logN),最差O(N)复杂度的查找。 Redis中跳跃表的实现:
其中包括表头和表尾节点,length记录节点的数量,level用于获取跳跃表中层高最大的那个节点的层数量 (表头节点的层高不计算在内)
Redis中集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合中元素的数量不多时,就会使用整数集合作为集合键的底层实现。 整数集合的升级策略:能够提高整数集合的灵活性,并且能够尽可能的节约内存。升级后不支持降级
Redis中列表键和哈希键的底层实现之一。
Redis使用上述的数据结构创建了一个对象系统。包括:字符串对象、列表对象、哈希对象、集合对象和有序集合对象。其实这就是一直说的Redis五种数据结构:字符串、列表、字典、集合、有序集合。
Redis服务器讲所有数据库保存在一个db数组中,默认创建16个数据库。
切换数据库:select 0 #选择0号数据库
键空间的键也是数据库的键。每个键都是一个字符串对象。 键空间的值也是数据库的值,每个值可以是字符串对象、列表对象、哈希对象、集合对象,有序集合对象中的任意一个Redis对象。 一个键空间的例子:
原理是:过期时间是一个UNIX时间戳,当键的过期时间来临是,服务器就会自动从数据库中删除一个键。 命令:
expire <key> <ttl> #key的生存时间为ttl秒
pexpire <key> <ttl> #key的生存时间为ttl毫秒
expireat <key> <timestamp> #key的生存时间直到timestamp指定的时间戳s
pexpireat <key> <timestamp> #key的生存时间直到timestamp指定的时间戳ms
persist <key> #移除key的过期时间
ttl <key> #计算key的剩余生存时间
setex命令可以设置一个字符串键的同时为键设置过期时间。 一个带有过期字典的数据库例子:(实际中,键空间的键和过期字典中的键都指向同一个键对象)
通过保存数据库中的键值对来记录数据库状态不同。 功能:将Redis在内存中的数据库状态保存到磁盘中,避免数据意外丢失。RDB文件是一个经过压缩的二进制文件,保存在硬盘中,因此Redis进程退出,只要RDB文件仍在,就可以用来还原数据库的状态。
服务器在载入RDB文件期间,会一直阻塞。 SAVE命令由服务器进程执行保存工作,因此会阻塞服务器。BGSAVE命令由子进程执行保存工作。
设置服务器配置的save选项,让服务器每隔一段时间自动执行一次BGSAVE命令。
save 900 1 # 900s内发生了至少一次修改
save 300 10
save 60 10000
满足上述一个条件,BASAVE就会执行。
头部 | 数据库版本 | 数据 | 正文结束符 | 校验和 |
---|---|---|---|---|
REDIS | db_version | databases | EOF | check_sum |
通过保存Redis服务器所执行的写命令来记录数据库状态。
命令追加:将内容追加到aof_buf缓冲区的末尾。 写入与同步:服务器每次结束一个时间循环之前,都会调用flushAppendOnlyFile函数,考虑是否将aof_buf缓冲区中的内容写入和保存到AOF文件中。选项值为:alwals,everysec,no 载入与数据还原:还原过程:创建一个不带网络连接的伪客户端;从AOF文件中分析并读取一条写命令;使用伪客户端执行被读出的写命令;循环处理。
目的:解决AOF文件体积膨胀。 实现原理:从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令。 后台重写:子进程AOF重写期间,服务器进程可以继续处理命令请求。 后台重写问题:子进程重写期间,服务器还需要处理命令请求,可能导致服务器当前数据库状态和重写后的AOF文件所保存的数据库状态不一致。解决办法:AOF重写缓冲区。
文件事件处理器。基于Reactor模式,使用IO多路复用程序同时监听多个套接字。
使用setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。 如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样? 同时把setnx和expire合成一条指令来用
假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如果将它们全部找出来? 用keys指令可以扫出指定模式的key列表。 redis的单线程的。keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。
Redis可以使用主从同步,从从同步。第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。
最近最久未用算法。当内存达到限制时,Redis 具体的回收策略是通过 maxmemory-policy 配置项配置的。 no-eviction:不清除数据,只是返回错误,这样会导致浪费掉更多的内存,对大多数写命令(DEL 命令和其他的少数命令例外) allkeys-lru:从所有的数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰,以供新数据使用 volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰,以供新数据使用 allkeys-random:从所有数据集(server.db[i].dict)中任意选择数据淘汰,以供新数据使用 volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰,以供新数据使用 volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰,以供新数据使用
NoSQL,泛指非关系型的数据库,全称Not Only SQL,意即“不仅仅是SQL”。 NoSQL数据库的四大家族:
默认10000
https://www.bookstack.cn/read/note-of-interview/framework-redis.md http://www.techug.com/post/nosql.html