赞
踩
通常以“命名空间:业务key”的方式作为Redis的key值,如 “article:12563”,类似关系型数据库article表中主键未12563的数据。
value值的类型包括:string、list、set、map、sorted-set
type表示结构化类型,string、list等
encoding表示结构化类型具体实现方式,string可以是int、char[];list可以是ziplist等
lru即可被lru清理时长
refcount为引用计数,用于垃圾回收
ptr指向引用地址
ziplist
ziplist的数据结构:zlbytes表示本ziplist的总长度;zltail指向最末元素;zllen表示元素个数;后续每个<entry>即元素自身内容;zlend恒未0xFF作为定界符
ziplist中的元素是连续存放的;适合存储list的元素个数不多且元素本身长度不大的情况
Map
map内部的key和value不能在嵌套使用map,只能是String所能表达的类型
hashtable扩容:
rehashindex标记已完成迁移的桶,迁移时分为源表和目标表,已完成迁移的访问目标表,未完成迁移的访问源表。
redis为单线程处理请求,所以迁移过程不存在并发问题。
Set
set中的数据以intset和hashtable来存储:hashtable中的value为null;若数据都会int,则用intset,且intset从小到大排序,所以使用二分法查找
Sorted-set
有序的kev-value对
value为浮点数,称为score,按score排序
基本操作:ZRAND、ZRANGE、ZRANGEBYSCORE、ZSCORE、ZINCRBY
采用跳表skiplist实现这种数据结构
Redis交互协议分为:
网络模型:
序列化协议:通过数据的首字符区分不同的协议类型
inline command:首字符为字母,代表命令,如EXISTS key1,首字符E表示Redis检查key1是否存在这个命令。
simple string:首字符为+,手续字符就为string的内容,以\r\n结束,所以不能包含\r\n。
bulk string:收字符为$,之后跟着数字表示string内容长度,以\r\n结束;数字0表示空字符、数字-1表示null字符。
error:与simple string相同,但是以-开头。
integer:以字符 :开头,后紧跟数字
array:以*开通,而后为长度+\r\n+数组元素+\r\n,如*2\r\n+abc\r\n:9\r\n这个13个字节表示["abc",9]
请求/响应模式:服务器对于客户端的每个请求返回一个响应数据,可以使用pipeline实现请求的批处理,而不用串行发生请求。
事务模式:MULTI+EXEC命令实现事务
MULTI命令开启事物模式
接下来的命令都放到暂存到服务端连接的队列上
EXEC为批量处理命令(Redis执行一次的粒度是命令)
非一致性:入队阶段出错,不执行EXEC;执行阶段出错,不回滚,在返回的array数据中标记出错结果。
入队操作应都为写操作,读操作是没有意义的,因为每次的写操作值应在入队前就确认,而不依赖批处理命令中的上一个结果。
串行事务的隔离:
问题:
解决:
引入WATCH,观察本次事务涉及到的所有key,此时时间为tstart
tcommit为批处理命令EXEC的执行时间
在sstart~tcommit之前有相关key值被修改,拒绝执行EXEC
脚本模型:Redis允许客户端以脚本的模式在服务端嵌入逻辑。
发布/订阅模式
单线程+IO多路复用
evport->epoll->kqueue->select效率从高到低
fd(文件描述符、socket的句柄)的处理逻辑有3种实现
acceptTcpHandle:处理建立连接的请求
readQueryFromClient:处理来自客户端的数据
sendReplyToClient:将暂存的执行结果写回客户端
aeApiPoll的等待时间取决于定时任务。如下图所示,以确保单线程情况下能执行定时任务
定时任务(processEvent),默认情况下Redis只有一个周期性定时任务serverCon,负责:
全量模式
两种写入方式:SAVE和BGSAVE
两种方式都可以由客户端通过命令显示出发
SAVE在当前线程执行,期间不能提供数据读写服务
BGSAVE为子线程执行,期间可以提供服务,代价在于子进程复制父进程内存,在内存不足时,会造成秒级的不可用
增量模式
仅对数据的变化进行存储
Redis的AOF(append-only file,增量持久话)有3中同步策略
always:在每个迭代中通过flushAppendOnlyFile函数直接触发fsync()是数据落地磁盘
every second:每秒异步的触发一次fsync方法。flushAppendOnlyFile函数只是作为生产着将fsync job放入bio_jobs队列中,由bio线程消费。当磁盘吞吐量小于Redis服务器的写服务的吞吐量时,会造成bio_jobs中任务积压,所以当bio线程在执行时,阻塞任务入队。
增量模式的优化(结合快照snapshot)
当AOF过多超过一个全量快照时,将AOF合并为一个快照
快照写入期间的增量在写入完快照后append在快照末尾
后续增量写入新的AOF
数据分布:hash映射、范围映射、hash映射+范围映射
slave主动发起同步流程
当有多个slave并发发起同步请求时,在master执行BGSAVE前的请求会收到同一份快照。
断点续传:PSYNC,主从都维护一个offset记录当前已同步过的命令。
sentinel集群用于解决故障发现、failover决策协商机制等问题。
sentinel集群中的所有监视相同master的节点两两连接
故障发现:当认为matser不可用的sentinel节点数大于某个阈值(可配置),则进入failover流程
failover决策:通过类型Raft协议实现选举发起failvoer决策的sentinel节点。
Redis3.0,提供了去中心化的方案,Redis Cluter。将proxy/senetinel的工作都融合到了普通的Redis节点里。
A和A1,B和B1、B2,构成两个节点组
1、2、3、4、5为一个数据全集分成的5个slot
配置一致性:
所有节点通过gossip协议向其他节点发送自身观察到的其他节点的信息的PING包
所有节点收到其他节点的PONG包,并更新自身关于其他节点的信息
由于Redis Cluster大多数时候是稳定的,所以PING包中只有随机选取的部分节点信息
各节点通过比较消息和自身的epoch、currentEpoch值,确认是否更新节点信息
客户端路由:ask和move
ask只是本条操作重定向到新节点,后续的相同slot操作仍路由到旧节点
move会更新client数据分布
由于迁移过程可能持续一段时间,所以应该将重定向和路由缓存更新分离,即在迁移完成后返回move,迁移中返回ask
分片迁移:
A节点在MGRATING状态下:
如果客户端访问尚未迁出的key,则正常访问
如过key已迁出或根本不存在,则回复ASK使其跳转到B执行
B节点在IMPORTING状态下
对于该slot上所有非ASK跳转操作,都不处理,返回MOVE命令让客户端跳转到A执行
slave选举:
在收到选票时,未发起选举,则同意选票
每个slave在发现master处于FAIL时,发起竞选
为了避免平票,高优先级的slave会更早的发起竞选,优先级根据最后一次同步master节点的时间判断
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。