由于早期redis面试被问挂过,近期依然问挂,反正是各种各样的方式。放下过往,重新思索Redis到底是什么,Redis能提供什么。
源码功能数据结构:学习Redis 主要数据结构的设计思想和实现,包括字符串的实现方法、内存紧凑型结构的设计、哈希表性能优化设计,以及 ziplist、quicklist、listpack、跳表的设计与实现等。 网络通信与执行模型:试着去掌握 Redis server 的启动流程、高性能网络通信设计与实现、事件驱动框架的设计与实现、Redis 线程类型的设计和优化等。缓存:你将了解常见缓存替换算法如何从原理转变为代码。 可靠性保证:试着去掌握 RDB、AOF 的具体实现,分布式系统中 Raft 一致性协议的设计实现,故障切换的关键代码实现等。 切片集群:学习到 Redis 切片集群中关键机制的设计与实现,包括 Gossip 通信协议、请求重定向、数据迁移等。
这些都是宝贵的计算机领域宝贵的知识,如果打算写/用中间件、分布式系统等都是必不可少的。如果我们主导一个选型技术上线的时候,不了解它的机制,遇到问题的时候,可能只有重启一个办法。遇到它,分析它,解决它。(除非是祖传改不了的屎山,还是不动为好)
学习目标能讲清某个模块的基本运行原理 能画出运行流程图 能用代码实践它的基本功能 做出部门内的分享(不要提前进行,最好进度过了90%,太早了很虚浮)
基于历史的经验,大部分系列都夭折了,最长的坚持了三篇。期待这次能走的更远一些。
学习前提会一些c的基本语法。 跟随 极客时间蒋德钧老师《Redis 源码剖析与实战》。
“他的是以Redis5.0,我的是Redis6.0
”
一些国内外的博客
一是 Redis 依赖的、实现更加高效的功能库,如内存分配; 二是独立于 Redis 开发演进的代码,如客户端; 三是 lua 脚本代码。后续你在学习这些功能的设计实现时,就可以在 deps 目录找到它们。
Redis 实现的测试代码可以分成四部分,分别是
单元测试(对应 unit 子目录) Redis Cluster 功能测试(对应 cluster 子目录) 哨兵功能测试(对应 sentinel 子目录) 主从复制功能测试(对应 integration 子目录)
除了有针对特定功能模块的测试代码外,还有一些代码是用来支撑测试功能的,这些代码在 assets、helpers、modules、support 四个目录中。
还有一些功能属于辅助性功能,包括
用于创建 Redis Cluster 的脚本 用于测试 LRU 算法效果的程序,以及 可视化 rehash 过程的程序。
在 Redis 代码结构中,这些功能代码都被归类到了 utils 目录中统一管理。
除了 deps、src、tests、utils 四个子目录以外,Redis 源码总目录下其实还包含了两个重要的配置文件:
一个是 Redis 实例的配置文件 redis.conf, 另一个是哨兵的配置文件 sentinel.conf。
当你需要查找或修改 Redis 实例或哨兵的配置时,就可以直接定位到源码总目录下。
这个目录里面包含了 Redis 所有功能模块的代码文件,也是 Redis 源码的重要组成部分.
adapters modules 各功能模块代码
“Redis 在运行时是一个网络服务器实例,因此相应地就需要有代码实现服务器实例的初始化和主体控制流程,而这是由 server.h/server.c 实现的,Redis 整个代码的 main 入口函数也是在 server.c 中。如果你想了解 Redis 是如何开始运行的,那么就可以从 server.c 的 main 函数开始看起
”
“对于一个网络服务器来说,它还需要提供网络通信功能。Redis 使用了基于事件驱动机制的网络通信框架,涉及的代码文件包括 ae.h/ae.c,ae_epoll.c,ae_evport.c,ae_kqueue.c,ae_select.c。
”
“与网络通信相关的功能还包括底层 TCP 网络通信和客户端实现。Redis 对 TCP 网络通信的 Socket 连接、设置等操作进行了封装,这些封装后的函数实现在 anet.h/anet.c 中。这些函数在 Redis Cluster 创建和主从复制的过程中,会被调用并用于建立 TCP 连接。
”
“数据库数据类型与操作客户端在 Redis 的运行过程中也会被广泛使用,比如实例返回读取的数据、主从复制时在主从库间传输数据、Redis Cluster 的切片实例通信等,都会用到客户端。Redis 将客户端的创建、消息回复等功能,实现在了 networking.c 文件中,如果你想了解客户端的设计与实现,可以重点看下这个代码文件
”
“Redis 数据库提供了丰富的键值对类型,其中包括了 String、List、Hash、Set 和 Sorted Set 这五种基本键值类型。此外,Redis 还支持位图、HyperLogLog、Geo 等扩展数据类型。而为了支持这些数据类型,Redis 就使用了多种数据结构来作为这些类型的底层结构。比如,String 类型的底层数据结构是 SDS,而 Hash 类型的底层数据结构包括哈希表和压缩列表
”(引用蒋老师原图) Redis如何优化内存?它从下面三个方面优化:
内存分配
“在内存分配方面,Redis 支持使用不同的内存分配器,包括 glibc 库提供的默认分配器 tcmalloc、第三方库提供的 jemalloc。Redis 把对内存分配器的封装实现在了 zmalloc.h/zmalloc.c。
”
内存回收
“Redis 支持设置过期 key,并针对过期 key 可以使用不同删除策略,这部分代码实现在 expire.c 文件中。同时,为了避免大量 key 删除回收内存,会对系统性能产生影响,Redis 在 lazyfree.c 中实现了异步删除的功能,所以这样,我们就可以使用后台 IO 线程来完成删除,以避免对 Redis 主线程的影响。
”
内存替换
“针对数据替换,如果内存满了,Redis 还会按照一定规则清除不需要的数据,这也是 Redis 可以作为缓存使用的原因。Redis 实现的数据替换策略有很多种,包括 LRU、LFU 等经典算法。这部分的代码实现在了 evict.c 中。
”
高可靠性和高扩展性
“,虽然 Redis 一般是作为内存数据库来使用的,但是它也提供了可靠性保证,这主要体现在 Redis 可以对数据做持久化保存,并且它还实现了主从复制机制,从而可以提供故障恢复的功能
”
持久化
主要分为 RDB(Redis Database)和AOF(Append Only File),分别实现在了 rdb.h/rdb.c 和 aof.c 中。 注意,在使用 RDB 或 AOF 对数据库进行恢复时,RDB 和 AOF 文件可能会因为 Redis 实例所在服务器宕机,而未能完整保存,进而会影响到数据库恢复。
因此针对这一问题,Redis 还实现了对这两类文件的检查功能,对应的代码文件分别是 redis-check-rdb.c 和 redis-check-aof.c。
主从复制
Redis把主从复制功能实现在了 replication.c 文件中,Redis 的主从在进行恢复时,主要是依赖于哨兵机制,而这部分功能则直接实现在了sentinel.c 文件中。
其次,与 Redis 实现高可靠性保证的功能类似,Redis 高可扩展性保证的功能,是通过Redis Cluster来实现的,这部分代码也非常集中,就是在 cluster.h/cluster.c 代码文件中。所以这样,我们在学习 Redis Cluster 的设计与实现时,就会非常方便,不用在不同的文件之间来回跳转了。
辅助功能
“Redis 还实现了一些用于支持系统运维的辅助功能。比如,为了便于运维人员查看分析不同操作的延迟产生来源,Redis 在 latency.h/latency.c 中实现了操作延迟监控的功能;
”
为了便于运维人员查找运行过慢的操作命令,Redis 在 slowlog.h/slowlog.c 中实现了慢命令的记录功能,等等。
此外,运维人员有时还需要了解 Redis 的性能表现,为了支持这一目标,Redis 实现了对系统进行性能评测的功能,这部分代码在
redis-benchmark.c 中
(Kaito)
数据类型:
String(t_string.c、sds.c、bitops.c) List(t_list.c、ziplist.c) Hash(t_hash.c、ziplist.c、dict.c) Set(t_set.c、intset.c) Sorted Set(t_zset.c、ziplist.c、dict.c) HyperLogLog(hyperloglog.c) Geo(geo.c、geohash.c、geohash_helper.c) Stream(t_stream.c、rax.c、listpack.c)
全局:
Server(server.c、anet.c) Object(object.c) 键值对(db.c) 事件驱动(ae.c、ae_epoll.c、ae_kqueue.c、ae_evport.c、ae_select.c、networking.c) 内存回收(expire.c、lazyfree.c) 数据替换(evict.c) 后台线程(bio.c) 事务(multi.c) PubSub(pubsub.c) 内存分配(zmalloc.c) 双向链表(adlist.c)
高可用&集群:
持久化:RDB(rdb.c、redis-check-rdb.c)、AOF(aof.c、redis-check-aof.c) 主从复制(replication.c) 哨兵(sentinel.c) 集群(cluster.c)
辅助功能:
延迟统计(latency.c) 慢日志(slowlog.c) 通知(notify.c) 基准性能(redis-benchmark.c)