Redis 原理
2020-10-17 11:05:04 23 举报
Redis原理总结(Redis设计与实践)
作者其他创作
大纲/内容
len:3
int argc
元素个数
MUTIL:开启事务
注意:1. dictType *type 指针指向一系列操作字典函数指针集合(一个结构 体),可以通过设置不同的 dictType *type 来处理不同类型的字典(键值对类型决定字典的类型)2. void *private ,执行 dictType *type 指向的函数时传入的数据参数3. int rehashIdx 记录了当前rehash情况,没有进行rehash时为-14. dictht ht[2] 存在两个hash表方便扩容(扩容时将一个表的数据移到 另外一个表中)
套接字
事务
从服务器
int slave_listening_port
Redis事件
dictType
Redis如果保证事务的ACID
前进指针
订阅字典(key->链表)
字符串数组 以‘\\0' 结尾
关于AOF持久化:1. 对于客服端的命令AOF将会先写入到aof_buff缓存中,并且按一定的频率将缓存中的内容刷新到os_buf中,最后os同步到磁盘中2. 参数appendfsync来控制AOF的写入频率: no:Redis中有一个循环时间,每次循环结束都将aof_buf中的内容同步到os_buf,而os_buf何时写入磁盘由操作系统决定 always:每次循环结束都将aof_buf中的内容同步到os_buf,并且强制操作系统将os_buf写入磁盘 everysec:每秒中将aof_buf -> os_buf -> 磁盘文件
head
事务队列
编码转换:集合中包含非整数字符串或数量大于512时转换成字典
返回结果
4
客服端
命令
os_buf
NULL
固定大小输出缓冲区
SYNC
遍历套接字
SLAVEOF ip:port
磁盘
命令传播
如果服务器打开了maxmemory功能,并且内存回收失败返回error
entry2
int
调用命令执行器
对比键函数指针
void *value
ptr
元素数组
redisDb
复制的整个流程
key_value_pairs(包含0或多个该结构)
buff数组当前剩余空间
分数
更redisCommand结构的milliseconds和calls属性
zlbytes
未通过身份验证的客户端只能执行AUTH命令.返回error
int len
zltail
流程:Redis会创建一个新的AOF文件 --> 直接扫描数据库中的键,通过命令的方式写入AOF文件中(该过程不会与旧的AOF有任何交互)注意:为了避免key-value中value过大导致缓冲区溢出,可以将其分成多个命令写入64
int fd
......
unsigned int type
int8_t content[]
embstr优势(连续空间分配)1.内存分配和释放只需要一次2.充分利用到了局部性原则
载入配置文件
调用命令的实现函数
0
缓冲区所有写命令
int masterport
dict *watched_keys
RDB文件结构
redisClient
Redis
载入
身份是否已验证
redisDB *db
关于rehash1.负载因子:load_factor = ht[0].used / ht[0].size2.负载因子大小:服务器在BGSAVE或BGREWRITEAOF时(写日志时)大于等于5否则大于等于1为什么写日志时load_factor为5?在进行写入日志AOF或RDB时,Redis会创建子进程,而大多数操作系统都采用的写时复制技术(子进程会与父进程共享一块内存只有当进程进行写入操作时才会复制一份副本)来提高效率,所以在写日志的时候尽量避免进程对内存的写而导致副本的拷贝来提升内存效率。3.字典超过负载因子指定的值时进行渐进性扩容,小于0.1时进行收缩4. 扩容过程(渐进性) 为ht[1] 分配空间(大小为大于等于ht[0].used 的第一个2次幂的数)-> 将ht[0]中的键值对rehash并且不断的加入到ht[1]中(此过程可以对字典进crud, 查看,删除,更新操作在ht[0]或ht[1]上进行,增加操作在ht[1]上进行) -> 完成一个操作rehashIdx不断加1 -> 直到ht[0]中不存在键值对将ht[1]进行交换 ht[0]
文件结尾表示符
为了避免数据的丢失我们通常使用日志文件来保存数据。
PSYNC
五大对象
3.哈希对象(2种编码)
同时使用跳跃表和字典
hash冲突时形成链表
AOF文件的载入
RDB文件:1. 压缩的二进制文件2. 对于不同类型的value ,会通过底层数据结构进行不同的保存
intset
double sorce
计算hash值函数指针
SELECTDB
hash表数组大小为2
发现主服务器新的从服务器与这些从服务器创建命令和订阅连接
int flag
entryN
发送ping命令(保证主从正常通信)
EXEC:顺序执行队列中的命令
生成
字典(键和值都是String对象)
复制 / Sentinel(哨兵)
5
db_version
embstr编码(<32Byte)
如果客户端当前正在用SUBSCRIBE命令订阅频道,或者正在用PSUBSCRIBE命令订阅模式,那么服务器只会执行客户端发来的SUBSCRIBE、PSUBSCRIBE、UNSUBSCRIBE、PUNSUBSCRIBE四个命令,其他命令都会被服务器拒绝。
sds aof_buf
如果服务器因为执行Lua脚本而超时并进入阻塞状态,那么服务器只会执行客户端发来的SHUTDOWN nosave命令和SCRIPT KILL命令,其他命令都会被服务器拒绝。
客服端通过发送slaveof 命令让从服务器复制主服务数据从而达到数据库一直的状态。从服务器:为了减轻主服务器压力分担一些读操作主服务器:可以进行读写操作
int free
载入:在Redis服务启动时会先判断是否有AOF日志有则载入AOF文件(之后不再载入RDB日志),否则判断是否有RDB日志有则载入。生成:服务器运行期间通过SAVE 或 BGSAVE命令可以生成RDB日志文件SAVE:SAVE命令执行期间所有其他线程都将阻塞,服务器拒绝所有客服端的请求,因为SAVE命令是在父进程中进行的。BGSAVE:BGSAVE命令执行期间可以同时执行客服端命令,BGSAVE是通过fork()开启了一个子进程,但是该命令期间服务器不允许执行SAVE/BGSAVE命令会产生竞态条件,也不允许执行BGWRITEAOF考虑到数据库性能问题。(fork系统调用:点击这里)
robj **argv
RDB文件
intset编码格式
写入OS缓冲区
跳表中节点数
char buf[常数]
db_number
k
编码转换:数量大于128个或成员长度大于64字节时转换dict和ziplist
文件事件处理器1
客服端/服务端
databases(包含0或多个该结构)
键和值总是紧挨在一起的
值
SDS
Redis是基于键值对的数据库,一个键是一个对象,一个值也是一个对象。1.键对象只能值字符串对象2.值对象可以是:字符串,哈希表,列表,集合,有序集合对象
尾节点
实际存键值对的地方
载入日志文件
注意:连锁更新虽然影响性能但是发生的条件苛刻,所以一般不考虑
键
特折:1.双向链表2.链表节点值可以是不同类型(void *)3.可以O(1)计算出链表长度4.节点操作函数可以动态指定
链表长
命令执行前
entry的个数
数据库号
数据库数组
2.列表对象(2种编码)
pre
关于RDB / AOF / 复制 时对过期键的处理:RDB文件的生成会忽略掉过期键,RDB载入时:1.主服务器模式下:忽略过期键 2.从服务器模式下:不忽略过期键AOF文件的生成不会忽略过期键会显示的在该键之后增加一个DEL命令,AOF文件重写时会忽略掉过期键复制模式下从服务器不会主动对过期间进行删除出除非主服务器发送DEL命令采用导致过期键的删除
list *clients
判断协议格式
buff数组当前长度不包括 '\\0'
sds querybuf
是否需要写入慢日志
后退指针
check_sum
1
开启循环事件
intset(整数集合)
服务器初始化过程
void *private
集合数据都是整数且数量不多时
ziplist编码
5.有序集合对象(2中编码)
事务执行过程
关压缩列表的连锁更新问题:previous_entry_length: 如果前一节点的长度小于254字节,那么previous_entry_length属性需要用1字节长的空间来保存这个长度值。 如果前一节点的长度大于等于254字节,那么previous_entry_length属性需要用5字节长的空间来保存这个长度值。如下情况存在连锁更新: 1. 如果链表中连续存在多个节点previous_entry_length属性大小为253字节,假如该连续节点第一个节点大小修改成了大于254个 字节,此时该节点 的后续节点将要修改previous_entry_length的值,此时该后续节点变为257字节,此时该节点后续节点又需要修改previous_entry_length的值.... 2.删除节点也存在连锁更新
Redis的时间事件分为以下两类:定时事件:让一段程序在指定的时间之后执行一次。比如说,让程序X在当前时间的30毫秒之后执行一次。周期性事件:让一段程序每隔指定时间就执行一次。比如说,让程序Y每隔30毫秒就执行一次。(Reids仅使用周期时间)时间事件组成:ID,何时到达,时间处理器Redis时间时间都放在一个链表中:需要区遍历链表查看已到任务serverCron函数(Redis一般仅有一个时间时间就是其):工作任务:更新服务器的各类统计信息,比如时间、内存占用、数据库占用情况等。清理数据库中的过期键值对。关闭和清理连接失效的客户端。尝试进行AOF或RDB持久化操作。如果服务器是主服务器,那么对从服务器进行定期同步。如果处于集群模式,对集群进行定期同步和连接测试。
Redis根据对象中数据特征使用不同的数据结构来提供效率
dictEntry(节点)
v
dictEntry **table
检查cmd是否为null
为了避免重写期间客服端新来的命令导致数据库与AOF文件不一致Redis提供AOF重写缓冲区,重写期间新来的命令也会加入到AOF重写缓冲区和AOF缓冲区中。前者可以在AOF重写完成后将缓冲区数据以命令方式载入新的AOF文件中去,后者保证旧的AOF文件正常工作。
文件事件处理器3
底层数据结构
节点复制函数
私有数据
struct zskiplistNode *backword
int refcount
dictType *type
AOF执行机制
ListNode *head
套接字相关(伪客服端时为-1)
压缩列表(ziplist)是列表键和哈希键的底层实现之一。当一个列表键只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用压缩列表来做列表键的底层实现。
1.字符串对象(3种编码)
客服端所扮演的角色
字典编码
节点值可以是一个字节数组或者整数,值的类型和长度由节点的encoding属性决定
EOF
并且以10s/次发送INFO获取从服务器信息
格式转换:列表元素大于64bytes或元素个数大于512个时ziplist编码将会转换成linkedlist
可变大小缓冲区
命令和参数保存到argv和argc中
void* value
返回PONG表示正常
跳表头尾节点
key
..
注意:1. 哈希算法(redis采用MurmurHash算法) index = (dict->type->hash函数(key)) & dictht.sizemask注意:这里使用了 &运算代替了取余 (提高效率) 如 hashcode % size = hashcode& (size - 1) 该式子成立的前提时size必须是2的次幂,因此我们dictht.table 的大小dictht.size总是2的次幂2. size表示table大小 , sizemask = size - 1用于确定下标是与运算3. key 是键 , v 是值可以是void* / int64 / unsigned int 644. hash冲突时使用头插法形成链表
不符合规范关闭客服端连接
头节点
tail
zlend
unsigned long length
struct dictEntry *next
A:Redis通过事务队列保证原子性,但是事务不支持回滚(当队列中某个命令出错时,队列其他命令仍然继续执行下去直到结束),不支持回滚的原因,官方文档中说命令出错是编程的错误,而实际环境中不会发生C:1.入队错误,拒绝事务 2.执行错误将会继续执行下去 3.服务器宕机数据全部丢失时数据库是一致的,有日志文件恢复时数据库是一致的I:Redis是单线程的事务也是在该线程中串行执行的D:AOF和RDB
文件事件(网络通信相关)
指向底层数据结构的指针
节点属性:1. struct zskiplistNode *forward 根据 span(跨度)的值指向离当前节点 span距离的节点2. struct zskiplistNode *backword 指向当前节点前一个节点3. level[] 其大小是1 到 32中随机生成的一个数注意:跳表与链表的区别多了level[]数组 ,即当前节点可以指向不仅仅只有下一个节点了可以指向离当前节点更远的节点跳表的数据是根据sorce排序的跳表实现了有序集合
skiplist(跳表)
dict(字典)
判断内存情况
为客服端关联回复缓冲器
检验和
将命令格式放入输入缓冲区
文件事件处理器2
pexpireat
struct saveparam *saveparams
符合规则
常量字符串
缓冲区中数据长度
表示当前对象被引用次数(为0时释放)
文件事件分发器
摧毁值函数指针
客服端链表
7
unsigned long len
上一次成功执行完SAVE/BGSAVE的时间
zllen
redisObject
跨度
RDB执行频率配置,从配置文件获取该值,(秒/修改次数)
客服端关闭:1. 网络关闭导致客服端关闭 2. 客服端发送不符合规范的协议 3. timeout客服端超时 4.输入输出缓冲区过大时强制关闭 5.服务器主动clientkill服务器使用两种模式来限制客户端输出缓冲区的大小:❑硬性限制(hard limit):如果输出缓冲区的大小超过了硬性限制所设置的大小,那么服务器立即关闭客户端。❑软性限制(soft limit):如果输出缓冲区的大小超过了软性限制所设置的大小,但还没超过硬性限制,那么服务器将使用客户端状态结构的obuf_soft_limit_reached_time属性记录下客户端到达软性限制的起始时间;之后服务器会继续监视客户端,如果输出缓冲区的大小一直超出软性限制,并且持续时间超过服务器设定的时长,那么服务器将关闭客户端;相反地,如果输出缓冲区的大小在指定时间之内,不再超出软性限制,那么客户端就不会被关闭,并且obuf_soft_limit_reached_time属性的值也会被清零。
AOF文件
next
时间事件
dict(字典使用哈希表实现)
网络请求
服务器载入
dictht ht[2]
属性:1. encoding 属性规定了content[] 数组中元素的大小(INTSET_ENC_INT16 ,INTSET_ENC_INT32 ,INTSET_ENC_INT64)注意:content[] 中数据按数字从小到大进行排序,并且不含重复元素当一个集合中的数据都是整数并且数量不多时底层将会使用intsetintset集合的升级:当我们向本来全是16位类型的content中插入一个32位的数据时会引发集合的升级,导致encoding变成INTSET_ENC_INT32,并且content中每一个元素都占有32位(升级机制使得内存得到了节省,只在有必要的时候进行内存的升级)(intset不支持降级)
ListNode
1.主观下线:Sentinel会每秒中的频率发ping命令给主服务器/从服务器/其他的Sentinel,如果在指定时间内多次发送没有返回将认为他们下线2.客观下线:当Sentinel发现主服务器主观下线时,他会询问其他同时监视该主服务器的Sentinel,当赞同数达到一定数量时认为该主服务器确实下线3.领头Sentinel:当认为主服务器客观下线时需要选出一个领头Sentinel来进行故障转移4.故障转移:领头Sentinel会根据网络,离线,优先级,以及ID选出一个从服务器作为新的主服务器(向选出者发送SLAVEOF no one),为其他从服务器设置新的主服务器,当离线的旧的主服务器上线时也将成为新主服务器的从服务器
过程:SYNC :从服务器项主服务器发起同步请求,主服务器接收到命令后开启BGSAVE生成RDB日志RDB :主服务将生成的RDB文件发送个从服务器发送缓冲区写任务:由于BGSAVE期间主服务器还需处理其他客服端请求,为了保证主从一致,会将期间处理过的命令写入缓冲区中,之后再发送给从服务器命令传播:之后客服端对数据库修改数据主服务器都将命令同时发送给从服务器缺点:断线重连:如果在命令传播过程中从服务器断开了连接,之后连接上主从不一致了,此时主服务器会从写将所有数据写给从服务器,即使他们之间前面大部分相同,这样做十分耗时。SYNC:十分耗时1.主服务器接收大SYNC进行BGSAVE占用大量IO/CPU/内存2.发送RDB占用大量网络带宽3.从服务器执行RDB载入阻塞其他线程命令执行
expire
模式订阅链表
正确
robj *name
Redis通过MULTI、EXEC、WATCH等命令来实现事务(transaction)功能。事务提供了一种将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕,然后才去处理其他客户端的命令请求。
非订阅命令都将拒绝
解析命令法
previous_entry_length
IO多路复用程序通过队列的方式缓存待处理的事件并且是一个一个的传给分发器,等上一个事件执行完才开始下一个任务
为null说明之前没有找到对应的命令返回一个error
void *ptr
ziplist(压缩列表)
list *pubsub_patterns
SDS(simple dynamic String)
接收命令
已验证
正常
如果服务器打开了监视器功能,那么服务器会将要执行的命令和参数等信息发送给监视器。当完成了以上预备操作之后,服务器就可以开始真正执行命令了。
是否需要AOF
保存数据库所有键值对,键是String类型值可以是五种类型
指向客服端当前使用的数据库(通过select num切换数据库)
实际数据地方
pexpire
主服务器端口
aof缓冲区
主服务器
监听的客服端端口
记录了压缩列表中前一个节点的长度
linkedlist编码(双向链表 每个节点保存一个字符串对象)
aof_buf
Sentinel哨兵机制(保证高可用)
OK回复给客服端
值和分紧挨(按分从小到大排序)
char* masterhost
大写为常量小写为变量
输入命令
写入缓冲区
关于RDB执行周期:1.通过在配置文件中设置 如save 1 10 即一秒内修改十次执行一次BGSAVE2.Redis服务器启动时会将该条件载入saveparams属性中3.Redis服务器的函数serverCron默认每个100ms会根据diry和lastsave来遍历saveparams中是否有满足条件的项,从而执行BGSAVE
robj *obj
新版复制使用PSYNC代替了SYNC
服务器保存的客服端状态:客户端的套接字描述符。客户端的名字。客户端的标志值(flag)。指向客户端正在使用的数据库的指针,以及该数据库的号码。客户端当前要执行的命令、命令的参数、命令参数的个数,以及指向命令实现函数的指针。客户端的输入缓冲区和输出缓冲区。客户端的复制状态信息,以及进行复制所需的数据结构。客户端执行BRPOP、BLPOP等列表阻塞命令时使用的数据结构。客户端的事务状态,以及执行WATCH命令时用到的数据结构。客户端执行发布与订阅功能时用到的数据结构。客户端的身份验证标志。客户端的创建时间,客户端和服务器最后一次通信的时间,以及客户端的输出缓冲区大小超出软性限制(soft limit)的时间。
Sentinel 服务器的启动和初始化:1)初始化服务器。(该过程与普通Redis服务器不同不会加载AOF/RDB)2)将普通Redis服务器使用的代码替换成Sentinel专用代码。(更换一些命令以及代码)3)初始化Sentinel状态。(初始化Sentinel结构体)4)根据给定的配置文件,初始化Sentinel的监视主服务器列表。(master指向监视的服务器)5)创建连向主服务器的网络连接。(命令连接和订阅连接)
日志原理(RDB/AOF)
新加入的键值对总是放在尾部
char[] buff
key:订阅的频道 value:订阅的用户
SDS方式(raw)字符串大小大于32Byte
list *pubsub_patterns
unsigned lru
zskiplist
6
查找命令表
检查arity是否正确
4.集合对象(2种编码)
是。返回error
long long dirty
AOF重写
关于Sentinel与服务器订阅连接的作用:Sentinel通过订阅连接来发现其他同样监视相同服务器的Sentinel,并将它们记录下来,与他们建立起命令连接(不需要订阅连接)Sentinel会以每2秒一次的频率向该订阅频道发送消息向其他订阅该频道的Sentinel证明自己的存在
命令执行函数
对象最后一次被命令程序访问的时间
value的类型
以10s/次的频率来获取当前监视的主服务器以及获得最新的从服务器列表
命令及参数
databases
为了避免AOF文件因为无效数据而导致体积过于庞大的问题,AOF提供了重写机制。例如多个相同命令是渐渐覆盖的,只保留最后一个。
dict *expires
字典类型
struct zskiplistLevel{ struct zskiplistNode *forward; unsigned int span;}level[]
zskiplistNode
int level
AOF重写Redis开启了新的进程,因此重写期间仍然可以处理客服端命令
uint32_t encoding
dictht(哈希表)
从上一次成功执行完SAVE/BGSAVE期间数据库键的修改次数
RDB
struct redisCommand *cmd
客服端名字
摧毁键函数指针
节点释放函数
同步的到文件
REPLCONF listening-port <port-number> 发送端口信息
跳表中层次最高的节点的高度
复制
给cmd赋值
Lua
服务端内部接收命令执行总过程
旧版Redis复制
新版Redis复制解决了短线时进行全盘复制的问题,引入如下3个概念:复制偏移量:主从服务器都会维护一个复制偏移量如果偏移量相同则说明数据库状态是一致的(从偏移量 <= 主偏移量)积压缓冲区:FIFO固定大小队列,主服务器会缓存一部分最近执行过得命令,当从服务器断线重连时,会根据复制偏移量来判断从服务器与主服务器数据差多少(即离线那段时间丢失的数据),并判断该部分数据是否在积压缓冲区中如果在进行部分同步(只将丢失的这部分数据发送给从服务器)服务运行ID:每次主服务器与从服务器连接时都会将自己的运行ID发送给从服务器,从而保证从服务器在断线重连时重连的是原来的主服务器
argc长度
指定该对象底层所使用的数据结构
Reactor模型
unsigned int encoding
int编码ptr直接指向一个整数(字符串的值为一个整数)
成员对象
主服务器ip
uint32_t length
int dbnum
RedisServer
value
压缩列表占用内存字节数
节点对比函数
3
time_t lastsave
list(链表)
如果服务器正在执行载入,那么客户端发送的命令必须带有l标识(比如INFO、SHUTDOWN、PUBLISH等等)才会被服务器执行,其他命令都会被服务器拒绝。
复制键函数指针
对象的类型(上面介绍的五种)
unsigned long used
监视器
注意:1.服务器开启时默认在内存中创建0~9999个对象给所有程序共享(由于int整数操作的时间复杂度为O(1)效率高所以进行预先分配,如果预想分配的是字符串对象操作复杂度为O(N)或更加复杂的对象如链表集合等操作复杂度为O(N^2)考虑到效率所以Redis只分配整数对象)
如果客户端正在执行事务,那么服务器只会执行客户端发来的EXEC、DISCARD、MULTI、WATCH四个命令,其他命令都会被放进事务队列中。
2
OxFF标记压缩列表末端
WATCH指令
void* key
通过字典,可以O(1)获得成员的分值字典和跳表同时指向共享的成员和分数
Redis服务器是一个事件驱动程序,服务器需要处理以下两类事件:文件事件(file event):Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接,而文件事件就是服务器对套接字操作的抽象。服务器与客户端(或者其他服务器)的通信会产生相应的文件事件,而服务器则通过监听并处理这些事件来完成一系列网络通信操作。时间事件(time event):Redis服务器中的一些操作(比如serverCron函数)需要在给定的时间点执行,而时间事件就是服务器对这类定时操作的抽象。
事务/事件
unsigned long size
数据库数量(默认大小为16)
输入缓冲区
size - 1
SLAVEOF ip:port
RDB文件表示(常量)
redisServer
IO多路复用程序
执行结果写入输出缓冲区
content
过期键删除策略:1.三种删除策略 定时删除:设置一个定时器(需要用到服务器的时间事件而事件事件使用无序链表实现需要O(N)复杂度)保证内存无效键的尽快删除,存在影响吞吐量问题 惰性删除:只有在取到过期键时删除该键,容易导致内存泄漏(有些过期键永远无法被释放) 定期删除:控制系统删除过期键的频率2.Redis采用了策略 惰性删除 + 定期删除:每次对数据库进行crud时会先检查键是否过期过期则删除,Redis会定期扫描数据库,并用current_db来记录当前已扫描到的数 据库,每扫描到一个数据库会随机选取一部分键进行检查其是否过期并进行删除操作
expireat
建立套接字连接
dict *pubsub_channels
时间调度过程
如果redisCommand结构的arity属性的值为-3,那么用户输入的命令参数个数必须大于等于3个才行。返回error
dict *pubsub_channels
key_value_pairs
过期字典保存了键的过期时间
新版Redis复制
与 C字符串 区别1. SDS 遵循C字符串以'\\0'结尾,可以调用C库中的部分函数。2. SDS 通过len记录了字符串数组的长度,获取字符串长度时间复杂度为O(1)3. C 字符串没有边界检查可能引发缓冲区溢出问题,即当两个紧挨的字符串当前一 个字符串被赋上更长的值时可能会覆盖掉第二个字符串部分位置,SDS通过free 来防止缓冲区溢出。4. 内存重分配带来的性能问题 a. C字符数组在每次修改时都会进行相关的内存扩展或收缩(比较耗时) b. SDS 通过内存预分配 和 惰性空间释放 避免了内存的频繁分配 (内存预分配:当扩展字符串数组时两种情况 1. < 1MB 分配时多分配当前len长度字符 2. > 1MB 分配时多分配 1MB 长度字符串) (惰性空间释放: 字符串数组收缩时不会立刻释放多余空间会先保存在free中)5. C字符串是以'\\0'结束因此只能保存文本数据不能保存二进制数据,SDS有len属 性可以根据其来判断数据是否结束而不是 '\\0'
entry1
TYPE
压缩列表为节点地址距离起始位置多远
客户端通过订阅给定的频道或者模式,来获知数据库中键的变化,以及数据库中命令的执行情况。(subscribe 命令)键空间通知:某个特定键执行了某些命令键事件通知:某个命令被那些键执行了
encoding属性记录了节点的content属性所保存数据的类型以及长度
list *reply
注意:1.如果字符串是浮点数将先转换成字符串存起来,取出来时会将字符串又转换成浮点数返回。2.embstr字符串是只读数据,当对该编码方式修改时总是会转换成raw格式再修改3.int编码修改成非整数的字符串时会转换成 raw格式
非null
过期键相关:设置多少秒/毫秒后过期: expire key 秒 ; pexpire key 毫秒;expireat key 秒时间戳;pexpireat key 毫秒时间戳;查看键多少秒/毫秒过期:ttl key;pttl key;移除过期时间:PERSIST key;
dict *dict
格式转换:列表元素大于64bytes或元素个数大于512个时ziplist编码将会转换成字典编码
ziplist
命令转换成协议格式发送给服务器端
int rehashIdx
初始化结构体状态等
list
数据库原理
订阅
订阅的模式 :节点(client:模式)
AUTH NUM(身份验证 与主服务requirepass设置相同时通过)
内存
输入命令并入队
union{void*val;uint64_tu64int64_ts64}v
encoding
ListNode *tail
WATCH指令监视的键
数据库版本号
BGSAVE出错
编码方式
是否需要命令传播
unsigned long sizemask
否
Sentinel执行过程
int bufpos
如果服务器上一次执行BGSAVE命令时出错,并且服务器打开了stop-writes-on-bgsave-error功能,而且服务器即将要执行的命令是一个写命令,那么服务器将拒绝执行这个命令,并向客户端返回一个错误。
REDIS
0 条评论
回复 删除
下一页