從事php開發的都知道,LNMP一般是指linux+Nginx+MySQL+PHP組合,也是日常開發和線上環境中最簡單的Web服務器架構。為盡可能的提升服務器響應速度,LNMP的配置優化是十分關鍵的步驟。下面分別總結一下LNMP各組件的配置優化方法。
Linux
關于Linux優化,我們這次主要從內核配置方面去講(硬件優化增加投入即可)。內核配置優化主要圍繞如何提供更好更穩定的TCP/IP服務為主,可以查看這篇文章:從TCP/IP協議談Linux內核參數優化, 這里不在單獨寫了。
工作進程數量
Nginx運行工作進程個數,建議按照cpu 數目來指定,一般為它的倍數 (如,2個四核的cpu計為8)。
worker_processes 8;
CPU親和力
worker_cpu_affinity 為每個進程分配cpu,一般情況下一個進程分配一個cpu,例如8cpu:
worker_processes 8; worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
最大打開文件數
worker_rlimit_nofile 65535;
這個指令是指當一個nginx進程打開的最多文件描述符數目,理論值應該是最多打開文件數(ulimit -n)與nginx進程數相除,但是nginx分配請求并不是那么均勻,所以最好與ulimit -n的值保持一致。
注:文件資源限制的配置可以在/etc/security/limits.conf設置,針對root/user等各個用戶或者*代表所有用戶來設置。
* soft nofile 65535 * hard nofile 65535
用戶重新登錄生效。
Nginx事件處理模型
events { use epoll; }
nginx采用epoll事件模型,處理效率高。
工作進程連結束
worker_connections 65535;
設置每個進程允許的最多連接數, 理論上每臺nginx 服務器的最大連接數為worker_processes*worker_connections,一般設置為65535。
開啟Gzip壓縮
使用gzip壓縮功能,可能為節約帶寬,加快傳輸速度。
一般我們需要壓縮的內容有:文本,js,html,css,對于圖片,視頻,flash什么的不壓縮,使用gzip的功能是需要消耗CPU的。
gzip on; gzip_min_length 2k; gzip_buffers 4 32k; gzip_http_version 1.1; gzip_comp_level 6; gzip_typestext/plain text/css text/JAVAscriptApplication/json application/JavaScript application/x-javascriptapplication/xml; gzip_vary on; gzip_proxied any; gzip on; #開啟壓縮功能
參數說明:
- gzip_min_length 1k :設置允許壓縮的頁面最小字節數,頁面字節數從header頭的Content-Length中獲取,默認值是0,不管頁面多大都進行壓縮,建議設置成大于1K,如果小與1K可能會越壓越大。
- gzip_buffers 4 32k :壓縮緩沖區大小,表示申請4個單位為32K的內存作為壓縮結果流緩存,默認值是申請與原始數據大小相同的內存空間來存儲gzip壓縮結果。
- gzip_http_version 1.1 :壓縮版本,用于設置識別HTTP協議版本,默認是1.1,目前大部分瀏覽器已經支持GZIP解壓,使用默認即可。
- gzip_comp_level 6 :壓縮比例,用來指定GZIP壓縮比,1壓縮比最小,處理速度最快,9壓縮比最大,傳輸速度快,但是處理慢,也比較消耗CPU資源。
- gzip_types text/css text/xml application/javascript :用來指定壓縮的類型,‘text/html’類型總是會被壓縮。默認值: gzip_types text/html (默認不對js/css文件進行壓縮)
- 壓縮類型,匹配MIME型進行壓縮;
- 不能用通配符 text/*;
- text/html默認已經壓縮 (無論是否指定);
- 設置哪壓縮種文本文件可參考 conf/mime.types。
- gzip_vary on :varyheader支持,改選項可以讓前端的緩存服務器緩存經過GZIP壓縮的頁面,例如用Squid緩存經過nginx壓縮的數據。
連接超時設置
keepalived_timeout 65; client_header_timeout 30; client_body_timeout 30; sned_timeout 60; proxy_send_timeout 300; reset_timedout_connection on;
參數說明:
- keepalived_timeout :客戶端連接保持會話超時時間,超過這個時間,服務器斷開這個鏈接,對于一些請求比較大的內部服務器通訊的場景,適當加大為120s或者300s,具體根據不同場景,默認值是60秒。
- client_header_timeout : 客戶端向服務器發送一個完整的request header的超時時間,如果客戶端在此時間內沒有發送一個完整的request header,那么Nginx返回HTTP 408錯誤(Request Timed Out),默認值是60秒。
- client_body_timeout: 客戶端與服務器建立連接后發送request body的超時時間,如果客戶端在此時間內沒有發送任何內容,那么Nginx返回HTTP 408錯誤(Request Timed Out),默認值是60秒。
- reset_timeout_connection :告訴nginx關閉不響應的客戶端連接。這將會釋放那個客戶端所占有的內存空間。
- send_timeout :發送數據至客戶端超時時間,默認60s,如果連續的60s內客戶端沒有收到1個字節,連接關閉。
- proxy_send_timeout:發送請求給upstream服務器的超時時間,超時設置不是整個發送期間, 而是在兩次write操作期間, 如果超時后,upstream沒有收到新的數據,nginx會關閉連接。
Buffer緩解后端的負載
在大部分場景下,利用 Nginx 的 buffer(緩沖) 和 cache(緩存) 能力,可以大大地減輕負擔。
client_body_buffer_size 16K client_header_buffer_size 1K
- client_body_buffer_size:允許客戶端請求的最大單個文件字節數,在32位系統上默認是8k,在64位系統上默認是16k。可以在http, server 和 location模塊中指定
- client_header_buffer_size:用于設置客戶端請求的Header頭緩沖區大小,大部分情況1KB大小足夠, 默認的值是1k
開啟高效傳輸模式
http { include mime.types; default_type application/octet-stream; …… sendfile on; tcp_nopush on; …… }
- sendfile on:開啟高效文件傳輸模式,sendfile指令指定nginx是否調用sendfile函數來輸出文件,對于普通應用設為 on,如果用來進行下載等應用磁盤IO重負載應用,可設置為off,以平衡磁盤與網絡I/O處理速度,降低系統的負載。注意:如果圖片顯示不正常把這個改成off。
- tcp_nopush on:必須在sendfile開啟模式才有效,防止網路阻塞,積極的減少網絡報文段的數量(將響應頭和正文的開始部分一起發送,而不一個接一個的發送。)
expires 緩存調優
緩存,主要針對于圖片,css,js等元素更改機會比較少的情況下使用,特別是圖片,占用帶寬大,我們完全可以設置圖片在瀏覽器本地緩存365d,css,js,html可以緩存個10來天,這樣用戶第一次打開加載慢一點,第二次,就非常快了!緩存的時候,我們需要將需要緩存的拓展名列出來, Expires緩存配置在server字段里面。
location ~* .(ico|jpe?g|gif|png|bmp|swf|flv)$ { expires 30d; } location ~* .(js|css)$ { expires 7d; }
fastcgi 調優
fastcgi_connect_timeout 600; fastcgi_send_timeout 600; fastcgi_read_timeout 600; fastcgi_buffer_size 64k; fastcgi_buffers 4 64k; fastcgi_busy_buffers_size 128k; fastcgi_temp_file_write_size 128k; fastcgi_temp_path/usr/local/nginx1.10/nginx_tmp; fastcgi_intercept_errors on; fastcgi_cache_path/usr/local/nginx1.10/fastcgi_cache levels=1:2 keys_zone=cache_fastcgi:128minactive=1d max_size=10g;
- fastcgi_connect_timeout 600 :指定連接到后端FastCGI的超時時間。
- fastcgi_send_timeout 600 :向FastCGI傳送請求的超時時間。
- fastcgi_read_timeout 600 :指定接收FastCGI應答的超時時間。
- fastcgi_buffer_size 64k :指定讀取FastCGI應答第一部分需要用多大的緩沖區,默認的緩沖區大小為。fastcgi_buffers指令中的每塊大小,可以將這個值設置更小。
- fastcgi_buffers 4 64k :指定本地需要用多少和多大的緩沖區來緩沖FastCGI的應答請求,如果一個php腳本所產生的頁面大小為256KB,那么會分配4個64KB的緩沖區來緩存,如果頁面大小大于256KB,那么大于256KB的部分會緩存到fastcgi_temp_path指定的路徑中,但是這并不是好方法,因為內存中的數據處理速度要快于磁盤。一般這個值應該為站點中php腳本所產生的頁面大小的中間值,如果站點大部分腳本所產生的頁面大小為256KB,那么可以把這個值設置為“8 32K”、“4 64k”等。
- fastcgi_busy_buffers_size 128k :建議設置為fastcgi_buffers的兩倍,繁忙時候的buffer。
- fastcgi_temp_file_write_size 128k :在寫入fastcgi_temp_path時將用多大的數據塊,默認值是fastcgi_buffers的兩倍,該數值設置小時若負載上來時可能報502BadGateway。
- fastcgi_temp_path :緩存臨時目錄。
- fastcgi_intercept_errors on :這個指令指定是否傳遞4xx和5xx錯誤信息到客戶端,或者允許nginx使用error_page處理錯誤信息。注:靜態文件不存在會返回404頁面,但是php頁面則返回空白頁!
- fastcgi_cache_path /usr/local/nginx1.10/fastcgi_cachelevels=1:2 keys_zone=cache_fastcgi:128minactive=1d max_size=10g :fastcgi_cache緩存目錄,可以設置目錄層級,比如1:2會生成16*256個子目錄,cache_fastcgi是這個緩存空間的名字,cache是用多少內存(這樣熱門的內容nginx直接放內存,提高訪問速度),inactive表示默認失效時間,如果緩存數據在失效時間內沒有被訪問,將被刪除,max_size表示最多用多少硬盤空間。
- fastcgi_cache cache_fastcgi :#表示開啟FastCGI緩存并為其指定一個名稱。開啟緩存非常有用,可以有效降低CPU的負載,并且防止502的錯誤放生。cache_fastcgi為proxy_cache_path指令創建的緩存區名稱。
- fastcgi_cache_valid 200 302 1h :#用來指定應答代碼的緩存時間,實例中的值表示將200和302應答緩存一小時,要和fastcgi_cache配合使用。
- fastcgi_cache_valid 301 1d :將301應答緩存一天。
- fastcgi_cache_valid any 1m :將其他應答緩存為1分鐘。
- fastcgi_cache_min_uses 1 :該指令用于設置經過多少次請求的相同URL將被緩存。
- fastcgi_cache_key http://$host$request_uri :該指令用來設置web緩存的Key值,nginx根據Key值md5哈希存儲.一般根據$host(域名)、$request_uri(請求的路徑)等變量組合成proxy_cache_key 。
- fastcgi_pass :指定FastCGI服務器監聽端口與地址,可以是本機或者其它。
禁用訪問日志文件
這一點影響較大,因為高流量站點上的日志文件涉及大量必須在所有線程之間同步的IO操作。
access_log off; log_not_found off; error_log /var/log/nginx-error.log warn;
若你不能關閉訪問日志文件,至少應該使用緩沖:
access_log /var/log/nginx/access.log main buffer=16k;
關閉版本顯示
server_tokens off;
server_tokens并不會讓nginx執行的速度更快,但它可以關閉在錯誤頁面中的nginx版本數字,這樣對于安全性是有好處的。
MySql
innodb_file_per_table
表的數據和索引存放在共享表空間里或者單獨表空間里。我們的工作場景安裝是默認設置了innodb_file_per_table = ON,這樣也有助于工作中進行單獨表空間的遷移工作。MySQL 5.6中,這個屬性默認值是ON。
innodb_flush_log_at_trx_commit
默認值為1,表示InnoDB完全支持ACID特性。當你的主要關注點是數據安全的時候這個值是最合適的,比如在一個主節點上。但是對于磁盤(讀寫)速度較慢的系統,它會帶來很巨大的開銷,因為每次將改變flush到redo日志都需要額外的fsyncs。
如果將它的值設置為2會導致不太可靠(unreliable)。因為提交的事務僅僅每秒才flush一次到redo日志,但對于一些場景是可以接受的,比如對于主節點的備份節點這個值是可以接受的。如果值為0速度就更快了,但在系統崩潰時可能丟失一些數據:只適用于備份節點。說到這個參數就一定會想到另一個sync_binlog。
innodb_flush_method
這項配置決定了數據和日志寫入硬盤的方式。一共有三種方式,我們默認使用O_DIRECT 。O_DIRECT模式:數據文件的寫入操作是直接從mysql innodb buffer到磁盤的,并不用通過操作系統的緩沖,而真正的完成也是在flush這步,日志還是要經過OS緩沖。
innodb_log_buffer_size
這項配置決定了為尚未執行的事務分配的緩存。其默認值(1MB)一般來說已經夠用了,但是如果你的事務中包含有二進制大對象或者大文本字段的話,這點緩存很快就會被填滿并觸發額外的I/O操作。看看Innodb_log_waits狀態變量,如果它不是0,增加innodb_log_buffer_size。
innodb_buffer_pool_size
這個參數應該是運維中必須關注的了。緩沖池是數據和索引緩存的地方,它屬于MySQL的核心參數,默認為128MB,正常的情況下這個參數設置為物理內存的60%~70%。(不過我們的實例基本上都是多實例混部的,所以這個值還要根據業務規模來具體分析。)
innodb_log_file_size
這是redo日志的大小。redo日志被用于確保寫操作快速而可靠并且在崩潰時恢復。如果你知道你的應用程序需要頻繁地寫入數據并且你使用的是MySQL 5.6,那么你可以一開始就把它這是成4G。(具體大小還要根據自身業務進行適當調整)
innodb_support_xa
innodb_support_xa可以開關InnoDB的XA兩段式事務提交。默認情況下,innodb_support_xa=true,支持XA兩段式事務提交。由于XA兩段式事務提交導致多余flush等操作,性能影響會達到10%,所有為了提高性能,有些DBA會設置innodb_support_xa=false。這樣的話,redolog和binlog將無法同步,可能存在事務在主庫提交,但是沒有記錄到binlog的情況。這樣也有可能造成事務數據的丟失。
innodb_additional_mem_pool_size
該參數用來存儲數據字段信息和其他內部數據結構。表越多,需要在這里分配的內存越多。如果InnoDB用光了這個池內的內存,InnoDB開始從操作系統分配內存,并且往MySQL錯誤日志寫警告信息,默認8MB。一般設置16MB。
max_connections
MySQL服務器默認連接數比較小,一般也就100來個最好把最大值設大一些。一般設置500~1000即可每一個鏈接都會占用一定的內存,所以這個參數也不是越大越好。有的人遇到too many connections會去增加這個參數的大小,但其實如果是業務量或者程序邏輯有問題或者sql寫的不好,即使增大這個參數也無濟于事,再次報錯只是時間問題。在應用程序里使用連接池或者在MySQL里使用進程池有助于解決這一問題。
server-id
復制架構時確保 server-id 要不同,通常主ID要小于從ID。
log_bin
如果你想讓數據庫服務器充當主節點的備份節點,那么開啟二進制日志是必須的。如果這么做了之后,還別忘了設置server_id為一個唯一的值。就算只有一個服務器,如果你想做基于時間點的數據恢復,這(開啟二進制日志)也是很有用的:從你最近的備份中恢復(全量備份),并應用二進制日志中的修改(增量備份)。
二進制日志一旦創建就將永久保存。所以如果你不想讓磁盤空間耗盡,你可以用 PURGE BINARY LOGS 來清除舊文件,或者設置expire_logs_days 來指定過多少天日志將被自動清除。記錄二進制日志不是沒有開銷的,所以如果你在一個非主節點的復制節點上不需要它的話,那么建議關閉這個選項。
skip_name_resolve
當客戶端連接數據庫服務器時,服務器會進行主機名解析,并且當DNS很慢時,建立連接也會很慢。因此建議在啟動服務器時關閉skip_name_resolve選項而不進行DNS查找。唯一的局限是之后GRANT語句中只能使用IP地址了,因此在添加這項設置到一個已有系統中必須格外小心。
sync_binlog
sync_binlog 的默認值是0,像操作系統刷其他文件的機制一樣,MySQL不會同步到磁盤中去而是依賴操作系統來刷新binary log。
當sync_binlog =N (N>0) ,MySQL 在每寫N次二進制日志binary log時,會使用fdatasync()函數將它的寫二進制日志binary log同步到磁盤中去。當innodb_flush_log_at_trx_commit和sync_binlog 都為 1 時是最安全的,在mysqld服務崩潰或者服務器主機crash的情況下,binary log只有可能丟失最多一個語句或者一個事務。但是魚與熊掌不可兼得,雙1會導致頻繁的IO操作,因此該模式也是最慢的一種方式。出于我們的業務考慮在業務壓力允許的情況下默認的都是雙1配置。
log_slave_update
當業務中需要使用級聯架構的時候log_slave_update = 1這個參數必須打開,否者第三級可能無法接收到第一級產生的binlog,從而無法進行數據同步。
tmpdir
如果內存臨時表超出了限制,MySQL就會自動地把它轉化為基于磁盤的MyISAM表,存儲在指定的tmpdir目錄下.因此盡可能將tmpdir配置到性能好速度快的存儲設備上。
慢日志相關
slow_query_log = 1 #打開慢日志
PHP
進程數
pm = dynamic #pm參數指定了進程管理方式,有兩種可供選擇:static或dynamic,從字面意思不難理解,為靜態或動態方式。如果是靜態方式,那么在php-fpm啟動的時候就創建了指定數目的進程,在運行過程中不會再有變化(并不是真的就永遠不變);而動態的則在運行過程中動態調整,當然并不是無限制的創建新進程,受pm.max_spare_servers參數影響;動態適合小內存機器,靈活分配進程,省內存。靜態適用于大內存機器,動態創建回收進程對服務器資源也是一種消耗 pm.max_children = 24 #static模式下創建的子進程數或dynamic模式下同一時刻允許最大的php-fpm子進程數量 pm.start_servers = 16 #動態方式下的起始php-fpm進程數量 pm.min_spare_servers = 12 #動態方式下服務器空閑時最小php-fpm進程數量 pm.max_spare_servers = 24 #動態方式下服務器空閑時最大php-fpm進程數量
一般php-fpm進程占用20~30m左右的內存就按30m算。如果單獨跑php-fpm,動態方式起始值可設置物理內存Mem/30M。
最大處理請求數
pm.max_requests = 10240
最大處理請求數是指一個php-fpm的worker進程在處理多少個請求后就終止掉,master進程會重新respawn一個新的,這個配置的主要目的是避免php解釋器或程序引用的第三方庫造成的內存泄露。
最長執行時間
max_execution_time = 20 request_terminate_timeout = 20
這個是用來處理因為PHP執行時間超長而報502錯誤的解決。這個時長配置可以在php.ini(max_execution_time)或php-fpm.conf中配置均可,為了不影響全局配置,可在php-fpm.conf中實現