Redis服务端初始化流程
参考链接:https://redissrc.readthedocs.io/en/latest/init/server.htmlhttps://www.jianshu.com/p/1166288c6d32?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
·
Redis版本:Redis 4.0.1
Redis服务端有个入口,其入口如下:
server.c -> main(int argc, char **argv)
服务端启动初始化流程分为如下5个步骤:
1 初始化服务器全局状态
-- 初始化
redisServer结构体对应的数据,如db数据库、事件状态、日志、AOF/RDB、统计信息
2 加载配置文件参数
-- 通过redis-server /etc/my-redis.conf加载my-redis.conf配置信息覆盖redis默认配置,比如port
3 初始化服务器功能模块
* 初始化 Redis 进程的信号功能。
* 初始化日志功能。
* 初始化客户端功能。
* 初始化共享对象。
* 初始化事件功能。
* 初始化网络连接。
* 初始化数据库。
* 初始化订阅与发布功能。
* 初始化各个统计变量。
* 关联服务器常规操作(cron job)到时间事件,关联客户端应答处理器到文件事件。
* 如果 AOF 功能已打开,那么打开或创建 AOF 文件。
* 设置内存限制。
* 初始化 Lua 脚本环境。
* 初始化慢查询功能。
* 初始化后台操作线程。
4 加载持久化数据
根据配置模式的模式进行加载,如果开启aof就aof加载,否则rdb
5 开启事件循环,epoll事件循环
启动流程源码分析如下(具体见gitee:
https://gitee.com/lidishan/redis-source-code-analysis/blob/master/src/server.c
):
int main(
int argc,
char **argv) {
.........................省略,前面是一部分处理逻辑
//
填充哨兵模式
server.sentinel_mode = checkForSentinelMode(argc,argv);
// 1 初始化服务器全局状态==========================================
initServerConfig();
// --
初始化
ACL
控制相关
ACLInit();
// --
初始化模块 加载动态链接库 可自定义命令,字典做映射关联
moduleInitModulesSystem();
tlsInit();
//
初始化
ssl
// --
设置传入的执行参数
server.executable = getAbsolutePath(argv[
0]);
server.exec_argv = zmalloc(
sizeof(
char*)*(argc+
1));
server.exec_argv[argc] = NULL;
for (j =
0; j < argc; j++) server.exec_argv[j] = zstrdup(argv[j]);
if (server.sentinel_mode) {
//
初始化哨兵相关配置
initSentinelConfig();
//
初始化端口、保护模式
initSentinel();
//
一些其他参数,有点多,自己看
}
// --
判断是否需要启动
RDB
和
AOF
if (strstr(argv[
0],
"redis-check-rdb") != NULL)
redis_check_rdb_main(argc,argv,NULL);
else if (strstr(argv[
0],
"redis-check-aof") != NULL)
redis_check_aof_main(argc,argv);
if (argc >=
2) {
//
如果命令行参数
>= 2
j =
1;
/* First option to parse in argv[] */
sds options = sdsempty();
//
判断第二个参数是否特殊参数,如果是就进行特殊处理,比如
-version
调用
version()
返回版本信息
/* Handle special options --help and --version */
if (strcmp(argv[
1],
"-v") ==
0 ||
strcmp(argv[
1],
"--version") ==
0) version();
if (strcmp(argv[
1],
"--help") ==
0 ||
strcmp(argv[
1],
"-h") ==
0) usage();
if (strcmp(argv[
1],
"--test-memory") ==
0) {
if (argc ==
3) {
memtest(atoi(argv[
2]),
50);
exit(
0);
}
else {
fprintf(stderr,
"Please specify the amount of memory to test in megabytes.
\n
");
fprintf(stderr,
"Example: ./redis-server --test-memory 4096
\n\n
");
exit(
1);
}
}
if (argv[
1][
0] !=
'-') {
/* Replace the config file in server.exec_argv with its absolute path. */
server.configfile = getAbsolutePath(argv[
1]);
zfree(server.exec_argv[
1]);
server.exec_argv[
1] = zstrdup(server.configfile);
j =
2;
// Skip this arg when parsing options
}
while(j < argc) {
/* Either first or last argument - Should we read config from stdin? */
if (argv[j][
0] ==
'-' && argv[j][
1] ==
'
\0
' && (j ==
1 || j == argc-1)) {
config_from_stdin =
1;
}
else if (argv[j][
0] ==
'-' && argv[j][
1] ==
'-') {
/* Option name */
if (sdslen(options)) options = sdscat(options,
"
\n
");
options = sdscat(options,argv[j]+
2);
options = sdscat(options,
" ");
}
else {
/* Option argument */
options = sdscatrepr(options,argv[j],strlen(argv[j]));
options = sdscat(options,
" ");
}
j++;
}
// 2 加载配置文件参数,如./redis-server /path/to/redis.conf xxx
loadServerConfig(server.configfile, config_from_stdin, options);
if (server.sentinel_mode) loadSentinelConfigFromQueue();
sdsfree(options);
}
// --
如果是哨兵模式则检查配置文件参数
if (server.sentinel_mode) sentinelCheckConfigFile();
server.supervised = redisIsSupervised(server.supervised_mode);
int background = server.daemonize && !server.supervised;
if (background) daemonize();
//
设置了守护进程后,会把
pid
写入到
pidfile
指定的文件中
// --
写日志
serverLog(LL_WARNING,
"oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo");
serverLog(LL_WARNING,
"Redis version=%s, bits=%d, commit=%s, modified=%d, pid=%d, just started"
,
REDIS_VERSION,
(
sizeof
(
long
) ==
8
) ?
64
:
32
,
redisGitSHA1(),
strtol(redisGitDirty(),NULL,
10) >
0,
(
int)getpid());
// --
写日志
if (argc ==
1) {
serverLog(LL_WARNING,
"Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/redis.conf", argv[
0]);
}
else {
serverLog(LL_WARNING,
"Configuration loaded");
}
//
读取内存溢出评分的调整值
readOOMScoreAdj();
// 3 初始化服务器功能模块
initServer();
if (background || server.pidfile) createPidFile();
// --
将命令行下标为
0
的命令行参数设置为进程名
if (server.set_proc_title) redisSetProcTitle(NULL);
redisAsciiArt();
//
打印
redis
工作模式,端口进程号等
checkTcpBacklogSettings();
// --
判断是否哨兵模式,然后打日志
if (!server.sentinel_mode) {
/* Things not needed when running in Sentinel mode. */
serverLog(LL_WARNING,
"Server initialized");
#ifdef __linux__
linuxMemoryWarnings();
#if defined (__arm64__)
int ret;
if ((ret = linuxMadvFreeForkBugCheck())) {
if (ret ==
1)
serverLog(LL_WARNING,
"WARNING Your kernel has a bug that could lead to data corruption during background save. "
"Please upgrade to the latest stable kernel.");
else
serverLog(LL_WARNING,
"Failed to test the kernel for a bug that could lead to data corruption during background save. "
"Your system could be affected, please report this error.");
if (!checkIgnoreWarning(
"ARM64-COW-BUG")) {
serverLog(LL_WARNING,
"Redis will now exit to prevent data corruption. "
"Note that it is possible to suppress this warning by setting the following config: ignore-warnings ARM64-COW-BUG");
exit(
1);
}
}
#endif
/* __arm64__ */
#endif
/* __linux__ */
moduleInitModulesSystemLast();
moduleLoadFromQueue();
ACLLoadUsersAtStartup();
InitServerLast();
// 4 加载持久化数据 根据配置模式的模式进行加载,如果开启aof就aof加载,否则rdb
loadDataFromDisk();
if (server.cluster_enabled) {
//
判断集群是否可用,如果可用但配置出错则终止进程
if (verifyClusterConfigWithData() == C_ERR) {
serverLog(LL_WARNING,
"You can't have keys in a DB different than DB 0 when in
Cluster mode. Exiting."
);
exit(
1);
}
}
// --
输出日志
if (server.ipfd.count >
0 || server.tlsfd.count >
0)
serverLog(LL_NOTICE,
"Ready to accept connections");
if (server.sofd >
0)
serverLog(LL_NOTICE,
"The server is now ready to accept connections at %s", server.unixsocket);
if (server.supervised_mode == SUPERVISED_SYSTEMD) {
if (!server.masterhost) {
redisCommunicateSystemd(
"STATUS=Ready to accept connections
\n
");
}
else {
redisCommunicateSystemd(
"STATUS=Ready to accept connections in read-only mode. Waiting for MASTER <-> REPLICA sync
\n
");
}
redisCommunicateSystemd(
"READY=1
\n
");
}
}
else {
//
到这步说明是哨兵模式,下面做一些哨兵的初始化收尾 和 判断哨兵是否运行中
ACLLoadUsersAtStartup();
InitServerLast();
sentinelIsRunning();
if (server.supervised_mode == SUPERVISED_SYSTEMD) {
redisCommunicateSystemd(
"STATUS=Ready to accept connections
\n
");
redisCommunicateSystemd(
"READY=1
\n
");
}
}
/* Warning the user about suspicious maxmemory setting. */
if (server.maxmemory >
0 && server.maxmemory <
1024*
1024) {
//
如果内存小于
1M
,输出警告日志
serverLog(LL_WARNING,
"WARNING: You specified a maxmemory value that is less than 1MB (current value is %llu bytes). Are you sure this is what you really want?", server.maxmemory);
}
// --
设置
CPU
亲缘属性
redisSetCpuAffinity(server.server_cpulist);
setOOMScoreAdj(-
1);
//
设置内存溢出评分的调整值
// 5 开启事件循环,epoll事件循环
aeMain(server.el);
// --
服务器关闭,删除事件循环
aeDeleteEventLoop(server.el);
return
0;
}
更多推荐
已为社区贡献1条内容
所有评论(0)