Redis源码详解1:概述
REmote DIctionary Server(Redis)是当前使用最广泛的高性能内存数据库,使用C语言开发,常常被用来实现缓存、分布式锁等功能。
本系列分析Redis 5.0版本,源代码可以从GitHub下载,付上下载地址。
项目结构⌗
Redis项目的目录结构如下:
-
redis/
-
deps/ 依赖项目
-
hiredis C语言客户端,Redis作者开发
-
jemalloc 内存管理
-
linenoise 命令行编辑库,Redis作者开发
-
lua Lua脚本
-
-
src/ 源代码目录
-
100多个源代码文件
-
modules/ Redis module扩展模块的例子
-
-
tests/ 测试代码目录
-
utils/ 脚本程序目录
-
Makefile
-
redis.conf 默认配置文件
-
其他文件
-
其中最重要的是src文件夹,包含了Redis服务端的源代码,本系列主要分析的代码都在这个文件夹下。
Redis服务器主程序入口在server.c文件,客户端的主程序入口在redis-cli.c文件中。
Redis如何处理请求⌗
在深入细节之前,让我们先从主程序入口开始,对Redis的启动过程,以及如何处理客户端的指令有一个大致的了解。
server.c
int main(int argc, char **argv){
// 省略代码,处理启动参数,初始化配置,指令列表,等等
initServer();
// 省略代码
aeSetBeforeSleepProc(server.el,beforeSleep);
aeSetAfterSleepProc(server.el,afterSleep);
aeMain(server.el); // 运行事件循环,处理请求
aeDeleteEventLoop(server.el);
return 0;
}
void initServer(void){
// 省略代码
// 开始监听端口
if (server.port != 0 &&
listenToPort(server.port,server.ipfd,&server.ipfd_count) == C_ERR)
exit(1);
// 省略代码
// 创建定时事件
if (aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
serverPanic("Can't create event loop timers.");
exit(1);
}
// 省略代码
// 创建文件事件,处理TCP请求
for (j = 0; j < server.ipfd_count; j++) {
if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
acceptTcpHandler,NULL) == AE_ERR)
{
serverPanic(
"Unrecoverable error creating server.ipfd file event.");
}
}
}
networking.c
void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
int cport, cfd, max = MAX_ACCEPTS_PER_CALL;
char cip[NET_IP_STR_LEN];
UNUSED(el);
UNUSED(mask);
UNUSED(privdata);
while(max--) {
cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport);
if (cfd == ANET_ERR) {
if (errno != EWOULDBLOCK)
serverLog(LL_WARNING,
"Accepting client connection: %s", server.neterr);
return;
}
serverLog(LL_VERBOSE,"Accepted %s:%d", cip, cport);
acceptCommonHandler(cfd,0,cip);
}
}
static void acceptCommonHandler(int fd, int flags, char *ip) {
client *c;
if ((c = createClient(fd)) == NULL) { // 创建新的client
serverLog(LL_WARNING,
"Error registering fd event for the new client: %s (fd=%d)",
strerror(errno),fd);
close(fd);
return;
}
// 省略代码
}
client *createClient(int fd) {
client *c = zmalloc(sizeof(client));
if (fd != -1) {
anetNonBlock(NULL,fd);
anetEnableTcpNoDelay(NULL,fd);
if (server.tcpkeepalive)
anetKeepAlive(NULL,fd,server.tcpkeepalive);
// 创建读取请求事件,注册处理请求的回调函数readQueryFromClient
if (aeCreateFileEvent(server.el,fd,AE_READABLE,
readQueryFromClient, c) == AE_ERR)
{
close(fd);
zfree(c);
return NULL;
}
}
selectDb(c,0); //默认使用db0
// 省略代码
}
main函数做了以下几件事情:
- 处理程序运行参数
- 配置并初始化server
- 监听端口
- 创建事件循环,注册回调函数
- 运行事件循环
networking.c中createClient函数注册了回调函数readQueryFromClient,当服务器收到请求时会调用server.c中的call函数处理具体的请求,比如get,set,hmget等等。