`
zsxxsz
  • 浏览: 444249 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
阅读更多

一、概述

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

 

二、五种服务器模型

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

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

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

      3、非阻塞模型:高并发、非阻塞是这些年来高性能服务器的一种时髦语,这种方式一般是一个进程维护一个事件循环(采用 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 的非阻塞框架有多种措施防止因嵌套而产生的错误,但用户在实际使用时仍需小心谨慎。

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

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

      5、网络协程模型:该模型采用协程方式,将阻塞IO模式在底层转变为非阻塞模式,这样既可以象编写多线程一样简单,又可以象非阻塞程序一样高效,从而使技术人员快速地编写出高并发、高性能的网络服务程序。

 

三、服务器编程注意事项

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

      1、安全问题:在 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

      2、进程空闲退出机制:为了避免服务子进程有轻微的内存泄露或避免内存数据泄露,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=进程空闲秒数

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

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

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

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

 

四、为什么事件引擎没有采用 libevent 等库

      原因很简单:

      1、Postfix 本身的事件引擎设计的就非常不错(acl 中的事件引擎是在此基础上改造的);

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

      3、使用 libevent 无疑增长了 acl 框架库的依赖性,造成用户使用上的不便;

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

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

 

      个人微博:http://weibo.com/zsxxsz

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

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

      github: https://github.com/acl-dev/acl

      QQ 群:242722074

 

4
3
分享到:
评论

相关推荐

    acl 工程是一个跨平台的网络通信库及服务器编程框架,同时提供更多的实用功能库

    acl 工程是一个跨平台(支持LINUX,WIN32,Solaris...支持线程池、协程、进程池、非阻塞、触发器等多种服务器编程模型;支持XML/JSON/MIME/BASE64/UUCODE/QPCODE/RFC2047 等常见格式编解码;还有其它更多有价值的功能。

    acl-master.zip

    跨平台网络通信与服务器开发框架;...支持线程池、协程、进程池、非阻塞、触发器等多种服务器编程模型;支持 XML/JSON/MIME/BASE64/UUCODE/QPCODE/RFC2047 等常见格式编解码;还有其它更多有价值的功能。

    Windows安全性编程

    书中介绍了Windows 2000安全机制的核心内容,包括Kerberos、SSL、任务对象、新的ACL模型、COM+以及II5.0,同时说明了Windows 2000和Windows NT中安全机制的主要区别。 作者有着非常丰富的开发经验,写作本书的...

    Java服务器程序设计

    第3部分 java服务器编程[/font] [/font] 第5章 servlet包介绍[/font] [/font] 5.1 javax.servlet包[/font] 5.1.1 接口servlet[/font] 5.1.2 接口servletconfig[/font] 5.1.3 接口servletcontext[/font] 5.1.4 接口...

    IIS6.0 IIS,互联网信息服务

    下面简单介绍IIS的安装过程: 依次点击“开始” => “控制面板” => “程序”,选择“打开或关闭Windows功能”。 这是一个触发UAC的操作,如果Windows Vista没有关闭UAC,则会弹出提示信息,确认并继续; 如果仅需要...

    graphql-apollo-server-client-example:node.js中GraphQL服务器和客户端的示例实现+解释+教程

    2016 年12月16 日更新:在花了几个月的时间构建了一个带有 auth+ACL 的生产级 GraphQL 服务器之后,我不推荐本教程中描述的服务器端方法(本教程很适合让您涉足,但它不可扩展) ,并建议改用以下库: - 使用此库与...

    操作系统安全:linux常用安全技术.docx

    linux常用安全技术包括PAM机制,linux能力机制,入侵检测系统,加密文件系统,安全审计,基于ACL的自主访问控制,强制访问控制,防火墙,杀毒软件,网络安全和DRM,等等。 PAM机制 PAM介绍 PAM(Pluggable ...

    Fourinone分布式计算框架

    首先,对分布式协同方面,它实现了Zookeeper所有的功能,并且做了很多改进,包括简化Zookeeper的树型结构,用domain/node两层结构取代,简化Watch回调多线程等待编程模型,用更直观的容易保证业务逻辑完整性的内容...

    Fourinone分布式并行计算四合一框架

     首先,对分布式协同方面,它实现了Zookeeper所有的功能,并且做了很多改进,包括简化Zookeeper的树型结构,用domain/node两层结构取代,简化Watch回调多线程等待编程模型,用更直观的容易保证业务逻辑完整性的内容...

    fourinone-3.04.25

    首先,对分布式协同方面,它实现了Zookeeper所有的功能,并且做了很多改进,包括简化Zookeeper的树型结构,用domain/node两层结构取代,简化Watch回调多线程等待编程模型,用更直观的容易保证业务逻辑完整性的内容...

    JAVA_API1.6文档(中文)

    javax.sql 为通过 JavaTM 编程语言进行服务器端数据源访问和处理提供 API。 javax.sql.rowset JDBC RowSet 实现的标准接口和基类。 javax.sql.rowset.serial 提供实用工具类,允许 SQL 类型与 Java 编程语言数据...

Global site tag (gtag.js) - Google Analytics