近一段時間一直在做全省高一階段的綜合素質評價系統的運維,短時間內用戶幷發很高操作很多流量也比較大,在維護過程中一直跌跌撞撞遇到很多問題,目前已經告一段落。問題很多,收穫也很多,我想有必要系統的總結一下。
整體系統狀況如下: 主要功能是全省高中學生的網上素質評價,大約40w用戶,每個班內學生需要互評,以每個班60人計算,最大的互評表規模60*40w=2400w的規模。評價時間需要在15天完成,評價採用開放式,部份在學校機房集中填報,有條件也可在家自由填報,學生評價之後的修改沒有限制,個班老師需要網上對所有評價進行審核確認。
系統開發環境php+oracle,在前端採用一台千兆負載均衡設備,後端採用6臺nginx/php-cgi節點(建立在3臺服務器上的虛擬機),1臺NFS文件服務器共享web目錄和session目錄,1臺oracle10g數據庫。
難點問題:
1、系統互動性很強,php應用負載幷發的問題(虽然启用了memcache,但是用户大量的脚本数据操作很频繁)
2、數據庫的性能問題,sql幷發很高(应用功能决定了在大量insert、update的同时也有大量的select)
3、文件系統的性能問題(从某种方式来讲,文件系统的并发性能会比数据库低)
運行這一段時間來的web流量視圖,峰值流出帶寬200Mb/s。
web日誌統計視圖,日均PV700多萬。
在運維期間遇到了很多問題,很多都是細節問題平時沒有注意,在流量放大之後都暴露得很明顯,微小的問題都導致系統當機。
一一小結如下:
1。首先遇到的就是session.auto_start的問題。
<value name=”request_slowlog_timeout”>10s</value>
<value name=”slowlog”>logs/slow.log</value>
如上, 在php-fpm中我們配置了slowlog來紀錄相應比較慢的腳本,開始紀錄的是大量的腳本提示session_start()。我們在php.ini中配置的session以文件形式保存,而且保存在一個nfs server上,這樣來保證所有nginx/php-cgi節點的session一致性,考慮到session量會很大,是以兩級目錄來存放的。
session.save_path = “2;/data/session_tmp”
由於php腳本開發不嚴謹,session變量的調用比較亂,所以生成了大量的空字節的session文件,一個小時之內新建的session文件達到了20w以上,我們關閉了session.auto_start=0之後,空字節session減少,session保持在2.7w以內,當然這也促使開發人員更嚴謹的使用session。
2。nfs和文件系統的效率問題
因為session是集中在nfs上存放,那麼6臺web節點對nfs頻繁的文件調用就出現了瓶頸,nfs server的io一直居高不下,這是在nfs上iostat -x採集的信息:
基本上io await很高,io工作佔用了所有時間。在運行前期,nfs高負載運行一段時間就會down,造成所有節點停止響應。
我們對nfs的做了一些處理:
a、增加nfs線程數到32,這是一般手段
b、修改nfs中session目錄所在分區文件系統屬性,關閉ext3的日誌功能,在/etc/fstab中修改默認為data=writeback,減少磁盤日誌對性能的損傷。畢竟session的安全要求沒那麼高,屬於短期效果的臨時文件而已。
c、修改/etc/exports中的session目錄nfs屬性為async
/data/session_tmp xx.xx.xx.0/255.255.255.0(rw,async,anonuid=99,anongid=99)
經過測試表現,對於很多小文件的nfs用戶幷發操作來講,async的性能要比sync好很多很多。async相對而言沒有sync的文件一致性保護,但是對於session文件來講,都是獨立操作的,用戶不可能同時共享session文件操作,對於我們這樣的session共享方式來講,async比較適合,修改之後可以看到io效果改善非常好。
當然也可以考慮在客戶端通過udp來mount session目錄,畢竟在局域網udp是優於tcp模式的,不過這只需要在客戶端mount的時候設置下即可。
3。oracle的效率問題
這次oracle運行在一台四路六核32G內存的服務器上,配置比較高性能也不錯,我們設置的processes/session和分別是1000/1105。
在初期遇到的問題是CPU佔用過大,裏面等待的非常多,但是相對來講io和oracle進程卻不飽滿,分析日誌和ASH報告,發現大量的資源都在做線程的建立和關閉,就對php/oci的鏈接方式做了一些修改,在php的數據操作類中全部改為pconnect保持鏈接的方式,web節點和oracle建立的鏈接不會在php-cgi執行完畢之後馬上釋放然後重新再次鏈接,而一直保持,減少oracle不斷的打開和關閉線程,這樣對於高幷發時的效果改善非常明顯。
每台服务器启动的php-cgi进程是150个,6台服务器一共有900个php-cgi进程,这也是我们设置oracle processes=1000的原因,在采用pconnect的方式连接数据库时,oracle连接一般极少释放,当访问量较高的时候,php-cgi节点会很快的按照php-cgi进程数启动与oracle的连接进程,然后保持,在使用pconnect方式的时候,一定要注意把php-cgi总进程数限制在processes以内。
因為sql操作很頻繁,統計中重複的sql集中在不多的一些操作中,開發人員對於這些sql操作進行了修改,在php中綁定變量方式來操作,很有效的減少了sql分析佔用cpu時間的問題,效率提高也很明顯。
4。其他的一些小問題。
在php-fpm.log中曾發現flock()預警,然後查看腳本發現,開發人員操作一個計數的文本文件,每次操作的時候都是用flock()來鎖定,但是讀取也使用flock鎖定,而且每次使用之後並沒有fclose釋放,這可能是開發人員很隨意的一種習慣。
NFS服務器在高強度運行一段時間之後,在client端會有某臺節點產生一些message,提示rpc的報警,php-cgi調用nfs文件變得異常緩慢,但是在nfs server端沒有預警而且文件操作也一樣正常,google了一下可能是由於內核版本的bug問題,將內核升級到2.6.22后仍然在繼續觀察,貌似沒有這類錯誤。
還有幾點想法:
效率問題從大的方面來講是構架問題,採用什麽樣的負載模式,資源搭配,應用劃分,這些可能從技術方面關注的人更多,但是這比較容易找到規律和範例。而目前在運維這類系統更多的問題是在應用和系統層面的一些小細節,這些小細節往往會帶來致命的故障,這些細節是很難有範例的,從某種層面來講這應該是一種經驗吧。
日志是非常重要的一种运维基础元素,任何系统应用在不严重影响效率的前提下,都应该采用一定的设置保存日志、分析日志,通过日志来发现问题、解决问题。日志一种必须的运维习惯。
一些非技術部門的人員多有一些很有意思的說法,當系統出現down機之後要求運維人員保持關注時刻注意重啟服務器,這是一種電器使用思路,讓人哭笑不得,不定位和解決故障所在而妄圖通過reload的方式來滿足短時間的需求,這是一種極不可取的運維思路。所以,很多問題出現之後可能得到臨時性恢復,但是作為技術人員必須追尋起根源所在,以求徹底決絕問題。
我還是喜歡這樣比較有挑戰的系統部署和運維,比較有挑戰性的東西可以提神也可醒腦。不過,開發和系統脫節太多,也是造成目前運維效率低反應時間慢的一個原因。
遇到类似的问题,谢谢博主,好久不见你的blog更新,呵呵
一些小问题:
session如果写去memcached会不会更好?
session.save_handler = memcache
session.save_path = “tcp://127.0.0.1:11211”
总对nfs有偏见,或者是不会优化,nfs的读写频繁时io队列很大
非常感謝你的建議,memcached用來保存session肯定比nfs效率要高很多,不存在IO問題了,在最近的一個高負載系統上應用下。