摘要:指標(biāo)虛擬內(nèi)存已使用的大小,如果大于,表示你的機(jī)器物理內(nèi)存不足了每秒從磁盤讀入虛擬內(nèi)存的大小,如果這個(gè)值大于,表示物理內(nèi)存不夠用或者內(nèi)存泄露了,要查找耗內(nèi)存進(jìn)程解決掉。每秒虛擬內(nèi)存寫入磁盤的大小,如果這個(gè)值大于,同上,單位為。
原理剖析(第 013 篇)應(yīng)用系統(tǒng)性能調(diào)優(yōu)
-
一、大致介紹1. 本人接手的一個(gè)打車系統(tǒng),因?yàn)槌霈F(xiàn)了一次響應(yīng)十分緩慢的情況,因此才有了應(yīng)用調(diào)優(yōu)的篇章; 2、由于過(guò)程中可能沒(méi)有闡述的太清楚,如想詳細(xì)了解可以留言之類的,希望其中的點(diǎn)點(diǎn)滴滴對(duì)大家有所幫助;二、調(diào)優(yōu)背景
在某一個(gè)月黑風(fēng)高的夜晚,21點(diǎn)多以后,許許多多的小伙伴都相繼下班了,然后大家開(kāi)始習(xí)慣性的掏出自己心愛(ài)的手機(jī), 點(diǎn)擊了公司的打車應(yīng)用App,大概在 21:00 ~ 21:30 期間還風(fēng)平浪靜的,但是就在 21:30 ~ 21:40 的樣子,突然打車應(yīng)用App 響應(yīng)非常緩慢,App頁(yè)面上的菊花一直轉(zhuǎn)個(gè)不停,直到App請(qǐng)求超時(shí)菊花才消失, 然后用戶還是不停的點(diǎn)擊App,因?yàn)檫@個(gè)時(shí)候 小伙伴們都急著回家,都相繼不停的請(qǐng)求下單,獲取詳情等頁(yè)面操作,體驗(yàn)非常不友好; 因?yàn)槌霈F(xiàn)了這么一次情況,雖然沒(méi)有給用戶沒(méi)有給公司帶來(lái)什么損失,但是該現(xiàn)象從側(cè)面已經(jīng)反應(yīng)出了系統(tǒng)某些方面的 問(wèn)題,或許系統(tǒng)參數(shù)需要優(yōu)化一番,或許系統(tǒng)設(shè)計(jì)交互需要優(yōu)化一番,或許等等等的可能,才有了后續(xù)系統(tǒng)調(diào)優(yōu)的歷程。三、計(jì)劃分析
1、流程相關(guān)分析優(yōu)化:看看哪些流程可以同步轉(zhuǎn)異步處理,App哪些請(qǐng)求可以合并起來(lái),Server哪些業(yè)務(wù)場(chǎng)景需要補(bǔ)償機(jī)制等。 2、數(shù)據(jù)庫(kù)相關(guān)分析優(yōu)化:哪些Sql耗時(shí)較長(zhǎng),哪些方法可以去除事務(wù)且去除事務(wù)后的帶來(lái)的問(wèn)題場(chǎng)景分析,數(shù)據(jù)庫(kù)連接池參數(shù) 是否合理,數(shù)據(jù)庫(kù)本身相關(guān)參數(shù)的閾值情況的一些綜合考慮; 3、內(nèi)存使用情況分析優(yōu)化:新老年代內(nèi)存使用率及回收情況,CPU使用率,磁盤使用率,swap區(qū)使用情況, 線程dump,堆dump。 4、JVM參數(shù)分析調(diào)優(yōu):YGC的平均耗時(shí),YGC的平均間隔,F(xiàn)GC的平均耗時(shí),F(xiàn)GC的平均間隔等等,根據(jù)具體情況反映具體問(wèn)題; 5、TCP/Tomcat參數(shù)分析調(diào)優(yōu):這個(gè)得根據(jù)實(shí)際壓測(cè)情況來(lái)相應(yīng)評(píng)估是否需要調(diào)整;四、Linux命令相關(guān)查看指標(biāo) 4.1 CPU 指標(biāo)
1、 vmstat n m 每n秒采集一次,一共采集m次,r:表示運(yùn)行隊(duì)列,r值一般負(fù)載超過(guò)了3就比較高,超過(guò)了5就高,超過(guò)了10就不正常了; bi和bo一般都要接近0,不然就是IO過(guò)于頻繁 ) [root@svr01]$ vmstat 1 3 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 206944 633564 29876 1252176 0 0 10 27 0 0 1 1 98 0 0 0 0 206944 634232 29876 1252192 0 0 0 0 811 1504 1 1 98 0 0 0 0 206944 634480 29876 1252264 0 0 0 0 951 1458 6 1 93 0 0 2、 uptime 最近1分鐘,5分鐘,15分鐘的系統(tǒng)平均負(fù)載, <=3 則系統(tǒng)性能較好。 <=4 則系統(tǒng)性能可以,可以接收。 >5 則系統(tǒng)性能負(fù)載過(guò)重,可能會(huì)發(fā)生嚴(yán)重的問(wèn)題,那么就需要擴(kuò)容了,要么增加核 [root@svr01]$ uptime 21:27:44 up 207 days, 11:15, 1 user, load average: 26.45, 16.76, 7.50 3、 top 主要看us和sy,其中us<=70,sy<=35,us+sy<=70說(shuō)明狀態(tài)良好, 同時(shí)可以結(jié)合idle值來(lái)看,如果id<=70 則表示IO的壓力較大。4.2 Memory 指標(biāo)
1、 vmstat swpd:虛擬內(nèi)存已使用的大小,如果大于0,表示你的機(jī)器物理內(nèi)存不足了 每秒從磁盤讀入虛擬內(nèi)存的大小,如果這個(gè)值大于0,表示物理內(nèi)存不夠用或者內(nèi)存泄露了,要查找耗內(nèi)存進(jìn)程解決掉。 so:每秒虛擬內(nèi)存寫入磁盤的大小,如果這個(gè)值大于0,同上,單位為KB。 [root@svr01]$ vmstat 1 3 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 206944 633564 29876 1252176 0 0 10 27 0 0 1 1 98 0 0 0 0 206944 634232 29876 1252192 0 0 0 0 811 1504 1 1 98 0 0 0 0 206944 634480 29876 1252264 0 0 0 0 951 1458 6 1 93 0 04.3 Disk 指標(biāo)
1、 df Use%:已使用占比,Use% <= 90% 表示還勉強(qiáng)接受正常 [root@svr01]$ df Filesystem 1K-blocks Used Available Use% Mounted on /dev/mapper/VolGroup00-LVroot 17737040 4286920 12542448 26% / tmpfs 1893300 0 1893300 0% /dev/shm /dev/sda1 194241 127341 56660 70% /boot /dev/mapper/VolGroup00-LVhome 487652 2348 459704 1% /home /dev/mapper/VolGroup00-LVcloud 3030800 260440 2613076 10% /opt/cloud /dev/mapper/VolGroup00-LVtmp 8125880 18724 7687728 1% /tmp /dev/mapper/VolGroup00-LVvar 25671996 848996 23512280 4% /var /dev/mapper/VolGroup1-LVdata1 41149760 33707952 5344864 87% /wls/applogs4.4 Disk IO 指標(biāo)
1、 sar -d 1 1 查看磁盤報(bào)告 1 1 表示間隔1s,運(yùn)行1次 如果svctm的值與await很接近,表示幾乎沒(méi)有I/O等待,磁盤性能很好,如果await的值遠(yuǎn)高于svctm的值, 則表示I/O隊(duì)列等待太長(zhǎng),系統(tǒng)上運(yùn)行的應(yīng)用程序?qū)⒆兟? 如果%util接近100%,表示磁盤產(chǎn)生的I/O請(qǐng)求太多,I/O系統(tǒng)已經(jīng)滿負(fù)荷的在工作,該磁盤請(qǐng)求飽和,可能存在瓶頸。 idle小于70% I/O壓力就較大了,也就是有較多的I/O。 [root@svr01]$ sar -d 1 1 Linux 2.6.32-642.6.2.el6.x86_64 (SHB-L0044551) 07/20/2018 _x86_64_ (1 CPU) 03:00:23 PM DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util 03:00:24 PM dev252-0 23.00 808.00 80.00 38.61 9.88 375.35 43.48 100.00 03:00:24 PM dev252-16 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 03:00:24 PM dev253-0 4.00 448.00 0.00 112.00 1.11 222.00 249.50 99.80 03:00:24 PM dev253-1 50.00 400.00 0.00 8.00 24.40 523.20 20.00 100.00 03:00:24 PM dev253-2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 03:00:24 PM dev253-3 3.00 32.00 0.00 10.67 0.99 242.33 331.67 99.50 03:00:24 PM dev253-4 0.00 0.00 0.00 0.00 1.61 0.00 0.00 100.00 03:00:24 PM dev253-5 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 03:00:24 PM dev253-6 3.00 0.00 24.00 8.00 1.30 393.67 261.33 78.40 Average: DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util Average: dev252-0 23.00 808.00 80.00 38.61 9.88 375.35 43.48 100.00 Average: dev252-16 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 Average: dev253-0 4.00 448.00 0.00 112.00 1.11 222.00 249.50 99.80 Average: dev253-1 50.00 400.00 0.00 8.00 24.40 523.20 20.00 100.00 Average: dev253-2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 Average: dev253-3 3.00 32.00 0.00 10.67 0.99 242.33 331.67 99.50 Average: dev253-4 0.00 0.00 0.00 0.00 1.61 0.00 0.00 100.00 Average: dev253-5 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 Average: dev253-6 3.00 0.00 24.00 8.00 1.30 393.67 261.33 78.404.5 Network IO 指標(biāo)
1、 netstat -nat |awk "{print $6}"|sort|uniq -c|sort -rn 在不考慮系統(tǒng)負(fù)載、CPU、內(nèi)存等情況下,netstat監(jiān)控大量ESTABLISHED連接與Time_Wait連接 [root@svr01]$ netstat -nat |awk "{print $6}"|sort|uniq -c|sort -rn 265 TIME_WAIT 45 ESTABLISHED 38 CLOSE_WAIT 18 LISTEN 8 FIN_WAIT2 2 SYN_SENT 1 Foreign 1 established)五、一些關(guān)于統(tǒng)計(jì)的量化指標(biāo)
注意:有些命令通用,有些是我根據(jù)系統(tǒng)的日志文件格式利用awk/sed兩個(gè)命令結(jié)合寫出來(lái)的。 1、netstat -nat |awk "{print $6}"|sort|uniq -c|sort -rn ( 查看TCP連接狀態(tài) ) 2、netstat -n|grep TIME_WAIT|awk "{print $5}"|sort|uniq -c|sort -rn|head -n20( 查找較多time_wait連接 ) 3、netstat -anlp|grep tcp |awk "{print $5}" |awk -F":" "{print $1}" |uniq -c |sort -nr | head -n3( 查出訪問(wèn)靠前的IP地址 ) 4、cat hmilyylimh_sql.log | awk "{print $6}" | awk -F"ms" "{print $1}" | awk -F"=" "{print $2 | "sort -r -n" }" | head -n5( 查詢sql文件中耗時(shí)最高的前5個(gè)耗時(shí)數(shù)據(jù)值 ) 5、cat hmilyylimh_supp.log | awk "{print $10}" | awk -F"timeConsuming=" "{print $2 }" | awk -F"ms" "{print $1 | "sort -r -n" }" | head -n5( 查看supp文件中耗時(shí)最高的前5個(gè)耗時(shí)數(shù)據(jù)值 ) 6、cat hmilyylimh_sql.log | grep "sql:=" | awk "{print $5}" | uniq -c | sort -rn | head -n2( 查詢sql文件總共打印了多少條SQL日志 ) 7、cat hmilyylimh_sql.log | grep "NormalTimeConsuming" | awk "{print $5}" | uniq -c | sort -rn | head -n2( 查看sql文件成功執(zhí)行了多少條SQL日志 ) 8、cat hmilyylimh_sql.log | grep "BadTimeConsuming" | awk "{print $5}" | uniq -c | sort -rn | head -n2( 查看sql文件失敗或者異常執(zhí)行了多少條SQL日志 ) 9、cat hmilyylimh_supp.log | grep "sendReqSupp start"| awk "{print $6$7$8}" | uniq -c | sort -nr | head -n2( 查詢supp文件sendReqSupp start字符串出現(xiàn)的次數(shù) ) 10、lsof -n | awk "{print $1,$2}" | sort | uniq -c | sort -nr | head -n10( 統(tǒng)計(jì)持有各個(gè)進(jìn)程持有句柄數(shù)最高的10個(gè) ) 11、lsof -n | awk "{print $1,$2}" | sort | uniq -c | sort -nr | awk "{ sum+=$1 };END { print sum } "( 計(jì)算所有進(jìn)程持有句柄數(shù)的總和,ulimit -n命令查看最大句柄數(shù) ) 12、lsof | awk "NF == 9 { print $0}" | sort +6 -7nr | head -n10( 查看系統(tǒng)打開(kāi)的大文件列表 ) 13、top -b -n 1 | grep -E "Cpu(s)|Mem|Swap"( 一次性查出系統(tǒng)當(dāng)前的CPU、內(nèi)存、交換區(qū)的情況 ) 14、iostat -p sda | awk -F"Device" "{ print $1 }"( 查看cpu的統(tǒng)計(jì)信息(平均值) ) 15、cat access_log.`date +%Y%m%d`.txt | awk "{print $6}" | uniq -c | sort -k2 -r | head -n10( 統(tǒng)計(jì)每秒請(qǐng)求并發(fā),按照時(shí)間降序排列 ) 16、cat access_log.`date +%Y%m%d`.txt | awk "{print $6}" | uniq -c | sort -rn | head -n10( 統(tǒng)計(jì)每秒并發(fā),按照并發(fā)量降序排列 ) 17、cat access_log.`date +%Y%m%d`.txt | awk "{ sum+=$NF }; END { print sum*2/8/1024/1024, "M" }"( 查看訪問(wèn)hmilyylimh服務(wù)器每天的總流量 ) 18、cat gc.log | tail -n20|awk "{print $4}"| awk -F"->" "{print $1, $2, $3 }"| awk -F"(" "{print $1, $2, $3}" | awk -F")" "{print $1}" | awk -F"K" "{print $1/$3*100, "% used -> " ,$2/$3*100, "% used " , 100-$2/$3*100, "% free ", $3/1024, "M total --- 新生代" }"( 查看gc指標(biāo),新生代最后n條記錄的新生代內(nèi)存變化率 ) 19、cat gc.log | tail -n20 | awk "{print $7}" | awk -F"->" "{print $1, $2, $3 }" | awk -F"(" "{print $1, $2, $3}" | awk -F")" "{print $1}" | awk -F"K" "{print $1/$3*100, "% used -> " ,$2/$3*100, "% used " , 100-$2/$3*100, "% free ", $3/1024, "M total --- 堆內(nèi)存" }"( 查看最后10條GC日志的堆內(nèi)存已使用轉(zhuǎn)化率 ) 20、cat /etc/sysctl.conf | grep "tcp_"( 查看TCP參數(shù)設(shè)置信息 ) 21、cat hmilyylimh.log | awk "{if($2>"15:17:00.236") print $0}" | grep "max_user_connections" | wc -l( 查看具體時(shí)間點(diǎn)后某個(gè)字符串出現(xiàn)的次數(shù) )六、系統(tǒng)常用計(jì)數(shù)器命令
1、echo "<<<<<<<<<<<<<< 線程阻塞等待計(jì)數(shù): "`less hmilyylimh_error.log | grep "with callerRunsPolicy" | wc -l`", ""db事務(wù)嵌套鎖AcquireLock計(jì)數(shù): "`less hmilyylimh_error.log | grep "CannotAcquireLockException" | wc -l`", ""創(chuàng)建事務(wù)異常計(jì)數(shù): "`less hmilyylimh_error.log | grep "CannotCreateTransactionException" | wc -l`", ""db連接池溢出計(jì)數(shù): "`less hmilyylimh_error.log | grep "more than "max_user_connections"" | wc -l`", ""Pool Empty計(jì)數(shù): "`less hmilyylimh_error.log | grep "Unable to fetch a connection" | wc -l`" >>>>>>>>>>>>>>" 2、echo "<<<<<<<<<<<<<< UnknownHostException計(jì)數(shù): "`less hmilyylimh_error.log | grep "UnknownHostException" | wc -l`", ""ConnectionPoolTimeout計(jì)數(shù): "`less hmilyylimh_error.log | grep "ConnectionPoolTimeout" | wc -l`", ""ConnectException計(jì)數(shù): "`less hmilyylimh_error.log | grep "ConnectException" | wc -l`", ""ConnectTimeoutException計(jì)數(shù): "`less hmilyylimh_error.log | grep "ConnectTimeoutException" | wc -l`", ""SocketTimeoutException計(jì)數(shù): "`less hmilyylimh_error.log | grep "SocketTimeoutException" | wc -l`", ""OtherException計(jì)數(shù): "`less hmilyylimh_error.log | grep "OtherException" | wc -l`" >>>>>>>>>>>>>>" 3、echo "<<<<<<<<<<<<<< Sql耗時(shí)最高的前5個(gè)數(shù)值: "`cat hmilyylimh_sql.log | awk "{print $6}" | awk -F"ms" "{print $1}" | awk -F"=" "{print $2 | "sort -r -n" }" | head -n5`", ""Supp耗時(shí)最高等待前5個(gè)數(shù)值: "`cat hmilyylimh_supp.log | awk "{print $10}" | awk -F"timeConsuming=" "{print $2 }" | awk -F"ms" "{print $1 | "sort -r -n" }" | head -n5`" >>>>>>>>>>>>>>" 4、echo "<<<<<<<<<<<<<< Http請(qǐng)求耗時(shí)最高前10個(gè)數(shù)值: "`less hmilyylimh.log | grep "timeConsuming=" | awk "{print $9}" | awk -F"=" "{print $2}" | awk -F"ms" "{print $1 | "sort -r -n" }" | head -n10`" >>>>>>>>>>>>>>"七、流程相關(guān)分析優(yōu)化
1. 通過(guò) access_log.txt 日志分析,在特定時(shí)間段內(nèi),將請(qǐng)求至系統(tǒng)的 url 分組計(jì)數(shù),最后會(huì)出一個(gè)根據(jù)url調(diào)用次數(shù)的排序; 2、針對(duì)請(qǐng)求次數(shù)數(shù)一數(shù)二的url接口,在分析完業(yè)務(wù)場(chǎng)景后,決定將高頻率的接口優(yōu)化成同步轉(zhuǎn)異步; 3、然而想查看Server端每個(gè)Http請(qǐng)求的耗時(shí)時(shí)間,卻發(fā)現(xiàn)沒(méi)有相關(guān)功能點(diǎn)統(tǒng)計(jì),于是乎又新增切面Aspect來(lái)統(tǒng)計(jì)Client請(qǐng)求至 Server的耗時(shí)統(tǒng)計(jì)日志,然后通過(guò) less,grep,awk 命令來(lái)分析耗時(shí)最高的url請(qǐng)求,后續(xù)可做成監(jiān)控及時(shí)發(fā)現(xiàn)長(zhǎng)耗時(shí)請(qǐng)求; 4、同樣發(fā)現(xiàn)請(qǐng)求下游系統(tǒng)也沒(méi)有相關(guān)耗時(shí)統(tǒng)計(jì),因此依葫蘆畫瓢再次新增請(qǐng)求下游系統(tǒng)切面來(lái)統(tǒng)計(jì)耗時(shí)情況; 5、在后續(xù)的壓測(cè)過(guò)程中,效果顯著,單臺(tái)服務(wù)器的TPS提升了3倍,而且在壓測(cè)過(guò)程不斷打出線程dump, 堆dump日志,然后 重點(diǎn)將 hmilyylimh_20180716-143726.threads 放到網(wǎng)頁(yè)中分析,結(jié)果發(fā)現(xiàn)一個(gè)比較嚴(yán)重的問(wèn)題,Log4J 1.x blocked 問(wèn)題,總計(jì)大概有90多個(gè)線程在等待同一把鎖。于是乎將應(yīng)用的 log4j 1.x 版本升級(jí)至 log4j 2.x 版本。但是呢,官方 明確說(shuō)明:Log4j 2.4 and greater requires Java 7, versions 2.0-alpha1 to 2.3 required Java 6。因此我們就只好 采用了2.3版本。 6、后面還考慮了將請(qǐng)求下游系統(tǒng)的日志做成了異步打印,效果更佳; 7、通過(guò)和前端溝通,將一些請(qǐng)求進(jìn)行了進(jìn)行了聚合處理返回給前端,在某種程度上友好的提升了交互體驗(yàn); 8、針對(duì)支付場(chǎng)景的支付狀態(tài)同步新增了補(bǔ)償機(jī)制,后臺(tái)主動(dòng)查詢下游系統(tǒng)訂單的支付狀態(tài),最大力度的保證用戶看到的支付 狀態(tài)是準(zhǔn)實(shí)時(shí)的; 9、針對(duì)Http的工具類,根據(jù)業(yè)務(wù)的實(shí)際情況定制一套超時(shí)參數(shù),盡量減少Http連接長(zhǎng)時(shí)間被Hold住不釋放,必要時(shí)Http請(qǐng)求 工具類做相應(yīng)的嘗試次數(shù)控制; 10、最后的壓測(cè)也比較簡(jiǎn)單,通過(guò)寫程序操控狀態(tài)扭轉(zhuǎn),將整個(gè)打車流程走完,程序只需要傳入人數(shù)來(lái)壓測(cè)系統(tǒng)最高負(fù)荷; 經(jīng)過(guò)后續(xù)壓測(cè)顯示,日志鎖顯然不存在了,最后一次統(tǒng)計(jì)的數(shù)據(jù)得知TPS相比最初提升了至少5倍以上,由此可見(jiàn)流程的優(yōu)化 和日志的優(yōu)化對(duì)于系統(tǒng)的性能提升有很大的幫助;八、數(shù)據(jù)庫(kù)相關(guān)分析優(yōu)化
1、通過(guò)收集產(chǎn)線出問(wèn)題時(shí)刻的數(shù)據(jù)庫(kù)指標(biāo)( max_used_connections/max_user_connections/max_connections ),除了這三個(gè) 參數(shù)意外,還收集了數(shù)據(jù)庫(kù)連接超時(shí)時(shí)間,出問(wèn)題時(shí)刻數(shù)據(jù)庫(kù)實(shí)例前后幾個(gè)小時(shí)的時(shí)序分析圖; 2、在測(cè)試環(huán)境壓測(cè)情況下,而后臺(tái)應(yīng)用的連接池的參數(shù)配置為: 嘗試步驟一: (max_connections=160, max_user_connections=80, 兩臺(tái)1核2G的服務(wù)器) tomcat.initialSize=25 tomcat.validationInterval=25000 tomcat.maxActive=85 tomcat.minIdle=25 tomcat.maxIdle=25 結(jié)論:系統(tǒng)部署重啟后直接啟動(dòng)不起來(lái),報(bào)的什么錯(cuò)已經(jīng)忘記了,然后繼續(xù)調(diào)整連接池參數(shù); 嘗試步驟二: (max_connections=160, max_user_connections=80, 兩臺(tái)1核2G的服務(wù)器) tomcat.initialSize=12 tomcat.validationInterval=25000 tomcat.maxActive=85 tomcat.minIdle=12 tomcat.maxIdle=12 結(jié)論:系統(tǒng)能正常啟動(dòng),相對(duì)于步驟一來(lái)說(shuō),連接池的合理配置非常重要,但是在壓測(cè)情況下發(fā)生了一些異常; --- Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: User hmily already has more than "max_user_connections" active connections,于是乎繼續(xù)后續(xù)步驟; 嘗試步驟三: (max_connections=160, max_user_connections=80, 兩臺(tái)1核2G的服務(wù)器) tomcat.initialSize=12 tomcat.validationInterval=25000 tomcat.maxActive=80 tomcat.minIdle=12 tomcat.maxIdle=12 結(jié)論:相對(duì)于步驟二來(lái)說(shuō),異常還是有一些,數(shù)據(jù)庫(kù)的 160 剛剛等于 tomcat.maxActive * 2 = 160, 但是又引發(fā)了另外一個(gè)異常: Cause: org.apache.tomcat.jdbc.pool.PoolExhaustedException: [http-nio-0.0.0.0-40009-exec-91] Timeout: Pool empty. Unable to fetch a connection in 5 seconds, none available[size:40; busy:3; idle:37; lastwait:5000]; 于是乎繼續(xù)后續(xù)步驟; 嘗試步驟四: (max_connections=160, max_user_connections=80, 兩臺(tái)1核2G的服務(wù)器) tomcat.initialSize=12 tomcat.validationInterval=25000 tomcat.maxActive=80 tomcat.minIdle=12 tomcat.maxIdle=12 結(jié)論:相對(duì)于步驟二來(lái)說(shuō),異常還是有一些,數(shù)據(jù)庫(kù)的 160 剛剛等于 tomcat.maxActive * 2 = 160, 但是還是會(huì)引發(fā)了另外一個(gè)異常: Cause: org.apache.tomcat.jdbc.pool.PoolExhaustedException: [http-nio-0.0.0.0-40009-exec-91] Timeout: Pool empty. Unable to fetch a connection in 5 seconds, none available[size:40; busy:3; idle:37; lastwait:5000]; 于是乎繼續(xù)后續(xù)步驟; 在這一步,我們無(wú)法計(jì)算每個(gè)SQL的耗時(shí)情況,于是集成了SqlMapClientTemplate類,在SqlMapClientTemplate的擴(kuò)展類 中針對(duì)queryForObject、queryForList、update、delete主流的方法進(jìn)行了before/after/finally增強(qiáng)處理打印SQL耗時(shí); 嘗試步驟五: (max_connections=160, max_user_connections=80, 兩臺(tái)1核2G的服務(wù)器) tomcat.initialSize=12 tomcat.validationInterval=25000 tomcat.maxActive=40 tomcat.minIdle=12 tomcat.maxIdle=12 結(jié)論:在步驟四中,通過(guò)將maxActive改回40, 且對(duì)耗時(shí)的SQL進(jìn)行優(yōu)化處理,同時(shí)對(duì)一些不常變化的SQL配置進(jìn)行了緩存 處理,這樣一來(lái)在壓測(cè)高并發(fā)的情況下,所有情況全部有所好轉(zhuǎn),一切正常自如; 但是我遠(yuǎn)不滿足于此,然后我又開(kāi)始調(diào)整連接池參數(shù)配置; 嘗試步驟六: (max_connections=320, max_user_connections=160, 兩臺(tái)1核2G的服務(wù)器) tomcat.initialSize=12 tomcat.validationInterval=25000 tomcat.maxActive=80 tomcat.minIdle=12 tomcat.maxIdle=12 結(jié)論:之前出現(xiàn)的異常也沒(méi)有了,于是我綜合以上我的各種嘗試,實(shí)際測(cè)試總結(jié)了一些關(guān)于個(gè)人理解的參數(shù)配置; 3、小結(jié): 對(duì)于連接池這塊,想必大家也同樣都是從網(wǎng)上摘抄下來(lái)的配置,雖然調(diào)整后的配置不一定是最佳的,但是對(duì)整個(gè)應(yīng)用沒(méi)有 起到副作用的話,那就是對(duì)應(yīng)用最適合的配置。而且大家在配置的時(shí)候,還得綜合考慮服務(wù)器水平擴(kuò)展后對(duì)數(shù)據(jù)庫(kù)的一個(gè)壓力 情況,調(diào)整的時(shí)候一定要參照數(shù)據(jù)庫(kù)實(shí)例的參數(shù)配置來(lái)綜合考慮衡量應(yīng)用的參數(shù)配置。 #初始化連接: 連接池啟動(dòng)時(shí)創(chuàng)建的初始化連接數(shù)量 tomcat.initialSize=12 -- 原因:線程快照?qǐng)D最小連接數(shù)為22,目前由于業(yè)務(wù)量大,僅僅只是2臺(tái)服務(wù)器,考慮到后續(xù)的業(yè)務(wù)還會(huì)繼續(xù)擴(kuò)大, 因?yàn)樵搮?shù)不適宜調(diào)整的太高,根據(jù)實(shí)際情況最后調(diào)整為12。 #避免過(guò)度驗(yàn)證,保證驗(yàn)證不超過(guò)這個(gè)頻率——以毫秒為單位 tomcat.validationInterval=25000 -- 原因:數(shù)據(jù)庫(kù)的連接超時(shí)時(shí)間是29秒,我們盡可能小于數(shù)據(jù)庫(kù)的連接超時(shí)時(shí)間 #最大活動(dòng)連接: 連接池在同一時(shí)間能夠分配的最大活動(dòng)連接的數(shù)量,如果設(shè)置為非正數(shù)則表示不限制 tomcat.maxActive=50 -- 原因:線程快照?qǐng)D的最大連接數(shù)為82,目前產(chǎn)線只有2臺(tái)服務(wù)器,最大也就是 50 * 2 = 100,還遠(yuǎn)遠(yuǎn)小于 max_user_connections數(shù)值,最初是滴測(cè)試情況調(diào)整的為40,而產(chǎn)線的服務(wù)器性能絕對(duì)比測(cè)試環(huán)境好,綜合評(píng)估定位50。 #最小空閑連接: 連接池中容許保持空閑狀態(tài)的最小連接數(shù)量, 低于這個(gè)數(shù)量將創(chuàng)建新的連接, 如果設(shè)置為0則不創(chuàng)建.默認(rèn)與initialSize相同 tomcat.minIdle=12 -- 原因:考慮和initialSize調(diào)整為一樣的 #最大空閑連接: 連接池中容許保持空閑狀態(tài)的最大連接數(shù)量, 超過(guò)的空閑連接將被釋放, 如果設(shè)置為負(fù)數(shù)表示不限制 tomcat.maxIdle=12 -- 原因:考慮和minIdle一樣九、內(nèi)存使用情況分析優(yōu)化
1、通過(guò) awk 命令分析gc日志文件,發(fā)現(xiàn)老年代還有較多的空間可以利用,于是就是看看哪些是可以不經(jīng)常變化的配置,盡量 減少數(shù)據(jù)庫(kù)IO的操作,最大程度先去讀取緩存,緩存沒(méi)有再去從數(shù)據(jù)庫(kù)中加載數(shù)據(jù)。 2、在壓測(cè)的過(guò)程中,盡量多一些headDump文件,然后通過(guò) eclipse 工具來(lái)分析看看都有哪些大對(duì)象,也沒(méi)有發(fā)現(xiàn)任何有疑點(diǎn) 的地方,于是反查代碼,在一些定時(shí)任務(wù)需要加載大量數(shù)據(jù)的地方,當(dāng)加載出來(lái)的數(shù)據(jù)用完之后直接手動(dòng)釋放,盡快讓垃圾 回收期回收內(nèi)存。 3、還有一點(diǎn)就是,在一些后臺(tái)定時(shí)輪詢的任務(wù)中,有些任務(wù)需要通過(guò)for循環(huán)來(lái)處理一些任務(wù),這個(gè)時(shí)候我們可以每循環(huán)一次 或者循環(huán)數(shù)次之后通過(guò)調(diào)用Thead.sleep(xxx)休眠一下,一是可以緩沖一下IO高密度的操作,還有就是讓出CPU時(shí)間片, 讓有些緊急的任務(wù)可以優(yōu)先獲取CPU執(zhí)行權(quán)。 4、做完這些后,壓測(cè)后通過(guò)GC日志分析,老年代內(nèi)存相比未優(yōu)化前多了一些,但是性能吞吐率卻大大的得到了提高,磁盤IO 的TPS也在一定程度上降低了。十、JVM參數(shù)分析調(diào)優(yōu)
1、為了應(yīng)對(duì)將來(lái)的高業(yè)務(wù)量,目前需要擴(kuò)容服務(wù)器,將2臺(tái)服務(wù)器擴(kuò)容至4臺(tái)服務(wù)器,然后將服務(wù)器由2核4G升級(jí)成為4核8G。 因此在升級(jí)過(guò)程中對(duì)于參數(shù)的調(diào)整也存在了一定的迷惑期。 2、JVM參數(shù)的調(diào)整測(cè)試過(guò)程一兩句話也說(shuō)不清,這里我就講解一下大致的思路: ? YGC的平均耗時(shí),YGC的平均間隔,可以通過(guò)GC日志完整分析出來(lái),根據(jù)實(shí)際情況是否需要調(diào)整堆大小,年輕代占比,存活區(qū)占比; ? FGC的平均耗時(shí),F(xiàn)GC的平均間隔,同樣可以通過(guò)GC日志完整分析出來(lái),重點(diǎn)關(guān)注FGC耗時(shí),想辦法調(diào)整堆大小,年輕代占比,存活區(qū)占比,垃圾回收器方式; ? S2區(qū)的使用占比,如果S2占比為0,且YGC平均耗時(shí)也在40ms以內(nèi)的話,也沒(méi)有FGC,這也算是相對(duì)比較理想的情況; ? S2區(qū)滿的話,F(xiàn)GC頻繁或者GC效果很差時(shí)建議調(diào)整堆大小,還得不到改善就要開(kāi)發(fā)分析實(shí)際Heap消耗的對(duì)象占比了; 3、最后附上我的4核8G的JVM參數(shù)情況如下: -Xms2048M -Xmx2048M -Xss256k -XX:NewSize=512m -XX:MaxNewSize=512m -XX:SurvivorRatio=22 -XX:PermSize=256m -XX:MaxPermSize=512m -XX:+UseParNewGC -XX:ParallelGCThreads=4 -XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=60 -XX:CMSInitiatingPermOccupancyFraction=70 -XX:+PrintGCApplicationConcurrentTime -XX:+PrintHeapAtGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=logs/oom.log -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -verbose:gc -Xloggc:logs/gc.log -Djava.net.preferIPv4Stack=true 4、GC優(yōu)化的一點(diǎn)建議: ? Minor GC 執(zhí)行非常迅速 ( 建議 50ms 以內(nèi) ) ? Minor GC 沒(méi)有頻繁執(zhí)行 ( 建議大約 10s 執(zhí)行一次 ) ? Full GC 執(zhí)行非常迅速 ( 建議 1000ms 以內(nèi) ) ? Full GC 沒(méi)有頻繁執(zhí)行 ( 建議大約 10min 執(zhí)行一次 )十一、TCP/Tomcat參數(shù)分析調(diào)優(yōu)
1、在測(cè)試壓測(cè)過(guò)程中,由于很大提升系統(tǒng)應(yīng)用的請(qǐng)求并發(fā),因此需要調(diào)整Tomcat中相關(guān)的參數(shù),maxThreads、acceptCount (最大線程數(shù)、最大排隊(duì)數(shù)),也就是說(shuō)需要查看 tomcat的Connector、Executor 所有屬性值,但產(chǎn)線本人并未做相應(yīng)調(diào)整; 2、在壓測(cè)過(guò)程中,發(fā)現(xiàn)大量的TIME-WAIT的情況,于是根據(jù)實(shí)際調(diào)整系統(tǒng)的TCP參數(shù),在高并發(fā)的場(chǎng)景中,TIME-WAIT雖然會(huì)峰 值爬的很高,但是降下來(lái)的時(shí)間也是非常快的,主要是需要快速回收或者重用TCP連接。 3、最后附上我的4核8G的TCP參數(shù)情況如下: vim /etc/sysctl.conf #編輯文件,加入以下內(nèi)容: net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_fin_timeout = 30 #然后執(zhí)行 /sbin/sysctl -p 讓參數(shù)生效。十二、小結(jié)
總而言之,經(jīng)過(guò)這一系列的分析調(diào)優(yōu)下來(lái),對(duì)于系統(tǒng)來(lái)說(shuō),應(yīng)用的系統(tǒng)性能提升相當(dāng)可觀,同時(shí)也在優(yōu)化的過(guò)程中建立起了 一套自己獨(dú)有的思考方式,雖說(shuō)目前優(yōu)化下來(lái)的這套配置并不是最完美的,但是它確實(shí)最適合系統(tǒng)的。 以上這些數(shù)據(jù)值僅供參考,如果大家有更好的方式或者更優(yōu)雅的調(diào)優(yōu)方式,也歡迎大家一起來(lái)多多討論。十三、下載地址
https://gitee.com/ylimhhmily/SpringCloudTutorial.git
SpringCloudTutorial交流QQ群: 235322432
SpringCloudTutorial交流微信群: 微信溝通群二維碼圖片鏈接
歡迎關(guān)注,您的肯定是對(duì)我最大的支持!!!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/77121.html
摘要:本文會(huì)以引出問(wèn)題為主,后面有時(shí)間的話,筆者陸續(xù)會(huì)抽些重要的知識(shí)點(diǎn)進(jìn)行詳細(xì)的剖析與解答。敬請(qǐng)關(guān)注服務(wù)端思維微信公眾號(hào),獲取最新文章。 原文地址:梁桂釗的博客博客地址:http://blog.720ui.com 這里,筆者結(jié)合自己過(guò)往的面試經(jīng)驗(yàn),整理了一些核心的知識(shí)清單,幫助讀者更好地回顧與復(fù)習(xí) Java 服務(wù)端核心技術(shù)。本文會(huì)以引出問(wèn)題為主,后面有時(shí)間的話,筆者陸續(xù)會(huì)抽些重要的知識(shí)點(diǎn)進(jìn)...
摘要:理解內(nèi)存模型對(duì)多線程編程無(wú)疑是有好處的。干貨高級(jí)動(dòng)畫高級(jí)動(dòng)畫進(jìn)階,矢量動(dòng)畫。 這是最好的Android相關(guān)原創(chuàng)知識(shí)體系(100+篇) 知識(shí)體系從2016年開(kāi)始構(gòu)建,所有的文章都是圍繞著這個(gè)知識(shí)體系來(lái)寫,目前共收入了100多篇原創(chuàng)文章,其中有一部分未收入的文章在我的新書《Android進(jìn)階之光》中。最重要的是,這個(gè)知識(shí)體系仍舊在成長(zhǎng)中。 Android 下拉刷新庫(kù),這一個(gè)就夠了! 新鮮出...
閱讀 2752·2021-11-16 11:45
閱讀 1660·2021-09-26 10:19
閱讀 2055·2021-09-13 10:28
閱讀 2809·2021-09-08 10:46
閱讀 1537·2021-09-07 10:13
閱讀 1533·2019-08-30 13:50
閱讀 1378·2019-08-30 11:17
閱讀 1460·2019-08-29 13:18