记录一下最近这学期学习的sylar服务器框架项目,输出整理一下项目的结构,用到的知识和自己的体会
项目仓库地址
https://github.com/sylar-yin/sylar/
整理博客过程中参考的大佬资料链接:
============================================
基础介绍
守护进程模块可以将进程与终端解绑,在后台运行,父进程还可以检测子进程是正常结束还是异常崩溃,如果是异常崩溃可以重新拉起子进程
ProcessInfo结构体
用于存储进程信息,采用单例模式,提供字符串方法
// 进程信息结构体
struct ProcessInfo {
pid_t parent_id = 0; // 父进程ID
pid_t main_id = 0; // 主进程ID
uint64_t parent_start_time = 0; // 父进程启动时间
uint64_t main_start_time = 0; // 主进程启动时间
uint32_t restart_count = 0; // 主进程重启次数
std::string toString() const;
};
typedef sylar::Singleton
<ProcessInfo> ProcessInfoMgr;
std::string ProcessInfo::toString() const {
std::stringstream ss;
ss << "[ProcessInfo parent_id=" << parent_id
<< " main_id=" << main_id
<< " parent_start_time=" << sylar::Time2Str(parent_start_time)
<< " main_start_time=" << sylar::Time2Str(main_start_time)
<< " restart_count=" << restart_count << "]";
return ss.str();
}
start_deamon函数
当第三个参数为true的时候才开启deamon模式,从循环的开始位置fork子进程,子进程执行main函数,父进程检测子进程返回值
使用daemon(1, 0)开启daemon
int start_daemon(int argc, char** argv
, std::function<int(int argc, char** argv)> main_cb
, bool is_daemon) {
if(!is_daemon) {
return real_start(argc, argv, main_cb);
}
return real_daemon(argc, argv, main_cb);
}
static int real_start(int argc, char** argv
, std::function<int(int argc, char** argv)> main_cb) {
return main_cb(argc, argv);
}
static int real_daemon(int argc, char** argv
, std::function<int(int argc, char** argv)> main_cb) {
int rt = daemon(1, 0);
if(rt != 0) {
SYLAR_LOG_ERROR(g_logger) << "deamon() error rt=" << rt
<< " errno=" << errno << " errstr=" << strerror(errno);
}
ProcessInfoMgr::GetInstance()->main_id = getpid();
ProcessInfoMgr::GetInstance()->main_start_time = time(0);
while(true) {
pid_t pid = fork();
if(pid == 0) { // 子进程返回
ProcessInfoMgr::GetInstance()->main_id = getpid();
ProcessInfoMgr::GetInstance()->main_start_time = time(0);
SYLAR_LOG_INFO(g_logger) << "process start pid=" << getpid()
<< " errno=" << errno << " errstr=" << strerror(errno);
return real_start(argc, argv, main_cb);
} else if(pid < 0) {
SYLAR_LOG_ERROR(g_logger) << "fork fail return=" << pid
<< " errno=" << errno << " errstr=" << strerror(errno);
return -1;
} else { // 父进程返回
int status = 0;
waitpid(pid, &status, 0);
if(status) {
SYLAR_LOG_ERROR(g_logger) << "child crash pid=" << pid
<< " status=" << status;;
} else {
SYLAR_LOG_INFO(g_logger) << "child finished pid=" << pid;
break;
}
ProcessInfoMgr::GetInstance()->restart_count++;
sleep(g_daemon_restart_interval->getValue());
}
}
return 0;
}
子进程重启时间间隔
注册了一个配置项
static sylar::ConfigVar
<uint32_t>::ptr g_daemon_restart_interval
= sylar::Config::Lookup("daemon.restart_interval", (uint32_t)5, "daemon restart interval");
测试
模拟服务进程为一个循环5次的1s定时器,第5次超时之后手动调用abort()模拟崩溃
#include "sylar/daemon.h"
#include "sylar/iomanager.h"
#include "sylar/log.h"
static sylar::Logger::ptr g_logger = SYLAR_LOG_ROOT();
sylar::Timer::ptr timer;
int server_main(int argc, char** argv) {
SYLAR_LOG_INFO(g_logger) << sylar::ProcessInfoMgr::GetInstance()->toString();
sylar::IOManager iom(1);
timer =
iom.addTimer(1000, [](){
SYLAR_LOG_INFO(g_logger) << "on Timer";
static int count = 0;
if(++count > 5) {
abort(); // 手动崩溃
timer->cancel();
}
}, true);
return 0;
}
int main(int argc, char** argv) {
return sylar::start_daemon(argc, argv, server_main, argc != 1);
}
使用非守护进程模式运行,可以看到5次超时之后程序崩溃

使用守护进程模式运行,在btop命令行工具中可以看到fork了一个子进程,子进程崩溃之后5s被拉回重新运行




总结
为服务器稳定性提供保障




严肃责怪中……(这么高产,不要命啦啊喂?
水课写的
那很勤奋了( ,,´・ω・)ノ”(´っω・`。)