宅米网性能优化实践
宅米是一家專注校園電子商務的互聯網企業,目前主營校園超市O2O。公司成立于2014年11月,僅僅一年多的時間,公司即經過4輪融資,覆蓋近200座城市,1000多所大中專院校,10000多棟宿舍樓,日均訂單20萬,峰值訂單50萬。
像所有高速發展的初創互聯網企業一樣,宅米的成長是一部野蠻成長的歷史。公司成立之初,只有三個工程師,是創始人CEO孫高峰在上海交通大學計算機學院和軟件學院挨個宿舍敲門敲出來,他逢人便問:『同學,要不要創業?』。就這樣,三個尚未畢業休學創業的學生開發上線了宅米的第一個版本。
早期,為了迅速開發,技術人員選擇了Ruby作為開發語言。由于業務快速增長,技術人員缺乏經驗,系統甫一上線,即經歷了各種bug,各種系統崩潰。往往在業務最繁忙的時候系統宕機了,公司上下焦頭爛額匆忙應對,工程師每天工作近20個小時,困了就在桌子上趴一會,醒來接著寫代碼,修bug。
但是就是在這樣的跌跌撞撞中,公司業務仍然快速增長,只幾個月的時間就成為該領域中最主要的競爭者,公司順利獲得A輪融資。有錢了,公司便期望在技術研發方面投入更多資源,招聘更多專業技術人才,開發出更完善更穩定的系統迎接下一輪更快速的發展。但是招聘的時候才發現,市面上Ruby工程師非常稀缺,難以招募,技術團隊迅速決定轉型,使用Java作為主要的后端開發語言。于是幾個工程師一邊自己學Java,一邊招Java,不到兩個月的時間,組建了一個20多人的Java技術團隊,完成對原有幾個核心系統的Java重構。
開發人員增加了,可以更加從容開展開發工作,應對新增業務和需求變更,Bug減少了,系統穩定了。但是這時候的系統架構依然是一個非常簡單的Web架構,如圖1。
圖1 最開始的系統架構
這樣的系統能不能應對今后快速的業務發展?性能問題會不會成為持續增長的交易量的瓶頸?系統能不能撐得住訪問高峰期的大規模并發訪問?
性能優化成為這個時候最重要的工作,于是安排專門的工程師進行性能測試和性能優化,從架構、代碼、數據庫、運維各個層面梳理系統狀況,發現系統瓶頸,進行針對性優化。
一、 性能測試
校園零食購物的特點是在晚上10點左右進入高峰,在此前后一小時的交易量大概占整天交易量的一半,也就是說,如果要設計一個日訂單100萬的系統,其實要承受的交易壓力是每小時50萬單。
當初按照二八法則推算峰值每秒單量為556筆『500000 * 0.8 / (60 * 60 * 0.2)』,以此為基準根據Nginx日志分析后端接口調用頻率,推算出接口調用比率前20的請求,以此構造測試場景。
在執行性能測試時,我們使用Jmeter作為性能測試工具,利用了云服務提供的系統資源監控作為基礎,同時抓取應用服務線程快照和MySQL數據庫slow.log分析系統瓶頸。腳本分別如下:
二、架構優化
性能測試結果并不樂觀,我們結合互聯網領域常用技術架構模式以及自身性能瓶頸,進行了架構優化重構。
雖然系統此前使用了分布式緩存對熱點數據進行緩存,但是比較隨意,哪些數據需要緩存,失效策略如何設置都沒有認真分析和設計。性能測試后決定規范緩存使用,盡可能將各種頻繁讀取的數據全部緩存起來,并將Redis服務器做集群和主從復制部署。
此外還使用第三方CDN服務進行靜態文件訪問加速,產品圖片、JavaScript文件、CSS文件等都通過CDN加速,同時通過Nginx反向代理服務器提供靜態文件的前端緩存。
性能測試發現,系統主要瓶頸點在數據庫上,雖然使用Redis將熱點數據緩存起來,但是數據庫依然在并發量達到一定程度后表現出系統過載的情況。于是對數據庫進行主從分離。
優化后的系統架構如圖2。
圖2 優化后的系統架構
三、H5響應壓縮優化
性能測試發現App應用比移動Web端響應速度更快,分析發現H5響應內容因為包含了大量HTML,數據包大小遠遠大于App響應包。因此決定采用Nginx作為反向代理的同時,對HTML內容進行壓縮。
開啟Nginx gzip壓縮的指令如下:
#config gzip;gzip on;gzip_min_length 1k;gzip_buffers 4 16k;gzip_comp_level 2;gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript image/jpeg image/gif image/png application/json;關于gzip_types,我們針對JSON數據也開啟gzip壓縮,降低App響應數據包大小,提高響應性能。圖3是開啟gzip前后的性能測試結果對比:
圖3 H5頁面開啟壓縮前后性能對比
四、SQL語句與索引優化
性能測試過程中發現,由于此前主要精力都在關注如何快速實現業務,大量數據庫查詢語句寫得比較隨意,索引設計非常不合理。
結合性能測試中Mysql數據庫slow.log分析,定位慢查詢SQL追加index,然后利用解釋執行計劃explain優化SQL。在此簡要列舉幾處示例。
(1) 某字段類型為varchar類型,根據查詢關鍵字段查詢時,寫入值為Int類型,導致無法命中索引。
優化前:
select * from aa where aa.bb = 1449220364536130715;
優化后:
select * from aa where aa.bb = '1449220364536130715';
(2) 查詢條件左邊寫入函數,導致無法命中索引。
優化前:
select * from cc where date_format(dd,'%Y-%m-%d')=(DATE_SUB(CURDATE(),INTERVAL 1 DAY));
優化后:
select * from cc where dd=(DATE_SUB(CURDATE(),INTERVAL 1 DAY))
(3) 追加Index時,計算數據唯一性巧妙添加左前綴索引,提高索引命中率,保證索引字段唯一性。
利用如下SQL計算索引命中率:
select count(distinct left(pinyin_initial,3))/count(*) as sel3, count(distinct left(pinyin_initial,4))/count(*) as sel4, count(distinct left(pinyin_initial,5))/count(*) as sel5, count(distinct left(pinyin_initial,6))/count(*) as sel6, count(distinct left(pinyin_initial,7))/count(*) as sel7 from city;以此算出城市拼音縮寫長度為3時,命中率和唯一性比較高,則寫下如下SQL:
ALTER TABLE `city` ADD INDEX `index_on_pinyinInitial` USING BTREE (pinyin_initial(3));五、數據庫連接池優化
數據庫的訪問優化也比較重要,宅米后臺系統開發使用了Mybatis + C3P0組合,在做性能測試的時候發現在某些情況下有較為嚴重的性能問題。在高并發情況下,長時間施加壓力,應用程序出現不能訪問的狀況。
上網查找資料,發現很多人也遇到了C3P0的”APPARENT DEADLOCK”問題。
將C3P0切換成國產數據庫連接池Druid之后,狀況明顯好轉,類似問題再未出現過。
六、緩存使用優化
經過對數據庫和緩存應用的一系列優化后,緩存的命中率保持在90%以上,進一步研究后發現,Redis使用依然有提升的空間。
應用程序訪問Redis的時候,可以通過使用Jedis的pipeline減少redis通信次數,有效提升性能。Jedis是基于socket通信實現的,每次與Redis通信都會消耗相當的網絡連接時間,pipeline則是以打包批量的形式執行命令,圖4是執行5000次set操作的響應時間對比:
圖4 Jedis pipeline性能測試結果
七、訂單數據冷熱分離
隨著業務的持續發展,訂單表的數據會越來越多。按我們現在日訂單量20萬單預估,月訂單量則為600萬單,年訂單量則達到7200萬單,而且日訂單量還在不斷的增加,用不了多久,數據量就會超過MySQL的極限。
一開始我們考慮使用分布式數據庫的方案,對訂單表進行水平切分,使用訂單號進行hash,將訂單數據切分到多張表上。 進一步分析后發現,訂單數據具有明顯的冷熱不均的特點,即剛剛創建的訂單是熱數據,不同應用以各種方式訪問修改這些訂單。經過一段時間以后,特別是訂單完成后,訂單訪問頻率急劇降低,而且只有訂單查詢這一種操作。于是我們考慮采取冷熱數據分離的策略,以控制熱庫中數據總量,保障訂單表數據量始終維持在一個可以接受的范圍內,進而提供穩定的數據訪問性能。訂單數據冷熱分離方案如圖5。
圖5訂單數據冷熱分離
八、系統性能監控
性能測試和性能優化雖然對系統做了充分的改進,但是實際線上性能表現究竟如何,出現緊急性能問題時如何快速應對,還必須要對生產環境進行性能監控。在此簡要列舉一些宅米的性能監控報警要點:
除了系統自身監控,很多系統故障和性能問題會直接反應到業務上。如果系統響應緩慢甚至宕機,那么實時訂單量也會受到影響,因此監控實時交易也可以發現系統問題。圖6是實時交易監控圖,在這里例子中,21:33訂單量突然降到零,雖然系統監控指標正常,但是可以斷定系統必定出了問題,馬上打開應用日志查看,發現有個Bug導致某個外部資源死鎖,立刻手工釋放該資源,系統恢復正常。
圖6實時訂單監控
九、總結
性能問題是實打實的問題,解決辦法也應該針對具體問題各個擊破。通過性能測試了解系統現狀,通過瓶頸分析發現具體問題,針對具體問題尋找解決方案,實現解決方案再進行性能測試,整個性能優化形成閉環,系統得以持續優化。
經過一系列各種性能優化,雖然宅米主要系統性能現階段能夠滿足需求,但是技術永遠要走到業務的前面,才能在業務增長以后從容應對。而初創互聯網公司的野蠻成長速度,永遠也不要猜測,技術必須要做好充分準備,才能不拖業務的后腿,從容應對各種局面。
總結
- 上一篇: 微软督促客户修复本地 Exchange
- 下一篇: python开发区_最新章节测试答案20