在LInux服務器上實現web服務,常見無非也就是Apache、Nginx、Tomcat。
三者之間的區別:
- Apache:支持的模塊比較多,採用servlet處理模型,同步阻塞模型,工作模式多變,對於高併發的場景處理速度比較慢,運行穩定;
- Nginx :輕量級web服務器,自身支持模塊少,需要藉助第三方模塊支持(Nginx官網就可以下載),採用epoll處理模式,異步非阻塞型,適合高併發場景,配置簡單;
- Tomcat:apache軟件基金會下開源的子項目,也成爲容器,主要處理java語言編寫的頁面,也可以處理html頁面,併發連接小;
今天這篇博文主要就是圍繞apache-2.4.23版本展開的:
對apache不太瞭解的朋友可以參考博文:基於Apache搭建Web服務器詳解
這裏就不具體介紹apache究竟是什麼、它的起因什麼的了。
博文大綱:
一、httpd-2.4.23版本特性
二、編譯安裝httpd-2.4.23
三、apche的三種工作模式
四、進程與線程的區別
一、httpd-2.4.23版本特性
新版本的httpd-2.4.23新增模塊:
- mod_proxy_fcgi(可提供fcgi代理);
- mod_ratelimit(限制用戶帶寬);
- mod_request(請求模塊,對請求進行過濾);
- mod_remoteip(匹配客戶端的IP地址);
對於基於IP的訪問控制進行了修改,不再支持allow、deny、order機制,而是統一使用require進行!
新增的特性有:
- MPM支持在運行時裝載;
- 支持envet工作模式;
- 支持異步讀寫功能;
- 每個模塊都可以指定輸出的日誌級別;
- 增強版的表達式分析器;
- 請求配置:<if>,<elseif>;
- 毫秒級別的keepalive timeout;
- 支持FQDN的虛擬主機;
- 支持自定義變量;
接下來開始安裝!
二、編譯安裝httpd-2.4.23
安裝環境:
- 使用centos 7系統;
- 下載所需軟件包
(1)首先檢查是否安裝httpd軟件包
[root@localhost ~]# rpm -q httpd
未安裝軟件包 httpd
//如果存在,使用“-e”選項進行卸載
(2)安裝apr
apr是Apache可移植運行庫,是一個對操作系統條用的抽象庫,用於實現Apache內部組件對操作系統的使用,提高系統的可移植性。
[root@localhost ~]# tar zxf apr-1.5.2.tar.gz -C /usr/src
[root@localhost ~]# cd /usr/src/apr-1.5.2/
[root@localhost apr-1.5.2]# ./configure --prefix=/usr/local/apr && make && make install
(3)安裝apr-util
[root@localhost ~]# tar zxf apr-util-1.5.4.tar.gz -C /usr/src
[root@localhost ~]# cd /usr/src/apr-util-1.5.4/
[root@localhost apr-util-1.5.4]# ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr && make && make install
(4)安裝zlib
[root@localhost ~]# tar zxf zlib-1.2.8.tar.gz -C /usr/src
[root@localhost ~]# cd /usr/src/zlib-1.2.8/
[root@localhost zlib-1.2.8]# ./configure --prefix=/usr/local/zlib && make && make install
(5)安裝pcre
[root@localhost ~]# tar zxf pcre-8.39.tar.gz -C /usr/src
[root@localhost ~]# cd /usr/src/pcre-8.39/
[root@localhost pcre-8.39]# ./configure -- prefix=/usr/local/pcre && make && make install
(6)安裝openssl
安裝apache-2.4.23版本時,會提示openssl自帶的版本過低,需要自行手動安裝新的版本。
[root@localhost ~]# tar zxf openssl-1.0.1u.tar.gz -C /usr/src
cd [root@localhost ~]# cd /usr/src/openssl-1.0.1u/
[root@localhost openssl-1.0.1u]# ./config -fPIC --prefix=/usr/local/openssl enable-shared && make && make install
//PIC使.so文件的代碼段變爲真正意義上的共享
//如果不加-fPIC,則加載.so文件的代碼段時,代碼段引用的數據對象需要重定位, 重定位會修改代碼段的內容,這就造成每個使用這個.so文件代碼段的進程在內核裏都會生成這個.so文件代碼段的copy.每個copy都不一樣,取決於 這個.so文件代碼段和數據段內存映射的位置.
(7)安裝 httpd-2.4.23
[root@localhost ~]# tar zxf httpd-2.4.23.tar.gz -C /usr/src
[root@localhost ~]# cd /usr/src/httpd-2.4.23/
[root@localhost httpd-2.4.23]# ./configure --prefix=/usr/local/http-2.4.23 --enable-so --enable-cgi \
--enable-cgid --enable-ssl --with-ssl=/usr/local/openssl --enable-rewrite \
--with-pcre=/usr/local/pcre --with-z=/usr/local/zlib --with-apr=/usr/local/apr \
--with-apr-util=/usr/local/apr-util --enable-modules=most --enable-mods-shared=most \
--enable-mpms-shared=all --with-mpm=event --enable-proxy --enable-proxy-fcgi --enable-expires \
--enable-deflate && make && make install
各選項含義:
- --enable-so:支持動態共享模塊;
- --enable-rewrite:支持url重寫;
- --enable-ssl:支持ssl;
- --with-ssl=/usr/local/openssl:指定ssl安裝位置;
- --enable-cgi:開啓cgi通用網管接口;
- --enable-cgid:開啓cig通用網管接口管理程序;
- --enable-modules=most:編譯成二進制是安裝常用模塊;
- --enable-mpms-shared=all:安裝apache的所有工作模式;
- --with-mpm=event:指定默認的運行方式
- --with-pcre=/usr/local/pcre:支持 pcre ;
- --with-z=/usr/local/zlib:使用 zlib 壓縮庫;
- --with-apr=/usr/local/apr:指定 apr 的安裝路徑;
- --with-apr-util=/usr/local/apr-util:指定 apr-util 的安裝路徑;
- --enable-expires:支持緩存;
- --enable-deflate:支持壓縮;
(8)優化http程序的執行路徑
[root@localhost httpd-2.4.23]# ln -s /usr/local/http-2.4.23/bin/* /usr/local/bin/
(9)添加爲系統服務
[root@localhost httpd-2.4.23]# cp /usr/local/http-2.4.23/bin/apachectl /etc/init.d/httpd
[root@localhost httpd-2.4.23]# vim /etc/init.d/httpd
#!/bin/bash //修改
#chkconfig: 35 85 15 //添加
………… //省略以下內容
[root@localhost httpd-2.4.23]# chkconfig --add httpd
[root@localhost httpd-2.4.23]# systemctl start httpd
[root@localhost httpd-2.4.23]# netstat -anpt | grep 80
tcp6 0 0 :::80 :::* LISTEN 108903/httpd
[root@localhost ~]# httpd -M //可以查看到httpd服務啓動加載的模塊
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using localhost.localdomain. Set the 'ServerName' directive globally to suppress this message
//關於啓動服務時提示以上的信息,可以省略,也可修改其配置文件(/usr/local/http-2.4.23/conf/httpd.conf)文件找到“ServerName ”一行,根據實際情況進行修改
Loaded Modules:
core_module (static)
so_module (static)
http_module (static)
authn_file_module (shared)
authn_core_module (shared)
authz_host_module (shared)
authz_groupfile_module (shared)
authz_user_module (shared)
authz_core_module (shared)
access_compat_module (shared)
auth_basic_module (shared)
reqtimeout_module (shared)
filter_module (shared)
mime_module (shared)
log_config_module (shared)
env_module (shared)
headers_module (shared)
setenvif_module (shared)
version_module (shared)
mpm_prefork_module (shared)
unixd_module (shared)
status_module (shared)
autoindex_module (shared)
dir_module (shared)
alias_module (shared)
至此apache-2.4.23已經安裝完成。
三、apche的三種工作模式
(1)Prefork模式
其工作方式:當Apache服務啓動後,mpm_prefork模塊會預先創建多個子進程(默認爲5個),每個子進程只有一個線程,當接收到客戶端請求後,mpm_prefork模塊再將請求轉交給子進程進行處理,並且每個子進程同時只能用於單個請求。如果當前的請求數將超過預先創建的子進程數時,mpm_prefork模塊就會創建新的子進程來處理額外的請求。
如圖:
Apache總是試圖保持一些備用或空閒的子進程用於迎接即將到來的請求。這樣客戶端的請求就不需要在接收後等待子進程的產生。
由於在 mpm_prefork 模塊中,每個請求對應一個子進程,因此其佔用的系統資源相對其他 兩種模塊而言較多。不過 mpm_prefork 模塊的優點在於它的每個子進程都會獨立處理對應 的單個請求,這樣,如果其中一個請求出現問題就不會影響到其他請求。Prefork 在效率上 要比 Worker 要高,但是內存使用大得多不擅長處理高併發的場景。
開啓prefork模式的方法:
[root@localhost ~]# vim /usr/local/http-2.4.23/conf/httpd.conf
//編寫httpd的主配置文件,修改一下內容
Include conf/extra/httpd-mpm.conf //默認存在刪除“#”號即可
#LoadModule mpm_event_module modules/mod_mpm_event.so
//添加#號
LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
//默認存在,刪除#號即可!
#LoadModule mpm_worker_module modules/mod_mpm_worker.so
//這三行便是apache的三種工作模式,可根據實際情況進行切換
[root@localhost ~]# systemctl restart httpd //重新啓動httpd服務
[root@localhost ~]# systemctl start httpd //手動再啓動一下
[root@localhost ~]# httpd -V //查看httpd的工作模式
//找到這一行即可
Server MPM: prefork //可以看到現在Apache工作在prefork模式
與prefork模式有關的配置文件如下:
[root@localhost ~]# vim /usr/local/http-2.4.23/conf/extra/httpd-mpm.conf
//設置prefork模式也就只有這幾個參數,具體含義:
<IfModule mpm_prefork_module> //這就是prefork工作模式的參數-
StartServers 5 //apache啓動時默認開啓的子進程數
MinSpareServers 5 //最小的閒置子進程數
MaxSpareServers 10 //最大的閒置子進程數
MaxRequestWorkers 250 // 設置了允許同時的最大接入請求數量
MaxConnectionsPerChild 0 //0表示每個子進程處理完數據後進程永不銷燬,設置成非0時,可防止內存泄漏,服務器在負載小時自動減少自己進程數
</IfModule>
關於其配置內容可參考圖片:
//注 1:MaxRequestWorkers 是這些指令中最爲重要的一個,設定的是 Apache 可以同時處理 的請求,是對 Apache 性能影響最大的參數。如果請求總數已達到這個值(可通過 ps -ef|grep http|wc -l 來確認),那麼後面的請求就要排隊,直到某個已處理請求完畢。這就是系統資源 還剩下很多而 HTTP 訪問卻很慢的主要原因。雖然理論上這個值越大,可以處理的請求就越 多,建議將初始值設爲(以 Mb 爲單位的最大物理內存/2),然後根據負載情況進行動態調整。 比如一臺 4G 內存的機器,那麼初始值就是 4000/2=2000
注 2:prefork 控制進程在最初建立“StartServers”個子進程後,爲了滿足 MinSpareServers 設置的需要創建一個進程,等待一秒鐘,繼續創建兩個,再等待一秒鐘,繼續創建四個……如 此按指數級增加創建的進程數,最多達到每秒 32 個,直到滿足 MinSpareServers 設置的值爲止。這種模式 可以不必在請求到來時再產生新的進程,從而減小了系統開銷以增加性能。 MaxSpareServers 設置了最大的空閒進程數,如果空閒進程數大於這個 值,Apache 會自動 kill 掉一些多餘進程。這個值不要設得過大,但如果設的值比 MinSpareServers 小,Apache 會自 動把其調整爲 MinSpareServers+1。如果站點負載較大,可考慮同時加大 MinSpareServers 和 MaxSpareServers。
注 3:ServerLimit 和 MaxClients(MaxRequestWorkers)有什麼區別呢? 是因爲在 apache1 時代,控制最大進程數只有 MaxClients 這個參數,並且這個參數最大值爲 256,並且是寫死了的,試圖設置爲超過 256 是無效的,這是由於 apache1 時代的服務器硬 件限制的。但是 apache2 時代由於服務器硬件的升級,硬件已經不再是限制,所以使用 ServerLimit 這個參數來控制最大進程數,ServerLimit 值>=MaxClient 值纔有效。ServerLimit 要放在 MaxClients 之前,值要不小於 MaxClients
優點:成熟,兼容所有新老模塊。進程之間完全獨立,使得它非常穩定。同時,不需要擔心線程安全的問題。(我們常用的mod_php,PHP的拓展不需要支持線程安全)
缺點:一個進程相對佔用更多的系統資源,消耗更多的內存。而且,它並不擅長處理高併發請求,在這種場景下,它會將請求放進隊列中,一直等到有可用進程,請求才會被處理。
(2)Worker工作模式
Worker 模式(多線程多進程): 和 prefork 模式相比,worker 使用了多進程和多線程的混合模式,worker 模式也同樣會先預派生一些子進程,然後每個子進程創建一些線程,同時包括一個監聽線程,每個請求過來會 被分配到一個線程來服務。線程比起進程會更輕量,因爲線程是通過共享父進程的內存空間, 因此,內存的佔用會減少一些,在高併發的場景下會比 prefork 有更多可用的線程,表現會 更優秀一些;另外,如果一個線程出現了問題也會導致同一進程下的線程出現問題,如果是 多個線程出現問題,也只是影響 Apache 的一部分,而不是全部。由於用到多進程多線程, 需要考慮到線程的安全了,在使用 keep-alive 長連接的時候,某個線程會一直被佔用,即使 中間沒有請求,需要等待到超時纔會被釋放(該問題在 prefork 模式下也存在) 總的來說,prefork 方式速度要稍高於 worker,然而它需要的 cpu 和 memory 資源也稍多於 woker。如圖:
Apache總是試圖維持一個備用(spare)或是空閒的服務線程池。這樣,客戶端無須等待新線程或新進程的建立即可得到處理。在Unix中,爲了能夠綁定80端口,父進程一般都是以root身份啓動,隨後,Apache以較低權限的用戶建立子進程和線程。User和Group指令用於配置Apache子進程的權限。雖然子進程必須對其提供的內容擁有讀權限,但應該儘可能給予他較少的特權。另外,除非使用了suexec(負責處理CGI和SSI程序的請求,確保網頁使用者能以該目錄或程序的用戶ID來執行遠程程序。) ,否則,這些指令配置的權限將被CGI腳本所繼承。
線程比起進程會更輕量,因爲線程通常會共享父進程的內存空間,因此,內存的佔用會減少一些,在高併發的場景下,表現得比 prefork模式好。
有些人會覺得奇怪,那麼這裏爲什麼不直接使用多線程呢?主要是需要考慮穩定性,如果一個線程異常掛了,會導致父進程連同其他正常的子線程都掛了(它們都是同一個進程下的)。多進程+多線程模式中,各個進程之間都是獨立的,如果某個線程出現異常,受影響的只是Apache的一部分服務,而不是整個服務。其他進程仍然可以工作。
有關work模式的配置:
//自行修改httpd主配置文件,切換模式並重啓服務,接下來
[root@localhost ~]# vim /usr/local/http-2.4.23/conf/extra/httpd-mpm.conf
<IfModule mpm_worker_module> //這是worker工作模式的參數
StartServers 3 //apache啓動時默認開始的子進程數
MinSpareThreads 75 //最小空閒數量的工作線程-
MaxSpareThreads 250 //最大空閒數量的工作線程-
ThreadsPerChild 25 //每個子進程產生的線程數量
MaxRequestWorkers 400 //每個進程最大接受的請求數量
MaxConnectionsPerChild 0 //表示永不銷燬
</IfModule>
有關work模式的詳細介紹請參考圖片:
Worker模式下所能同時處理的請求總數是由子進程總數乘以ThreadsPerChild 值決定的,應該大於等於MaxRequestWorkers。如果負載很大,現有的子進程數不能滿足時,控制進程會派生新的子進程。默認最大的子進程總數是16,加大時 也需要顯式聲明ServerLimit(最大值是20000)。需要注意的是,如果顯式聲明瞭ServerLimit,那麼它乘以 ThreadsPerChild的值必須大於等於MaxRequestWorkers,而且MaxRequestWorkers必須是ThreadsPerChild的整數倍,否則 Apache將會自動調節到一個相應值。
優點:佔據更少的內存,高併發下表現更優秀。
缺點:必須考慮線程安全的問題,因爲多個子線程是共享父進程的內存地址的。如果使用keep-alive的長連接方式,也許中間幾乎沒有請求,這時就會發生阻塞,線程被掛起,需要一直等待到超時纔會被釋放。如果過多的線程,被這樣佔據,也會導致在高併發場景下的無服務線程可用。(該問題在prefork模式下,同樣會發生)。
(3)Event MPM
這是Apache最新的工作模式,它和worker模式很像,不同的是在於它解決了keep-alive長連接的時候佔用線程資源被浪費的問題,在event工作模式中,會有一些專門的線程用來管理這些keep-alive類型的線程,當有真實請求過來的時候,將請求傳遞給服務器的線程,執行完畢後,又允許它釋放。這增強了在高併發場景下的請求處理。如圖:
有關Event MPM模式的配置:
//自行修改httpd主配置文件,切換模式並重啓服務,接下來
[root@localhost ~]# vim /usr/local/http-2.4.23/conf/extra/httpd-mpm.conf
<IfModule mpm_event_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
//其各項配置內容與work模式十分相似,這裏就不多說了!
四、進程與線程的區別
線程就是指進程內的一個執行單元,也是進程內的可調度實體。
線程與進程的區別:
- 地址空間:進程內的一個執行單元;進程至少有一個線程;它們共享進程的地址空間;而進程有自己獨立的地址空間;
- 資源擁有:進程是資源分配和擁有的單位,同一個進程內的線程共享進程的資源;
- 線程是處理器調度的基本單位,但進程不是;
- 二者均可併發執行;
進程和線程都是由操作系統所體會的程序運行的基本單元,系統利用該基本單元實現系統對應用的併發性。
進程和線程的區別在於:
簡而言之,一個程序至少有一個進程,一個進程至少有一個線程。
線程的劃分尺度小於進程,使得多線程程序的併發性高。
另外,進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,從而極大地提高了程
序的運行效率。
———————— 本文至此結束,感謝閱讀 ————————