羅清波
關(guān)鍵詞:LNMP;Moodle;服務(wù)器;PHP;高并發(fā);抗擁塞
中圖分類號(hào):TP393 文獻(xiàn)標(biāo)識(shí)碼:A
文章編號(hào):1009-3044(2023)02-0069-03
Moodle是基于PHP語言開發(fā)的免費(fèi)開放學(xué)習(xí)管理系統(tǒng)(LMS),由于采用了組件化管理,教學(xué)手段靈活,功能齊全,所以被國內(nèi)外教育機(jī)構(gòu)普遍使用。LNMP是當(dāng)今比較流行的免費(fèi)開源Web服務(wù)框架,該架構(gòu)涉及技術(shù)范圍廣,安裝和配置相對(duì)復(fù)雜。如果沿用傳統(tǒng)的配置方式,不能最大程度發(fā)揮Moodle教學(xué)服務(wù)器的性能,而且系統(tǒng)在安全性和高效性方面也得不到保證。服務(wù)器在高并發(fā)情況下網(wǎng)頁很容易卡死,甚至?xí)?dǎo)致數(shù)據(jù)庫崩潰,所以對(duì)LNMP架構(gòu)進(jìn)行優(yōu)化是亟待解決的問題[1]。
1 LNMP 架構(gòu)介紹
LNMP架構(gòu)由Linux 內(nèi)核服務(wù)器、Nginx 服務(wù)器、Mysql數(shù)據(jù)庫系統(tǒng)、PHP腳本服務(wù)器組合而成。Nginx 是高性能輕量級(jí)反向代理服務(wù)器,Mysql是一款安全、跨平臺(tái)、高效的數(shù)據(jù)庫系統(tǒng),PHP腳本服務(wù)器用于編譯和執(zhí)行PHP腳本。LNMP架構(gòu)數(shù)據(jù)請(qǐng)求與返回如圖1所示[2]。
從圖1可以看出,數(shù)據(jù)總是從客戶端瀏覽器經(jīng)過Nginx服務(wù)器、php-fpm服務(wù)器、MySQL數(shù)據(jù)庫后,又按原路返回,形成閉環(huán)回路,為了提高M(jìn)oodle教學(xué)服務(wù)器的性能,需要對(duì)LNMP 架構(gòu)的各個(gè)環(huán)節(jié)進(jìn)行優(yōu)化處理。
2 Moodle 教學(xué)平臺(tái)介紹
Moodle是由澳大利亞教師Martin發(fā)起的開放學(xué)習(xí)管理系統(tǒng)(LMS)[3] 。該學(xué)習(xí)管理系統(tǒng)采用模塊化組件設(shè)計(jì),目前系統(tǒng)組件種類高達(dá)1967個(gè),提供全方位教學(xué)手段。教師可以使用這些組件完成不同的教學(xué)方案,可以實(shí)現(xiàn)不同的教育教學(xué)模式。這些組件安裝方便,操作簡單,與原有的系統(tǒng)共存使用。目前世界上多個(gè)國家近千所高校和教科研機(jī)構(gòu)都采用Moodle 作為網(wǎng)絡(luò)在線教學(xué)平臺(tái)[4]。
3 服務(wù)器處理速度優(yōu)化
通過開啟Opcache 和TMPFS,優(yōu)化Mysql 數(shù)據(jù)庫的InnoDB,優(yōu)化PHP進(jìn)程,開啟gzip傳輸、開啟Cron.php定時(shí)運(yùn)行,可以大幅度提高M(jìn)oodle教學(xué)服務(wù)器的處理速度。
3.1 開啟Opcache
PHP作為一種解釋性語言,每次運(yùn)行都會(huì)將代碼進(jìn)行加載解析,運(yùn)行結(jié)束后再釋放,下次運(yùn)行又要重新加載解析再釋放。這種方式顯然不適合高并發(fā)運(yùn)行的Moodle教學(xué)服務(wù)器。
為了避免這樣的問題出現(xiàn),PHP開發(fā)了Opcache 組件,系統(tǒng)啟用Opcache后,在解析過程中可以將一些相同并且重復(fù)的中間件保存在Opcache緩存中,下次加載時(shí)無須再編譯,加快了代碼的執(zhí)行效率,降低了CPU的消耗,減少了PHP網(wǎng)頁的響應(yīng)時(shí)間。
3.2 開啟TMPFS
服務(wù)器的內(nèi)存儲(chǔ)器訪問速度比磁盤的訪問速度要快得多,如果將Moodle網(wǎng)站的程序文件和數(shù)據(jù)庫直接放置在內(nèi)存儲(chǔ)器中,Moodle站點(diǎn)的處理速度就會(huì)大幅度提高。將磁盤文件存儲(chǔ)在內(nèi)存儲(chǔ)器中的方法是啟用TMPFS緩存系統(tǒng)。TMPFS的特點(diǎn)是暫時(shí)存儲(chǔ)、高速讀寫和動(dòng)態(tài)收縮。TMPFS默認(rèn)的初始化存儲(chǔ)空間為物理內(nèi)存的一半,這部分存儲(chǔ)空間不會(huì)被獨(dú)占,僅在掛載存儲(chǔ)文件后才會(huì)占用。掛載命令:mount-tTMPFS -o size=65536M,mode=0755 tmpfs /var/www/cache。
3.3 多進(jìn)程處理
為了充分發(fā)揮CPU的多核特征,可以將Nginx和php-fpm設(shè)置為多進(jìn)程模式,提高處理效率。Nginx通過反向代理功能將用戶瀏覽器的PHP動(dòng)態(tài)請(qǐng)求分配給空閑的Nginx工作進(jìn)程。Nginx并不參與PHP的請(qǐng)求編譯和運(yùn)行工作,而是交由php-fpm 管理進(jìn)程處理。php-fpm將具體的任務(wù)分配給空閑的Fast-CGI協(xié)議[5],由Fast-CGI協(xié)議負(fù)責(zé)編譯和運(yùn)行,并與后臺(tái)數(shù)據(jù)庫實(shí)現(xiàn)數(shù)據(jù)交互,最后將結(jié)果以超文本形式返回給用戶瀏覽器。
Nginx 通過配置worker_ processes 的值開啟多進(jìn)程工作模式。這個(gè)數(shù)值必須與CPU的內(nèi)核數(shù)相匹配,如果設(shè)置不恰當(dāng)會(huì)使服務(wù)器假死。
php-fpm 進(jìn)程管理有三種模式,分別為onde?mand、dynamic和static。配置文件地址為/etc/php/7.2/php-fpm.conf。
如果將配置文件中pm參數(shù)設(shè)置為Ondemand(按需模式),在php-fpm開始啟動(dòng)時(shí),不會(huì)創(chuàng)建任何進(jìn)程,當(dāng)有連接請(qǐng)求時(shí)才會(huì)創(chuàng)建。進(jìn)程數(shù)量取決于pm.max_children設(shè)定值,如果空閑進(jìn)程時(shí)間超過pm.pro?cess_idle_timeout設(shè)定的值,進(jìn)程將關(guān)閉,一般默認(rèn)設(shè)置為10ms。
如果將配置文件中pm參數(shù)設(shè)置為Dynamic(動(dòng)態(tài)模式),在php-fpm 啟動(dòng)時(shí),初始啟動(dòng)的個(gè)數(shù)為pm.start_servers 設(shè)定值,在運(yùn)行過程中動(dòng)態(tài)調(diào)整進(jìn)程數(shù)量,進(jìn)程數(shù)量最大取決于pm.max_children設(shè)定值。
如果將配置文件中的pm參數(shù)設(shè)置為Static (靜態(tài)模式),php-fpm開始啟動(dòng)后始終保持pm.max_children 設(shè)定值,在運(yùn)行期間也不會(huì)擴(kuò)容。
Moodle 教學(xué)服務(wù)器采用static 靜態(tài)模式。一般php-fpm進(jìn)程占用最大內(nèi)存空間為30M,在靜態(tài)模式下pm.max_children的值可設(shè)置為物理內(nèi)存Mem/30M,但考慮到操作系統(tǒng)、Nginx、MySQL都需要占用內(nèi)存,所以php-fpm進(jìn)程數(shù)可以設(shè)為物理內(nèi)存Mem/30M/2。
3.4 存儲(chǔ)引擎InnoDB
InnoDB作為MySQL數(shù)據(jù)庫的默認(rèn)存儲(chǔ)引擎被廣泛應(yīng)用。MySQL數(shù)據(jù)庫接收SQL請(qǐng)求后,通過InnoDB存儲(chǔ)引擎與磁盤存儲(chǔ)文件進(jìn)行交互。在LNMP架構(gòu)中,和數(shù)據(jù)庫有關(guān)的用戶請(qǐng)求都要通過InnoDB存儲(chǔ)引擎,因此,優(yōu)化InnoDB 存儲(chǔ)引擎的性能決定了LNMP架構(gòu)的性能。InnoDB存儲(chǔ)引擎參數(shù)設(shè)置文件為/etc/mysql/my.cnf,設(shè)置參數(shù)如表1所示。
在InnoDB存儲(chǔ)引擎中,通常情況下將日志文件組設(shè)置為3,為了避免日志覆蓋導(dǎo)致緩沖池的不必要刷新,每個(gè)日志文件的大小最好設(shè)置為InnoDB緩沖池的25%。為了防止線程設(shè)置過高產(chǎn)生抖動(dòng),一般將線程并發(fā)數(shù)設(shè)置為16。讀線程和寫線程是InnoDB存儲(chǔ)引擎用來同步操作系統(tǒng)中的讀寫操作,一般設(shè)定參數(shù)值為8。控制Innodb事務(wù)日志寫入的參數(shù)值設(shè)置為2,確保日志及時(shí)寫入磁盤并刷新,這樣設(shè)置不僅可以使InnoDB存儲(chǔ)引擎的日志存盤時(shí)間變小,而且保證了數(shù)據(jù)的安全。
3.5 Cron.php 計(jì)劃任務(wù)定時(shí)運(yùn)行
在Moodle教學(xué)服務(wù)器中,Cron.php主要用于計(jì)劃執(zhí)行課程備份、郵件收發(fā)、臨時(shí)文件清理、課程整理、刪除不需要的檢測(cè)事件等,設(shè)置為每隔5分鐘執(zhí)行一次效果最佳。
通過命令sudo apt-get install cron安裝Cron,然后用命令crontab -e 打開活動(dòng)列表,將下面的命令添加到Cron活動(dòng)列表中,實(shí)現(xiàn)每5分鐘執(zhí)行一次cron.php 程序文件,password的值通過Moodle管理后臺(tái)獲取。
*/5 **** wget –q –o /dev/null
https://ke.qingbosoft.cn/admin/data/cron.php?pass?word=”*****”
4 抗擁塞處理
當(dāng)服務(wù)器遇到高并發(fā)請(qǐng)求時(shí),會(huì)使服務(wù)器響應(yīng)速度變慢,數(shù)據(jù)庫崩潰,甚至服務(wù)器宕機(jī)等事故發(fā)生,所以需要對(duì)服務(wù)器進(jìn)行抗擁塞處理。出現(xiàn)擁塞的原因主要有兩個(gè)方面,一方面MySQL數(shù)據(jù)庫采用默認(rèn)的單線程處理模式,另一方面PHP進(jìn)程數(shù)開啟過大,使數(shù)據(jù)庫同步連接數(shù)變大??箵砣幚淼姆椒ㄊ菍?duì)MySQL 數(shù)據(jù)庫啟用線程池,并配置合理的PHP 進(jìn)程數(shù)。
4.1 Thread Pool 線程池優(yōu)化
PHP 與MySQL 建立連接后,PHP 通過MySQL 的線程機(jī)制來處理請(qǐng)求。MySQL默認(rèn)的線程調(diào)度方式為One-Connection-Per-Thread單線程模式,當(dāng)使用單線程處理每個(gè)客戶的連接請(qǐng)求時(shí),對(duì)于每一個(gè)數(shù)據(jù)庫連接,MySQL 都要?jiǎng)?chuàng)建獨(dú)立的線程服務(wù),請(qǐng)求結(jié)束后再銷毀掉,當(dāng)數(shù)據(jù)庫遇到高并發(fā)時(shí),線程頻繁創(chuàng)建和銷毀,服務(wù)器的性能會(huì)大幅度降低。
為了解決這個(gè)問題,Oracle 公司推出了線程池(Thread Pool Plugin)方案。線程池通過緩存并重用方式,將連接分配給不同的組隊(duì)列,對(duì)用戶的SQL 請(qǐng)求進(jìn)行排隊(duì)處理,減少上下文切換次數(shù),通過隊(duì)列機(jī)制縮短了處理請(qǐng)求的時(shí)間。同時(shí),線程的重用降低了頻繁的連接請(qǐng)求次數(shù),即使在訪問高峰期,數(shù)據(jù)庫仍然能保持高吞吐量,有效解決擁塞問題。Thread Pool線程池的參數(shù)配置文件為/etc/mysql/my.cnf,配置參數(shù)如表2所示。
4.2 PHP 進(jìn)程數(shù)配置
在Moodle教學(xué)服務(wù)器中,用戶請(qǐng)求通過Nginx發(fā)送到php-fpm,然后以隊(duì)列的形式發(fā)送給多個(gè)Fast-CGI 進(jìn)行處理,每個(gè)Fast-CGI 與MySQL 建立連接,MySQL數(shù)據(jù)庫通過Thread Pool線程池處理Fast-CGI 的SQL請(qǐng)求。
當(dāng)Nginx的pm參數(shù)設(shè)置為Dynamic動(dòng)態(tài)模式時(shí),如果有1024 個(gè)用戶同時(shí)訪問Moodle 應(yīng)用服務(wù)器,MySQL數(shù)據(jù)庫就需要?jiǎng)?chuàng)建1024個(gè)鏈接與php-fpm所創(chuàng)建的1024個(gè)Fast-CGI相連,并同時(shí)處理1024個(gè)工作線程,這樣會(huì)造成Mysql數(shù)據(jù)庫阻塞,使服務(wù)器無法高效運(yùn)行。
為了提高服務(wù)器的運(yùn)行效率,需要固定PHP的進(jìn)程數(shù)目。所以將Nginx的pm參數(shù)設(shè)置為Static靜態(tài)模式。pm.max_children進(jìn)程值可以根據(jù)MySQL數(shù)據(jù)庫的最大允許連接數(shù)來推算。如果MySQL數(shù)據(jù)庫的每個(gè)連接所占內(nèi)存容量最大為36.8MB,而分配給數(shù)據(jù)庫的總內(nèi)存為36G, 則MySQL數(shù)據(jù)庫的最大連接數(shù)可以設(shè)置為1000,php-fpm中pm.max_children進(jìn)程數(shù)可以設(shè)置為1000。但一般情況下Fast-CGI進(jìn)程占用內(nèi)存最大值為30MB,而且還要考慮到服務(wù)器其他應(yīng)用的開銷,所以pm.max_children進(jìn)程數(shù)的值一般設(shè)置為64 就夠用了[6]。
5 服務(wù)器性能測(cè)試
5.1 性能測(cè)試
使用Google瀏覽器自帶的Network工具對(duì)Moodle 應(yīng)用服務(wù)器進(jìn)行整體性能測(cè)試,測(cè)試服務(wù)器Request 和Response的請(qǐng)求響應(yīng)耗時(shí)。
發(fā)現(xiàn)優(yōu)化前加載https://ke.qingbosoft.cn/course 課程頁面,PHP訪問MySQL數(shù)據(jù)庫需要耗時(shí)350ms左右,而通過系統(tǒng)優(yōu)化處理后,Moodle課程頁面加載耗時(shí)總體穩(wěn)定在146ms左右,處理速度提高了2.6倍,服務(wù)器性能得到了很大程度的提升[7]。
5.2 抗擁塞檢測(cè)
通過使用Sysbench壓力測(cè)試工具對(duì)MySQL數(shù)據(jù)庫進(jìn)行只讀壓力測(cè)試。分別設(shè)置MySQL數(shù)據(jù)庫為單線程(One-Connection-Per-Thread)模式和線程池(Thread Pool)模式,對(duì)兩種模式進(jìn)行高并發(fā)條件下TPS數(shù)據(jù)吞吐量測(cè)試,測(cè)試結(jié)果如圖2所示。
檢測(cè)結(jié)果表明,伴隨著并發(fā)數(shù)目的不斷增大,單線程模式下TPS數(shù)據(jù)吞吐量急速下降,當(dāng)并發(fā)數(shù)達(dá)到5000時(shí),單線程TPS數(shù)據(jù)吞吐量幾乎為0,而線程池模式的TPS 數(shù)據(jù)吞吐量始終穩(wěn)定在6500~7100左右。所以使用線程池模式,可以很好地解決數(shù)據(jù)庫在高峰訪問時(shí)的擁塞問題,有效提高了Moodle教學(xué)服務(wù)器的訪問速度[8]。
6 結(jié)束語
本文詳細(xì)論述了基于LNMP架構(gòu)的Moodle教學(xué)服務(wù)器的構(gòu)建與優(yōu)化,對(duì)服務(wù)器的LNMP架構(gòu)進(jìn)行深度優(yōu)化,目前應(yīng)用在Moodle在線教學(xué)平臺(tái)(網(wǎng)址https://ke.qingbosoft.cn)上,服務(wù)器性能穩(wěn)定可靠,起到了很好的教學(xué)應(yīng)用效果。
文中提出的構(gòu)建及優(yōu)化方案對(duì)搭建基于Linux內(nèi)核操作系統(tǒng)的網(wǎng)站服務(wù)器具有很好的參考價(jià)值。隨著科技不斷進(jìn)步,受新冠肺炎疫情影響,更多的教育機(jī)構(gòu)都在開發(fā)和搭建自己的在線教學(xué)系統(tǒng),人們對(duì)基于LNMP架構(gòu)的應(yīng)用服務(wù)器進(jìn)行不斷地探索與研究,必將使其能更加安全、快速、高效地提供服務(wù)。