Redis
2022-06-02 15:51:36 0 举报
基于黄健宏版《Redis设计与实现》整理
作者其他创作
大纲/内容
clusterNode *importing_slots_from[16384]存当前节点正从其他节点导入的槽
AOF:过期键被删后,AOF文件被追加DEL命令AOF重写时检查过期键
\\0
int flags实例类型及当前状态
哈希表节点
int tilt是否进入tilt模式
length节点数,不算表头
固定大小缓冲区:存长度较小的回复可变大小缓冲区:存长度较大的回复
建立好连接后订阅sentinel_:hello频道,哨兵收到频道信息时检查:信息中的sentinel运行id和接收信息的sentinel运行id相同说明该信息是自己发的,丢弃,不同时会根据信息的参数更新相应主的实例结构通过该频道发现新的sentinel后建立命令连接
服务器结束事件循环前调flushAppendOnlyFile函数考虑是否将缓冲区内容写入和保存到AOF,函数行为由appendfsync决定:always:同步缓冲区所有内容并写入AOF文件everysec:默认,同步缓冲区所有内容写入到AOF文件,如上次同步时间离现在超过1s则再次同步,由一个线程专门执行同步no:将缓冲区所有内容写入到AOF文件但不对文件进行同步,何时同步由系统决定
uint16_t zllen节点数(值<65535时是节点数,值=65535时要遍历计算)
dictht ht[2]哈希表
连接:通过网络连接的普通客户端:用connect函数连到服务器时,服务器调连接事件处理器为其创建相应的客户端状态并将其加到clients表尾Lua伪客户端:服务器初始化时创建执行Lua脚本中包含的redis命令的伪客户端,并将其加到lua_clientAOF文件的伪客户端:载入AOF文件时创建用于执行AOF文件包含的redis命令的伪客户端,载入完成后将其关闭
null
L3
unsigned lruclock:22默认每10s更新一次的时钟缓存算键的空转时长用
故障转移:领头哨兵把已下线所有从存到列表1、从 中选新主:删列表中所有处于下线或断线的从、删列表内最近5s没回复过领头哨兵的INFO命令的从、删所有与已下线主连接断开超过down-after-milliseconds*10ms的从;领头哨兵根据从的优先级对剩下的从排序,优先级相同按从的复制偏移量排,偏移量相同按运行id排,选运行id最小的从;领头哨兵每1s一次向新 主发INFO并观察回复中的角色信息,当新主角色变为master时新主成功升级2、其他从复制新主3、下线主设为新主的从:重新上线后复制新从
int8_t contents[]保存元素的数组
RDB文件结构二进制数据
mstime_t tilt_start_time进入tilt模式的时间
mstime_t down_after_period实例无响应多少ms后被判为主观下线
关闭:强退、发了不合协议格式的命令、成为Client kill的目标、服务器设置timeout、命令超过输入缓冲的限制、命令回复超过输出缓冲的限制
p199 命令执行器:查命令实现(命令表是个字典,k是命令名,v是redisCommand,存命令实现信息)、执行预备操作、调命令的实现函数、执行后续工作
所有对库修改的命令执行后调multi.c/touchWatchKey函数对字典检查,看是否有客户端正监视刚被改过的键,有touchWatchKey函数会把监视被改键的客户端REDIS_DIRTY_CAS标识打开,标识事务安全性被破坏
集群节点状态
L4
int port
2
BW
int authenticated身份验证标志0:未通过身份验证1:已通过身份验证
struct zskiplistNode *backward后退指针
每个节点可以存一个字节数组或一个整数字节数组可以是:长度<=63*(2^6-1)字节的字节数组长度<=16383*(2^14-1)字节的字节数组长度<=4294967295*(2^32-1)字节的字节数组整数可以是:4位长,介于0~12间的无符号整数1字节长的有符号整数3字节长的有符号整数int16_t类型整数int32_t类型整数int64_t类型整数
命令要处理的键恰好属于正被迁移的槽:源节点自查,有就直接执行命令,没有则返回ASK,指引客户端转向正导入槽的模板节点并再次发之前要执行的命令,集群模式cli不会打印错误信息客户端收到ASK错误并转向正导入槽的节点时,先发个ASKING命令,然后再发要执行的命令,如果客户端不发ASKING命令而发要执行的命令,命令会被拒绝并返回MOVED错误
encoding节点数据类型及长度
sentinel.c/sentinelState
定期删由redis.c/activeExpireCycle函数实现,每周期性操作redis.c/serveraCorn函数(次/100ms)时它会被调用:1、从一定数量(默认16)数据库随机取一定数量(默认20)键检查并删除过期键2、全局变量current_db记录检查进度,下次函数被调用时接着上次进度处理3、所有数据库被检查一遍时current_db重置为0
struct {clusterMsgDataGossip gossip[1];}pingmeet、ping、pong消息的正文
sentinel默认每10s一次向被监视的主发INFO命令获取关于主本身的信息及下属从的信息,发现新从后创建新从的实例结构并建立连接
unsigned char slots[16384/8]二进制数组,2048字节索引上值为1表示负责该槽int numslots负责处理的槽数
。。。
int refcount引用计数,内存回收用
bufchar数组
新版复制:psync替代sync:完整同步处理初次复制、span style=\"font-size: inherit;\
char *ip
节点值释放函数
对象共享:将键的指针指向一个现有的值对象将被共享的值对象refcount值加1
节点组成的链表没有指向表尾的指针,所以为了速度,新节点会加到表头
int size集群中至少处理着一个槽的节点数
哈希表
dictEntry **table哈希表数组
dict *lua_scriptsk:校检和 v:脚本
sds aof_bufAOF缓冲区
int dbnum数据库数量,默认16
char buf[redis_reply_chunk_bytes]固定大小输出缓冲区,默认16Kint bufpos存数组目前已用字节数---list *reply可变大小输出缓冲区
L2
消息:节点间通过消息通信,主要有五种MEET:发送者收到客户端的 cluster meet 命令后向消息接收者发meet消息,请求接收者加入到发送者当前所处集群PING:每个节点默认每1s从已知节点随机选5个,对这5个中最长时间没发过ping消息的节点发ping消息,发送者最后一次收到pong回复的时间离当前时间超过cluster-node-tieout设置的一半时发送者会向接收者发pingPONG:确认meet或ping消息已到达、向集群广播pong让其他节点刷新关于这个节点的认识FAIL:一个主判断另一个主进入fail状态时向集群广播关于它的fail消息,收到消息的节点立即将它标为已下线PUBLIST:节点收到一个publish命令时会执行这个命令并向集群广播publish消息,所有收到这条消息的节点都会执行相同的publish命令一条消息由消息头和正文组成,消息头本身也是消息的一部分,
int port端口号
adlist.h/listNode
struct {time_t seconds;秒数int changes;修改数}
void *ptr指向数据结构的指针
selectdb1字节,要读库号的标识
v2.8前的复制:实现:同步:从向主发sync命令,主执行bgsave生成RDB文件,用缓冲区记录从现在开始执行的所有写命令、主将RDB发给从,从载入RDB、主将缓冲区的所有写命令发给从,从执行写命令命令传播:主将执行的写命令发给从执行缺点:断线后复制效率低,大部分是相同的数据sync很耗资源:主每次要执行bgsave生成RDB,耗CPU、内存和I/O主发送RDB给从,耗网络资源、影响主对命令的请求响应时间从载入RDB期间会阻塞而无法处理命令请求
cluster.h/clusterState
渐进式rehash:避免rehash影响性能1、为ht[1]分配空间2、在字典维持rehashidx,设值为0,表示rehash正式开始3、rehash期间,对字典crud时程序除了执行指定的操作还顺带将ht[0]中在rehashidx上的所有键值对rehash到ht[1]上,完成后rehashidx值加14、ht[0]所有键值对都rehash到ht[1]时程序将rehashidx值设为1
redis.h/redisClient
0
dict.h/dictht
L5
sentinel将一个主标为主观下线后会询问其他监视该主的sentinel,当收到足够数量的已下线判断后将该主的flag属性打开sri_o_down标识标为客观下线并进行故障转移
char slaveof[REDIS_CLUSTER_NAMELEN]发送者是从,存发送者正复制的主名是主,存REDIS_NODES_NULL_NAME
n-1
time_t lastsave上次执行保存的时间
dictType *type特定类型函数
content节点值
struct clusterNode **slaves每个数组项指向一个正在复制这个主节点的从节点的clusterNode结构
int fdTCP套接字描述符
3.0
adlist.h/list
sds querybuf输入缓冲区,<=1G,否则关闭客户端
pid_t rdb_child_pid执行bgsave命令的子进程id-1:没执行gbsave---pid_t aof_child_pid执行bgrewriteaof命令的子进程id-1:没执行
char *runid实例的运行id
embstr存短字符串,调两次内存分配函数分别创建redisObject、sdshdr;raw调一次内存分配函数分配连续空间embstr是只读的,redis没为其提供修改方法,修改时得先转成raw再改
对象
redis只会将对库修改的命令写入AOF文件,pubsub、script load虽没改库,但:pubsub会向所有频道的订阅者发消息这一行为有副作用,所以服务器用redis_force_aof标志强制将命令写入AOF文件,使执行AOF时产生相同的副作用script load改了服务器状态,为让主从都能正确载入指定脚本,服务器用redis_force_repl标志强制将其复制给所有从服务器
object idletime 命令不会修改lru值、开启maxmemory时回收内存用
空间预分配:改sds后len<1M时分配len大小的未使用空间;len>=1M时分配1M未使用空间惰性空间释放:sds缩短后并不立即内存重分配来回收多出的字节
特点:双端、无环、带头尾指针、多态(void* 可存不同类型的值)
time_t unixtime秒级精度系统当前unix时间戳long long mstime毫秒级精度系统当前unix时间戳
robj **argv命令参数int argc参数个数
数据库
当前节点视角下集群状态
int fd套接字描述符
redisDb *db当前数据库
L1
unsigned type:4类型
mstime_t ctime创建节点的时间
entryX列表节点,长度由内容决定
执行brpop、blpop等列表阻塞命令时用的数据结构
check_num8字节,校检和,无符号整数,检查文件是否损坏用
uint64_t current_epoch当前纪元,故障转移用
list *scripts_queueFIFO队列,存所有要执行的用户脚本
2.0
cluster.h/clusterLink
EOF1字节,正文结束标识
redis中每个对象都是一个redisObject,键总是一个字符串对象
每个节点层高是1~32间的随机数obj指向一个字符串对象,字符串对象保存一个SDS值,各节点obj唯一score可以相同,相同时按对象在字典序中的大小排序,小的在前
int slave_listening_port从服务器监听的端口号主服务器执行 info replication 命令时打印从服务器的端口号用
struct saveparam *saveparamsRDB保存条件数组
sentinel默认每2s一次向所有被监视的主从发命令publish _sentinel_:hello \
连接节点的信息
键对象
REDIS5字节
正在用的数据库指针及该库号
dictEntry
简单动态字符串
sds sndbuf输出缓冲区存待发给其他节点的消息
shs.h/sdshdr
list *pubsub_patterns所有模式的订阅关系
创建新对象时refcount值被初始化为1对象被一个新程序使用时refcount值加1对象不再被一个程序使用时refcount值减1对象的refcount值为0时所在内存被释放
struct sentinelState sentinel哨兵模式相关
整数集合
dict *pubsub_channels所有频道的订阅关系k:被订阅频道 v:所有订阅了这个频道的客户端链表v为空时删除k
o2
mstime_t ctime连接的创建时间
db_version4字节,版本号
用ziplist编码时键值对紧挨着,键在前值在后、尾插法所有键和值的字符串长度<64字节、键值对数量<512个时用ziplist编码
previous_entry_length前一个节点长度
排序:SORT命令可对列表键、集合键或有序集合键的值排序ALPHA选项:对含字符串的集合键排序BY选项:指定字符串键ASC/DESC选项:升序/降序,快速排序算法LIMIT <offset> <count>选项:从指定位置返回指定数量元素GET选项:根据被排序的及get选项指定的模式查找并返回某些键的值STORE选项:保存排序结果到指定键并在需要时重用这个排序结果实现原理:p360
unsigned char myslots[REDIS_CLUSTER_SLOTS/8]发送者目前的槽指派信息
list *clients存所有客户端状态,符合条件时关闭客户端
1
sentinel默认每1s一次向所有与它创建命令连接的实例发ping命令,通过命令返回判断实例在线状态,指定时间内连续收到无效回复会将该实例的flags属性打开sri_s_down标识,表示主观下线
复制
二进制数组/位数组:SETBIT、GETBIT、BITCOUNT、BITOP实现原理:p378
uint16_t type消息类型
dict *watched_keys被WATCH监视的键k:键 v:监视对应键的客户端链表
list *fail_reports存所有其他节点对该节点的下线报告
1.0
uint16_t port发送者端口号
扩展条件:服务器没执行bgsave、bgrewriteaof,且ht负载因子>=1服务器正在执行bgsave、bgrewriteaof,且ht负载因子>=5收缩条件:负载因子<0.1loa_factor=ht[0].used/size
uint32_t zlbytes列表占内存字节数
AOF重写:不对现有AOF文件读写、分析,通过读服务器当前库状态实现为避免客户端输入缓冲区溢出,当一个集合键超过redis_aof_rewrite_items_per_cmd(默认64)元素时,重写程序用多条命令记录这个集合
struct {uint32_t channel_len;uint32_t message_len;usigned char bulk_data[8]定义为8时为了对齐其他消息结构实际长度由内容决定} clusterMsgDataPublish
复制模式:从服务器过期键的删除由主服务器控制,主删一个过期键会显示向所有从发个DEL命令从服务器只有接到主服务器的DEL命令后才会删过期键
struct listNode *next后置节点
union clusterMsgData data消息正文
unsigned long len节点数量
字符串对象数组,argv[0]是命令,后边是参数,命令本身也是参数,服务器在命令表找命令对应的函数
集群节点数多时单用Gossip协议传播节点已下线信息有延迟,发FAIL消息可让集群立即知道某主节点已下线,因为集群里所有节点名独一无二,fail消息只需存下线节点名 收到消息的节点就知道哪个节点下线了
free未分配
redis.h/zskiplist
dict *nodes集群节点名单k:节点名,v:clusterNode
mstime_t previous_time最后一次执行时间处理器的时间
void *privadata私有数据
Lua相关
int state集群当前状态在线/下线
multiState mstate事务状态
节点
cluster.h/clusterNode
int numslaves正复制这个主节点的从节点数
redis.h/zskiplistNode
zskiplistLevel{struct zskiplistNode *forward;前进指针unsigned int span;跨度} level[]层
int parallel_syncs故障转移时可同时对新主服务器进行同步的从服务器数
uint16_t flags发送者标识值
zskiplist *slots_to_keys存槽和键间的关系分值是槽号,节点是键
列表对象的 所有字符串元素长度<64字节、元素数量<512个 时列表对象用ziplist编码
level最大的层,不算表头
struct listNode *prev前置节点
char ip[REDIS_IP_STR_LEN]ip
RDB:(主)载入RDB文件时检查键,忽略过期键(从)载入RDB文件时载入所有键,主从同步时从库会被清空,所以过期键不会影响从库
uint64_t configEpoch发送者是主,存是发送者的配置纪元是从,存是发送者正复制的主的配置纪元
添加的新元素的类型比现所有元素的类型都长时需先升级再添加:1、根据新元素类型扩展整个数组大小,为新元素分配空间2、将所有元素都换成与新元素相同的类型,并放到正确位置3、将新元素加到数组不支持降级
redis_string:int->整数、embstr->SDS、raw->SDSredis_list:ziplist->压缩列表、linkedlist->链表redis_hash:ziplist->压缩列表、ht->字典redis_set:intset->整数集合、ht->字典redis_zset:ziplist->压缩列表、skiplist->跳跃表
集群额外结构
unsigned long sizemask哈希表大小掩码,算索引用,=size-1
listNode *head表头节点
过期键删除策略:定时删:设置键过期时间时创建定时器,让定时器在键过期时删->对cpu不友好,定时器要用时间事件惰性删:每次从键空间取键时检验->内存泄露定期删:每隔一段时间删->难以确定删除执行的时长和频率redis服务器用惰性删和定期删
sentinel.c/sentinelAddr
robj *obj成员对象
值对象
客户端状态
复制状态信息
uint64_t config_epoch配置纪元
uint32_t totlen消息长度(头+正文)
int running_scripts正执行的脚本数
为减少获取系统当前时间的调用次数serverCron函数默认每100ms更新一次这俩属性,所以精确度不高,只用于对精度不高的操作如日志、算服务器上线时间等
struct multiCmd {robj **argv;参数int argc;参数数量struct redisCommand *cmd;命令指针} multicmd
慢查询日志:服务器配置相关选项:slowlog-log-slower-than:执行时间超过指定微秒的命令被记录到日志上slowlog-max-len:指定服务器最多存的慢查询日志数量详间:p394
跳跃表节点
uint64_t currentEpoch发送者所处的配置纪元
char *name实例名,从服务器及哨兵的是由哨兵自动设置的:ip:port
char sender[REDIS_CLUSTER_NAMELEN]发送者名字(ID)
redis.h/redisDb
dict *masters被该哨兵监视的主服务器键是名,值是→
监视器:执行MONITOR命令让客户端变成监视器实时接收并打印服务器当前处理的命令请求相关信息客户端向服务器发送命令时服务器处理会处理命令还会将关于命令的信息通过调replicationFeedMonitors函数发给所有监视器
数组元素有序且不重复元素虽然声明为int8_t但真正类型取决于编码方式:INTSET_ENC_INT16->int16_t,INTSET_ENC_INT32->int32_t,INTSET_ENC_INT64->int64_t
table数组
struct clusterNode *node与连接相关联的节点
L32
struct clusterNode *slaveof如果是从节点则指向主节点
sentinelAddr *addr实例的地址
union {void *val;uint64_tu64;int64_ts64;} v值
……
后台重写:用子进程重写:父进程可继续处理命令、避免用锁,保证数据安全AOF重写缓冲区在创建子进程后开始使用,保证重写期间数据库状态一致:服务器执行完写命令后同时将命令发给AOF缓冲和AOF重写缓冲,子进程完成重写后向父进程发送信号,父进程收到信号后调信号处理函数,将AOF重写缓冲的所有内容写到新AOF文件、对新AOF文件改名,原子的覆盖现有AOF文件
double score分值(double)
节点值复制函数
serverCron函数相关
服务器限制客户端输出缓冲:硬性限制:输出缓冲大小超过硬性限制立即关闭软性限制:输出缓冲超过软性限制没超过硬性限制时记下obuf_soft_limit_reached_time,输出缓冲在指定时间内一直超出软性限制时关闭、否则不关,属性清0
time_t ctime客户端创建时间time_t lastinteraction与服务器最后一次互动时间time_t obuf_soft_limit_reached_time输出缓冲区第一次到软性限制的时间
。。。其他消息的正文
dict *expires过期字典,存键过期时间
int flags节点标识及状态任一节点未被处理就下线
listNode *tail表尾节点
3
db_number1/2/5字节,库号,切库用
clusterNode *migrating_slots_to[16384]存当前节点正迁至其他节点的槽
-1:伪客户端,命令源于AOF或Lua,而非网络>-1的整数:普通客户端
ziplist编码时每个元素用两个节点保存,第一个存内容,第二个存分值有序集合保存的元素数量<128个、所有元素成员长度<64字节时用ziplist编码
不带过期时间:type:1字节,对象类型或编码key:字符串对象value:由type决定(p144)
char *masterhost主服务器地址int masterport主服务器端口
套接字因客户端的写入变得可读时服务器调命令请求处理器执行如下:读套接字中协议格式的命令请求,存到缓冲区、分析命令请求,提取并保存参数及其个数、调命令执行器执行客户端的命令
服务器状态
lua指向Lua环境
struct {clusterMsgDataPublish msg;} publispublish消息的正文
服务器初始化Lua环境:1、创建并修改Lua环境:服务器调Lua的C API函数lua_open创建基本Lua环境载入函数库:基础库(删除loadfile函数以防止从外部文件引入不安全的代码)、表格库、字符串库、数学库、调试库、Lua CJSON库(处理UTF-8编码的JSON)、Struct库(在Lua值和C结构间转换)、Lua cmsgpack创建reids全局表格并将其设为全局变量,表格包含执行Reids命令的redis.call、redis.pcall函数;记录Redis日志的redis.log函数及相应的日志基本常量、计算SHA1校检和的redis.sha1hex函数、返回错误信息的redis.error_reply函数和redis.status_reply函数用Redis自制的随机数替换Lua原有的随机函数以保证相同的脚本在不同的机器上产生相同的结果:Redis用自制的函数替换了math库中原有的math.random函数和math.randomseed函数创建排序辅助函数:不确定性的命令(sinter、sunion、sdiff、smembers、hkeys、hvals、keys)也会产生不一致数据,创建排序辅助函数_redis_compare_helper作为对比函数,自动调table.sort函数对命令返回值做一次排序创建redis.pcall函数的错误报告辅助函数:_redis_err_handler保护Lua的全局环境:确保传入服务器的脚本不会因忘记用local关键字而将额外的全局变量加到Lua环境将Lua环境保存到服务器状态的lua属性里将Lua环境和服务器状态的lua属性关联,因为redis用串行化方式执行命令,所以在任何特定时间最多只会有一个脚本能被放进Lua环境里运行2、Lua环境协作组件:伪客户端:Lua环境将redis.call或redis.pcall函数要执行的命令传给伪客户端,伪客户端将命令传给命令执行器、命令执行器执行命令并将结果返回给伪客户端,伪客户端接收结果并返回给Lua环境,Lua环境将结果返回给函数,函数将结果返回给脚本调用者lua_scripts字典:键是SHA1校检和,值是SHA1校检和对应的脚本,用于实现script exists命令和脚本复制功能
unsigned long size哈希表大小
struct dictEntry *next指向下个节点
对象空转时间=服务器lru-对象lru
服务器
int cronloopsserverCron函数运行次数计数器
databases0/任意个库及库中数据
slaves指向从服务器字典k:ip:port,v:sentinelRedisInstance
struct clusterNodeFailReport{structclusterNode *node;报告目标节点已下线的节点mstime_t time;最后一次从node节点收到下线报告的时间,检查报告是否过期用}typedef clusterNodeFailReport
uint32_t length元素数量
集群通过Gossip协议交换各自关于不同节点的状态信息,该协议由meet、ping、pong实现,通过消息头判断具体是哪个每次发消息时发送者从自己已知节点列表随机选两个,将其存到clusterMsgDataGossip接收者收到消息时访问两个clusterMsgDataGossip结构,根据里面记录的被选中节点判断进行哪种操作:被选中节点不在接收者已知列表时接受者根据ip端口等信息与其进行握手,在接收者列表时对其对应的clusterNode结构更新
void *value节点的值
cluster.h/clusterMsg
Reids要求主服务器传播EVALSHA命令时必须确保EVALSHA命令要执行的脚本已被所有从服务器载入过,否则主服务器会将其转为等价的EVAL命令传播或转换EVALSHA命令要用到服务器状态的lua_scripts字典和repl_scriptcache_dict字典
前节点长度<254字节时,前节点长度为1字节前节点长度>=254字节时,前节点长度为5字节,第一个字节被设为0xFE当节点长度都介于250~253字节时,在头节点插入一个长度>254字节的节点会导致连锁更新(删除节点反之),真正造成性能问题的几率很低(节点连续长度介于250~253的情况少、节点数不多时问题不大)
uint64_t currentEpoch集群当前的配置纪元故障转移用
EVAL命令实现:定义脚本函数:函数名是f_加校检和,函数体是脚本本身,用函数存脚本的好处:让脚本执行步骤简单、函数的局部性让Lua环境清洁,减少了垃圾回收的工作量,避免了用全局变量、某脚本对应的函数在Lua环境至少被定义过一次可直接通过校检和执行脚本将脚本存到lua_scripts字典执行脚本函数:将eval命令传入的jian名参数和脚本参数分别存到KEYS数组和ARGV数组,将其作为全局变量传入Lua环境、为Lua环境装载超时处理钩子,可在脚本超时时让客户端通过script kill停止脚本或通过shutdown关闭服务器、执行脚本函数、移出超时钩子、将结果存到客户端状态的输出缓冲区、对Lua环境执行垃圾回收
monitors服务器的监视器链表
跳跃表示例
dict *dict键空间,存所有键值对键是字符串对象
cluster.h/clusterMsgData
uint64_t configEpoch配置纪元,故障转移用
sds rcvbuf输入缓冲区存从其他节点收到的消息
unsigned long used哈希表已有节点数
robj *name名,默认没有
int shutdown_asap关闭服务器标识1:关闭0:不做动作
1、ht[1]空间取决于要执行的操作:扩展:ht[1]=最小的 大于(ht[0].used*2)的 2^n 的值收缩:ht[1]=最小的 大于(ht[0].used)的 2^n 的值2、将ht[0]的所有键值对rehash到ht[1]上3、ht[0]迁移完后释放ht[0],将ht[1]设置为ht[0],在ht[1]建个空白哈希表
clusterNode *myself指向当前节点的指针
redisDb *db数据库数组
redisObject
主被标为客观下线后监视该主的哨兵会选一个领头哨兵,由领头哨兵进行故障转移:谁都能当领头哨兵、每轮选举后是否成功,所有哨兵的配置纪元值增1、配置纪元里所有哨兵都有一次将某个哨兵设为局部领头哨兵的机会,一旦设置,在这个纪元里就不能修改、每个发现主客观下线的哨兵都要求其他哨兵设自己为领头哨兵、设置局部领头哨兵时先到先得,后到被拒、某哨兵被半数以上哨兵支持时会成为领头哨兵、给定时限内没选出时进程新一轮选举
tail指向表尾
intset.h/intset
redisClient *lua_client执行Lua的伪客户端,服务器被关闭时才关闭
int aof_rewrite_scheduled1:有bgrewriteaof命令被延迟了
列表节点
header指向表头
len长度
o3
dict *repl_scriptcache_dict存哪些脚本传给了所有从服务器
mstime_t failover_timeout刷新故障迁移状态的最大时限
dictEntry*[n]
redis.h/redisServer
1/2/5字节长,值最高位为00/01/10的是字节数组编码1字节长,值最高位为11的是整数编码,整数值的类型和长度由编码除去最高两位后的其他位记录
int flags标志,存客户端角色及状态、事务标识等
独立模块实现
节点值对比函数
struct {clusterMsgDataFail about;} failfail消息的正文
链表
unsigned lru:22对象空转时长记录对象最后一次被访问的时间
unsigned encoding:4编码
dictType计算哈希值的函数复制键的函数复制值的函数对比键的函数销毁键的函数销毁值的函数
unsigned char state发送者所处集群的状态
压缩列表
struct { char nodename[REDIS_CLUSTER_NAMELEN];节点名uint32_t ping_sent;最后一次向该节点发ping的时间戳uint32_t pong_received最后一次从该节点收到pong的时间戳char ip[16];节点ipuint16_t port;节点端口uint16_t flags;节点标识} clusterMsgDataGossip
struct multiState {multiCmd *commands;事务队列,FIFO顺序int count;已入队命令计数} multiState
o1
struct {char nodename[REDIS_CLUSTER_NAMELEN} clusterMsgDataFail
database
void *key键
uint32_t zltail表尾离起始地址字节数
启动并初始化sentinel:初始化服务器sentinel模式、用sentinel专用代码、初始化sentinel状态、初始化sentinel的masters属性、创建连向主服务器的网络连接(命令连接:向主发命令并接收命令回复、订阅连接:订阅主的sentinel_:hello频道:发布订阅中信息不被保存,断线会丢失信息,为了保证不丢失频道的信息,专开了个订阅连接)
数据结构
所有节点都被指派后集群进入上线状态,客户端向节点发和数据库键有关的指令时会算键属于哪个槽(CRC16key & 16383),该槽没指派给当前节点时返回MOVED错误并指引客户端转向正确的节点,并再次发送要执行的指令集群模式cli:redis-cli -c -p ip:port,不会打印MOVED信息,单机模式cli不清楚MOVED错误,会打印信息
serverCron函数的trackOperationsPerSecond函数以抽样计算的方式估算服务器在最近1s处理的命令数
char name[REDIS_CLUSTER_NAMELEN]节点名,40个十六进制字符
long long ops_sec_last_sample_time上次抽样时间long long ops_sec_last_sample_ops上次抽样时服务器已执行命令数量
uint32_t encoding编码方式
size_t stat_peak_memory已用内存峰值
uint8_t zlend0xFF,标记末端
集合对象 所有元素都是整数值、元素数量<=512时用intset编码
带过期时间:expiretime_ms:1字节,ms过期时间标识ms:8字节带符号整数,ms单位时间戳typekeyvalue
dict.h/dict
字典
客户端
struct pubsubPattern {redisClient *pattern;订阅模式的客户端robj *pattern被订阅的模式} pubsubPattern
clusterNode *slots[16384]集群中所有槽的指派信息
int quorum定实例为客观下线的支持票数
收到publish命令的节点向channel频道发消息,还向集群广播publish消息,所有收到publish消息的节点向channel频道发消息不直接向节点广播publish是因为这样不符合redis集群的各节点通过收发消息进行通信的规则
type、privdata针对不同类型的键值对,为多态字典而设置
key_value_pairs所有键值对
发布订阅相关
in rehashidxrehash索引,rehash不在进行时值为-1
serverCron函数(时间事件):更新服务器各类统计信息、清理过期键值对、关闭和清理连接失效的客户端、尝试RDB/AOF的持久化、主从中对从定期同步、集群中对集群定期同步和连接测试v2.6每秒运行10次,2.8开始通过改hz选项调整频率
sentinel.c/sentinelRedisInstance
long long dirty修改计数器成功执行n个修改命令后值加n
clusterLink *link连接节点所需信息
0 条评论
下一页