過去
很早以前,做管理系統,對性能體會並不是特別明顯。因為一些用戶非常聰明,會通過調整自己的使用方式來適應系統的處理能力。現在想起來,有環境的原因也有能力的原因,沒有做好性能的事情,覺得有些好笑也有些遺憾。
現在做的程序,對響應速度、處理能力都有一定的要求,而且這些指標直接和效益掛鈎。這個時候,性能問題就隨着系統的運行不斷顯現出來,並在運行過程中左右一項重要任務不斷改進、調優。
性能優化的過程是一種辛苦又有趣的挑戰。
改進總是在事關利害的時候才會有推動力。
來自業務上的簡化
很多時候,自己是一個理想主義者,公司的其他一些也是,所以在系統設計時:總試圖考慮周全,試圖具備很強的擴展性,試圖一勞永逸。事實是,在沒有對業務成竹於胸、對設計沒有深刻立即的時候,很難做到。所以往往過度設計、過度開發。
多做事情,不是好事情,尤其是那些高頻度執行的業務流程上,影響尤其嚴重。多一個環節,都是意味着多消耗計算資源。
很早前,我們做的程序在結算上,要求對交易賬號三方進行資金划撥(一方減少,另外一方增加,第三方佣金增加),要記錄資金變動明細,要有事務保護。這業務,在交易量不大的情況下,沒有問題;小幅度的性能提升也可以通過提升硬件配置來解決。但是對於我們,運營一段時間后,性能真的很難再提升:1、業務邏輯寫得很復雜,改動風險很大,2、所有瓶頸在數據庫上,事務經常失敗
經過很長時間的觀察,我們發現業務並沒有朝預想的方向發展,我們並不需要三方划賬,只需要單方扣款就可以了;我們也發現,資金做好變動日志就可以了,事務也可以不需要。這個業務調整確定下來后,砍掉了這個模塊6成的代碼,單台的服務性能大幅提高。
事后感嘆,真的想多了,業務沒有想的復雜。業務上的簡化,比其他方面的優化,我認為更加有效,也更加樂意去做:
1. 可以刪掉很多無用的東西,維護簡單了,
2. 以前不爽的代碼終於可以丟掉了
部署上的優化
業務總是在上升的,單台服務器,總會有一個上限。這是常理,但在開始做程序的時候,只是想過,並有做預案。那時的想法是先完成業務,再考慮性能(這個策略,仁者見仁,智者見智)。因此解決方法必定是增加硬件。
要增加硬件,首先需要硬件,首先要考慮系統自身的伸縮性問題。對之前開發的大而全的程序來說,首先要做的拆解。將業務流程拆解成多個獨立的環節,每個環節自成一體,獨立運行,環節之間通過網絡通訊。業務流程拆解帶來諸多好處:降低整體的復雜度,學習、開發、維護成本會大大下降。
系統具備一定伸縮性后,就可以調整部署,我的理解是有兩個維度:
1. 不同環節部署到不同的服務器上,分攤壓力
2. 關鍵環節多套部署,增加處理能力
通過部署,基本上能解決性能的問題。在這個過程中,尤其是第二個維度,數據唯一性是一個技術單點。
就現在的情況看,增加硬件的成本,還是遠低於開發、維護的人力成本的,所有這個方式的性能優化,是運維喜歡干的。
來自數據庫上優化
數據庫的優化空間,還是挺大的,主要表現在表索引的合理使用、表字段設計、表關聯查詢、事務。
個人認為:
1、對於性能要求的程序,盡量避免使用事務、和表關聯。
2、好的索引能夠很大程度上提高速度
3、如果數據量大,要考慮表分區
一些編碼的人,對數據庫了解不多,沒有連主鍵、索引的都沒有,也時常發生。所以優化這個,是程序員,尤其懂數據庫的程序員喜歡干的事情。時常聽到一些牛人將一些耗時巨大的數據計算,瞬間提升數百、數千倍。
來自程序實現上優化
一般公司的程序,只是完成某一些業務而且,沒有什么大不了的技術攻關,所有也談不上什么高深的技術。而我們寫的程序,經常會因為各種各樣的原因,多做一些沒用的事情:
1、沒有用的for循環
2、可以在一個循環里面搞定的,做了多個循環
3、一個事情反復做,通常是代碼相互調用(因為計算結果沒有共享或傳遞)
這個事情,程序員會比較喜歡做。程序員每隔一段時間都會回頭看自己的過去,每每發現以前的幼稚表現,都有沖動去修正一下。
來自硬件的提升
換一個性能高一點的設備。想想比較簡單,實際上也是需要有很專業的測試,才知道硬件是否真的合適。
一些小經驗
IIS行嗎
在開發現在這個程序的時候,有人提醒我們IIS容易崩潰,不穩定,性能不行。
在系運行之初,我們的確也是碰到這兩個問題,也懷疑IIS是否真的不行。遇到內存消耗居高不下、線程消耗居高不下、CPU滿負荷,總是間歇性崩潰。
隨着問題的逐步解決,我們發現,其實大部分原因是代碼編寫不當,一小部分是不了解IIS的運行機制。目前系統還能夠持續穩定運行。
內存問題
.Net有垃圾回收機制,但也不能濫用,少New一點也許會好點
.Net的垃圾回收,並不是一個對象釋放了,就馬上會回收的,內存占用高,不代表就是真的消耗了那么多
線程消耗
多線程是解決一些性能問題的良方,但是線程是有成本的,線程太多,CPU會把時間浪費在線切換上
對於IO密集型的,最好采用異步的方式。同步方式意味着一個線程大部分時間消耗在等待上。
對於cpu密集性的,處理升級增加硬件投入,好像沒有辦法。
不要把ThreadPool中的線程耗光了,不然IIS就不響應了:1、asp.net也用這個線程池;2、每秒只會創建2個新線程;
CPU滿負荷
多數情況下,是死循環了
還有就是做了一些多余的事情
MsSql之Nolock
通常,在MSSQL中,有Nolock的提示符,表示允許臟讀,這種情況下,避免使用鎖,非常有效。多數情況下,我們的一些數據並沒有那么嚴格要求,即便是臟讀,也沒有什么關系。
MsSql之with(rowlock)
使用Update語句,一些時候是明確只更新單行的,尤其是狀態轉換的,使用rowlock,會好一些(感覺,沒有測試確認過)。
