1.度量性能
持續地對性能進行度量在兩個方面有幫助。首先,度量可以幫助了解性能趨勢,包括好壞兩方面的趨勢。作為一個簡單的方法,查看一下 Web 服務器上的中央處理單元(CPU)使用率,就可以了解 CPU 是否負載過重。同樣,查看過去使用的總帶寬並推斷未來的變化,可以幫助判斷什么時候需要進行網絡升級。這些度量最好與其他度量和觀測結合考慮。例如,當用戶抱怨應用程序太慢時,可以檢查磁盤操作是否達到了最大容量。
性能度量的第二個用途是,判斷調優是對系統性能有幫助,還是使它更糟糕了。方法是比較修改之前和之后的度量結果。但是,為了進行有效的比較,每次應該只修改一個設置,然后對適當的指標進行比較以判斷修改的效果。每次只修改一個設置的原因應該是很明顯的:同時做出的兩個修改很可能會相互影響。選擇用來進行比較的指標比較微妙。
選擇的指標必須能夠反映應用程序用戶感覺到的響應。如果一項修改的目標是減少數據庫的內存占用量,那么取消各種緩沖區肯定會有幫助,但是這會犧牲查詢速度和應用程序性能。所以,應該選擇應用程序響應時間這樣的指標,這會使調優向着正確的方向發展,而不僅僅是針對數據庫內存使用量。
(1).可以以許多方式度量應用程序響應時間。最簡單的方法可能是使用 curl 命令.
1.使用curl度量 fix.weirenmai.dragon-stone.cn的響應時間
[fanlinlin@web ~]$ curl -o /dev/null -s -w %{time_connect}:%{time_starttransfer}:%{time_total} \
http://fix.weirenmai.dragon-stone.cn/?token=2.002JoF6BGNDM9Bbe36c372f0Hg28FE 0.004:0.882:1.393 |
對 fix.weirenmai.dragon-stone.cn執行curl命令,輸出通常是html代碼,通過 -o參數將html代碼發送到/dev/null。-s去除掉所有的狀態信息,-w參數是讓curl列出計時器的狀態信息:
curl使用的計時器:
time_connect |
建立到服務器的 TCP 連接所用的時間 (0.004) |
time_starttransfer |
在發出請求之后,Web 服務器返回數據的第一個字節所用的時間 (0.882) |
time_total |
完成請求所用的時間 (1.393) |
服務器建立tcp連接所用時間: 0.004s.
web服務器處理請求並開始返回數據所用的時間 : 0.882 - 0.004 = 0.878s.
客戶端從服務器下載數據所用的時間是: 1.393 - 0.882 = 0.511s.
通過觀察curl數據及其隨時間變化的趨勢,可以很好的了解網站對用戶響應性.
(2).可以通過uptime了解系統負載情況
[fanlinlin@web ~]$ uptime 11:11:39 up 67 days, 1:30, 9 users, load average: 4.41, 4.40, 3.22 |
load average后的3個數字,分別代表系統最近一分鍾,五分鍾,十五分鍾的系統負載.
(3).使用sar監控系統(sar 主要負責收集,匯報與存儲系統運行信息)
1)通過sar -u輸出cpu使用情況:
[fanlinlin@web ~]$ sar -u 1 3
Linux 2.6.32-220.el6.x86_64 (web.youlu.com.cn) 2013年02月18日 _x86_64_ (4 CPU)
11時38分59秒 CPU %user %nice %system %iowait %steal %idle
11時39分00秒 all 88.31 0.00 8.71 0.00 0.00 2.99
11時39分01秒 all 90.75 0.00 7.50 1.25 0.00 0.50
11時39分02秒 all 80.75 0.00 19.25 0.00 0.00 0.00
平均時間: all 86.61 0.00 11.81 0.42 0.00 1.16
- %user: 在用戶模式中運行進程所花的時間比。
- %nice : 運行正常進程所花的時間.
- %system: 在內核模式(系統)中運行進程所花的時間。
- %iowait:沒有進程在該CPU上執行時,處理器等待I/O完成的時間
- %idle:沒有進程在該CPU上執行的時間
1. 若 %iowait 的值過高,表示硬盤存在I/O瓶頸
2. 若 %idle 的值高但系統響應慢時,有可能是 CPU 等待分配內存,此時應加大內存容量
3. 若 %idle 的值持續低於1,則系統的 CPU 處理能力相對較低,表明系統中最需要解決的資源是 CPU 。
2)通過sar -d 查看硬盤活動:
sar -d 10 3
Linux 2.6.32-220.el6.x86_64 (web.youlu.com.cn) 2013年02月18日 _x86_64_ (4 CPU)
11時55分16秒 DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
11時55分26秒 dev8-0 3.30 0.00 69.67 21.09 0.02 7.09 6.55 2.16
11時55分26秒 dev8-16 3.20 0.00 69.67 21.75 0.02 6.69 6.16 1.97
11時55分26秒 dev8-32 16.32 108.91 146.55 15.66 0.09 5.48 3.50 5.72
11時55分26秒 dev8-48 15.42 8.81 146.55 10.08 0.07 4.86 3.03 4.66
- tps : 每秒從物理磁盤I/O的次數.多個邏輯請求會被合並為一個I/O磁盤請求,一次傳輸的大小是不確定的
- rd_sec/s : 每秒讀扇區的次數.
- wr_sec/s:每秒寫扇區的次數.
- avgrq-sz:平均每次設備I/O操作的數據大小(扇區).
- avgqu-sz:磁盤請求隊列的平均長度.
- await:從請求磁盤操作到系統完成處理,每次請求的平均消耗時間,包括請求隊列等待時間,單位是毫秒(1秒=1000毫秒).
- svctm:系統處理每次請求的平均時間,不包括在請求隊列中消耗的時間.
- %util:I/O請求占CPU的百分比,比率越大,說明越飽和
1. avgqu-sz 的值較低時,設備的利用率較高。
2. 當%util的值接近 1% 時,表示設備帶寬已經占滿
3) 要判斷系統瓶頸問題,有時需幾個 sar 命令選項結合起來
1.懷疑CPU存在瓶頸,可用 sar -u 和 sar -q 等來查看
2.懷疑內存存在瓶頸,可用 sar -B、sar -r 和 sar -W 等來查看
3.懷疑I/O存在瓶頸,可用 sar -b、sar -u 和 sar -d 等來查看
(4) 使用top查看cpu,內存使用情況:
Tasks: 219 total, 2 running, 217 sleeping, 0 stopped, 0 zombie
Cpu(s): 8.4%us, 0.8%sy, 0.0%ni, 90.3%id, 0.2%wa, 0.0%hi, 0.2%si, 0.0%st
Mem: 3853728k total, 3415984k used, 437744k free, 197692k buffers
Swap: 8388600k total, 350820k used, 8037780k free, 799716k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7605 root 20 0 212m 9352 3772 S 4.3 0.2 0:00.13 svn
12004 root 20 0 305m 9756 3216 S 1.3 0.3 27:26.98 php
9720 xufengqi 20 0 299m 13m 6440 S 1.0 0.4 1:16.80 php
12667 root 20 0 806m 9452 888 S 0.7 0.2 62:12.83 opportunity_rec
22854 root 20 0 147m 67m 664 S 0.7 1.8 194:47.15 redis-server
24161 mysql 20 0 2188m 45m 4172 S 0.7 1.2 295:30.25 mysqld
8744 zhusheng 20 0 340m 6392 2540 S 0.3 0.2 57:03.99 recommend_compa
1.輸入P查看系統cpu使用情況.
2.輸入M查看系統內存使用情況.
2. linux系統調優
大多數 Linux 發布版都定義了適當的緩沖區和其他 Transmission Control Protocol(TCP)參數。可以修改這些參數來分配更多的內存,從而改進網絡性能。設置內核參數的方法是通過 proc 接口,也就是通過讀寫 /proc 中的值。幸運的是,sysctl 可以讀取/etc/sysctl.conf 中的值並根據需要填充 /proc,這樣就能夠更輕松地管理這些參數.
1).添加/etc/sysctl.conf中的參數
# Use TCP syncookies when needed
net.ipv4.tcp_syncookies = 1
# Enable TCP window scaling
net.ipv4.tcp_window_scaling: = 1
# Increase TCP max buffer size
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
# Increase Linux autotuning TCP buffer limits
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# Increase number of ports available
net.ipv4.ip_local_port_range = 1024 65000
將這些設置添加到 /etc/sysctl.conf 的現有內容中。
第一個設置啟用 TCP SYN cookie。當從客戶機發來新的 TCP 連接時,數據包設置了 SYN 位,服務器就為這個半開的連接創建一個條目,並用一個 SYN-ACK 數據包進行響應。在正常操作中,遠程客戶機用一個 ACK 數據包進行響應,這會使半開的連接轉換為全開的。有一種稱為 SYN 泛濫的網絡攻擊,它使 ACK 數據包無法返回,導致服務器用光內存空間,無法處理到來的連接。SYN cookie 特性可以識別出這種情況,並使用一種優雅的方法保留隊列中的空間。大多數系統都默認啟用這個特性,但是確保配置這個特性更可靠。
第二個設置是啟用tcp窗口伸縮使客戶機能夠以更高的速度下載數據。tcp允許在未從遠程端收到確認的情況下發送多個數據包,默認設置最多使64k,在與延遲比較大的遠程機進行通訊時這個設置是不夠。窗口伸縮會在頭中啟用更多的位,從而增加窗口大小.
后面4個配置項是增加tcp發送和接收緩存區。這使得運用程序可以更快丟掉它的數據,從而為另一個請求服務.還可以強化遠程客戶機在服務器繁忙時發送數據的能力。
最后一個配置是增加可用的本地端口數量,這樣就增加了可以同時服務的最大連接數量. 運行 sysctl -p /etc/sysctl.conf ,這樣設置就會生效.
2)磁盤調優
磁盤在 LAMP 架構中扮演着重要的角色。靜態文件、模板和代碼都來自磁盤,組成數據庫的數據表和索引也來自磁盤。對磁盤的許多調優(尤其是對於數據庫)集中於避免磁盤訪問,因為磁盤訪問的延遲相當高.
首先要在文件系統上禁用atime日志記錄特性.atime是最近訪問文件的時間,每當訪問文件時,底層文件系統必須記錄這個時間戳。因為我們很少使用atime,禁用它可以減少磁盤的訪問時間. 禁用該特性的方法是,在/etc/fstab的第四列中添加noatime。
如何啟用 noatime 的 fstab 示例
/dev/mapper/VolGroup-lv_root / ext4 defaults,noatime 1 1
UUID=ba007d22-b42b-4b1e-9301-eec5535dffe1 /boot ext4 defaults,noatime 1 2
/dev/mapper/VolGroup-LogVol02 /opt ext4 defaults,noatime 1 2
/dev/mapper/VolGroup-lv_swap swap swap defaults 0 0
tmpfs /dev/shm tmpfs defaults 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
sysfs /sys sysfs defaults 0 0
proc /proc proc defaults 0 0
上述修改了 ext4 文件系統,因為 noatime 只對駐留在磁盤上的文件系統有幫助。為讓這一修改生效,不需要重新引導;只需重新掛裝每個文件系統, 運行 mount / -o remount。
可以使用 hdparm 命令查明和設置用來訪問 IDE 磁盤的方法。hdparm -t /path/to/device 執行速度測試,可以將這個測試結果作為性能基准。為了使結果盡可能准確,在運行這個命令時系統應該是空閑的.
在/dev/sda 上執行的速度測試
# hdparm -t /dev/sda
/dev/sda:
Timing buffered disk reads: 290 MB in 3.18 seconds = 91.27 MB/sec
這一測試說明,在這個磁盤上讀取數據的速度是大約每秒 91.27 MB。
3) I/O調優
在/etc/grub.conf中加入相應的I/O調度算法.
I/O調度算法總共有4種.
1.deadline算法 (適合小文件讀寫,跳躍式讀寫,零散讀寫,適合吞吐量非常大的運用)(數據庫)
2. anticipatory算法 (適合大文件讀寫,整塊式,重復讀寫) (web server)
3. cfg算法 (完全公平算法)
4. noop算法 (沒有算法)
將I/o調度算法改為deadline算法.
echo deadline > /sys/block/sda/queue/scheduler
4)將訪問數超過150的ip加上防火牆
1 #!/bin/sh
2 status=`netstat -na|awk '$5 ~ /[0-9]+:[0-9]+/ {print $5}' |awk -F ":" -- '{print $1}' |sort -n|uniq -c |sort -n|tail -n 1`
3 NUM=`echo $status|awk '{print $1}'`
4 IP=`echo $status|awk '{print $2}'`
5 result=`echo "$NUM > 150" | bc`
6 if [ $result = 1 ]
7 then
8 echo IP:$IP is over $NUM, BAN IT!
9 /sbin/iptables -I INPUT -s $IP -j DROP
10 fi
將該shell腳本加入crontab中,5秒運行一次.
5)查看apache的並發請求數及其tcp連接狀態:
[fanlinlin@weirenmai-dev ~]$ netstat -nat|awk '{print awk $NF}'|sort|uniq -c|sort -n
1 established)
1 State
3 LAST_ACK
4 FIN_WAIT2
11 SYN_SENT
14 LISTEN
19 CLOSE_WAIT
43 FIN_WAIT1
244 SYN_RECV
696 TIME_WAIT
1126 ESTABLISHED
上述參數的描述
SYN_RECV : 表示正在等待處理的請求數.
ESTABLISHED : 表示正常數據傳輸狀態
TIME_WAIT : 表示處理完畢,等待超時結束的請求數。
3. apache調優
1)MPM(多處理模塊)配置(主要負責管理網絡連接,調度請求)
Apache有3個MPM,分別是: event , prefork和worker。
event這個MPM是在Apache2.4后才有穩定版,比較適用於大量連續連接的情況。event為不同的任務使用單獨的線程池. KeepAlive的好處是,可以同一個tcp連接中響應多個請求,這種方式,可以使一個包含大量圖片和html文檔的請求加速50%,在Apache配置文件httpd.conf中設置KeepAlive設置為On.
prefork是一個非線程的MPM。它的特點:不快但很穩定.它能夠隔離每個請求,所以如果某個請求出現故障,不會影響其他請求.使用prefork最重要的一個參數是MaxClients。這個MaxClients足夠大,這樣可以在訪問高峰時發揮很好的性能,但是同時又不能太大,致使Apache所需內存超過物理內存。
worker這個MPM,速度比prefork快很多,由於使用多線程進行訪問處理,所以能夠處理相對海量的請求,而系統資源的占用要小於基於進程的服務器.work有2個比較重要的參數:ThreadPerChild和MaxClients.ThreadPerChild是用來控制每個子進程允許建立的線程數,MaxClients用來控制允許建立的總線程數.
perfork MPM
<IfModule mpm_prefork_module]]>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 250
MaxConnectionsPerChild 0
</IfModule]]>
- StartServers : 數量的服務器進程的開始
- MinSpareServers : 最小數量的服務器進程
- MaxSpareServers : 最大數量的服務器進程
- MaxRequestWorkers : 最大數量的服務器進程允許開始
- MaxConnectionsPerChild: 最大連接數的一個服務器進程服務
worker MPM
<IfModule mpm_worker_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
- StartServers : 數量的服務器進程的開始
- MinSpareThreads : 最小數量的工作線程
- MaxSpareThreads : 最大數量的工作線程
- ThreadsPerChild : 每個服務進程包含的固定數量的工作線程
- MaxRequestWorkers : 最大數量的工作線程
- MaxConnectionsPerChild: 最大連接數的一個服務器進程服務
event MPM
<IfModule mpm_event_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
- StartServers : 數量的服務器進程的開始
- MinSpareThreads : 最小數量的工作線程
- MaxSpareThreads : 最大數量的工作線程
- ThreadsPerChild : 每個服務進程包含的固定數量的工作線程
- MaxRequestWorkers : 最大數量的工作線程
- MaxConnectionsPerChild: 最大連接數的一個服務器進程服務
通過/opt/apache/bin/httpd -l,我們可以看到我們的使用是event MPM
<IfModule mpm_event_module>
ServerLimit 10000
StartServers 8
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 4000
MaxConnectionsPerChild 2000
</IfModule>
2)Apache其他參數優化
1. ExtendedStatus Off 關閉對每個請求連接的擴展狀態信息跟蹤.
2. KeepAlive On //使用keepalive可以在單一連接時進行多個請求.
MaxKeepAliveRequests 0 //最大保持連接數, 0為不限制.
KeepAliveTimeout 5 //每個連接保持時間
3. HostnameLookups Off
//盡量較少DNS查詢的次數。如果你使用了任何”Allow fromdomain”或”Denyfrom domain”指令(也就是domain使用的是主機名而不是IP地址),則代價是要進行兩次DNS查詢(一次正向和一次 反向,以確認沒有作假)。所以,為了得到最高的性能,應該避免使用這些指令.
4.使用mod_deflat模塊,這個模塊可以在用戶訪問網站時實時將內容進行壓縮,然后再傳給客戶端.所以mod_deflat能極大地加速網站,節約帶寬,當然壓縮需要花費cpu時間.
LoadModule deflate_module modules/mod_deflate.so
<ifmodule mod_deflate>
DeflateCompressionLevel 9
SetOutputFilter DEFLATE
#DeflateFilterNote Input instream
#DeflateFilterNote Output outstream
#DeflateFilterNote Ratio ratio
#LogFormat '"%r" %{outstream}n/%{instream}n (%{ratio}n%%)' deflate
#CustomLog logs/deflate_log.log deflate
</ifmodule>
5.減少Timeout值 Timeout 30
6. UseCanonicalName on
打開UseCanonicalName是Web服務器的標准做法。這是因為客戶發送的大部分請求都是對本服務器的引用,打開該項設置就能使用 ServerName和Port選項的設置內容構建完整的URL。如果將這個參數設置為Off,那么Apache將使用從客戶請求中獲得服務器名字和端口值,重新構建URL。
7. 取消符號連接 Options FollowSymLinks
FollowSymLinks允許使用符號連接,這將使用瀏覽器有可能訪問文檔根目錄(DocumentRoot)之外的內容,並且只有符號連接的目的與符號連接本身為同一用戶所擁有時(SymLinksOwnerMatch),才允許訪問,這個設置將增加一些安全性,但將耗費Apache大量的資源。
4. php調優
1) 使用APC模塊(緩存opcodes)
安裝APC模塊
tar -zxvf APC-3.0.19.tar.gz
cd APC-3.0.19
/opt/php/bin/phpize
./configure
make
make install
APC模塊配置參數:
apc.enabled=1
apc.shm_segmemnts = 1
apc.shm_size = 64
APC把數據緩存到內存里面,我們就有必要對內存資源進行限定,通過這二個配置可以限定APC可以使用的內存空間大小。
apc.shm_segments指定了使用共享內存塊數,而apc.shm_size則指定了一塊共享內存空間大小,單位是M。所以,允許APC使用的內存大小應該是 apc.shm_segments * apc.shm_size = 64M。
apc.num_files_hint = 1000
apc.user_entries_hint = 4096
這二配置指定apc可以有多少個緩存條目。apc.num_files_hint說明你估計可能會有多少個文件相應的opcodes需要被緩成,即大約可以有多少個apc_compiler_cache條目。另外apc.user_entries_hint則說明你估計可能會有多少個apc_userdata_cache條目需要被緩存。如果項目中不使用apc_store()緩存用戶數據的話,該值可以設定得更小。也就是說apc.num_files_hint與apc.user_entries_hint之和決定了APC允許最大緩存對象條目的數量。准確地設置這二個值可以得到最佳查詢性能.
apc.stat =1
apc.stat_ctime
這二個參數,只跟apc_compiler_cache緩存相關,並不影響apc_user_cache。apc_complier_cache,它緩存的對象是php源文件一一對應的opcodes(目標文件)。PHP源文件存放在磁盤設備上,與之相對應的Opcodes目標文件位置內存空間(共享內存),那么當php源文件被修改以后,怎么通知更新內存空間的opcodes呢?每次接收到請求后,APC都會去檢查打開的php源文件的最后修改時間,如果文件的最后修改時間與相應的內存空間緩存對象記錄的最后修改時間不一致的話,APC則會認為存放在內存空間的Opcode目標文件(緩存對象)已經過期了,acp會將緩存對象清除並且保存新解析得到的Opcode。我們關心的是,即便沒有更新任何php源文件,每次接受到http請求后,APC都會請求系統內核調用stat()來獲取php源文件最后修改時。我們可以通過將apc.stat設置為0,要求APC不去檢查Opcodes相對應的php源文件是否更新了。這樣可以獲得最佳的性能,我們也推薦這么做。不過,這樣做有一點不好的就是,一旦有PHP源文件更新了之后,需要重啟httpd守護進程或者調用apc_cache_clear()函數清空APC緩存來保證php源文件與緩存在內存空間的Opcodes相一致。
apc.ttl =0
apc.user_ttl =0
apc.ttl作用於apc_compiler_cache。當apc.ttl大於0時,每次請求都會對比這次的請求時間與上一次請求時間之差是不是大於apc.ttl,如果大於apc.ttl,則會被認緩存條目過期了,會被清理。
推薦如果項目較為穩定,並且apc.stat設置為0。同時apc.shm_size、apc.num_files_hint設置合理的話,apc.ttl建議設置為0。即apc_compiler_cache永不回收,直到重啟httpd守護進程或者調用函數apc_cache_clear()清緩存。至於apc.user_ttl,建議設置為0,由開發人員調用apc_store()函數的時候,設置$ttl來指定該緩存對象的生命周期。
apc.max_file_size = 1M
apc.filters = NULL
apc.cache_by_default=1
這三個配置放在一起,是因為他們都用於限制緩存。其中apc.max_file_size表示如果php源文件超過了1M,則與之對應的opcodes不被緩存。而apc.filters指定一個文件過濾列表,以逗號(,)隔開。當apc.cache_by_default等於1時,與apc.filters列表中指定的文件名相匹配的文件不會被緩存。相反,apc.cache_by_default等於0時,僅緩存與acp.filters列表中指定的文件相匹配的文件。
2)使用xhprof模塊(性能分析工具)
xhprof安裝:
wget http://pecl.php.net/get/xhprof-0.9.2.tgz
tar zxf xhprof-0.9.2.tgz
cd xhprof-0.9.2
cp -r xhprof_html xhprof_lib /www/www.hx.com/xhprof/
cd extension/
/opt/php/bin/phpize
./configure –with-php-config=/opt/php/bin/php-config
make
make install
在php.ini中添加:
extension=xhprof.so
xhprof.output_dir=/opt/xhprof
xhprof的調用,在index.php中添加如下代碼:
if ($config->php->xhprof && mt_rand(1, 10000) == 1) {
xhprof_enable();
$xhprof_on = true;
}
if($config->php->xhprof && $xhprof_on){
$xhprof_data = xhprof_disable();
$xhprof_root = '/opt/xhprof'
include_once $xhprof_root."xhprof_lib/utils/xhprof_lib.php";
include_once $xhprof_root."xhprof_lib/utils/xhprof_runs.php";
$xhprof_runs = new XHProfRuns_Default();
$run_id = $xhprof_runs->save_run($xhprof_data, "hx");
echo '<a href="http://www.test.com/xhprof_html/index.php?run='.$run_id.'&source=hx" target="_blank">統計信息</a>';
}
運行程序,底部出現統計信息字樣,點過去就可以看到性能分析了。按運行時間排序,很容易找出化時間最長的函數。
Calls% |
IWall% |
EWall% |
||||
165 |
0.6% |
93,442 |
47.1% |
93,442 |
47.1% |
|
32 |
0.1% |
10,417 |
5.2% |
10,417 |
5.2% |
|
165 |
0.6% |
117,153 |
59.0% |
8,816 |
4.4% |
|
10 |
0.0% |
6,275 |
3.2% |
6,275 |
3.2% |
|
631 |
2.2% |
2,692 |
1.4% |
2,692 |
1.4% |
表格中一些參數的解釋:
- Function_Name : 函數名
- Calls : 調用次數
- Calls % : 調用百分比
- Incl.Wall Time : 調用包含子函數所有花費時間 以微妙計算
- Excl. Wall time : 函數執行本身所花費的時間, 不包括子函數執行時間.
5. mysql調優
加快mysql服務器的運行速度的方法,按照效率從低到高的依次為:
1. 替換有問題的硬件
2. 對mysql進程的設置進行調優
3. 對查詢進行優化
1) 記錄慢查詢
在一個 SQL 服務器中,數據表都是保存在磁盤上的。索引為服務器提供了一種在表中查找特定數據行的方法,而不用搜索整個表。當必須要搜索整個表時,就稱為表掃描。通常來說,您可能只希望獲得表中數據的一個子集,因此全表掃描會浪費大量的磁盤 I/O,因此也就會浪費大量時間。當必須對數據進行連接時,這個問題就更加復雜了,因為必須要對連接兩端的多行數據進行比較。
配置mysqld將這些慢查詢記錄到指定的慢查詢日志中,通過查看慢查詢日志可以定位到可能有問題的sql語句.啟用慢查詢日志需在my.cnf文件中添加如下設置.
[mysqld] ; enable the slow query log, default 10 seconds log-slow-queries=/opt/mysql/logs/mysql-slow.log ; log queries taking longer than 2 seconds long_query_time = 2 ; log queries that don't use indexes even if they take less than long_query_time ; MySQL 4.1 and newer only log-queries-not-using-indexes |
這3個設置一起使用,可以記錄執行時間超過2秒和沒有使用索引的查詢. 慢查詢日志會存放在 /opt/mysql/logs/mysql-slow.log.
閱讀慢查詢日志使用mysqldumpslow的命令進行。指定日志文件的路徑,就可以看到一個慢查詢排序后的列表,並且顯示它們在日志中出現的次數.一個非常有用的特性是mysqldumpslow在比較結果之前,會刪除任何用戶指定的數據,因此對同一個查詢的不同調用被記為一次,這樣可以找出工作量最多的查詢.
/opt/mysql/bin/mysqldumpslow -s c -t 20 mysql-slow.log //慢查詢中訪問次數最多的20條sql
/opt/mysql/bin/mysqldumpslow -s r -t 20 mysql-slow.log //返回記錄結果集最多的20條sql |
-s. 是order的排序,分別按照query的次數,時間,lock時間和返回的記錄數來排序.
-t , 是top n 的意思,就是返回 前面多少條數據。
顯示結果如下:
Count: 1147605 Time=0.01s (7931s) Lock=0.00s (107s) Rows=0.0 (984), wcontact[wcontact]@[172.16.236.115]
select Fuid, Fcompany_id from relation_company where Ftime >= N and Ftime <= N order by Fuid limit N,N
Count: 108878 Time=0.03s (2792s) Lock=0.00s (5s) Rows=1.0 (108878), wcontact[wcontact]@2hosts
SELECT COUNT(*) FROM msg_index WHERE Fobj_uid=N AND Funread=N AND Fdel=N
Count: 23142 Time=0.04s (1012s) Lock=0.00s (1s) Rows=15.7 (363685), wcontact[wcontact]@[172.16.236.115]
select Fcompany_id, count(*) num from relation_company where Ftime > N and Ftime <= N group by Fcompany_id limit N,N
............ |
對相應的sql語句進行優化:
例如
SELECT COUNT(*) FROM msg_index WHERE Fobj_uid=N AND Funread=N AND Fdel=N |
表結構:
CREATE TABLE `msg_index` ( `Fid` int(11) NOT NULL AUTO_INCREMENT COMMENT '短消息編號', `Fmsg_id` int(11) NOT NULL DEFAULT '0' COMMENT '消息ID', `Fuid` bigint(20) NOT NULL DEFAULT '0' COMMENT '發送者UID', `Fobj_uid` bigint(20) NOT NULL DEFAULT '0' COMMENT '接收者UID', `Ftype` tinyint(3) NOT NULL DEFAULT '0' COMMENT '0發送 1接收', `Funread` tinyint(3) NOT NULL DEFAULT '0' COMMENT '新短消息', `Ftime` bigint(20) NOT NULL DEFAULT '0' COMMENT '發送時間', `Fdel` tinyint(3) NOT NULL DEFAULT '0' COMMENT '刪除狀態', PRIMARY KEY (`Fid`), KEY `ft` (`Fuid`,`Fobj_uid`), KEY `taf` (`Ftime`,`Ftype`) ) ENGINE=MyISAM AUTO_INCREMENT=163376 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC |
通過explain查看索引使用情況
mysql> explain SELECT COUNT(*) FROM msg_index WHERE Fobj_uid=12 AND Funread=1 AND Fdel=0;
+----+-------------+-----------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | msg_index | ALL | NULL | NULL | NULL | NULL | 3775 | Using where | +----+-------------+-----------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec)
|
可以看到該sql語句未用到索引,導致了全表掃描. 故因將聯合索引 `ft`,拆分成2個索引.
alter table msg_index drop index `ft`; alter table msg_index add index `Fuid`(`Fuid`); alter table msg_index add index `Fobj_uid`(`Fobj_uid`); |
2).對mysqld進程參數進行調優
1.對查詢進行緩存
在/opt/mysql/my.cnf添加如下的參數:
###query_cache### query_cache_size = 64M //啟用64M查詢緩存 query_cache_type = 1 query_cache_limit = 2M query_cache_min_res_unit = 4K |
啟用查詢緩存之后,看它是否有效使用:
mysql> show status like 'qcache%'; +-------------------------+----------+ | Variable_name | Value | +-------------------------+----------+ | Qcache_free_blocks | 7321 | | Qcache_free_memory | 33249712 | | Qcache_hits | 17036563 | | Qcache_inserts | 15195159 | | Qcache_lowmem_prunes | 3166865 | | Qcache_not_cached | 370185 | | Qcache_queries_in_cache | 28664 | | Qcache_total_blocks | 64727 | +-------------------------+----------+ 8 rows in set (0.00 sec) |
上表中一些變量的解釋:
Qcache_free_blocks |
緩存中相鄰內存塊的個數。數目大說明可能有碎片。FLUSH QUERY CACHE 會對緩存中的碎片進行整理,從而得到一個空閑塊。 |
Qcache_free_memory |
緩存中的空閑內存。 |
Qcache_hits |
每次查詢在緩存中命中時就增大。 |
Qcache_inserts |
每次插入一個查詢時就增大。命中次數除以插入次數就是不中比率;用 1 減去這個值就是命中率。在上面這個例子中,大約有 87% 的查詢都在緩存中命中。 |
Qcache_lowmem_prunes |
緩存出現內存不足並且必須要進行清理以便為更多查詢提供空間的次數。這個數字最好長時間來看;如果這個數字在不斷增長,就表示可能碎片非常嚴重,或者內存很少。(上面的free_blocks 和 free_memory 可以告訴您屬於哪種情況)。 |
Qcache_not_cached |
不適合進行緩存的查詢的數量,通常是由於這些查詢不是 SELECT 語句。 |
Qcache_queries_in_cache |
當前緩存的查詢(和響應)的數量。 |
Qcache_total_blocks |
緩存中塊的數量。 |
間隔幾秒顯示這些變量就可以看出區別,這可以幫助確定緩存是否正在有效地使用。
2.強制限制
可以在mysqld中強制來確保系統負載不會導致系統資源耗盡.
max_connections = 800 wait_timeout = 15 max_connect_errors = 200 |
max_connections 是設置連接最大數,確保只建立服務器允許數目的連接.確定目前建立的最大連接數,可以執行show status like 'max_used_connections'.
mysql> show status like 'max_used_connections'; +----------------------+-------+ | Variable_name | Value | +----------------------+-------+ | Max_used_connections | 26 | +----------------------+-------+ 1 row in set (0.00 sec)
|
第 2 行告訴 mysqld 終止所有空閑時間超過 15 秒的連接。在 LAMP 應用程序中,連接數據庫的時間通常就是 Web 服務器處理請求所花費的時間。有時候,如果負載過重,連接會掛起,並且會占用連接表空間。如果有多個交互用戶或使用了到數據庫的持久連接,那么將這個值設低一點並不可取!
最后一行是一個安全的方法。如果一個主機在連接到服務器時有問題,並重試很多次后放棄,那么這個主機就會被鎖定,直到 FLUSH HOSTS 之后才能運行。默認情況下,10 次失敗就足以導致鎖定了。將這個值修改為 100 會給服務器足夠的時間來從問題中恢復。如果重試 100 次都無法建立連接,那么使用再高的值也不會有太多幫助,可能它根本就無法連接。
3.表緩存.
數據庫中每個表都可以表示為磁盤上的一個文件,必須先打開,后讀取。為了加快從文件中讀取數據,mysqld會對這些打開的文件進行緩存。其最大數目的是由/opt/mysql/my.cnf中的table_cache指定.
###表緩存 table_cache= 1024 |
顯示打開表的活動情況:
mysql> show status like 'open%tables';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Open_tables | 287 |
| Opened_tables | 12 |
+---------------+-------+
2 rows in set (0.00 sec)
上述說明: 目前有287表是打開的,有12個表是需要打開的,因為緩存中已經沒有可用的文件描述符了。 如果Opened_tables隨着運行show status命令而快速增加時,說明緩存的命中率不夠.如果Opened_tables比table_cache設置小很多,就說明該值太大.
4. 線程的緩存
所說線程緩存,就是mysqld早接收連接時會根據需要生成線程.在一個連接變化很快的繁忙服務器上,對線程進行緩存有助於可以加快最初的連接.
顯示線程使用的統計信息:
mysql> show status like 'threads%';
+-------------------+---------+
| Variable_name | Value |
+-------------------+---------+
| Threads_cached | 0 |
| Threads_connected | 68 |
| Threads_created | 1359226 |
| Threads_running | 1 |
+-------------------+---------+
上述中最重要的時 Threads_created值,每次mysqld需要創建一個新線程時,這個值都會增加。如果這個值隨着show status命令而快速增加,就應該嘗試增大線程緩存.
###線程緩存
Thread_cache 16
5.關鍵字緩存區(myisam)
關鍵字緩存區是保存myisam表的索引塊.在聯想情況下,對於這些塊的請求應該來自於內存,而非磁盤.如何確定有多少塊是從磁盤讀取,有多少塊是從內存讀取的.
mysql> show status like 'key_read%';
+-------------------+------------+
| Variable_name | Value |
+-------------------+------------+
| Key_read_requests | 2367514011 |
| Key_reads | 652489 |
+-------------------+------------+
2 rows in set (0.00 sec)
Key_reads代表命中磁盤的請求次數,key_read_requests是總數.命中磁盤的次數占總數的 652489 /2367514011 = 0.0002756.大約在1000個請求中有0.3次不會命中內存.如果該值(0.3)超過1時,就應該考慮
增大關鍵字緩存區.key_buffer = 2G會將緩存區設置為2G.
###MyISAM引擎參數###
key_buffer_size=2G
key_cache_block_size=1024
read_buffer_size=32M
read_rnd_buffer_size=32M
myisam_sort_buffer_size=2M
6.臨時表的使用
臨時表可以在高級查詢中使用, 其中數據在進一步進行處理(group by )之前, 都必須先保存在臨時表中.理想情況下,在內存中創建臨時表,如果臨時表變的太大,就需要寫入磁盤中.
mysql> show status like 'created_tmp%';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 0 |
| Created_tmp_files | 746 |
| Created_tmp_tables | 0 |
+-------------------------+-------+
3 rows in set (0.00 sec)
每次使用臨時表都會增大 Created_tmp_tables;基於磁盤的表也會增大 Created_tmp_disk_tables。對於這個比率,並沒有什么嚴格的規則,因為這依賴於所涉及的查詢。長時間觀察 Created_tmp_disk_tables 會顯示所創建的磁盤表的比率,您可以確定設置的效率。 tmp_table_size 和 max_heap_table_size 都可以控制臨時表的最大大小,因此請確保在 my.cnf 中對這兩個值都進行了設置。
優化查詢語句時候,要避免使用臨時表,如果避免不了的話,一定要保證臨時表存在內存中。如果你有很多group by語句,並且有很多內存的話,那就增大tmp_table_size和max_heap_table_size的值.
一般遵循的的公式:
Created_tmp_disk_tables/Created_tmp_tables<5%。
7.排序緩存區
當mysql進行排序時,就會在磁盤上讀取數據時分配一個緩存區來存放這些數據行.如果要排序的數據太大,那么數據就要存放在磁盤上的臨時文件中,並再次進行排序。如果sort_merge_passes狀態量很大,這就指示磁盤的活動情況.
mysql> SHOW STATUS LIKE "sort%";
+-------------------+---------+
| Variable_name | Value |
+-------------------+---------+
| Sort_merge_passes | 1 |
| Sort_range | 79192 |
| Sort_rows | 2066532 |
| Sort_scan | 44006 |
+-------------------+---------+
4 rows in set (0.00 sec)
如果sort_merge_passes很大.就表示要注意sort_buffer_size。 sort_buffer_size=16M將排序緩存區設置為16M.
###排序緩存區
sort_buffer_size=16M
8.innodb參數
1) innodb_buffer_pool_size
對於innodb表來說,innodb_buffer_pool_size的作用就相當於key_buffer_size相對於myisam一樣.innodb使用該參數指定大小的內存來緩沖數據和索引.對於單獨的mysql數據庫服務器,最大可以把該值設置成物理內存的80%。
2)innodb_additional_mem_pool_size
該參數指定Innodb用來存儲數據字典和其他內部數據結構的內存池大小。缺省值為1M。對於 2G內存的服務器推薦值為 20M.
3)innodb_log_buffer_size
推薦值為8M。
4)innodb_log_file_size
推薦值是 innodb_buffer_pool_size的25%.
5) innodb_flush_log_at_trx_commit
該值指定innodb記錄日志的方式.如果設置為1,則每個事務提交的時候,mysql都會將事務日志寫入磁盤.如果設置為0或2,則每秒將日志寫入磁盤一次.
6) innodb_file_per_table
將該值設置為1時,則innodb表將使用獨立的表空間.
###Innodb引擎參數###
innodb_buffer_pool_size = 4G
innodb_additional_mem_pool_size = 20M
innodb_log_file_size = 256M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 100
innodb_open_files=800
innodb_file_per_table = 1
innodb_commit_concurrency = 4
3)使用mysqlreport調優性能
下載 :http://hackmysql.com/scripts/mysqlreport-3.5.tgz
解壓 tar zxf mysqlreport-3.5.tgz
./mysqlreport -user test -password test -port 3306
Can't locate DBI.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at ./mysqlreport line 24.
BEGIN failed--compilation aborted at ./mysqlreport line 24.
解決該錯誤 : sudo yum install perl-DBI perl-DBD-MySQL -y
使用mysqlreport
[fanlinlin@WRM_DB01 mysqlreport-3.5]$ perl mysqlreport --host=127.0.0.1 --user=test --password=test
__ Key _________________________________________________________________
Buffer used 295.49M of 24.00G %Used: 1.20
Current 4.78G %Usage: 19.91
Write hit 65.12%
Read hit 99.97%
__ Questions ___________________________________________________________
Total 45.03M 19.2/s
DMS 22.87M 9.7/s %Total: 50.79
QC Hits 17.39M 7.4/s 38.63
Com_ 3.53M 1.5/s 7.85
COM_QUIT 1.41M 0.6/s 3.13
-Unknown 178.89k 0.1/s 0.40
Slow 2 s 2.93M 1.3/s 6.52 %DMS: 12.83 Log: ON
DMS 22.87M 9.7/s 50.79
SELECT 15.89M 6.8/s 35.28 69.48
INSERT 3.80M 1.6/s 8.44 16.63
UPDATE 1.41M 0.6/s 3.14 6.18
REPLACE 938.06k 0.4/s 2.08 4.10
DELETE 827.92k 0.4/s 1.84 3.62
Com_ 3.53M 1.5/s 7.85
set_option 2.03M 0.9/s 4.50
change_db 1.01M 0.4/s 2.25
show_status 366.23k 0.2/s 0.81
__ SELECT and Sort _____________________________________________________
Scan 2.51M 1.1/s %SELECT: 15.81
Range 3.98M 1.7/s 25.05
Full join 14.74k 0.0/s 0.09
Range check 0 0/s 0.00
Full rng join 0 0/s 0.00
Sort scan 1.68M 0.7/s
Sort range 251.33k 0.1/s
Sort mrg pass 371 0.0/s
__ Query Cache _________________________________________________________
Memory usage 35.67M of 64.00M %Used: 55.73
Block Fragmnt 9.92%
Hits 17.39M 7.4/s
Inserts 15.49M 6.6/s
Insrt:Prune 4.81:1 5.2/s
Hit:Insert 1.12:1
__ Table Locks _________________________________________________________
Waited 3.36k 0.0/s %Total: 0.01
Immediate 24.70M 10.5/s
__ Tables ______________________________________________________________
Open 287 of 1024 %Cache: 28.03
Opened 893 0.0/s
__ Connections _________________________________________________________
Max used 26 of 800 %Max: 3.25
Total 1.41M 0.6/s
__ Created Temp ________________________________________________________
Disk table 3.57k 0.0/s
Table 927.74k 0.4/s Size: 16.0M
File 748 0.0/s
__ Threads _____________________________________________________________
Running 3 of 7
Cached 13 of 16 %Hit: 100
Created 32 0.0/s
Slow 0 0/s
__ Aborted _____________________________________________________________
Clients 34 0.0/s
Connects 333 0.0/s
__ Bytes _______________________________________________________________
Sent 18.91G 8.1k/s
Received 9.19G 3.9k/s
__ InnoDB Buffer Pool __________________________________________________
Usage 1.00M of 4.00G %Used: 0.02
Read hit 92.17%
Pages
Free 262.08k %Total: 99.98
Data 64 0.02 %Drty: 0.00
Misc 0 0.00
Latched 0.00
Reads 166 0.0/s
From file 13 0.0/s 7.83
Ahead Rnd 1 0.0/s
Ahead Sql 0 0/s
Writes 0 0/s
Flushes 0 0/s
Wait Free 0 0/s
__ InnoDB Lock _________________________________________________________
Waits 0 0/s
Current 0
Time acquiring
Total 0 ms
Average 0 ms
Max 0 ms
__ InnoDB Data, Pages, Rows ____________________________________________
Data
Reads 26 0.0/s
Writes 3 0.0/s
fsync 3 0.0/s
Pending
Reads 0
Writes 0
fsync 0
Pages
Created 0 0/s
Read 64 0.0/s
Written 0 0/s
Rows
Deleted 0 0/s
Inserted 0 0/s
Read 0 0/s
Updated 0 0/s
6. apache ab 壓力測試
/opt/apache/bin/ab -c 1000 -n 1000 http://fix.weirenmai.dragon-stone.cn/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking fix.weirenmai.dragon-stone.cn (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software: Apache/2.4.3
Server Hostname: fix.weirenmai.dragon-stone.cn
Server Port: 80
Document Path: /
Document Length: 0 bytes
Concurrency Level: 1000 //並發數
Time taken for tests: 19.280 seconds //整個測試持續的時間
Complete requests: 1000 //完成的請求數
Failed requests: 0 //失敗的數量
Write errors: 0
Non-2xx responses: 1000
Total transferred: 669559 bytes // 整個傳輸量
HTML transferred: 0 bytes
//相當於 LR 中的每秒事務數,后面括號中的 mean 表示這是一個平均值
Requests per second: 51.87 [#/sec] (mean)
// 相當於 LR 中的平均事務響應時間,后面括號中的 mean 表示這是一個平均值
Time per request: 19279.633 [ms] (mean)
Time per request: 19.280 [ms] (mean, across all concurrent requests)
//平均每秒網絡上的流量,可以幫助排除是否存在網絡流量過大導致響應時間延長的問題
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1699 3354.9 0 13403
Processing: 60 2356 2019.0 1918 15280
Waiting: 60 2354 2019.4 1918 15280
Total: 61 4055 4334.0 2584 19277
Percentage of the requests served within a certain time (ms)
50% 2584
66% 4267
75% 5154
80% 5807
90% 9886
95% 16438
98% 18259
99% 18298
100% 19277 (longest request)
整個場景中所有的用戶請求的響應狀況,每個請求都有一個響應時間,其中50%的用戶響應的時間小於2584ms,66%的用戶響應時間小於4267,最大的響應時間為19277ms
優化后測試的結果:
[fanlinlin@web ~]$ /opt/apache/bin/ab -c 1000 -n 1000 http://fix.weirenmai.dragon-stone.cn/ This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking fix.weirenmai.dragon-stone.cn (be patient) Completed 100 requests Completed 200 requests Completed 300 requests Completed 400 requests Completed 500 requests Completed 600 requests Completed 700 requests Completed 800 requests Completed 900 requests Completed 1000 requests Finished 1000 requests
Server Software: Apache/2.4.3 Server Hostname: fix.weirenmai.dragon-stone.cn Server Port: 80
Document Path: / Document Length: 0 bytes
Concurrency Level: 1000 Time taken for tests: 11.070 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Non-2xx responses: 1000 Total transferred: 637429 bytes HTML transferred: 0 bytes Requests per second: 90.33 [#/sec] (mean) Time per request: 11070.237 [ms] (mean) Time per request: 11.070 [ms] (mean, across all concurrent requests) Transfer rate: 56.23 [Kbytes/sec] received
Connection Times (ms) min mean[+/-sd] median max Connect: 0 745 1929.5 0 9012 Processing: 529 2289 1451.9 1818 9833 Waiting: 529 2287 1451.8 1818 9833 Total: 544 3033 2312.3 2333 10987
Percentage of the requests served within a certain time (ms) 50% 2333 66% 3002 75% 3811 80% 4183 90% 6512 95% 8925 98% 10694 99% 10809 100% 10987 (longest request) |
根據測試結果進行對比 :
對於1000的並發數,總耗時從19.280s下降到11.070s
優化前:
Requests per second: 51.87 [#/sec] (mean)
Time per request: 19279.633 [ms] (mean)
Time per request: 19.280 [ms] (mean, across all concurrent requests)
Transfer rate: 33.91 [Kbytes/sec] received
優化后:
Requests per second: 90.33 [#/sec] (mean) Time per request: 11070.237 [ms] (mean) Time per request: 11.070 [ms] (mean, across all concurrent requests) Transfer rate: 56.23 [Kbytes/sec] received |
最能反應服務器性能的時 Request per second,即每秒完成的請求數從51.87提升到90.33。
每個請求花費的時間從19.280ms下降到11.070ms.
每秒的網絡流流量從33.91Kbytes提示到56.23Kbytes.