Redis源码解析——前言
今天开启Redis源码的阅读之旅。对于一些没有接触过开源代码分析的同学来说,可能这是一件很麻烦的事。但是我总觉得做一件事,不管有多大多难,我们首先要在战略上蔑视它,但是要在战术上重视它。除了一些高大上的技术,我们一般人都能用比较简单的方式描述它是干什么的。比如Redis,它不就是一个可以通过网络访问的KV型数据库嘛。在没有源码的情况下,可以想象出它应该是通过网络服务、指令解析、特殊的内存结构设计(方便增删改查)、持久化等技术构成。然后我们在战术上要重视它各个技术的实现,特别是一些我们没想到的一些技术。(转载请指明出于breaksoftware的csdn博客)
首先,我会先粗略阅读一遍代码。这个过程不会花费比较多的时间,因为只是简单看看。很多技术细节、算法等都是一带而过。这个过程只为了达到一个效果:大致清楚每个文件都是为了解决哪类问题的。其实第一遍“扫”代码并不能完全达到这个效果,但是能预判出我们确定需要使用的技术对应的文件就行了。剩下的一些未知文件可能就是我们在预估这个工程构成时没有考虑到的,它们往往隐藏了一些特殊功能。
然后,我会选择阅读Makefile文件,看看它是由哪些文件编译生成,以及它依赖的一些技术。再之后就按我们预估的技术点去看看它们的实现。在阅读的过程中,我们可能会遇到之前我们没有预估到的一些技术点,这个时候我们要采用广度优先方法去阅读还是深度优先方法去阅读就要看各自的技术能力和爱好了。
现在回到Redis上来。我准备阅读的源码地址是http://download.redis.io/releases/redis-3.2.5.tar.gz。它是目前稳定的3.2版本。解压完之后,可以发现
一般来说,我们可以通过文件命名猜测出它们的功能。但是阅读过程也是要“大胆猜测,小心求证”。比如上图中,Copying文件可以猜测出它是版本信息文件,我们可以不关心。Runtest、Runtest-cluster、Runtest-sentinel分别对应于“整体测试”、“分布式测试”和“主从切换测试”的脚本,这个时候我们就知道“分布式”和“主从切换”是Redis的重要功能,这样就补齐了我们对其技术点构成的认识。Redis.conf和Seninel.conf分别对应于Redis的配置和主从配置,此时看这些配置还没用,前期我们可以略过,等到用到时再回来看看。Deps应该是depends的英文缩写,即它应该是依赖的库
一般来说,依赖库都是开源的第三方库。上图可见Redis需要在内部使用到:
- Lua脚本引擎。Redis内嵌Lua脚本引擎,那么说明Redis需要Lua语言的解析能力。那么可以进一步猜测应该是用户可以定制Lua脚本让Reids去执行,这相当于Redis开放了一个非常自由的接口供外部使用。
- Linenoise是一个命令行编辑库。这个正是我们之前预估的Redis基础功能之一。它的相关资料可见https://github.com/antirez/linenoise
- Jemalloc是内存管理库。很多开源项目不使用glibc自带的ptmalloc,而是使用Jemalloc或者Tcmalloc这类更高效的内存管理库。
- Hiredis是Redis数据库的C接口。这块和Redis相关性比较大,我们之后也会重点关注下。
- Geohash-int是一种地理编码算法。它将二维经纬度信息转换成Int型数据。
上面这些第三方库,我们不会全部去看。比如Lua脚本引擎,这块技术非常独立,我们在阅读Redis代码时应该是不会深入阅读的。再比如Jemalloc库,它也是非常基础的库,未来我应该会分析ptmalloc、tcmalloc和jemalloc这三种内存管理库,但是在分析Redis代码时也不会去深入阅读。Geohash-int是一套算法,除非它提供的特性对redis非常重要,否则之后应该也不会去阅读。Linenoise是用于命令行编辑的,它也非Redis主要功能,可以不用去看。Hiredis可能和Redis的相关性大一些,这个模块应该会被关注。
退到上一层,再看看Tests,它是测试相关的目录。里面都是各种测试Redis的脚本。
可见测试脚本是一些后缀为tcl的文件。它的内容这是一种被广泛使用的脚本测试语言——TCL语言。这块我们应该也不会过多涉及。
Utils从命名看,它应该是一些工具
从上图看,我们可以发现其内容大部分是一些脚本语言。所以我们之后也不会太多涉及。
然后我们关注下Makefile文件
# Top level makefile, the real shit is at src/Makefiledefault: all.DEFAULT:cd src && $(MAKE) $@install:cd src && $(MAKE) $@.PHONY: install
它进入到src目录,然后再make。于是我们也进入最最重要的redis源码目录——src去一看究竟。
进入Src后,我们仍然关注Makffile文件。最开始除了一些编译参数和依赖项定义外,还有就是内存管理库的使用问题
# Default allocator
ifeq ($(uname_S),Linux)MALLOC=jemalloc
elseMALLOC=libc
endif# Backwards compatibility for selecting an allocator
ifeq ($(USE_TCMALLOC),yes)MALLOC=tcmalloc
endififeq ($(USE_TCMALLOC_MINIMAL),yes)MALLOC=tcmalloc_minimal
endififeq ($(USE_JEMALLOC),yes)MALLOC=jemalloc
endififeq ($(USE_JEMALLOC),no)MALLOC=libcendif
linux系统上,Redis默认选择的内存管理库是jemalloc,其他系统则是选择libc的ptmalloc。当然还可以通过指定库来修改内存管理库。如上可以见我们还可以选择tcmalloc或者tcmalloc_minimal。
之后还是一些编译对象组合
REDIS_SERVER_NAME=redis-server
REDIS_SENTINEL_NAME=redis-sentinel
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o geo.o
REDIS_GEOHASH_OBJ=../deps/geohash-int/geohash.o ../deps/geohash-int/geohash_helper.o
REDIS_CLI_NAME=redis-cli
REDIS_CLI_OBJ=anet.o adlist.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o
REDIS_BENCHMARK_NAME=redis-benchmark
REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o zmalloc.o redis-benchmark.o
REDIS_CHECK_RDB_NAME=redis-check-rdb
REDIS_CHECK_AOF_NAME=redis-check-aof
REDIS_CHECK_AOF_OBJ=redis-check-aof.o
…………………………………………
# redis-server
$(REDIS_SERVER_NAME): $(REDIS_SERVER_OBJ)$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/lua/src/liblua.a $(REDIS_GEOHASH_OBJ) $(FINAL_LIBS)# redis-sentinel
$(REDIS_SENTINEL_NAME): $(REDIS_SERVER_NAME)$(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME)# redis-check-rdb
$(REDIS_CHECK_RDB_NAME): $(REDIS_SERVER_NAME)$(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_RDB_NAME)# redis-cli
$(REDIS_CLI_NAME): $(REDIS_CLI_OBJ)$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS)# redis-benchmark
$(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ)$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a $(FINAL_LIBS)# redis-check-aof
$(REDIS_CHECK_AOF_NAME): $(REDIS_CHECK_AOF_OBJ)$(REDIS_LD) -o $@ $^ $(FINAL_LIBS)
上面脚本可以见这个Makefile可以编译出6个不同的最终产物。
其中最核心的应该是REDIS_SERVER_NAME对应的编译内容。我们从其需要链接的文件(REDIS_SERVER_OBJ中的内容)来看,程序的入口函数main应该位于server.o文件中。我们继续查看server.c文件,果然发现了它。
之后的代码我采用深度优先的方法去阅读,但是这种方式是需要在一条主线的基础之上进行的。这样就会导致主线的逻辑被打的很零散。所以我决定还是要分章节,从最基础的一些代码开始分析。如果模块和Redis不是强关联的,我将以该模块名为分析博文的标题,比如之前介绍的SDS字符串管理库,它的相关介绍名称为《Simple Dynamic Strings(SDS)源码解析和使用说明一》和《Simple Dynamic Strings(SDS)源码解析和使用说明二》。而和Redis强关联的模块,我将以《Redis源码解析——XXXXX》形式命名。
相关文章:

asp.net客户端脚本验证小技巧
通用的客户端脚本验证 Code//验证客户端function checkclient() { var list document.all; for(var i0 ;i<list.length; i) { var h list[i].hint; if(h ! null && h ! "") { if(list[i].isdrop"…
5个可以帮助你提高工作效率的新AI工具
作者 | Kyrylo Lyzanets译者 | 火火酱编辑 | Carol出品 | AI科技大本营(ID: rgznai100) 毫无意义的新闻、故事和活动会占用你每天多少的工作时间?假如你是一名需要高绩效的高管或专业人士,如果在工作中可以不分心,那你…

Centos6.5更换163源 epel源
想必大家都遇到过,安装新的centos系统,使用yum去安装软件的时候,要么找不到,要么慢的让人发疯。网上其实办法很多,直接更换163源就ok,但是基本所有的文章都是直接wget下163的源,但是不知道为什么…
图模型+Bert香不香?完全基于注意力机制的图表征学习模型Graph-Bert
作者 | Jiawei Zhang、Haopeng Zhang、Congying Xia、Li Sun译者 | 凯隐编辑 | Jane出品 | AI科技大本营(ID:rgznai100)【导读】本文提出了一种全新的图神经网络 Graph-Bert,仅仅基于 Attention 机制而不依赖任何类卷积或聚合操作…

闭关纪要17.Google app engine的简单应用
在上面用了十一篇博客的文章详细的介绍了,Step1账户登录系统之后,从现在开始,继续写闭关纪要,因为Step1账户登录系统也是闭关工作的一部分,因此保留序号,这篇纪要在上次的闭关纪要5.WML,UTF-8,BOM,签名及其…
Redis源码解析——内存管理
在《Redis源码解析——源码工程结构》一文中,我们介绍了Redis可能会根据环境或用户指定选择不同的内存管理库。在linux系统中,Redis默认使用jemalloc库。当然用户可以指定使用tcmalloc或者libc的原生内存管理库。本文介绍的内容是在这些库的基础上&#…

poj_2479 动态规划
题目大意 给定一列数,从中选择两个不相交的连续子段,求这两个连续子段和的最大值。 题目分析 典型的M子段和的问题,使用动态规划的方法来解决。 f[i][j] 表示将A[1...i] 划分为j个不相交连续子串,且A[j]属于第i个子串,…
Redis源码解析——字典结构
C语言中有标准的字典库,我们可以通过pair(key,value)的形式存储数据。但是C语言中没有这种的库,于是就需要自己实现。本文讲解的就是Redis源码中的字典库的实现方法。(转载请指明出于breaksoftware的csdn博客) 一般情况下…
十步,教你把Python运行速度提升 30%
作者 | Martin Heinz译者 | 陆离编辑 | Jane出品 | AI科技大本营(ID:rgznai100)【导读】一直以来,诟病 Python语言的人经常说,他们不想使用的一个原因是 Python 的速度太慢了。不管使用哪一种编程语言,程序…

字符串转换成NSDate类型的 为nil解决方法
方法一 通过下列函数来解决 但是得到的日期会改变 修改方法fix- (NSDate *)timeForString:(NSString *)string {NSMutableString *timeString [[NSMutableString alloc] initWithString:string]; [timeString setString:[timeString stringByReplacingOccurrence…
Redis源码解析——字典基本操作
有了《Redis源码解析——字典结构》的基础,我们便可以对dict的实现进行展开分析。(转载请指明出于breaksoftware的csdn博客) 创建字典 一般字典创建时,都是没有数据的,但是字典类型需要确定,所以我们看到R…

[转]控制 Cookie 的作用范围
默认时,网站的所有 Cookies 都一起被存储在客户端,并且所有 Cookies 连同网站的任何请求一起被发送到服务器。换句话说,网站中的每个页面都能够为网站获取所有的 Cookies。但是,你能够通过两个方式来设置 Cookies 的作用范围&…
强化学习70年演进:从精确动态规划到基于模型
作者 | Nathan Lambert译者 | 泓礼编辑 | 夕颜出品 | AI科技大本营(ID: rgznai100)【导读】这是一份帮你了解强化学习算法本质的资源,无需浏览大量文档,没有一条公式,非常适合学生和研究人员阅读。作为强化学习研究人员…

Android ActionBar相关
1.Android 5.0 删除ActionBar下面的阴影 于Android 5.0假设你发现的ActionBar下面出现了阴影,例如,下面的设置,以消除阴影: getActionBar().setElevation(0); Android 5.0之前能够用以下代码消除阴影: <item name&q…
Redis源码解析——字典遍历
之前两篇博文讲解了字典库的基础,本文将讲解其遍历操作。之所以将遍历操作独立成一文来讲,是因为其中的内容和之前的基本操作还是有区别的。特别是高级遍历一节介绍的内容,充满了精妙设计的算法智慧。(转载请指明出于breaksoftwar…
开发者在行动!中国防疫开源项目登上GitHub TOP榜
整理 | 唐小引出品 | CSDN(ID:CSDNnews)【导读】用开发者们的方式支援这场没有硝烟的战争!截止北京时间 1 月 28 日下午 15:47,全国确诊新型冠状病毒的数字已经到达了 4586 例,疑似高达 6973 例,…

像童话一样学习OSPF原理
可以把整个网络(一个自治系统AS)看成一个王国,这个王国可以分成几个 区(area),现在我们来看看区域内的某一个人(你所在的机器root)是怎样得到一张 世界地图(routing table)的。 首先,你得跟你周围的人(…

队列——PowerShell版
继续读啊哈磊《啊哈!算法》感悟系列——队列 地铁售票处排队,先来的人先到队首先买完先走,后来的人排在队尾等候后买完后走。 想买票,必须排在队尾;买完票,只能从队首离开。 这种先进先出(First…

Redis源码解析——双向链表
相对于之前介绍的字典和SDS字符串库,Redis的双向链表库则是非常标准的、教科书般简单的库。但是作为Redis源码的一部分,我决定还是要讲一讲的。(转载请指明出于breaksoftware的csdn博客) 基本结构 首先我们看链表元素的结构。因为…

12月第三周安全要闻回顾:浏览器安全不容忽视,SSL弱点影响网站安全
本周(081215至081221)安全方面的新闻众多,主要集中在***与威胁趋势方面。浏览器安全方向波澜起伏,微软推出了针对上周公开的IE7新漏洞的紧急安全补丁,但目前互联网上针对该漏洞的大规模***仍在继续,******的…
GPT2文本生成有问题?这里有些潜在解决思路
作者 | Leo Gao译者 | 凯隐编辑 | 夕颜出品 | AI科技大本营(ID: rgznai100) 【导读】在过去的一年中,人们对文本生成模型的兴趣重新燃起,这在很大程度上要归功于GPT2,它主要展示了使用更大模型、更大数据和更大计算量的…

HTML5学习之二:HTML5中的表单2
(本内容部分节选自《HTML 5从入门到精通》) 对表单的验证 ———————————————————————————————————————————————————————— •1、required属性 required属性主要目的是确保表单控件中的值已填写。在提交时&…
Redis源码解析——有序整数集
有序整数集是Redis源码中一个以大尾(big endian)形式存储,由小到大排列且无重复的整型集合。它存储的类型包括16位、32位和64位的整型数。在介绍这个库的实现前,我们还需要先熟悉下大小尾内存存储机制。(转载请指明出于…
GitHub标星1.2w+,Chrome最天秀的插件都在这里
作者 | Rocky0429来源 | Python空间(ID: Devtogether)大家好,我是 Rocky0429,一个沉迷 Chrome 不能自拔的蒟蒻...作为一个在远古时代用过什么 IE、360、猎豹等浏览器的资深器哥,当我第一次了解 Chrome 的时候ÿ…

基础篇 第四节 项目进度计划编辑 之 任务关联性设定
1.任务关联性的类型 ◎完成 —— 开始 FS ◎开始 —— 开始 SS ◎开始 —— 完成 SF 完成 —— 完成 FF 2.设定任务关联性 三种方法: ◎在条形图中直接拖拽 ◎在“前置任务”列中编辑 ◎在“任务信息”中的“前置任务”选项卡中编辑 3.设定“延隔时间” 延隔时间小于…
开坑,写点Polymer 1.0 教程第3篇——组件注册与创建
之前一篇算是带大家大致领略了一下Polymer的风采。这篇我们稍微深入一丢丢,讲下组件的注册和创建。 创建自定义组件的几种方式 这里我们使用Polymer函数注册了一个自定义组件"my-element" // register an element Polymer({is: my-element,created: funct…
Redis源码解析——Zipmap
本文介绍的是Redis中Zipmap的原理和实现。(转载请指明出于breaksoftware的csdn博客) 基础结构 Zipmap是为了实现保存Pair(String,String)数据的结构,该结构包含一个头信息、一系列字符串对(之后把一个“字符串对”称为一个“元素…

IIS7入门之旅:(3)CGI application和FastCGI application的区别
前言: 一如既往地,IIS支持通过提供pluggable module来提供对第3方script的支持,例如php等。在IIS7中,对于CGI的支持有了一个新的变化,就是同时提供了2种CGI支持模块,分别为:CGIModule (cgi.dll)和FastCGIMo…

抗击疫情!阿里云为加速新药疫苗研发提供免费AI算力
1月29日,阿里云正式宣布:疫情期间,向全球公共科研机构免费开放一切AI算力,以加速本次新型肺炎新药和疫苗研发。 目前,中国疾控中心已成功分离病毒,疫苗研发和药物筛选仍在争分夺秒地进行。新药和疫苗研发期…
SpriteBuilder中如何平均拉伸精灵帧动画的距离
首先要在Timeline中选中所有的精灵帧,可以通过如下2种的任意一种办法达成: 1按下Shift键的同时鼠标单击它们 2鼠标在Timeline空白区拖拽直到拉出的矩形包围住所有精灵帧方块后放开鼠标。 你可以通过查看Timeline中精灵帧方块上是否有阴影来辨识是否选中…