0
点赞
收藏
分享

微信扫一扫

Redis服务端初始化流程



参考链接: https://redissrc.readthedocs.io/en/latest/init/server.html



                  https://www.jianshu.com/p/1166288c6d32?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation



Redis版本:Redis 4.0.1


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
 
 

      .........................省略,前面是一部分处理逻辑
 
 
 
    // 
  填充哨兵模式
 
 

      server.sentinel_mode = checkForSentinelMode(argc,argv);
 
 
 
    
  // 1 初始化服务器全局状态==========================================
 
 

      initServerConfig();
 
 
 
    // -- 
  初始化
  ACL
  控制相关
 
 

      ACLInit(); 
 
 
 
    // -- 
  初始化模块 加载动态链接库 可自定义命令,字典做映射关联
 
 

 
 

      moduleInitModulesSystem();
 
 
 
// 
  初始化
  ssl
 
 

   
 
 
 
    // -- 
  设置传入的执行参数
 
 
0]);
 
 
 
sizeof(
  char*)*(argc+
  1));
 
 
 

      server.exec_argv[argc] = NULL;
 
 
 
    for (j = 
  0; j < argc; j++) server.exec_argv[j] = zstrdup(argv[j]);
 
 
 

   
 
 
 
    if
 
 
        // 
  初始化哨兵相关配置
 
 
// 
  初始化端口、保护模式
 
 
// 
  一些其他参数,有点多,自己看
 
 

      }
 
 
 

   
 
 
 
    // -- 
  判断是否需要启动
  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
 
 
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
 
 
1;
 
 
 
    
      }
 
 
 
        else if (argv[j][
  0] == 
  '-' && argv[j][
  1] == 
  '-') {
 
 
 
            /* Option name */
 
 
    
          
  if (sdslen(options)) options = sdscat(options,
  "
  \n
  ");
 
 
 
    
          options = sdscat(options,argv[j]+
  2);
 
 
 
" ");
 
 
 
    
      } 
  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
 
 

      
      sdsfree(options);
 
 
 

      }
 
 
 
    // -- 
  如果是哨兵模式则检查配置文件参数
 
 
    if
 
 
    // -- 
  计算是否可以后台启动,可以则调用
  daemonize()
 
 

      server.supervised = redisIsSupervised(server.supervised_mode);
 
 
 
    int
 
 
    if (background) daemonize();
  // 
  设置了守护进程后,会把
  pid
  写入到
  pidfile
  指定的文件中
 
 
    // -- 
  写日志
 
 
"oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo");
 
 
 
"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
 
 
"Configuration loaded");
 
 
 

      }
 
 
 
    // 
  读取内存溢出评分的调整值
 
 

      readOOMScoreAdj();
 
 
 
    
  // 3 初始化服务器功能模块
 
 

      initServer();
 
 
 
    if
 
 
    // -- 
  将命令行下标为
  0
  的命令行参数设置为进程名
 
 
    if
 
 
// 
  打印
  redis
  工作模式,端口进程号等
 
 

      checkTcpBacklogSettings();
 
 
 

   
 
 
 
    // -- 
  判断是否哨兵模式,然后打日志
 
 
    if
 
 
        /* Things not needed when running in Sentinel mode. */
 
 
    
      serverLog(LL_WARNING,
  "Server initialized");
 
 
 
    
      
  #ifdef
 
 
    
          linuxMemoryWarnings();
 
 
 
    
      
  #if
 
 
            int
 
 
    
          
  if
 
 
    
              
  if (ret == 
  1)
 
 
 
"WARNING Your kernel has a bug that could lead to data corruption during background save. "
 
 
"Please upgrade to the latest stable kernel.");
 
 
 
                else
 
 
"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")) {
 
 
 
"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");
 
 
 
1);
 
 
 

      
      
      
      }
 
 
 

      
      
      }
 
 
 
        #endif 
  /* __arm64__ */
 
 
    #endif 
  /* __linux__ */
 
 

      moduleInitModulesSystemLast();
 
 
 

      moduleLoadFromQueue();
 
 
 

      ACLLoadUsersAtStartup();
 
 
 

      InitServerLast();
 
 
 
    
  // 4 加载持久化数据 根据配置模式的模式进行加载,如果开启aof就aof加载,否则rdb
 
 

      loadDataFromDisk();
 
 
 
    if (server.cluster_enabled) {
  // 
  判断集群是否可用,如果可用但配置出错则终止进程
 
 
        if
 
 
"You can't have keys in a DB different than DB 0 when in 
  Cluster mode. Exiting."
  );
 
 
1);
 
 
 

          }
 
 
 

      }
 
 
 
    // -- 
  输出日志
 
 
    if (server.ipfd.count > 
  0 || server.tlsfd.count > 
  0)
 
 
 
"Ready to accept connections");
 
 
 
    if (server.sofd > 
  0)
 
 
 
"The server is now ready to accept connections at %s", server.unixsocket);
      
 
 
 
    if
 
 
        if
 
 
"STATUS=Ready to accept connections
  \n
  ");
 
 
 
else
 
 
"STATUS=Ready to accept connections in read-only mode. Waiting for MASTER <-> REPLICA sync
  \n
  ");
      
 
 
 

              }
 
 
 
"READY=1
  \n
  ");
 
 
 

          }
 
 
 
else
 
 
        // 
  到这步说明是哨兵模式,下面做一些哨兵的初始化收尾 和 判断哨兵是否运行中
 
 

      
      ACLLoadUsersAtStartup();
 
 
 

      
      InitServerLast();
 
 
 

      
      sentinelIsRunning();
 
 
 
        if
 
 
"STATUS=Ready to accept connections
  \n
  ");
 
 
 
"READY=1
  \n
  ");
 
 
 

      
      }
 
 
 

      }
 
 
 

   
 
 
 
    /* Warning the user about suspicious maxmemory setting. */
 
 
    if (server.maxmemory > 
  0 && server.maxmemory < 
  1024*
  1024) {
  // 
  如果内存小于
  1M
  ,输出警告日志
 
 
"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);
 
 
 
1);
  // 
  设置内存溢出评分的调整值
 
 
开启事件循环,epoll事件循环
 
 

      aeMain(server.el);
 
 
 
    // -- 
  服务器关闭,删除事件循环
 
 

      aeDeleteEventLoop(server.el);
 
 
 
    return 
  0;
 
 
 

  }

举报

相关推荐

0 条评论