Ruby如何成长成高性能系统构架
為什么80%的碼農(nóng)都做不了架構(gòu)師?>>> ??
? 結(jié)束了一份Ruby為主的工作,想把個(gè)方面總結(jié)一下,這篇是關(guān)于系統(tǒng)性能方面的.以下數(shù)據(jù)都是簡(jiǎn)單回憶的數(shù)據(jù),加之企業(yè)保密數(shù)據(jù)的需要,和精確數(shù)有些出入,僅供參考.
? 說起Ruby的性能,無論從官方到社區(qū),都公認(rèn)是劣于其它的框架的.
? 那么問題來了,當(dāng)Ruby為主的系統(tǒng)需要很高的性能的時(shí)候,要如何去處理呢?
? 以下是我優(yōu)化一個(gè)經(jīng)手的系統(tǒng)的經(jīng)過,僅供參考 .
? 項(xiàng)目背景
? 我經(jīng)手的是一個(gè)影票系統(tǒng).原先是java架構(gòu),后因java更新和維護(hù)都無法滿足商務(wù)方面的要求,才使用Ruby來重構(gòu)了核心系統(tǒng),這也是Ruby的一個(gè)重要優(yōu)勢(shì)之一,更新修改很靈活.但這也是這個(gè)項(xiàng)目?jī)?yōu)化時(shí)最困難的約束之一:必須兼容以前的老版本.
? 最早重構(gòu)版本,只是原來java版本API的重新實(shí)現(xiàn),外加一個(gè)很酷的自動(dòng)配價(jià)功能.幾乎沒有性能上要求.
??
? 先說說性能要求的背景,影票系統(tǒng)本身并沒有很多的性能上的要求,畢竟是消費(fèi)型的系統(tǒng),起初高峰的日子也就1w左右的成交量,如果算訪問成交比20:1,也才20w左右的日訪問量.當(dāng)然,這里不包括抓取數(shù)據(jù)的部分.正常這些訪問會(huì)被分配到每天15-20點(diǎn)左右,只要不是太差的系統(tǒng)都能吃下這些流量.
? 直到某天某行開始做整點(diǎn)搶活動(dòng),即在指定的時(shí)間放出大量很廉價(jià)或是免費(fèi)的票.這就是性能問題的開始.
? 這樣業(yè)務(wù)模型會(huì)造成流量的瞬間暴發(fā),系統(tǒng)終于沒有意外的崩潰了.
? 資源文件優(yōu)化
? 我們第一次活動(dòng)最早的表象問題是:系統(tǒng)緩慢,無法進(jìn)入活動(dòng)頁面/進(jìn)入活動(dòng)頁面白屏/支付無法點(diǎn)擊或是支付無結(jié)果.
? 當(dāng)時(shí)統(tǒng)計(jì),活動(dòng)開始時(shí)訪問量大概是2w/分鐘.即每秒要并發(fā)300多個(gè)訪問.這對(duì)純?cè)L問型的系統(tǒng)如新聞網(wǎng)站可能不是很高的數(shù)據(jù),但是對(duì)于一個(gè)復(fù)雜資訊并有資金交易的系統(tǒng)來說,是很致命的.關(guān)鍵和敏感的獎(jiǎng)金交易請(qǐng)求被淹沒在普通的訪問中,這就是上述表象問題的后續(xù)問題:交易訪問被淹沒拋棄.
? 這直接導(dǎo)致大量憤怒的用戶:搶到票無法交易的,支付完了無法出票,出票沒有結(jié)果的.這某種程度認(rèn)為活動(dòng)是失敗的了.這必須馬上被解決.
? 當(dāng)時(shí)解決問題的主要約束是時(shí)間,活動(dòng)是以周為單位的,兩天活動(dòng),5天處理,包括周末.不僅要保證系統(tǒng)正常,還能處理好問題,提高性能,所以花時(shí)間的高大上的解決方案都會(huì)是不現(xiàn)實(shí)的.
? 最現(xiàn)實(shí)的辦法就實(shí)際問題實(shí)際分析,將問題一個(gè)一個(gè)處理.
? 系統(tǒng)緩慢就不用說了,性能還上不去,自然緩慢,這個(gè)后面處理.
? 進(jìn)入頁面的白屏,是可以解決的.最早我認(rèn)為只是糟糕的web頁面造成的.這個(gè)活動(dòng)頁面是一個(gè)webView的頁面,這個(gè)web頁面幾乎沒有清理過,包含了這個(gè)項(xiàng)目上線以后各種歷史功能.是的,歷史功能.其中包括發(fā)短信等匪夷所思的功能.在項(xiàng)目的早期,因?yàn)槲沂强战当?對(duì)項(xiàng)目了解有所不足,所以很多的功能只能先粗暴的復(fù)制,留下的技術(shù)債務(wù)在這個(gè)最糟糕的時(shí)刻不得不拼命償還.
? 頁面優(yōu)化后,我還發(fā)現(xiàn)一個(gè)Ruby應(yīng)用框架很大問題:在某種情況下,通過Ruby?Web應(yīng)用,如passenger/thin等的請(qǐng)求(這里只試出了資源類型js和圖片),有可能形成無限傳輸,即用wget url得到一個(gè)無限大的文件,并且連接不會(huì)停止,這樣頁面就無法正常顯示給用用戶.
? 具體原因當(dāng)時(shí)沒有時(shí)間去深究.解決辦法是簡(jiǎn)單把資源文件放在nginx或是專用的資源服務(wù)器上,這里我使用了資源服務(wù)器,因?yàn)橘Y源服務(wù)器在不同的機(jī)房,這樣也給帶寬做了分流.
? 在高壓環(huán)境下,把資源文件這種簡(jiǎn)單粗重的活直接丟給nginx前端或是專用資源服務(wù)器(如s3)是很有較的.
?
? 數(shù)據(jù)庫及代碼優(yōu)化
? 數(shù)據(jù)庫優(yōu)化永遠(yuǎn)是系統(tǒng)優(yōu)化的第一步.數(shù)據(jù)庫問題也是系統(tǒng)性能的第一重要瓶頸.糟糕的查詢/沒有索引/過大的數(shù)據(jù),都會(huì)引起數(shù)據(jù)庫問題.
? 糟糕的查詢,也是糟糕的代碼.或許很多Ruby的程序員都抱著”不需要考慮性能問題”的教條.但是行而上學(xué)的方法會(huì)給項(xiàng)目代碼和自身的發(fā)展都事帶來很大的不良影響.
? 我們真的可以”不需要考慮性能問題”?.當(dāng)然不是,也許給出這個(gè)教條的大神并沒有生活在天朝it圈這個(gè)比較低端的環(huán)境,并不知道:原來還可能寫出這么糟糕的代碼!
? 我遇到比較糟糕的代碼是像這樣的:
? # 取出正在上影的影片列表?
? Even.includes(‘films').where(“…”).map{|e| e.film}.uniq
? 這個(gè)代碼取出所有有排期的排期,只是為了取出正在上影的影片.這段代碼在初期的時(shí)候因?yàn)檎J(rèn)為結(jié)果會(huì)被緩存,數(shù)據(jù)量也不大,所以沒有什么問題.
? 但在數(shù)據(jù)量增大后,總量達(dá)到千萬級(jí),有效數(shù)據(jù)萬條以上時(shí),就足以拖慢整個(gè)系統(tǒng).
??
? 這樣的問題代碼,不能總是從代碼review中取得,從數(shù)據(jù)庫日志中得到提示是更加聰明的辦法.
? 特別是你不是從頭開始就管這個(gè)項(xiàng)目的時(shí)候,拿我們使用的postgres來說,我們可以在數(shù)據(jù)庫的日志中找出有問題的查詢語句,再反查對(duì)應(yīng)的項(xiàng)目和語句.
??
? pg日志中,標(biāo)記為duration的語句,就是糟糕的查詢(需要配置).
? 不同的語句有不同的速度要求,不過一般情況下,10ms左右的查詢是優(yōu)質(zhì)的,100ms左右還過得去,大于200ms是默認(rèn)的duration值了,過了1s,這些查詢?cè)谛枰阅艿南到y(tǒng)里就很致命了.
? 那么duration是1s,是不是我這個(gè)請(qǐng)求也就1s多一點(diǎn)能處理完成?在系統(tǒng)壓力小的時(shí)候是的,但是壓力上去后,這些查詢就會(huì)把你的系統(tǒng)卡得死死的,他們由1s變成1min,也使得其它10ms能處理的查詢 變成1s以上.系統(tǒng)就是這樣崩潰的.
? 從系統(tǒng)中找出這些代碼,優(yōu)化他們,修改查詢方案或是添加新的索引,都是很好的解決辦法.
? 優(yōu)化數(shù)據(jù)庫訪問相關(guān)的代碼,可以大大地減少每一個(gè)請(qǐng)求影響的時(shí)間,但這只是處理問題的開始.
?
? pgbuncer
? 單獨(dú)的把pgbuncer當(dāng)成一個(gè)優(yōu)化內(nèi)容,因?yàn)檫@其實(shí)是一個(gè)優(yōu)化數(shù)據(jù)庫連接池的內(nèi)容.一個(gè)高性能的系統(tǒng)是不能沒有數(shù)據(jù)庫連接池的,而Ruby容器在這方面表現(xiàn)很差.
? Ruby擅長慢功出細(xì)活,但每一個(gè)”活”都要占用一個(gè)數(shù)據(jù)庫連接,這就很慘了,我一臺(tái)64G24core的數(shù)據(jù)庫服務(wù)器開800個(gè)連接,已經(jīng)是比較亂來的配置了.但如果不用連接池,這還遠(yuǎn)遠(yuǎn)不夠.
? 比如,我在搶票的時(shí)候,希望出一分鐘內(nèi)出1000個(gè)訂單,這些訂單要經(jīng)過復(fù)雜的網(wǎng)絡(luò)交互,加起來占上20/30s都是快的.那么我開400個(gè)進(jìn)程已經(jīng)是最少了,如果沒有連接池,這400個(gè)進(jìn)程每個(gè)都要占用一個(gè)連接,直到進(jìn)程完成,甚至直到這些進(jìn)程已經(jīng)不再使用.
? 而使用pgbuncer可以分配上萬個(gè)連接數(shù),而只有正在查詢的語句才會(huì)占用真正的連接數(shù).
? 引入新的高性能框架golang
? Ruby系統(tǒng)的性能很差,有的人不相信,并且罷出很多HelloWorld來表示我們也可以和java等應(yīng)用一拼高下.這是沒有意義的,起碼對(duì)我的企業(yè)級(jí)應(yīng)用來說,起碼連接一次redis,從中取得數(shù)據(jù),這樣的實(shí)例測(cè)試才是有效的.我做過測(cè)試,從redis中取得個(gè)緩存結(jié)果集返回給客戶端,go只占了2G左右內(nèi)存,就肯完所有的CPU,并在一分鐘完成了100w次請(qǐng)求,能力暴表,而Ruby應(yīng)用在2萬次左右就上不去了,特別的問題是已經(jīng)耗光了所有的內(nèi)存,而cpu并沒有完全利用.
? 以下是我認(rèn)為Ruby系統(tǒng)性能差的原因:
? 1. 內(nèi)存占有大. 一個(gè)進(jìn)程sinatra類的也有100M左右.而內(nèi)存是很固定而且昂貴的
? 2. 線程纖程類的支持差. 最新的Ruby或是Rails都可以支持線程和纖程之類消耗小但是可以提高性能的功能.但是可以支持和優(yōu)秀的支持是有很大差距的.使用線程模式后在大壓力下,進(jìn)程出現(xiàn)很多奇怪錯(cuò)誤并有僵死的問題.加大線程數(shù)并沒有其它的架構(gòu)那樣有明顯的提高.這里也可能和pg沒有好的Ruby并發(fā)gem有關(guān).而在這個(gè)方面,我使用過最好用的是go.這也是我后面用go來進(jìn)行開發(fā)cache服務(wù)器的原因.
? 3. 垃圾回收問題.1.9的垃圾回收很差,這點(diǎn)在2.1之后得到了改進(jìn),但是,在我使用的時(shí)候,2.1還有很大的問題,在試驗(yàn)性使用后,出現(xiàn)了Rails進(jìn)程”長大”到20+G搞壞系統(tǒng)的情況,極不穩(wěn)定.
?
? 這些問題都很大的影響了Ruby系統(tǒng)的性能,在到達(dá)一定瓶頸后,性能和可靠性都受到了極大的挑戰(zhàn).
? 為了解決這個(gè)問題,我引入了go寫了一個(gè)高性能緩存系統(tǒng).
? go的特點(diǎn)
? 1. 天然支持高并發(fā).
? 2. 內(nèi)存占用小,gorountine把第一/二點(diǎn)結(jié)合得淋漓盡至.
? 3. 有現(xiàn)代語言的特征,讓我們?cè)讷@得高性能的同時(shí),不會(huì)受到c/c++語言的折磨.
? go占內(nèi)存小cpu利用率高,Ruby占內(nèi)存大,占CPU小,兩者配合相得益彰.
??我把我的go服務(wù)稱為CacheServer,而把原來的ruby系統(tǒng)稱為RealtimeServer,原先的請(qǐng)求通過nginx分成兩個(gè)部分,一部分是讀,一部分是寫(交易).
? 讀的部分丟給CacheServer,如果CacheServer不能處理(找不到cache),就丟給RealTimeserver,ReadTimeServer負(fù)責(zé)寫入,cacheServer等待RealTimeServer寫完緩存后把緩存處理返回給用戶.這里之所以CacheServer是將緩存內(nèi)容返回而不是ReadTimeServer的返回返回,因?yàn)槲覀兊南到y(tǒng)很復(fù)雜,我不得不在Cache端也對(duì)Ruby返回的數(shù)據(jù)進(jìn)行了一定的處理,這個(gè)我后面有詳細(xì)講到.
? 交易部分處理仍然由原來的Ruby來直接處理.
? 這樣做的好處.go分擔(dān)了高性能要求的粗重活,而Ruby分擔(dān)了復(fù)雜的工作.如果有修改,還是只需要修改Ruby就足夠了.這是我很滿意的設(shè)計(jì).
??
? 將交易分離,提高可靠性
? 在壓力環(huán)境中,有一部分請(qǐng)求是要被拋棄的.在壓力測(cè)試中,90%的可靠性,就算通過了.但交易性的接口顯然不能是這樣的.它必須是100%可靠的.
? 為了保證金額交易部分的可靠性,大訪問量的接口與敏感交易接口分開是一個(gè)很好的辦法,并且讓交易接口使用線程安全模式.確保每次訪問在代碼正確的情況下不會(huì)因?yàn)榫€性安全的問題而出現(xiàn)問題.請(qǐng)求從nginx前端就分離,如果有條件,最好分配不同的機(jī)器和網(wǎng)絡(luò)接口.
? ?更細(xì)粒度的緩存?
? ?企業(yè)級(jí)應(yīng)用,與資訊網(wǎng)站的不同是每個(gè)接口對(duì)不同的用戶,甚至相同用戶的不同時(shí)間進(jìn)行訪問,都需要有不同的結(jié)果.
? ?一個(gè)用戶有一個(gè)結(jié)果,如果只緩存最終的結(jié)果,就相當(dāng)于不緩存.而不同時(shí)刻不同結(jié)果,這樣的接口對(duì)緩存帶來了很多的麻煩.
? ?比如我們有一個(gè)影院列表的接口,他返回用戶所在城市,有排期的(城市加或不加影片)影院列表,列表附上用戶是否去過的標(biāo)志和對(duì)用戶的距離,列表按距離排序.
? ?這樣不同的城市人來訪問有不同的列表,不同時(shí)間去過沒去的標(biāo)志不同,而不同坐標(biāo)有不同距離,更變態(tài)的,是還需要對(duì)此進(jìn)行排序.這樣的接口幾乎是不能夠進(jìn)行緩存的.
? ?我只能對(duì)他進(jìn)行拆分,細(xì)分緩存的粒度.
? ?首先來看流程:
? ?1. 根據(jù)城市(+影片)代碼取出有排期的影院
? ?2. 根據(jù)用戶號(hào)碼查看用戶去過哪些影院
? ?3. 根據(jù)用戶定位信息給出影院的距離
? ?這是糟糕的設(shè)計(jì),但必須兼容.這就是要求用戶每次請(qǐng)求都有不同的結(jié)果.根本不能緩存.但讓我們?cè)囋嚥鸱忠幌?
? ?首先,一個(gè)城市的影院是固定的,問題只是其下只否有排期或指定的影片是否有排期.那么緩存一個(gè)城市(+影片)的影院列表是可行的,這樣不同用戶但同一個(gè)城市看同一個(gè)電影,可以從同樣緩存中取出.這樣的場(chǎng)景在這個(gè)應(yīng)用用是非常大的,看電影人大多的是在北上廣,而同檔期里火爆的電影也就那么幾部,這樣這個(gè)緩存就非常有意義了.?
? ?再次,用戶去過的影院,這個(gè)其實(shí)變化得很少,這個(gè)數(shù)據(jù)是用戶購票成功過的影院,這個(gè)功能最后被我直接變成一個(gè)固定的放在redis里的kv值,這個(gè)表會(huì)記錄一個(gè)用戶去過的影院的ids,定時(shí)會(huì)更新新生成的訂單的用戶的記錄.想知道用戶去過哪個(gè)影院,直接從這個(gè)redis里取出就可以.這樣的修改甚至可以讓我們的產(chǎn)品線的產(chǎn)品可以通用這個(gè)信息.
? ?有了上面的緩存,下面”緩存”接口要做的,只是計(jì)算下影院的距離,這樣,接口避開了與pg數(shù)據(jù)庫的連接,能快速地響應(yīng)用戶.而這些,我可以直接在go cache接口完成.
? ?緩存的內(nèi)容,還包括一些select的結(jié)果集,由于很多的緩存機(jī)制都是對(duì)id=的單體結(jié)果,所以我自己寫了一個(gè)集合的緩存gem:https://github.com/azhao1981/kv_cache
??
? ?交換機(jī)的問題
? ?在壓力環(huán)境下,交換機(jī)也是很容易出問題的部分.
? ?我們有五臺(tái)機(jī)器,兩臺(tái)應(yīng)用,一臺(tái)數(shù)據(jù)庫,一個(gè)測(cè)試機(jī),一個(gè)交換機(jī).?
?? 做活動(dòng)的時(shí)候,我們發(fā)現(xiàn)了大量請(qǐng)求發(fā)不出去,包括rails c連接到數(shù)據(jù)庫查看,但是查看系統(tǒng)連接數(shù),卻只是3w多個(gè)連接,并沒有達(dá)到系統(tǒng)連接數(shù)的上限(5w+),數(shù)據(jù)庫的連接數(shù)也沒有達(dá)到上限.
? ?這是路由器問題的表象,我們最先使用單個(gè)交換機(jī),用虛擬網(wǎng)段分內(nèi)網(wǎng)和外網(wǎng).出問題后,我們通過借用機(jī)房外出接口,發(fā)現(xiàn)性能上去一些,這意味著交換機(jī)是一個(gè)瓶頸.
? ?我猜想問題是這樣產(chǎn)生的:
? ?首先,交換機(jī)是物理單體的,無論他分成多少網(wǎng)段,總的吞吐量都是一個(gè)定值.
? ?其次,交換機(jī)使用虛擬網(wǎng)段進(jìn)行連接,在高壓力環(huán)境下,可能會(huì)容易形成死循環(huán).想象下,一個(gè)外部的連接請(qǐng)求,需要差不多數(shù)5/6次的內(nèi)部請(qǐng)求來完成,外部的連接要保持并等待內(nèi)部的連接交互的完成.而只要內(nèi)部的連接有一個(gè)出現(xiàn)瓶頸,外部的連接就不能關(guān)閉,那么就很容易出現(xiàn)等待的死循環(huán).
? ?然后是路由器防火墻,在高壓力環(huán)境下,默認(rèn)的路由器防火墻會(huì)把請(qǐng)求當(dāng)成洪水攻擊處理掉.這個(gè)是在一定量后可靠性上不去后我們才發(fā)現(xiàn)的.
??
? ?系統(tǒng)的調(diào)優(yōu)
? ?服務(wù)器有很多的參數(shù),比如ulimit的文件最大數(shù)量,TIME_WAIT時(shí)間等,都是性能產(chǎn)生問題的原因.這個(gè)就得請(qǐng)專業(yè)的運(yùn)維人員來處理了. ??
? ?這里要注意一下nginx如果有http轉(zhuǎn)發(fā),就要設(shè)置一下http/1.1的頭,不然這些TIME_WAIT的連接并不能很好的得用.影響很大.一些應(yīng)用中的http調(diào)用連接,最好也要檢查一下,默認(rèn)是不是有http/1.1的報(bào)頭,如果沒有,需要人工指定.
? ?讀寫分離
? ?我這里的讀寫分離不是雙機(jī)熱備的那種讀寫分離,我們的系統(tǒng)原來是沒有雙機(jī)熱備的.我這里只是把只要讀取的接口的數(shù)據(jù)分離到另一個(gè)庫里.相當(dāng)于一個(gè)軟讀寫分離.
? ?我要做的很簡(jiǎn)單,使用原來的go cacheServer做為讀取的應(yīng)用,優(yōu)化一個(gè)redis配置專門用于cache.定時(shí)將pg庫里的信息寫到這個(gè)redis中.cacheServer由原來不能處理的丟還給RealtimeServer變成直接返回錯(cuò)誤信息.而定時(shí)任務(wù)來保證cacheServer能獲取所有的應(yīng)取得的東西.
? ?這就相當(dāng)于把讀數(shù)據(jù)分離到redis中,應(yīng)用也由高性能的go來處理.而寫的部分仍然由原來的pg和ruby來完成.
? ?這樣的修改很輕巧,幾乎可以無縫的進(jìn)行.接口也可以一個(gè)個(gè)的進(jìn)行修改,下次活動(dòng)來到的時(shí)候,有的接口沒有完成,也是可以接受的.這對(duì)于我的時(shí)間約束來說是一個(gè)好的消息.
?? 到此,讀寫分離最終完成了.系統(tǒng)的性能得到了很大的提高.特別是讀取信息部分,系統(tǒng)處理的功能遠(yuǎn)遠(yuǎn)大于帶寬的供給,而處理這部分功能的產(chǎn)用的資源很小,高峰期也只占到不到幾百M(fèi)而以.
? ?
? 橫向擴(kuò)展RealtimeServer
? 上面都是對(duì)cache層面的優(yōu)化,核心就是減少響應(yīng)時(shí)間.但是RealtimeServer就不能這么干了.
? RealTimeServer剩下的接口本身是一個(gè)多方交互的過程,又出于可靠的需求,使用進(jìn)程安全的模式.在搶票的時(shí)候,內(nèi)存和cpu都在向上飆升.剩下的解決方案就是橫向擴(kuò)展了,一臺(tái)能開400個(gè)進(jìn)程,那兩臺(tái)就是800,在需要的時(shí)候利用空閑的資源頂上.
? 更多的優(yōu)化
? 優(yōu)化是一個(gè)可持續(xù)的工作, 我們的舊版本因?yàn)橐嫒堇习姹镜年P(guān)系,只能用各種拆分的方法來進(jìn)行改進(jìn).但在新的版本中,我采用了服務(wù)器端盡量簡(jiǎn)單的原則.
? 一個(gè)互聯(lián)網(wǎng)項(xiàng)目的發(fā)展,一開始可能因?yàn)橄M煽匦愿鼜?qiáng),把更多的功能放在服務(wù)器端,這樣更新就不需要等待客戶端的升級(jí),可直接修改服務(wù)器就可以了,但是一但發(fā)展到服務(wù)器端要承受壓力的時(shí)候,那么就必須考慮把更多的功能放到客戶端了,就比如我上面提到的影院列表,距離之類的,其實(shí)用戶端很容易的進(jìn)行計(jì)算,而用影院坐標(biāo)代替距離,可以讓服務(wù)器非常簡(jiǎn)單,緩存起來也很容易.而且現(xiàn)在的手機(jī)端已經(jīng)擁有很強(qiáng)大的能力,不僅可以給你距離,還可以給出方向,這些都是服務(wù)端不能做到的.
? 從設(shè)計(jì)讓讓服務(wù)端更加簡(jiǎn)單,這是從根本上解決的辦法.
? AWS云
? AWS在其實(shí)在早些年已經(jīng)進(jìn)入了中國,但不知道為什么,現(xiàn)在都沒有正式的運(yùn)營.但現(xiàn)在公司好像已經(jīng)可以申請(qǐng)賬號(hào).
? 云的優(yōu)勢(shì)不用置疑.AWS超強(qiáng)的性能.彈性的帶寬等等,都是不是我們小公司自己罷幾個(gè)服務(wù)器可以比擬的.如果我們一早就是使用AWS,那上面的目標(biāo)估計(jì)不用做都可以實(shí)現(xiàn)了.只可惜,在準(zhǔn)備遷移前我已經(jīng)因病離開公司.無緣這個(gè)遷移優(yōu)化部分了.
??
? 總結(jié)
? 系統(tǒng)性能的提升,是一個(gè)長期而艱難的過程.在有實(shí)際業(yè)務(wù)壓力的情況下,每一步的修改都要小心翼翼.而每步的改進(jìn)又必須經(jīng)受實(shí)際壓力的檢驗(yàn).不夸夸其談高大上的集群或云,而是一小步一小步的實(shí)實(shí)在在提升自己系統(tǒng)的性能.也是自身能力的提升.
轉(zhuǎn)載于:https://my.oschina.net/zhao/blog/407413
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Ruby如何成长成高性能系统构架的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hi3520d uImage制作 ubo
- 下一篇: windows 建立wifi热点