linux使用一个守护进程处理系统日志——syslogd或升级版 rsyslogd
rsyslogd接收用户进程和内核的日志。用户进程使用syslog函数生成系统日志,该函数将日志输出到unix本地域docket类型的文件/dev/log中,rsyslogd监听该文件获取用户进程输出。内核日志在老系统上通过零一个rklogd管理,rsyslogd利用额外模块实现相同功能。内核日志通过printk打印至内核的环状内存(ring buffer),其直接映射到/proc/kmsg文件中。rsyslogd通过读取该文件获得内核日志。rsyslogd会将信息输出到特定日志文件:/var/log/debug /var/log/messages /var/log/kern.log。使用 /etc/rsyslog.conf 进行配置。
syslog函数指定日志级别打印日志
openlog设置日志格式
设置日志掩码,用于过滤日志
关闭日志功能:void closelog();
extern int getrlimit (
__rlimit_resource_t __resource, // 资源类型
struct rlimit *__rlimits) __THROW;
struct rlimit
{
/* The current (soft) limit. */
rlim_t rlim_cur; // 软限制,建议不要超过
/* The hard limit. */
rlim_t rlim_max; // 硬限制,超过可能被系统终止
};
可以使用ulimit命令修改软硬限制,只有root用户可以增加
bool daemonize() {
// 创建子进程,关闭父进程,这样使程序后台运行
pid_t pid = fork();
if (pid <0) {
return false;
} else if (pid > 0) {
exit 0;
}
// 设置文件掩码,当进程创建新文件时文件权限将为 mode & 0777
umask(0);
pid_t sid = setsid();
if (sid <0) {
return false;
}
if ((chdir("/")) <0) {
return false;
}
// 关闭 stdin stdout stderr
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// 将标准流重定向到 /dev/null
open("/dev/null", O_RDONLY);
open("/dev/null", O_RDWR);
open("/dev/null", O_RDWR);
return true;
}
linux提供了相同功能的库函数
extern int daemon (
int __nochdir, // 是否改变工作目录,传0时工作目录设置为 /
int __noclose // 为0时将stdio重定向到 /dev/null
) __THROW __wur;
高性能服务器程序框架
服务器程序通常要处理3类事件:io、信号、定时事件
两种高效事件处理模式 Reactor Proactor
主线程(IO处理单元)只负责监听fd是否有事件发生,有则通知工作线程(逻辑单元),主线程不做任何实质性工作。读写数据、接受新连接、处理客户请求都在工作线程内完成。
使用同步IO模型epoll实现:
所有io操作都交给主线程和内核处理,工作线程仅负责业务逻辑。
使用异步IO模型(以 aio_read 和 aio_write 为例):
主线程执行数据读写操作,读写完成后,主线程向工作线程通知这一“完成事件”。那么从工作线程角度来看,他们直接获得数据读写操作结果,接下来只要对结果进行逻辑处理
用于IO密集型程序,指IO处理单元和多个逻辑单元间协调完成任务的方法。服务器主要有两种并发编程模式:
在io模型种“同步”“异步”区分的是内核向程序通知的是何种io事件(就绪事件还是完成事件),以及谁来完成io读写(应用还是内核)。并发模式中,“同步”指程序完全按照代码序列顺序执行,“异步”指程序的执行需要由系统事件驱动,如终端、信号等事件。
半同步半异步模型(half-sync/half-async)中,同步线程用于处理客户逻辑,异步线程用于处理io事件。异步线程监听到客户请求后将其封装成请求对象并插入请求队列。请求队列将通知某个工作在同步模式的工作线程读取并处理该请求对象。具体选哪个工作线程取决于请求队列设计。
半同步半反应堆模式(half-sync/half-reactive)是这种模式的一种变体,异步线程只有一个由主线程充当。它监听所有socket上事件。由可读事件时主线程得到新的连接socket并向epoll内核事件表中注册该socket读写事件;若连接socket上由读写事件主线程就将该连接socket插入请求队列。所有工作线程都睡眠在请求队列上,当有任务时,他们通过竞争(不如互斥锁)获得任务。
主线程将就绪的连接socket插入请求队列,这说明半同步/半反应堆模式采用Reactor模式:它要求工作线程自己从socket上读取客户请求和向socket写入应答,这就是“half-reactive”的含义。
缺点:
在这个“高效的半同步/半异步模式”中,主线程只监听socket,连接socket由工作线程管理。当由新连接来时,主线程就接受并发给某个工作线程,此后该socket的所有io操作都有这个工作线程处理,知道关闭连接。派发socket最简单的方式就是向之间的管道写数据。工作线程从管道接收到新连接后把新socket的读写事件注册到自己的epoll内核事件表中。
主线程和所有工作线程都维持自己的事件循环,各自监听不同事件。所以这种模式中每个线程都工作在异步模式,并非严格的半同步/半异步模式。
多个工作线程轮流获得事件源集合,轮流监听、分发处理事件的一种模式。任意时间点程序都只有一个leader,它监听io事件;其他为follower,休眠在线程池中等待成为新领导者。当leader检测到io事件,要先从线程池中选出新leader,然后处理io事件。新leader等待新io事件,原leader则处理io事件,二者并发。
包含组件:
领导者追随者模式中leader线程监听io事件并处理请求,因而无需传递任何数据或操作同步队列。但一个缺点是:仅支持一个事件源集合,因此无法让每个工作线程独立地管理多个客户连接。