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

相關文章
相關標籤/搜索