acl 服务器编程模型介绍

1、概述nginx

      以前写过几篇有关如何使用 acl 的服务器框架编写网络服务器程序的文章(如:协做半驻留式服务器程序开发框架),如今总结一下,简要说明一下 acl 中所支持的几种服务器模型。acl 服务器框架支持四种模式:非阻塞模型、进程池模型、线程池进程混合模型,以及触发器模型。这四种服务器模型基本覆盖了咱们编程时的常见模式,其中的进程池模型(对应于 Postfix 中的 single_server 方式)与触发器模型(对于 Postfix 中的 trigger_server 方式)移植于 Postfix,非阻塞模型、线程池进程池混合模型由笔者编写。本文结合 acl 库,不只指明了服务器编程的方式,同时从实践角度讲述了在进行服务器编程时应该注意的事项。编程

 

2、四种服务器模型windows

      一、进程池模型:这是在 UNIX 上进行服务器编程时早期经常使用的方式,通常是每一个 TCP 网络链接对应一个服务子进程,优势是安全、稳定,由于一个子进程 Down 掉仅影响一个 TCP 链接,同时,各个子进程之间的内存由系统进行隔离,能够在必定程度上避免数据泄露;缺点也很明显,就是并发链接数不能过高,毕竟进程资源是操做系统的宝贵资源,同时若是进程之间须要共享数据,操做起来也是一件棘手的事。早期的 UNIX 服务器程序并未采用进程池方式,而是来一个 TCP 链接请求临时启动一个子进程,处理完请求后子进程便退出,这种方式的效率是最低的,由于操做系统建立进程的开销仍是比较昂贵的,象你们所熟知的 telnetd, ftpd, xinetd 等服务器程序都是这 种方式(CGI程序做为服务端也是这种方式);安全

      后来出于对性能的要求,便出现了进程池模型,而进程池模型又可分为:固定进程数量的进程池模型、动态变化的进程池模型,固定数量的进程池模型编程比较容易,但扩展性较差,动态进程池则更灵活,能够按须要建立进程,同时维持进程池的最小空闲进程数及最大进程数(象 Apache 的进程池模型有多个控制参数,分别表示预先启动进程数、最小空闲数、最大空闲数以及最大进程数;而 Postfix 的进程池则是半驻留进程池方式,限定的子进程的空闲时间及最大子进程数量,没有预先分配的策略;acl 中的进程池基于 Postfix,并在此基础上增长了预分配策略)。服务器

      二、触发器模型:UNIX 系统管理员常常会使用 cron 系统服务来执行一些按期的任务,但系统 cron 存在一个问题,就是当时间间隔设置的较短时,若是定时任务处理时间超过了 cron 中设置的时间间隔,则就会产生任务处理过程重叠的问题(须要经过互斥等手段来避免此问题),由于 cron 任务是基于时间点触发的;而 Postfix 的触发器模型是基于时间间隔触发的,同时能够限定同时处理任务的进程数量,这就避免了 cron 方式下任务过程重叠的问题。网络

      三、非阻塞模型:高并发、非阻塞是这些年来高性能服务器的一种时髦语,这种方式通常是一个进程维护一个事件循环(采用 select/poll/epoll/kqueue/devpoll/iocp 等系统调用),采用多路复用方式,使单个进程能够支撑很是高的并发链接,由于网络通信自己是有延迟的,采用非阻塞方式,则服务进程不会阻塞于任何 TCP 链接,哪一个链接有数据就处理哪一个,因此它能够处理很高的并发链接请求;但这种模型也有一个缺陷,就是一个非阻塞进程每每只能使用一个 CPU,这并不符合当今多核时代的要求(除了一个核以外,其它核都很空闲),象 squid、ircd 都是这种使用单核 CPU 的非阻塞表明,常常被人诟病,固然并不是全部的非阻塞程序都是这样,象 nginx 处理的要好些,nignx 能够启动多个服务进程,每一个进程是一个单独的非阻塞过程。多线程

      在 acl 中的非阻塞模型默认采用与 nginx 类似的做法,能够启动多个非阻塞子进程,这即达到了高并发的目的,又能够充分利用多核,但它也有一个小缺点,就是分配给每一个子进程的 TCP 链接并不均匀;另外,acl 的非阻塞模型还支持一个子进程由多个线程组成,每一个线程是一个独立的非阻塞过程,这种方式姑且称之为多线程非阻塞进程池模型,它的优势是能够保证每一个子进程内部线程池中的 TCP 链接分配是均匀的,但这种模型也有一个显著的缺点,当并发链接数高且内存分配比较频繁时,处理性能与线程池中线程数量是成反比的,缘由并非由于 CPU 核不够,而是由于在调用系统的 malloc/free 函数时,多个线程产生了大量的锁碰撞,致使性能降低,在 acl 中为了解决这个问题,专门有一个线程局部内存池,这个内存池能够从很大程度上避免系统全局内存锁碰撞, 当 CPU 核心越多,线程数越多时,总体性能则越高。并发

      非阻塞模型还有一个缺点,当用户使用此模型编程时,若是内部有 BUG,则在处理一个 TCP 链接的数据时进程崩溃了,则属于该进程的全部 TCP 任务都没法完成;因此,采用非阻塞编程的复杂度是较高,也容易出错,尤为是当产生了大量的函数嵌套递归时更是容易出错,acl 的非阻塞框架有多种措施防止因嵌套而产生的错误,但用户在实际使用时仍需当心谨慎。框架

      四、线程池进程池混合模型:顾名思义,就是多个服务子进程组成进程池方式,而每一个子进程自己又是由线程池组成的,每一个线程处理一个 TCP 链接,这种方式相比纯粹进程池的好处是能够有效地提升并发量、提升系统性能,同时可使线程池中的多个线路之间共享数据变得比较容易;固然,相对于纯进程池模型,该模型的稳定性会有所下降,当用户基于此模型编写的程序有 BUG 时,会由于线程池中一个线程的崩溃而致使整个子进程退出,从而影响了多个 TCP 链接(固然不会影响其它子进程中的线程)。异步

      acl 的线程池进程池混合模型能够说是纯粹的进程池模型与非阻塞模型的折中模型:相对于纯粹进程池模型,该模型能够有效地提供并发数(甚至能够实现半非阻塞或全阻塞过程);同时相对于非阻塞模型,编程更为容易,不易出错。

 

3、服务器编程注意事项

      在进行服务器编程,有几个方面是须要注意的,以下:

      一、安全问题:在 UNIX 下编写的程序运行时尽可能以普通用户身份运行,禁止以 root 运行,这样能够有效地防止因应用程序自己的漏洞而使黑客攻陷整个系统;acl 的服务器的配置文件中须要指定 master_args = -u 配置项,同时还须要配置:

      1.1)进程池模型:single_owner=xxx (xxx表明某个普通用户,如 nobody)

      1.2)触发器模型:trigger_owner=xxx

      1.3)非阻塞模型:aio_owner=xxx

      1.4)线程池进程池混合模型:ioctl_owner=xxx

      二、进程空闲退出机制:为了不服务子进程有轻微的内存泄露或避免内存数据泄露,acl 采用半驻留方式,即当每一个子进程空闲一段时间或处理必定 TCP 请求次数后子进程主动退出,为此,须要修改配置以下:

      2.1)进程池模型:single_use_limit=请求次数、single_idle_limit=进程空闲秒数

      2.2)触发器模型:trigger_use_limit=处理次数、trigger_idle_limit=进程空闲秒数

      2.3)非阻塞模型:aio_use_limit=处理次数、aio_idle_limit=进程空闲秒数

      2.4)线程池进程池混合模型:ioctl_use_limit=处理次数、ioctl_idle_limit=进程空闲秒数

      三、最大进程池限制:为了防止因用户编程失误而致使分配了大量的进程,使操做系统资源耗尽,acl 中经过配置限制了每种服务器模型的所启动的最大进程数量,配置统一为:master_maxproc=子进程最大数量(对于混合模型,配置项 ioctl_max_threads=每一个子进程中最大线程数控制子进程中半驻留线程池的线程数)。

      四、服务子进程崩溃延迟启动机制:当用户编写的服务器程序若是频繁地崩溃,为了防止形成大量的 fork 操做,acl 的服务器控制程序(acl_master)的配置文件中的配置选项(service_throttle_time=子进程崩溃延迟启动秒数)能够达到延迟启动有问题子进程目的。

      五、日志功能:acl 的服务器框架采用 acl 库中统一的日志记录方式(可支持 syslog-ng),这样便于收集用户服务程序的运行状态。

      六、子进程崩溃通知机制:由于大部分服务器程序都是在后台运行的,某个程序崩溃后又会被 acl 的 控制程序(acl_master)启动,虽然 acl_master 的日志中会记录子进程崩溃的时间等信息,但咱们毕竟不能一直盯着日志,为了解决此问题,编写了一个与 acl_master 配合的程序 acl_notify (在 acl/samples/master/acl_notify 目录下),能够接收来自于 acl_master 的消息,将服务子进程崩溃的消息以邮件或短信方式主动通知系统维护人员。

 

4、为何事件引擎没有采用 libevent 等库

      缘由很简单:

      一、Postfix 自己的事件引擎设计的就很是不错(acl 中的事件引擎是在此基础上改造的);

      二、libevent 是线程不安全的(原来的版本是不安全的,如今的版本不知如何);

      三、使用 libevent 无疑增加了 acl 框架库的依赖性,形成用户使用上的不便;

      四、acl 中的事件引擎功能更增强大:不只支持 libevent 所支持的 select/poll/epoll/kqueue/devpoll,并且还支持 windows 平台下的 iocp、基于窗口的异步消息;

      五、acl 中的事件引擎与 acl 中的网络通讯库结合的更为紧密。

 

      我的微博:http://weibo.com/zsxxsz

      原文地址:http://zsxxsz.iteye.com/blog/1563561

      acl 库下载:https://sourceforge.net/projects/acl/

      QQ 群:242722074

      bbs:http://www.aclfans.com

相关文章
相关标签/搜索