二、Redis服务启动以及请求流程

上一次我们大概熟悉了一下redis的目录结构,里面提到了服务启动相关的源码主要包含如下两个文件:

 

 找到server.c文件中的main函数开始了解服务的启动过程:

源码解析:

1、主流程:

 

/* Global vars */ // 全局变量 struct redisServer server; /* Server global state */ volatile unsigned long lru_clock; /* Server global current LRU time. */ struct redisCommand redisCommandTable[] ={...} /* Our command table.*/
int main(int argc, char **argv) { // 主入口     struct timeval tv;     int j;  #ifdef REDIS_TEST // redis测试环境设置     if (argc == 3 && !strcasecmp(argv[1], test)) {         ...return -1; /* test not found */     } #endif      /* We need to initialize our libraries, and the server configuration. */ // 初始化库和服务器配置。   #ifdef INIT_SETPROCTITLE_REPLACEMENT     spt_init(argc, argv); #endif     // 设置相关默认值
   setlocale(LC_COLLATE,); tzset(); /* Populates 'timezone' global. */
zmalloc_set_oom_handler(redisOutOfMemoryHandler); srand(time(NULL)^getpid()); gettimeofday(&tv,NULL); char hashseed[16]; getRandomHexChars(hashseed,sizeof(hashseed)); dictSetHashFunctionSeed((uint8_t*)hashseed); // 哨兵模式
server.sentinel_mode = checkForSentinelMode(argc,argv); // 默认配置加载
initServerConfig(); moduleInitModulesSystem(); /* Store the executable path and arguments in a safe place in order * to be able to restart the server later. */ 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]); /* We need to init sentinel right now as parsing the configuration file * in sentinel mode will have the effect of populating the sentinel * data structures with master nodes to monitor. */ if (server.sentinel_mode) { initSentinelConfig(); initSentinel(); }
   // 加载配置文件 /* Check if we need to start in redis-check-rdb/aof mode. We just execute * the program main. However the program is part of the Redis executable * so that we can easily execute an RDB check on loading errors. */ 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) { j = 1; /* First option to parse in argv[] */ sds options = sdsempty(); char *configfile = NULL; /* 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); } } /* First argument is the config file name? */ if (argv[j][0] != '-' || argv[j][1] != '-') { configfile = argv[j]; server.configfile = getAbsolutePath(configfile); /* Replace the config file in server.exec_argv with * its absolute path. */ zfree(server.exec_argv[j]); server.exec_argv[j] = zstrdup(server.configfile); j++; } /* All the other options are parsed and conceptually appended to the * configuration file. For instance --port 6380 will generate the * string port 6380\n to be parsed after the actual file name * is parsed, if any. */ while(j != argc) { if (argv[j][0] == '-' && argv[j][1] == '-') { /* Option name */ if (!strcmp(argv[j], --check-rdb)) { /* Argument has no options, need to skip for parsing. */ j++; continue; } 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++; } if (server.sentinel_mode && configfile && *configfile == '-') { serverLog(LL_WARNING, Sentinel config from STDIN not allowed.); serverLog(LL_WARNING, Sentinel needs config file on disk to save state. Exiting...); exit(1); } resetServerSaveParams(); // 加载配置文件
     loadServerConfig(configfile,options); sdsfree(options); } 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/%s.conf, argv[0], server.sentinel_mode ? sentinel : redis); } else { serverLog(LL_WARNING, Configuration loaded); } server.supervised = redisIsSupervised(server.supervised_mode); int background = server.daemonize && !server.supervised; if (background) daemonize(); // 初始化服务器
   initServer(); if (background || server.pidfile) createPidFile(); redisSetProcTitle(argv[0]); redisAsciiArt(); 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__ */ // 数据恢复
     moduleLoadFromQueue(); InitServerLast(); 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) 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); } else { InitServerLast(); // 哨兵模式执行 sentinelIsRunning(); } /* Warning the user about suspicious maxmemory setting. */ if (server.maxmemory > 0 && server.maxmemory < 1024*1024) { 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); } aeSetBeforeSleepProc(server.el,beforeSleep); aeSetAfterSleepProc(server.el,afterSleep); aeMain(server.el); // 关闭服务
   aeDeleteEventLoop(server.el); return 0; }

 

2、配置参数

  // 默认配置加载
initServerConfig(); 核心代码对象赋值(struct redisServer server;)
  // 加载配置文件
  loadServerConfig(configfile,options) 》》》 void loadServerConfigFromString(char *config){ ... strcasecmp(argv[0],port) ... } 配置文件加载数据

 3、初始化服务

--20220510待更新

void initServer(void) {     int j;      signal(SIGHUP, SIG_IGN);     signal(SIGPIPE, SIG_IGN);     setupSignalHandlers();      if (server.syslog_enabled) {         openlog(server.syslog_ident, LOG_PID | LOG_NDELAY | LOG_NOWAIT,             server.syslog_facility);     }      server.hz = server.config_hz;     server.pid = getpid();     server.current_client = NULL;     server.fixed_time_expire = 0;     server.clients = listCreate();     server.clients_index = raxNew();     server.clients_to_close = listCreate();     server.slaves = listCreate();     server.monitors = listCreate();     server.clients_pending_write = listCreate();     server.slaveseldb = -1; /* Force to emit the first SELECT command. */     server.unblocked_clients = listCreate();     server.ready_keys = listCreate();     server.clients_waiting_acks = listCreate();     server.get_ack_from_slaves = 0;     server.clients_paused = 0;     server.system_memory_size = zmalloc_get_memory_size();      createSharedObjects();     adjustOpenFilesLimit();     server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR);     if (server.el == NULL) {         serverLog(LL_WARNING,             Failed creating the event loop. Error message: '%s',             strerror(errno));         exit(1);     }     server.db = zmalloc(sizeof(redisDb)*server.dbnum);      /* Open the TCP listening socket for the user commands. */     if (server.port != 0 &&         listenToPort(server.port,server.ipfd,&server.ipfd_count) == C_ERR)         exit(1);      /* Open the listening Unix domain socket. */     if (server.unixsocket != NULL) {         unlink(server.unixsocket); /* don't care if this fails */         server.sofd = anetUnixServer(server.neterr,server.unixsocket,             server.unixsocketperm, server.tcp_backlog);         if (server.sofd == ANET_ERR) {             serverLog(LL_WARNING, Opening Unix socket: %s, server.neterr);             exit(1);         }         anetNonBlock(NULL,server.sofd);     }      /* Abort if there are no listening sockets at all. */     if (server.ipfd_count == 0 && server.sofd < 0) {         serverLog(LL_WARNING, Configured to not listen anywhere, exiting.);         exit(1);     }      /* Create the Redis databases, and initialize other internal state. */     for (j = 0; j < server.dbnum; j++) {         server.db[j].dict = dictCreate(&dbDictType,NULL);         server.db[j].expires = dictCreate(&keyptrDictType,NULL);         server.db[j].blocking_keys = dictCreate(&keylistDictType,NULL);         server.db[j].ready_keys = dictCreate(&objectKeyPointerValueDictType,NULL);         server.db[j].watched_keys = dictCreate(&keylistDictType,NULL);         server.db[j].id = j;         server.db[j].avg_ttl = 0;         server.db[j].defrag_later = listCreate();     }     evictionPoolAlloc(); /* Initialize the LRU keys pool. */     server.pubsub_channels = dictCreate(&keylistDictType,NULL);     server.pubsub_patterns = listCreate();     listSetFreeMethod(server.pubsub_patterns,freePubsubPattern);     listSetMatchMethod(server.pubsub_patterns,listMatchPubsubPattern);     server.cronloops = 0;     server.rdb_child_pid = -1;     server.aof_child_pid = -1;     server.rdb_child_type = RDB_CHILD_TYPE_NONE;     server.rdb_bgsave_scheduled = 0;     server.child_info_pipe[0] = -1;     server.child_info_pipe[1] = -1;     server.child_info_data.magic = 0;     aofRewriteBufferReset();     server.aof_buf = sdsempty();     server.lastsave = time(NULL); /* At startup we consider the DB saved. */     server.lastbgsave_try = 0;    /* At startup we never tried to BGSAVE. */     server.rdb_save_time_last = -1;     server.rdb_save_time_start = -1;     server.dirty = 0;     resetServerStats();     /* A few stats we don't want to reset: server startup time, and peak mem. */     server.stat_starttime = time(NULL);     server.stat_peak_memory = 0;     server.stat_rdb_cow_bytes = 0;     server.stat_aof_cow_bytes = 0;     server.cron_malloc_stats.zmalloc_used = 0;     server.cron_malloc_stats.process_rss = 0;     server.cron_malloc_stats.allocator_allocated = 0;     server.cron_malloc_stats.allocator_active = 0;     server.cron_malloc_stats.allocator_resident = 0;     server.lastbgsave_status = C_OK;     server.aof_last_write_status = C_OK;     server.aof_last_write_errno = 0;     server.repl_good_slaves_count = 0;      /* Create the timer callback, this is our way to process many background      * operations incrementally, like clients timeout, eviction of unaccessed      * expired keys and so forth. */     if (aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {         serverPanic(Can't create event loop timers.);         exit(1);     }      /* Create an event handler for accepting new connections in TCP and Unix      * domain sockets. */     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.);             }     }     if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE,         acceptUnixHandler,NULL) == AE_ERR) serverPanic(Unrecoverable error creating server.sofd file event.);       /* Register a readable event for the pipe used to awake the event loop      * when a blocked client in a module needs attention. */     if (aeCreateFileEvent(server.el, server.module_blocked_pipe[0], AE_READABLE,         moduleBlockedClientPipeReadable,NULL) == AE_ERR) {             serverPanic(                 Error registering the readable event for the module                  blocked clients subsystem.);     }      /* Open the AOF file if needed. */     if (server.aof_state == AOF_ON) {         server.aof_fd = open(server.aof_filename,                                O_WRONLY|O_APPEND|O_CREAT,0644);         if (server.aof_fd == -1) {             serverLog(LL_WARNING, Can't open the append-only file: %s,                 strerror(errno));             exit(1);         }     }      /* 32 bit instances are limited to 4GB of address space, so if there is      * no explicit limit in the user provided configuration we set a limit      * at 3 GB using maxmemory with 'noeviction' policy'. This avoids      * useless crashes of the Redis instance for out of memory. */     if (server.arch_bits == 32 && server.maxmemory == 0) {         serverLog(LL_WARNING,Warning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with 'noeviction' policy now.);         server.maxmemory = 3072LL*(1024*1024); /* 3 GB */         server.maxmemory_policy = MAXMEMORY_NO_EVICTION;     }      if (server.cluster_enabled) clusterInit();     replicationScriptCacheInit();     scriptingInit(1);     slowlogInit();     latencyMonitorInit(); }