
Redis设计与实现
文章平均质量分 89
吃着火锅x唱着歌
这个作者很懒,什么都没留下…
展开
-
Redis设计与实现 学习笔记 第二十四章 监视器
例如,客户端c10086向服务器发送MONITOR命令,那么这个客户端的REDIS_MONITOR标志会被打开,且这个客户端本身会被添加到monitors链表的表尾。服务器在每次处理命令请求前,都会调用replicationFeedMonitors函数,由这个函数将被处理的命令请求的相关信息发送给各个监视器。1.客户端可通过执行MONITOR命令,将客户端转换成监视器,接收并打印服务器处理的每个命令请求的相关信息。4.每次处理命令请求时,服务器都会遍历monitors链表,将相关信息发送给监视器。原创 2024-11-30 00:43:42 · 193 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第二十三章 慢查询日志
每次执行命令的之前和之后,程序都会记录微秒格式的当前UNIX时间戳,这两个时间戳之间的差就是服务器执行命令所耗费的时长,服务器会将这个时长作为参数之一传送给slowlogPushEntryIfNeeded函数,此函数会检查是否需要为这次执行的命令创建慢查询日志。服务器使用先进先出方式保存多条慢查询日志,当服务器存储的慢查询日志数量等于slowlog-max-len选项的值时,服务器在添加一条新的慢查询日志前,会先将最旧的一条慢查询日志删除。原创 2024-11-30 00:27:15 · 687 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第二十二章 二进制位数组
2.查表法的效果还受到CPU缓存的限制,对于固定大小的CPU缓存来说,创建的表越大,CPU缓存能保存的内容相比整个表格的比例就越少,查表时出现缓存不命中(cache miss)的情况就越多,缓存的换入和换出操作就会越频繁,最终影响查表法的实际效率。由于以上两个原因,我们可以得出结论,查表法是一种比遍历算法更好的统计办法,但受限于查表法带来的内存压力,以及缓存不命中可能带来的影响,我们只能考虑创建键长为8或16位的表,而这两种表带来的效率提升,对于处理非常长的位数组来说仍然远远不够。原创 2024-11-28 22:35:29 · 659 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第二十一章 排序
SORT命令为每个被排序的键都创建一个与键长度相同的数组,数组的每个项都是一个redisSortObject结构,根据SORT命令使用的选项不同,程序使用redisSortObject结构的方式也不同。8.当SORT命令使用了GET选项时,命令会根据排序结果集中的元素,以及GET选项给定的模式,查找并返回其他键的值,而不是返回被排序的元素。但通过使用GET选项,我们可以让SORT命令对键进行排序后,根据被排序的元素,以及GET选项指定的模式,查找并返回某些键的值。原创 2024-11-24 23:40:39 · 752 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第二十章 Lua脚本
主服务器清空repl_scriptcache_dict字典,可以强制自己向所有从服务器传播脚本,从而确保新的从服务器不会出现脚本未找到错误。repl_scriptcache_dict字典的键是一个个Lua脚本的SHA1校验和,而字典的值则全部都是NULL,当一个校验和出现在repl_scriptcache_dict字典时,说明这个校验和对应的Lua脚本已经传播给了所有从服务器,主服务器可以直接向从服务器传播包含这个SHA1校验和的EVALSHA命令,而不必担心从服务器会出现脚本未找到错误。原创 2024-11-23 17:20:29 · 1501 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第十九章 事务
所有对数据库进行修改的命令,如SET、LPUSH(将一个或多个值插入到列表头部)、SADD、ZREM(移除有序集合中的一个或多个成员,不存在的成员将被忽略)、DEL、FLUSHDB(清空数据库中的所有key)等,在执行后都会调用multi.c/touchWatchKey函数对watched_keys字典进行检查,查看是否有客户端正在监视刚刚被命令修改过的数据库键,如果有,那么touchWatchKey函数会将监视被修改键的客户端的REDIS_DIRTY_CAS标识打开,表示该客户端的事务安全性已经被破坏。原创 2024-11-18 22:44:33 · 648 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第十八章 发布与订阅
因为服务器状态中的pubsub_patterns链表记录了所有模式的订阅关系,所以为了将消息发送给所有与channel频道相匹配的模式的订阅者,PUBLISH命令要做的就是遍历整个pubsub_patterns链表,查找那些与channel频道相匹配的模式,并将消息发送给订阅了这些模式的客户端。通过执行SUBSCRIBE命令,客户端可订阅一个或多个频道,从而成为这些频道的订阅者(subscriber):每当有其他客户端向被订阅的频道发送消息(message)时,频道的所有订阅者都会收到这条消息。原创 2024-11-17 13:40:56 · 1013 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第十七章 集群
2.PING消息:集群里的每个节点默认每隔一秒就会从已知节点列表中随机选出五个节点,然后对这五个节点中最长时间没有发送过PING消息的节点发送PING消息,以此来检测被选中的节点是否在线。另外,一个节点也可以通过向集群广播自己的PONG消息来让集群中的其他节点刷新关于这个节点的认识,例如当一次故障转移操作成功执行后,新的主节点会向集群广播一条PONG消息,以此来让集群中的其他节点立即知道这个节点已经变成了主节点,并且接管了已下线节点负责的槽。原创 2024-11-13 22:34:12 · 1357 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第十六章 Sentinel
8.源Sentinel接收到目标Sentinel返回的命令回复后,会检查回复中leader_epoch参数的值和自己的配置纪元是否相同,如果相同,那么源Sentinel继续取出回复中的leader_runid参数,如果leader_runid参数的值和源Sentinel的运行ID一致,那么表示目标Sentinel将源Sentinel设置成了局部领头Sentinel。9.如果有某个Sentinel被半数以上Sentinel设置成了局部领头Sentinel,那么这个Sentinel成为领头Sentinel。原创 2024-11-07 21:19:36 · 950 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第十五章 复制
如果因为网络故障,主服务器传播给从服务器的写命令在半路丢失,那么当从服务器向主服务器发送REPLCONF ACK命令时,主服务器将发觉从服务器的复制偏移量少于自己的复制偏移量,然后主服务器就会根据从服务器提交的复制偏移量,在复制积压缓冲区里找到从服务器缺少的数据,并将这些数据重新发给从服务器。3.当主服务器的BGSAVE命令执行完毕时,主服务器会将BGSAVE命令生成的RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态。原创 2024-11-03 16:03:04 · 775 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第十四章 服务器
3.检查服务器设置的AOF重写条件是否满足,如果条件满足,且服务器没有在执行其他持久化操作,那么服务器将开始一次新的BGREWRITEAOF操作(虽然3是在rdb_child_pid和aof_child_pid属性都为-1时进行的检查,但由于1和2的存在,服务器还是会检查一下是否正在进行持久化操作)。命令的参数个数为-3,表示命令接受三个或以上数量的参数;命令的标识为“wm”,表示SET命令是一个写入命令,且在执行这个命令前,服务器应该对内存占用情况进行检查,因为这个命令可能会占用大量内存。原创 2024-10-31 19:52:29 · 727 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第十三章 客户端
但timeout选项也有例外情况:如果客户端是主服务器(打开了REDIS_MASTER标志)、从服务器(打开了REDIS_SLAVE标志)、正在被BLPOP等命令阻塞(打开了REDIS_BLOCKED标志)、正在执行SUBSCRIBE(订阅某个频道)和PSUBSCRIBE(订阅一个或多个符合给定匹配模式的频道)等订阅命令,那么即使客户端的空转时间超过了timeout选项的值,客户端也不会被服务器关闭。1.在主从服务器进行复制操作时,主服务器会成为从服务器的客户端,而从服务器也会成为主服务器的客户端。原创 2024-10-27 21:21:29 · 795 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第十二章 事件
3.对文件事件和时间事件的处理都是同步、有序、原子地执行的,服务器不会中途中断事件处理,也不会对事件进行抢占,因此,不管是文件事件的处理器,还是时间事件的处理器,它们都会尽可能减少程序的阻塞时间,并在有需要时主动让出执行权,从而降低造成事件饥饿的可能性。当回复能发送时,将产生AE_WRITABLE事件,触发命令回复处理器执行,当命令回复处理器将全部回复写入套接字后,将不再监听客户端套接字的AE_WRITABLE事件。正常情况下,服务器几乎是将无序链表退化成一个指针来使用,因此不会影响事件执行的性能。原创 2024-10-26 20:35:28 · 789 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第十一章 AOF持久化
上面介绍的aof_rewrite函数会进行大量的写入操作,所以调用这个函数的线程将被长时间阻塞,因为Redis使用单个线程来处理命令请求,所以如果服务器直接调用aof_rewrite函数,那么在AOF重写期间,服务器将无法处理客户端发来的命令请求。因为AOF持久化是通过保存被执行的写命令来记录数据库状态的,所以随着时间流逝,AOF文件中的内容会越来越多,文件也会越来越大,如果不加以控制,体积过大的AOF文件可能对Redis服务器或宿主机造成影响,且AOF文件越大,还原所需时间就越多。原创 2024-10-25 23:17:09 · 771 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第十章 RDB持久化
其中,REDIS_RDB_ENC_LZF常量标志着字符串已被LZF算法压缩过了,程序读入到这个常量时,会根据compressed_len(字符串被压缩后的长度)、origin_len(字符串被压缩前的长度)、compressed_string(被压缩后的字符串)对字符串进行解压。如果TYPE值为REDIS_RDB_TYPE_SET_INTSET,那么value保存的就是一个整数集合对象,RDB文件保存这种对象的方法是:先将整数集合转换为字符串对象,然后将这个字符串对象保存到RDB文件里。原创 2024-10-23 22:45:48 · 973 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第九章 数据库
例如,对于一些和时间有关的数据,比如日志(log),在某个时间点后,对它们的访问会大大减少,甚至不再访问,如果这类过期数据大量积压在数据库中,用户以为服务器已经自动将它们删除了,但实际上这些键仍存在,且键占用的内存也没有释放,那造成的后果是非常严重的。但定时策略对CPU时间最不友好,在过期键比较多的情况下,删除过期键的行为可能会占用相当一部分CPU时间,在内存不紧张但CPU时间非常紧张的情况下,将CPU时间用在删除和当前任务无关的过期键上,无疑会对服务器的响应时间和吞吐量造成影响。原创 2024-10-20 21:05:42 · 866 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第八章 对象
注意,linkedlist编码的列表对象在底层的双端链表结构中包含了多个字符串对象,这种嵌套字符串对象的行为在稍后介绍的哈希对象、集合对象、有序集合对象中都会出现,字符串对象是Redis五种类型的对象中唯一会被其他四种类型对象嵌套的对象。通过encoding属性来设定对象使用的编码,而不是为特定类型的对象关联一种固定的编码,极大地提升了Redis的灵活性和效率,因为Redis可以根据不同的场景来为一个对象设置不同的编码,从而优化对象在某一场景下的效率。原创 2024-10-17 23:20:35 · 1030 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第七章 压缩列表
如果e1至eN都是大小介于250至253字节的节点,big节点的长度大于等于254字节,而small节点的长度小于254字节,那么当我们将small节点从压缩列表中删除后,为了让e1的previous_entry_length属性可以记录big节点的长度,程序将扩展e1的空间,并由此引发之后的连锁更新。2.如果前一节点的长度大于等于254字节,那么previsou_entry_length属性长为5字节:第一字节被设置为0xFE(十进制254),之后四字节则用于保存前一节点的长度。原创 2024-10-12 23:24:17 · 1197 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第六章 整数集合
虽然contents数组保存的四个值中,只有第一个是真正需要用int64_t来保存的,其他三个值都可以用int16_t来保存,但根据整数集合的升级规则,当向一个底层为int16_t的整数集合添加一个int64_t类型的整数值时,整数集合已有的所有元素都会被转换成int64_t类型。要让一个数组可以同时保存int16_t、int32_t、int64_t三种类型的整数,最简单的做法是直接使用int64_t类型的数组作为整数集合的底层实现,但这样一来保存小整数时比较浪费内存。原创 2024-10-10 00:01:35 · 541 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第五章 跳跃表
在同一个跳跃表中,各个节点保存的成员对象必须是唯一的,但是多个节点保存的分值却可以是相同的:分值相同的节点将按照成员对象在字典序中的大小来排序,成员对象较小的节点会排在前面(靠近表头的方向),而成员对象较大的节点则会排在后面(靠近表尾的方向)。再举个例子,图5-5用虚线标记了在跳跃表中查找分值为2.0、成员对象为o2的节点时,沿途经历的层:在查找节点的过程中,程序经过了两个跨度为1的节点,因此可以计算出,目标节点在跳跃表中的排位为2。在跳跃表中,节点按各自保存的分值从小到大排列。原创 2024-10-04 12:16:38 · 763 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第四章 字典
根据BGSAVE命令或BGREWRITEAOF命令是否正在执行,服务器执行扩展操作所需的负载因子并不相同,这是因为在执行这两个命令的过程中,Redis需要创建子进程,而大多数操作系统都采用写时复制(copy-on-write)技术来优化子进程的使用效率,所以在子进程存在期间,服务器会提高执行扩展操作所需的负载因子,从而尽可能避免在子进程存在期间进行哈希表扩展操作,这可以避免不必要的内存写入操作,最大限度节约内存。原创 2024-10-03 00:26:52 · 593 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第三章 链表
5.多态:链表节点使用void *指针来保存节点值,且可以通过list结构的dup、free、match三个属性为节点值设置类型特定函数,所以链表可用于保存各种不同类型的值。4.带链表长度计数器:程序使用list结构的len属性来对list持有的链表节点进行计数,程序获取链表中节点数量的复杂度为O(1)。2.每个链表节点由一个ListNode结构来表示,每个节点都有一个指向前置节点和后置节点的指针,所以Redis的链表实现是双端链表。3.match函数用于对比链表节点保存的值和另一个输入值是否相等;原创 2024-10-01 21:49:33 · 889 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第二章 简单动态字符串
与C字符串不同,SDS的空间分配策略完全杜绝了发生缓冲区溢出的可能性:当SDS API需要对SDS进行修改时,API会先检查SDS的空间是否满足修改所需的要求,如果不满足,API会自动将SDS的空间扩展至执行修改所需的大小,然后才执行实际的修改操作,所以使用SDS既不需要手动修改SDS的空间大小,也不会出现前面所说的缓冲区溢出问题。为空字符分配额外的1字节空间、添加空字符到字符串末尾等操作,都是由SDS函数自动完成的,这个空字符对于SDS的使用者来说是完全透明的。原创 2024-10-01 15:08:59 · 1142 阅读 · 0 评论 -
Redis设计与实现 学习笔记 第一章 引言
本书是基于Redis 2.9——也就是Redis 3.0的开发版来编写的,因为Redis 3.0的更新主要与Redis的多机功能有关,而Redis 3.0的单机功能与Redis 2.6、Redis 2.8的单机功能基本相同,所以本书的内容对于使用Redis 2.6至Redis 3.0的读者来说应该都是有用的。在本书的第四部分中,除了第20章的其中一节涉及多机功能的内容之外,其他章节都没有涉及多机功能的内容,所以第四部分的大部分章节都可以在只阅读了本书第一部分和第二部分的情况下阅读。原创 2024-09-28 17:36:28 · 803 阅读 · 0 评论