好的系統(tǒng)有各自的好,傻逼的系統(tǒng)有一樣的傻逼行為:性能差!
系統(tǒng)非功能性指標(biāo)有林林總總,除了我們說的可用性之外,性能好是最直觀的,和用戶抱怨最多的一項(xiàng)。
2015年的時(shí)候,只有總共十幾個(gè)開發(fā)人員,兩個(gè)已經(jīng)要累死的測試,按照訂單總量計(jì)算,只有300萬,但是系統(tǒng)已經(jīng)不堪重負(fù)。
這個(gè)系統(tǒng)是一個(gè)業(yè)務(wù)操作系統(tǒng)。用戶可以手工的,或者表格導(dǎo)入的形式,或者接口導(dǎo)入的形式創(chuàng)建訂單。而在我加入以后不久,又增加了通過接口導(dǎo)出創(chuàng)建訂單后的自動(dòng)分配功能。當(dāng)時(shí)的主要功能點(diǎn)在于,對于任何一個(gè)訂單,生命周期是貫穿不同的操作步驟的,而每一步的操作,帶來的是基于狀態(tài)機(jī)的狀態(tài)變更。這聽起來就像是一個(gè)工作流系統(tǒng)。而,自動(dòng)分配功能就是根據(jù)計(jì)算邏輯,做自動(dòng)的狀態(tài)轉(zhuǎn)換的過程。
聽起來很美,不過,正是這種功能,讓我們吃了巨大的苦頭……
系統(tǒng)性能調(diào)優(yōu)的切入點(diǎn)是慢查詢,GC頻率。然后……你知道,會(huì)有一些效果。比如,有慢查詢,就調(diào)索引,GC過高,就調(diào)堆內(nèi)存比例,大小。之后的幾次系統(tǒng)不穩(wěn)定情況下,初始的調(diào)優(yōu)思路也是如此。
然而,回頭看下來,這種頭疼醫(yī)頭,腳疼醫(yī)腳的方式是讓一切變壞的起點(diǎn)。
文化的不同導(dǎo)致后期中外團(tuán)隊(duì)有各種爭論和不配合。拋開這些,有很多來自其他團(tuán)隊(duì)的觀點(diǎn)是正確的。比如在設(shè)計(jì)上,應(yīng)該保持無索引設(shè)計(jì)的思路,而不是依賴于索引做方案。這樣,隨著系統(tǒng)的變大,仍有足夠的調(diào)優(yōu)空間作為緩沖。
回到當(dāng)時(shí)的系統(tǒng)狀態(tài)。早期外包開發(fā),導(dǎo)致框架選擇上偏向快速開發(fā)工具。最典型的是使用基于GWT的展示端,以及脫離native SQL的hibernate。這些工具在早期發(fā)揮了巨大作用,但是同樣包裝過度導(dǎo)致有額外的資源消耗。比如,hibernate,對象關(guān)聯(lián)導(dǎo)致級(jí)聯(lián)查詢過多,而且開發(fā)人員很容易出現(xiàn)錯(cuò)用的情況。
這個(gè)時(shí)候是第一個(gè)系統(tǒng)架構(gòu)升級(jí)的時(shí)間節(jié)點(diǎn),而當(dāng)時(shí)的融資狀況是A輪。快速增長和架構(gòu)升級(jí)是需要小心翼翼的進(jìn)行?;厮莓?dāng)時(shí)的技術(shù)決策:
數(shù)據(jù)庫調(diào)優(yōu),優(yōu)化慢查詢,但是同時(shí)做了一個(gè)非常錯(cuò)誤的決定:合并表以減少join。這個(gè)決定是災(zāi)難性的,導(dǎo)致后期數(shù)據(jù)庫性能急劇下降。
拆分手機(jī)端調(diào)用的后臺(tái)服務(wù)。這個(gè)決定現(xiàn)在看來,也是不成功的。但是邁出了拆分服務(wù)的第一步。從一個(gè)巨大的單體應(yīng)用,包含WEB端,主業(yè)務(wù)邏輯,和手機(jī)調(diào)用API等所有資源請求主體,變成了手機(jī)調(diào)用校驗(yàn)邏輯,這部分查詢最頻繁的部分,擁有了自己的數(shù)據(jù)庫。從而,減少了主數(shù)據(jù)庫的連接壓力。但是,因?yàn)橹黧w業(yè)務(wù)邏輯仍然保留在主服務(wù)上,導(dǎo)致最終數(shù)據(jù)落盤仍在主庫上,并沒有實(shí)質(zhì)性的拆分完成。
此外,對于訂單匹配計(jì)算邏輯,內(nèi)存加載消耗,CPU消耗,以及數(shù)據(jù)庫查詢消耗都非常大的情況下,做了緩存化處理。雖然,仍然是利用推資源的方式去解決問題,但是這部分的決定被認(rèn)為是正確的。
系統(tǒng)暫時(shí)穩(wěn)住了,然而,下一波很快就來了……