Memcached源码阅读之服务器资源调整

本篇博客作为Memcached源码分析的开篇,这次阅读的源码版本为:1.4.15,开源软件各个版本之间差异比较大,同学们学习时,记得核对版本。

memcached的main函数位于memcached.c文件中,从main函数启动之后,会初始化一些资源和申请一些服务器资源,如下面所示:

1 Core文件大小和进程打开文件个数限制的调整。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. if (maxcore != 0)  
  2. {  
  3.     struct rlimit rlim_new;  
  4.     //获取当前Core文件大小的配置值  
  5.     if (getrlimit(RLIMIT_CORE, &rlim) == 0)  
  6.     {  
  7.                 //变量初始化为无限制  
  8.                 rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY;  
  9.         if (setrlimit(RLIMIT_CORE, &rlim_new) != 0)//如果设置失败  
  10.         {  
  11.             //变量初始化为当前值的最大值  
  12.             rlim_new.rlim_cur = rlim_new.rlim_max = rlim.rlim_max;  
  13.             (void) setrlimit(RLIMIT_CORE, &rlim_new);//重新进行设置  
  14.         }  
  15.     }  
  16.       
  17.         //再次确认Core文件允许的大小,如果当前的Core文件的大小为0,则不允许Core文件产生,和maxcore!=0不符,程序结束  
  18.     if ((getrlimit(RLIMIT_CORE, &rlim) != 0) || rlim.rlim_cur == 0)  
  19.     {  
  20.         fprintf(stderr, "failed to ensure corefile creation\n");  
  21.         exit(EX_OSERR);  
  22.     }  
  23. }  
  24. //读取进程允许打开的文件数信息,读取失败,程序退出  
  25. if (getrlimit(RLIMIT_NOFILE, &rlim) != 0)  
  26. {  
  27.     fprintf(stderr, "failed to getrlimit number of files\n");  
  28.     exit(EX_OSERR);  
  29. }  
  30. else  
  31. {       //按memcached启动时的指定的最大连接数进行设置  
  32.     rlim.rlim_cur = settings.maxconns;  
  33.     rlim.rlim_max = settings.maxconns;  
  34.     if (setrlimit(RLIMIT_NOFILE, &rlim) != 0)  
  35.     {  
  36.         fprintf(stderr,  
  37.                 "failed to set rlimit for open files. Try starting as root or requesting smaller maxconns value.\n");  
  38.         exit(EX_OSERR);  
  39.     }  
  40. }  

2 启动用户的选择。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //uid==0表示以root运行程序  
  2. if (getuid() == 0 || geteuid() == 0)  
  3. {       //以root运行程序,同时未指定新的用户名称  
  4.         if (username == 0 || *username == '\0')  
  5.     {  
  6.         fprintf(stderr, "can't run as root without the -u switch\n");  
  7.         exit(EX_USAGE);  
  8.     }  
  9.         //判断是否存在指定的用户名称  
  10.         if ((pw = getpwnam(username)) == 0)  
  11.     {  
  12.         fprintf(stderr, "can't find the user %s to switch to\n", username);  
  13.         exit(EX_NOUSER);  
  14.     }  
  15.         //按新的用户修改memcached的执行权限位  
  16.         if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0)  
  17.     {  
  18.         fprintf(stderr, "failed to assume identity of user %s\n", username);  
  19.         exit(EX_OSERR);  
  20.     }  
  21. }  
3 以daemon的方式启动,daemon的实现如下,该daemon没有进行2次fork,APUE上面也有说第二次fork不是必须的。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int daemonize(int nochdir, int noclose)  
  2. {  
  3.     int fd;  
  4.     //首先fork一次  
  5.     switch (fork()) {  
  6.     case -1://fork失败,程序结束  
  7.         return (-1);  
  8.     case 0://子进程执行下面的流程  
  9.         break;  
  10.     default://父进程安全退出  
  11.         _exit(EXIT_SUCCESS);  
  12.     }  
  13.     //setsid调用成功之后,返回新的会话的ID,调用setsid函数的进程成为新的会话的领头进程,并与其父进程的会话组和进程组脱离  
  14.     if (setsid() == -1)  
  15.         return (-1);  
  16.   
  17.     if (nochdir == 0) {  
  18.         //进程的当前目录切换到根目录下,根目录是一直存在的,其他的目录就不保证  
  19.         if(chdir("/") != 0) {  
  20.             perror("chdir");  
  21.             return (-1);  
  22.         }  
  23.     }  
  24.   
  25.     if (noclose == 0 && (fd = open("/dev/null", O_RDWR, 0)) != -1) {  
  26.         if(dup2(fd, STDIN_FILENO) < 0) {//将标准输入重定向到/dev/null下  
  27.             perror("dup2 stdin");  
  28.             return (-1);  
  29.         }  
  30.         if(dup2(fd, STDOUT_FILENO) < 0) {//将标准输出重定向到/dev/null下  
  31.             perror("dup2 stdout");  
  32.             return (-1);  
  33.         }  
  34.         if(dup2(fd, STDERR_FILENO) < 0) {//将标准错误重定向到/dev/null下  
  35.             perror("dup2 stderr");  
  36.             return (-1);  
  37.         }  
  38.   
  39.         if (fd > STDERR_FILENO) {  
  40.             if(close(fd) < 0) {//大于2的描述符都可以关闭  
  41.                 perror("close");  
  42.                 return (-1);  
  43.             }  
  44.         }  
  45.     }  
  46.     return (0);  
  47. }  

4 锁定内存,默认分配的内存都是虚拟内存,在程序执行过程中可以按需换出,如果内存充足的话,可以锁定内存,不让系统将该进程所持有的内存换出。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. if (lock_memory)  
  2. {  
  3. #ifdef HAVE_MLOCKALL  
  4.     int res = mlockall(MCL_CURRENT | MCL_FUTURE);  
  5.     if (res != 0)  
  6.     {  
  7.         fprintf(stderr, "warning: -k invalid, mlockall() failed: %s\n",  
  8.                 strerror(errno));  
  9.     }  
  10. #else  
  11.     fprintf(stderr,  
  12.             "warning: -k invalid, mlockall() not supported on this platform.  proceeding without.\n");  
  13. #endif  
  14. }  

5 忽略PIPE信号,PIPE信号是当网络连接一端已经断开,这时发送数据,会进行RST的重定向,再次发送数据,会触发PIPE信号,而PIPE信号的默认动作是退出进程,所以需要忽略该信号。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. if (sigignore(SIGPIPE) == -1)  
  2. {  
  3.     perror("failed to ignore SIGPIPE; sigaction");  
  4.     exit(EX_OSERR);  
  5. }  
6 保存daemon进程的进程id到文件中,这样便于控制程序,读取文件内容,即可得到进程ID。 

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. if (pid_file != NULL)  
  2. {  
  3.     save_pid(pid_file);  
  4. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值