偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

九大服務(wù)架構(gòu)性能優(yōu)化方式

開(kāi)發(fā)
本文主要總結(jié)進(jìn)行服務(wù)性能優(yōu)化的幾種方式,每一種方式在我們常用的中間件中都有所體現(xiàn)。

作者 | jialiangsun

最近做了一些服務(wù)性能優(yōu)化,文章池服務(wù)平均耗時(shí)跟p99耗時(shí)都下降80%左右,事件底層頁(yè)服務(wù)平均耗時(shí)下降50%多左右,主要優(yōu)化項(xiàng)目中一些不合理設(shè)計(jì),例如服務(wù)間使用json傳輸數(shù)據(jù),監(jiān)控上報(bào)處理邏輯在主流程中,重復(fù)數(shù)據(jù)每次都請(qǐng)求下游服務(wù),多個(gè)耗時(shí)操作串行請(qǐng)求等,這些問(wèn)題都對(duì)服務(wù)有著嚴(yán)重的性能影響。

在服務(wù)架構(gòu)設(shè)計(jì)時(shí)通??梢允褂靡恍┲虚g件去提升服務(wù)性能,例如使用mysql,redis,kafka等,因?yàn)檫@些中間件有著很好的讀寫(xiě)性能。除了使用中間件提升服務(wù)性能外,也可以通過(guò)探索它們通過(guò)什么樣的底層設(shè)計(jì)實(shí)現(xiàn)的高性能,將這些設(shè)計(jì)應(yīng)用到我們的服務(wù)架構(gòu)中。

常用的性能優(yōu)化方法可以分為以下幾種:

性能優(yōu)化九大方式

1.緩存

性能優(yōu)化,緩存為王,所以開(kāi)始先介紹一下緩存。緩存在我們的架構(gòu)設(shè)計(jì)中無(wú)處不在的,常規(guī)請(qǐng)求是瀏覽器發(fā)起請(qǐng)求,請(qǐng)求服務(wù)端服務(wù),服務(wù)端服務(wù)再查詢(xún)數(shù)據(jù)庫(kù)中的數(shù)據(jù),每次讀取數(shù)據(jù)都會(huì)至少需要兩次網(wǎng)絡(luò)I/O,性能會(huì)差一些,我們可以在整個(gè)流程中增加緩存來(lái)提升性能。首先是瀏覽器測(cè),可以通過(guò)Expires、Cache-Control、Last-Modified、Etag等相關(guān)字段來(lái)控制瀏覽器是否使用本地緩存。

其次我們可以在服務(wù)端服務(wù)使用本地緩存或者一些中間件來(lái)緩存數(shù)據(jù),例如redis。redis之所以這么快,主要因?yàn)閿?shù)據(jù)存儲(chǔ)在內(nèi)存中,不需要讀取磁盤(pán),因?yàn)閮?nèi)存讀取速度通常是磁盤(pán)的數(shù)百倍甚至更多;

然后在數(shù)據(jù)庫(kù)測(cè),通常使用的是mysql,mysql的數(shù)據(jù)存儲(chǔ)到磁盤(pán)上,但是mysql為了提升讀寫(xiě)性能,會(huì)利用bufferpool緩存數(shù)據(jù)頁(yè)。mysql讀取時(shí)會(huì)按照頁(yè)的粒度將數(shù)據(jù)頁(yè)讀取到bufferpool中,bufferpool中的數(shù)據(jù)頁(yè)使用LRU算法淘汰長(zhǎng)期沒(méi)有用到的頁(yè)面,緩存最近訪問(wèn)的數(shù)據(jù)頁(yè)。

此外小到cpu的l1、l2、l3級(jí)cache,大到瀏覽器緩存都是為了提高性能,緩存也是進(jìn)行服務(wù)性能優(yōu)化的重要手段,使用緩存時(shí)需要考慮以下幾點(diǎn):

(1) 使用什么樣的緩存

使用緩存時(shí)可以使用redis或者機(jī)器內(nèi)存來(lái)緩存數(shù)據(jù),使用redis的好處可以保證不同機(jī)器讀取數(shù)據(jù)的一致性,但是讀取redis會(huì)增加一次I/O,使用內(nèi)存緩存數(shù)據(jù)時(shí)可能會(huì)出現(xiàn)讀取數(shù)據(jù)不一致,但是讀取性能好。例如文章的閱讀數(shù)數(shù)據(jù),如果使用機(jī)器內(nèi)存作為緩存,容易出現(xiàn)不同機(jī)器上緩存數(shù)據(jù)的不一致,用戶(hù)不同刷次會(huì)請(qǐng)求到不同服務(wù)端機(jī)器,讀取的閱讀數(shù)不一致,可能會(huì)出現(xiàn)閱讀數(shù)變小的情況,用戶(hù)體驗(yàn)不好。對(duì)于閱讀數(shù)這種經(jīng)常變更的數(shù)據(jù)比較適合使用redis來(lái)統(tǒng)一緩存。

也可以將兩者結(jié)合提升服務(wù)的性能,例如在內(nèi)容池服務(wù),利用redis跟機(jī)器內(nèi)存緩存熱點(diǎn)文章詳情,優(yōu)先讀取機(jī)器內(nèi)存中的數(shù)據(jù),數(shù)據(jù)不存在的時(shí)候會(huì)讀取redis中的緩存數(shù)據(jù),當(dāng)redis中的數(shù)據(jù)也不存在的時(shí)候,會(huì)讀取下游持久化存儲(chǔ)中的全量數(shù)據(jù)。其中內(nèi)存級(jí)緩存過(guò)期時(shí)間為15s,在數(shù)據(jù)變更的時(shí)候不保證數(shù)據(jù)一致性,通過(guò)數(shù)據(jù)自然過(guò)期來(lái)保證最終一致性。redis中緩存數(shù)據(jù)需要保證與持久化存儲(chǔ)中數(shù)據(jù)一致性,如何保證一致性在后續(xù)講解。可以根據(jù)自己的業(yè)務(wù)場(chǎng)景可以選擇合適的緩存方案。

使用緩存時(shí)可以使用redis或者機(jī)器內(nèi)存來(lái)緩存數(shù)據(jù),使用redis的好處可以保證不同機(jī)器讀取數(shù)據(jù)的一致性,但是讀取redis會(huì)增加一次I/O,使用內(nèi)存緩存數(shù)據(jù)時(shí)可能會(huì)出現(xiàn)讀取數(shù)據(jù)不一致,但是讀取性能好。例如文章的閱讀數(shù)數(shù)據(jù),如果使用機(jī)器內(nèi)存作為緩存,容易出現(xiàn)不同機(jī)器上緩存數(shù)據(jù)的不一致,用戶(hù)不同刷次會(huì)請(qǐng)求到不同服務(wù)端機(jī)器,讀取的閱讀數(shù)不一致,可能會(huì)出現(xiàn)閱讀數(shù)變小的情況,用戶(hù)體驗(yàn)不好。對(duì)于閱讀數(shù)這種經(jīng)常變更的數(shù)據(jù)比較適合使用redis來(lái)統(tǒng)一緩存。

也可以將兩者結(jié)合提升服務(wù)的性能,例如在內(nèi)容池服務(wù),利用redis跟機(jī)器內(nèi)存緩存熱點(diǎn)文章詳情,優(yōu)先讀取機(jī)器內(nèi)存中的數(shù)據(jù),數(shù)據(jù)不存在的時(shí)候會(huì)讀取redis中的緩存數(shù)據(jù),當(dāng)redis中的數(shù)據(jù)也不存在的時(shí)候,會(huì)讀取下游持久化存儲(chǔ)中的全量數(shù)據(jù)。其中內(nèi)存級(jí)緩存過(guò)期時(shí)間為15s,在數(shù)據(jù)變更的時(shí)候不保證數(shù)據(jù)一致性,通過(guò)數(shù)據(jù)自然過(guò)期來(lái)保證最終一致性。redis中緩存數(shù)據(jù)需要保證與持久化存儲(chǔ)中數(shù)據(jù)一致性,如何保證一致性在后續(xù)講解??梢愿鶕?jù)自己的業(yè)務(wù)場(chǎng)景可以選擇合適的緩存方案。

(2) 緩存常見(jiàn)問(wèn)題

  • 緩存雪崩:緩存雪崩是指緩存中的大量數(shù)據(jù)同時(shí)失效或者過(guò)期,導(dǎo)致大量的請(qǐng)求直接讀取到下游數(shù)據(jù)庫(kù),導(dǎo)致數(shù)據(jù)庫(kù)瞬時(shí)壓力過(guò)大,通常的解決方案是將緩存數(shù)據(jù)設(shè)置的過(guò)期時(shí)間隨機(jī)化。在事件服務(wù)中就是利用固定過(guò)期時(shí)間+隨機(jī)值的方式進(jìn)行文章的淘汰,避免緩存雪崩。
  • 緩存穿透:緩存穿透是指讀取下游不存在的數(shù)據(jù),導(dǎo)致緩存命中不了,每次都請(qǐng)求下游數(shù)據(jù)庫(kù)。這種情況通常會(huì)出現(xiàn)在線(xiàn)上異常流量攻擊或者下游數(shù)據(jù)被刪除的狀況,針對(duì)緩存穿透可以使用布隆過(guò)濾器對(duì)不存在的數(shù)據(jù)進(jìn)行過(guò)濾,或者在讀取下游數(shù)據(jù)不存在的情況,可以在緩存中設(shè)置空值,防止不斷的穿透。事件服務(wù)可能會(huì)出現(xiàn)查詢(xún)文章被刪除的情況,就是利用設(shè)置空值的方法防止被刪除數(shù)據(jù)的請(qǐng)求不斷穿透到下游。
  • 緩存擊穿: 緩存擊穿是指某個(gè)熱點(diǎn)數(shù)據(jù)在緩存中被刪除或者過(guò)期,導(dǎo)致大量的熱點(diǎn)請(qǐng)求同時(shí)請(qǐng)求數(shù)據(jù)庫(kù)。解決方案可以對(duì)于熱點(diǎn)數(shù)據(jù)設(shè)置較長(zhǎng)的過(guò)期時(shí)間或者利用分布式鎖避免多個(gè)相同請(qǐng)求同時(shí)訪問(wèn)下游服務(wù)。在新聞業(yè)務(wù)中,對(duì)于熱點(diǎn)新聞經(jīng)常會(huì)出現(xiàn)這種情況,事件服務(wù)利用golang的singlefilght保證同一篇文章請(qǐng)求在同一時(shí)刻只有一個(gè)會(huì)請(qǐng)求到下游,防止緩存擊穿。
  • 熱點(diǎn)key: 熱點(diǎn)key是指緩存中被頻繁訪問(wèn)的key,導(dǎo)致緩存該key的分片或者redis訪問(wèn)量過(guò)高??梢詫⒖蔁狳c(diǎn)key分散存儲(chǔ)到多個(gè)key上,例如將熱點(diǎn)key+序列號(hào)的方式存儲(chǔ),不同key存儲(chǔ)的值都是相同的,在訪問(wèn)時(shí)隨機(jī)訪問(wèn)一個(gè)key,分散原來(lái)單key分片的壓力;此外還可以將key緩存到機(jī)器內(nèi)存中,避免redis單節(jié)點(diǎn)壓力過(guò)大,在新聞業(yè)務(wù)中,對(duì)于熱點(diǎn)文章就是采用這種方式,將熱點(diǎn)文章存儲(chǔ)到機(jī)器內(nèi)存中,避免存儲(chǔ)熱點(diǎn)文章redis單分片請(qǐng)求量過(guò)大。
key val    =>  key1 val 、  key2 val、  key3 val 、 key4 val

(3) 緩存淘汰

緩存的大小是有限的,因?yàn)樾枰獙?duì)緩存中數(shù)據(jù)進(jìn)行淘汰,通??梢圆捎秒S機(jī)、LRU或者LFU算法等淘汰數(shù)據(jù)。LRU是一種最常用的置換算法,淘汰最近最久未使用的數(shù)據(jù),底層可以利用map+雙端隊(duì)列的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)。

最原生的LRU算法是存在一些問(wèn)題的,不知道大家在使用過(guò)有沒(méi)有遇到過(guò)問(wèn)題。首先需要注意的是在數(shù)據(jù)結(jié)構(gòu)中有互斥鎖,因?yàn)間olang對(duì)于map的讀寫(xiě)會(huì)產(chǎn)生panic,導(dǎo)致服務(wù)異常。使用互斥鎖之后會(huì)導(dǎo)致整個(gè)緩存性能變差,可以采用分片的思想,將整個(gè)LRUCache分為多個(gè),每次讀取時(shí)讀取其中一個(gè)cache片,降低鎖的粒度來(lái)提升性能,常見(jiàn)的本地緩存包通常就利用這種方式實(shí)現(xiàn)的。

type LRUCache struct {
    sync.Mutex
    size int     
    capacity int
    cache map[int]*DLinkNode
    head, tail *DLinkNode
}
type DLinkNode struct {
    key,value int
    pre, next *DLinkNode
}

mysql也會(huì)利用LRU算法對(duì)buffer pool中的數(shù)據(jù)頁(yè)進(jìn)行淘汰。由于mysql存在預(yù)讀,在讀取磁盤(pán)時(shí)并不是按需讀取,而是按照整個(gè)數(shù)據(jù)頁(yè)的粒度進(jìn)行讀取,一個(gè)數(shù)據(jù)頁(yè)會(huì)存儲(chǔ)多條數(shù)據(jù),除了讀取當(dāng)前數(shù)據(jù)頁(yè),可能也會(huì)將接下來(lái)可能用到的相鄰數(shù)據(jù)頁(yè)提前緩存到bufferpool中,如果下次讀取的數(shù)據(jù)在緩存中,直接讀取內(nèi)存即可,不需要讀取磁盤(pán),但是如果預(yù)讀的數(shù)據(jù)頁(yè)一直沒(méi)有被訪問(wèn),那就會(huì)存在預(yù)讀失效的情況,淘汰原來(lái)使用到的數(shù)據(jù)頁(yè)。mysql將buffer pool中的鏈表分為兩部分,一段是新生代,一段是老生代,新老生代的默認(rèn)比是7:3,數(shù)據(jù)頁(yè)被預(yù)讀的時(shí)候會(huì)先加到老生代中,當(dāng)數(shù)據(jù)頁(yè)被訪問(wèn)時(shí)才會(huì)加載到新生代中,這樣就可以防止預(yù)讀的數(shù)據(jù)頁(yè)沒(méi)有被使用反而淘汰熱點(diǎn)數(shù)據(jù)頁(yè)。此外mysql通常會(huì)存在掃描表的請(qǐng)求,會(huì)順序請(qǐng)求大量的數(shù)據(jù)加載到緩存中,然后將原本緩存中所有熱點(diǎn)數(shù)據(jù)頁(yè)淘汰,這個(gè)問(wèn)題通常被稱(chēng)為緩沖池污染,mysql中的數(shù)據(jù)頁(yè)需要在老生代停留時(shí)間超過(guò)配置時(shí)間才會(huì)老生代移動(dòng)到新生代時(shí)來(lái)解決緩存池污染。

redis中也會(huì)利用LRU進(jìn)行淘汰過(guò)期的數(shù)據(jù),如果redis將緩存數(shù)據(jù)都通過(guò)一個(gè)大的鏈表進(jìn)行管理,在每次讀寫(xiě)時(shí)將最新訪問(wèn)的數(shù)據(jù)移動(dòng)到鏈表隊(duì)頭,那樣會(huì)嚴(yán)重影響redis的讀寫(xiě)性能,此外會(huì)增加額外的存儲(chǔ)空間,降低整體存儲(chǔ)數(shù)量。redis是對(duì)緩存中的對(duì)象增加一個(gè)最后訪問(wèn)時(shí)間的字段,在對(duì)對(duì)象進(jìn)行淘汰的時(shí)候,會(huì)采用隨機(jī)采樣的方案,隨機(jī)取5個(gè)值,淘汰最近訪問(wèn)時(shí)間最久的一個(gè),這樣就可以避免每次都移動(dòng)節(jié)點(diǎn)。但是LRU也會(huì)存在緩存污染的情況,一次讀取大量數(shù)據(jù)會(huì)淘汰熱點(diǎn)數(shù)據(jù),因此redis可以選擇利用LFU進(jìn)行淘汰數(shù)據(jù),是將原來(lái)的訪問(wèn)時(shí)間字段變更為最近訪問(wèn)時(shí)間+訪問(wèn)次數(shù)的一個(gè)字段,這里需要注意的是訪問(wèn)次數(shù)并不是單純的次數(shù)累加,而是根據(jù)最近訪問(wèn)時(shí)間跟當(dāng)前時(shí)間的差值進(jìn)行時(shí)間衰減的,簡(jiǎn)單說(shuō)也就是訪問(wèn)越久以及訪問(wèn)次數(shù)越少計(jì)算得到的值也越小,越容易被淘汰。

typedef struct redisObject {
 unsigned type:4;
 unsigned encoding:4;
 unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
 * LFU data (least significant 8 bits frequency
 * and most significant 16 bits access time). */
 int refcount;
 void *ptr;
} obj ;

可以看出不同中間件對(duì)于傳統(tǒng)的LRU淘汰策略都進(jìn)行了一定優(yōu)化來(lái)保證服務(wù)性能,我們也可以參考不同的優(yōu)化策略在自己的服務(wù)中進(jìn)行緩存key的淘汰。

(4) 緩存數(shù)據(jù)一致性

當(dāng)數(shù)據(jù)庫(kù)中的數(shù)據(jù)變更時(shí),如何保證緩存跟數(shù)據(jù)庫(kù)中的數(shù)據(jù)一致,通常有以下幾種方案:更新緩存再更新DB,更新DB再更新緩存,先更新DB再刪除緩存,刪除緩存再更新DB。這幾種方案都有可能會(huì)出現(xiàn)緩存跟數(shù)據(jù)庫(kù)中的數(shù)據(jù)不一致的情況,最常用的還是更新DB再刪除緩存,因?yàn)檫@種方案導(dǎo)致數(shù)據(jù)不一致的概率最小,但是也依然會(huì)存在數(shù)據(jù)不一致的問(wèn)題。例如在T1時(shí)緩存中無(wú)數(shù)據(jù),數(shù)據(jù)庫(kù)中數(shù)據(jù)為100,線(xiàn)程B查詢(xún)緩存沒(méi)有查詢(xún)到數(shù)據(jù),讀取到數(shù)據(jù)庫(kù)的數(shù)據(jù)100然后去更新緩存,但是此時(shí)線(xiàn)程A將數(shù)據(jù)庫(kù)中的數(shù)據(jù)更新為99,然后在T4時(shí)刻刪除緩存中的數(shù)據(jù),但是此時(shí)緩存中還沒(méi)有數(shù)據(jù),在T5的時(shí)候線(xiàn)程B才更新緩存數(shù)據(jù)為100,這時(shí)候就會(huì)導(dǎo)致緩存跟數(shù)據(jù)庫(kù)中的數(shù)據(jù)不一致。

為保證緩存與數(shù)據(jù)庫(kù)數(shù)據(jù)的一致性。常用的解決方案有兩種,一種是延時(shí)雙刪,先刪除緩存,后續(xù)更新數(shù)據(jù)庫(kù),休眠一會(huì)再刪除緩存。文章池服務(wù)中就是利用這種方案保證數(shù)據(jù)一致性,如何實(shí)現(xiàn)延遲刪除,是通過(guò)go語(yǔ)言中channel實(shí)現(xiàn)簡(jiǎn)單延時(shí)隊(duì)列,沒(méi)有引入第三方的消息隊(duì)列,主要為了防止服務(wù)的復(fù)雜化;另外一種可以訂閱DB的變更binlog,數(shù)據(jù)更新時(shí)只更新DB,通過(guò)消費(fèi)DB的binlog日志,解析變更操作進(jìn)行緩存變更,更新失敗時(shí)不進(jìn)行消息的提交,通過(guò)消息隊(duì)列的重試機(jī)制實(shí)現(xiàn)最終一致性。

2.并行化處理

redis在版本6.0之前都是號(hào)稱(chēng)單線(xiàn)程模型,主要是利用epllo管理用戶(hù)海量連接,使用一個(gè)線(xiàn)程通過(guò)事件循環(huán)來(lái)處理用戶(hù)的請(qǐng)求,優(yōu)點(diǎn)是避免了線(xiàn)程切換和鎖的競(jìng)爭(zhēng),以及實(shí)現(xiàn)簡(jiǎn)單,但是缺點(diǎn)也比較明顯,不能有效的利用cpu的多核資源。隨著數(shù)據(jù)量和并發(fā)量的越來(lái)越大,I/O成了redis的性能瓶頸點(diǎn),因此在6.0版本引入了多線(xiàn)程模型。redis的多線(xiàn)程將處理過(guò)程最耗時(shí)的sockect的讀取跟解析寫(xiě)入由多個(gè)I/O 并發(fā)完成,對(duì)于命令的執(zhí)行過(guò)程仍然由單線(xiàn)程完成。

mysql的主從同步過(guò)程從數(shù)據(jù)庫(kù)通過(guò)I/Othread讀取住主庫(kù)的binlog,將日志寫(xiě)入到relay log中,然后由sqlthread執(zhí)行relaylog進(jìn)行數(shù)據(jù)的同步。其中sqlthread就是由多個(gè)線(xiàn)程并發(fā)執(zhí)行加快數(shù)據(jù)的同步,防止主從同步延遲。sqlthread多線(xiàn)程化也經(jīng)歷了多個(gè)版本迭代,按表維度分發(fā)到同一個(gè)線(xiàn)程進(jìn)行數(shù)據(jù)同步,再到按行維度分發(fā)到同一個(gè)線(xiàn)程。

小到線(xiàn)程的并發(fā)處理,大到redis的集群,以及kafka的分topic分區(qū)都是通過(guò)多個(gè)client并行處理提高服務(wù)的讀寫(xiě)性能。在我們的服務(wù)設(shè)計(jì)中可以通過(guò)創(chuàng)建多個(gè)容器對(duì)外服務(wù)提高服務(wù)的吞吐量,服務(wù)內(nèi)部可以將多個(gè)串行的I/O操作改為并行處理,縮短接口的響應(yīng)時(shí)長(zhǎng),提升用戶(hù)體驗(yàn)。對(duì)于I/O存在相互依賴(lài)的情況,可以進(jìn)行多階段分批并行化處理,另外一種常見(jiàn)的方案就是利用DAG加速執(zhí)行,但是需要注意的是DAG會(huì)存在開(kāi)發(fā)維護(hù)成本較高的情況,需要根據(jù)自己的業(yè)務(wù)場(chǎng)景選擇合適的方案。并行化也不是只有好處沒(méi)有壞處的,并行化有可能會(huì)導(dǎo)致讀擴(kuò)散嚴(yán)重,以及線(xiàn)程切換頻繁存在一定的性能影響。

3.批量化處理

kafka的消息發(fā)送并不是直接寫(xiě)入到broker中的,發(fā)送過(guò)程是將發(fā)送到同一個(gè)topic同一個(gè)分區(qū)的消息通過(guò)main函數(shù)的partitioner組件發(fā)送到同一個(gè)隊(duì)列中,由sender線(xiàn)程不斷拉取隊(duì)列中消息批量發(fā)送到broker中。利用批量發(fā)送消息處理,節(jié)省大量的網(wǎng)絡(luò)開(kāi)銷(xiāo),提高發(fā)送效率。

redis的持久化方式有RDB跟AOF兩種,其中AOF在執(zhí)行命令寫(xiě)入內(nèi)存后,會(huì)寫(xiě)入到AOF緩沖區(qū),可以選擇合適的時(shí)機(jī)將AOF緩沖區(qū)中的數(shù)據(jù)寫(xiě)入到磁盤(pán)中,刷新到磁盤(pán)的時(shí)間通過(guò)參數(shù)appendfsync控制,有三個(gè)值always、everysec、no。其中always會(huì)在每次命令執(zhí)行完都會(huì)刷新到磁盤(pán)來(lái)保證數(shù)據(jù)的可靠性;everysec是每秒批量寫(xiě)入到磁盤(pán),no是不進(jìn)行同步操作,由操作系統(tǒng)決定刷新到寫(xiě)回磁盤(pán),當(dāng)redis異常退出時(shí)存在丟數(shù)據(jù)的風(fēng)險(xiǎn)。AOF命令刷新到磁盤(pán)的時(shí)機(jī)會(huì)影響redis服務(wù)寫(xiě)入性能,通常配置為everysec批量寫(xiě)入到磁盤(pán),來(lái)平衡寫(xiě)入性能和數(shù)據(jù)可靠性。

我們讀取下游服務(wù)或者數(shù)據(jù)庫(kù)的時(shí)候,可以一次多查詢(xún)幾條數(shù)據(jù),節(jié)省網(wǎng)絡(luò)I/O;讀取redis的還可以利用pipeline或者lua腳本處理多條命令,提升讀寫(xiě)性能;前端請(qǐng)求js文件或者小圖片時(shí),可以將多個(gè)js文件或者圖片合并到一起返回,減少前端的連接數(shù),提升傳輸性能。同樣需要注意的是批量處理多條數(shù)據(jù),有可能會(huì)降低吞吐量,以及本身下游就不支持過(guò)多的批量數(shù)據(jù),此時(shí)可以將多條數(shù)據(jù)分批并發(fā)請(qǐng)求。對(duì)于事件底層頁(yè)服務(wù)中不同組件下配置的不同文章id,會(huì)統(tǒng)一批量請(qǐng)求下游內(nèi)容服務(wù)獲取文章詳情,對(duì)于批量的條數(shù)也會(huì)做限制,防止單批數(shù)據(jù)量過(guò)大。

4.數(shù)據(jù)壓縮合并

redis的AOF重寫(xiě)是利用bgrewriteaof命令進(jìn)行AOF文件重寫(xiě),因?yàn)锳OF是追加寫(xiě)日志,對(duì)于同一個(gè)key可能存在多條修改修改命令,導(dǎo)致AOF文件過(guò)大,redis重啟后加載AOF文件會(huì)變得緩慢,導(dǎo)致啟動(dòng)時(shí)間過(guò)長(zhǎng)??梢岳弥貙?xiě)命令將對(duì)于同一個(gè)key的修改只保存一條記錄,減小AOF文件體積。

大數(shù)據(jù)領(lǐng)域的Hbase、cassandra等nosql數(shù)據(jù)庫(kù)寫(xiě)入性能都很高,它們的底層存儲(chǔ)數(shù)據(jù)結(jié)構(gòu)就是LSM樹(shù)(log structured merge tree),這種數(shù)據(jù)結(jié)構(gòu)的核心思想是追加寫(xiě),積攢一定的數(shù)據(jù)后合并成更大的segement,對(duì)于數(shù)據(jù)的刪除也只是增加一條刪除記錄。同樣對(duì)一個(gè)key的修改記錄也有多條。這種存儲(chǔ)結(jié)構(gòu)的優(yōu)點(diǎn)是寫(xiě)入性能高,但是缺點(diǎn)也比較明顯,數(shù)據(jù)存在冗余和文件體積大。主要通過(guò)線(xiàn)程進(jìn)行段合并將多個(gè)小文件合并成更大的文件來(lái)減少存儲(chǔ)文件體積,提升查詢(xún)效率。

對(duì)于kafka進(jìn)行傳輸數(shù)據(jù)時(shí),在生產(chǎn)者端和消費(fèi)者端可以開(kāi)啟數(shù)據(jù)壓縮。生產(chǎn)者端壓縮數(shù)據(jù)后,消費(fèi)者端收到消息會(huì)自動(dòng)解壓,可以有效減小在磁盤(pán)的存儲(chǔ)空間和網(wǎng)絡(luò)傳輸時(shí)的帶寬消耗,從而降低成本和提升傳輸效率。需要注意生產(chǎn)者端和消費(fèi)者端指定相同的壓縮算法。

在降本增效的浪潮中,降低redis成本的一種方式,就是對(duì)存儲(chǔ)到redis中的數(shù)據(jù)進(jìn)行壓縮,降低存儲(chǔ)成本,重構(gòu)后的內(nèi)容微服務(wù)通過(guò)持久化存儲(chǔ)全量數(shù)據(jù),采用snappy壓縮,壓縮后只是原來(lái)數(shù)據(jù)的40%-50%;還有一種方式是將服務(wù)之間的調(diào)用從http的json改為trpc的pb協(xié)議,因?yàn)閜b協(xié)議編碼后的數(shù)據(jù)更小,提升傳輸效率,在服務(wù)優(yōu)化時(shí),將原來(lái)請(qǐng)求tab的協(xié)議從json轉(zhuǎn)成pb,降低幾毫秒的時(shí)延,此外內(nèi)容微服務(wù)存儲(chǔ)的數(shù)據(jù)采用flutbuffer編碼,相比較于protobuffer有著更高的壓縮比跟更快的編解碼速度;對(duì)于JS/CSS多個(gè)文件下發(fā)也可以進(jìn)行混淆和壓縮傳遞;對(duì)于存儲(chǔ)在es中的數(shù)據(jù)也可以手動(dòng)調(diào)用api進(jìn)行段合并,減小存儲(chǔ)數(shù)據(jù)的體積,提高查詢(xún)速度;在我們工作中還有一個(gè)比較常見(jiàn)的問(wèn)題是接口返回的冗余數(shù)據(jù)特別多,一個(gè)接口服務(wù)下發(fā)的數(shù)據(jù)大而全,而不是對(duì)于當(dāng)前場(chǎng)景做定制化下發(fā),不滿(mǎn)足接口最小化原則,白白浪費(fèi)了很多帶寬資源和降低傳輸效率。

5.無(wú)鎖化

redis通過(guò)單線(xiàn)程避免了鎖的競(jìng)爭(zhēng),避免了線(xiàn)程之間頻繁切換才有這很好的讀寫(xiě)性能。

go語(yǔ)言中提供了atomic包,主要用于不同線(xiàn)程之間的數(shù)據(jù)同步,不需要加鎖,本質(zhì)上就是封裝了底層cpu提供的原子操作指令。此外go語(yǔ)言最開(kāi)始的調(diào)度模型時(shí)GM模型,所有的內(nèi)核級(jí)線(xiàn)程想要執(zhí)行g(shù)oroutine需要加鎖從全局隊(duì)列中獲取,所以不同線(xiàn)程之間的競(jìng)爭(zhēng)很激烈,調(diào)度效率很差。

后續(xù)引入了P(Processor),每一個(gè)M(thread)要執(zhí)行G(gorontine)的時(shí)候需要綁定一個(gè)P,其中P中會(huì)有一個(gè)待執(zhí)行G的本地隊(duì)列,只由當(dāng)前M可以進(jìn)行讀寫(xiě)(少數(shù)情況會(huì)存在偷其他協(xié)程的G),讀取P本地隊(duì)列時(shí)不需要進(jìn)行加鎖,通過(guò)降低鎖的競(jìng)爭(zhēng)大幅度提升調(diào)度G的效率。

mysql利用mvcc實(shí)現(xiàn)多個(gè)事務(wù)進(jìn)行讀寫(xiě)并發(fā)時(shí)保證數(shù)據(jù)的一致性和隔離型,也是解決讀寫(xiě)并發(fā)的一種無(wú)鎖化設(shè)計(jì)方案之一。它主要通過(guò)對(duì)每一行數(shù)據(jù)的變更記錄維護(hù)多個(gè)版本鏈來(lái)實(shí)現(xiàn)的,通過(guò)隱藏列rollptr和undolog來(lái)實(shí)現(xiàn)快照讀。在事務(wù)對(duì)某一行數(shù)據(jù)進(jìn)行操作時(shí),會(huì)根據(jù)當(dāng)前事務(wù)id以及事務(wù)隔離級(jí)別判斷讀取那個(gè)版本的數(shù)據(jù),對(duì)于可重復(fù)讀就是在事務(wù)開(kāi)始的時(shí)候生成readview,在后續(xù)整個(gè)事務(wù)期間都使用這個(gè)readview。mysql中除了使用mvcc避免互斥鎖外,bufferpool還可以設(shè)置多個(gè),通過(guò)多個(gè)bufferpool降低鎖的粒度,提升讀寫(xiě)性能,也是一種優(yōu)化方案。

日常工作 在讀多寫(xiě)少的場(chǎng)景下可以利用atomic.value存儲(chǔ)數(shù)據(jù),減少鎖的競(jìng)爭(zhēng),提升系統(tǒng)性能,例如配置服務(wù)中數(shù)據(jù)就是利用atomic.value存儲(chǔ)的;syncmap為了提升讀性能,優(yōu)先使用atomic進(jìn)行read操作,然后再進(jìn)行加互斥鎖操作進(jìn)行dirty的操作,在讀多寫(xiě)少的情況下也可以使用syncmap。

秒殺系統(tǒng)的本質(zhì)就是在高并發(fā)下準(zhǔn)確的增減商品庫(kù)存,不出現(xiàn)超賣(mài)少賣(mài)的問(wèn)題。因此所有的用戶(hù)在搶到商品時(shí)需要利用互斥鎖進(jìn)行庫(kù)存數(shù)量的變更?;コ怄i的存在必然會(huì)成為系統(tǒng)瓶頸,但是秒殺系統(tǒng)又是一個(gè)高并發(fā)的場(chǎng)景,所以如何進(jìn)行互斥鎖優(yōu)化是提高秒殺系統(tǒng)性能的一個(gè)重要優(yōu)化手段。

無(wú)鎖化設(shè)計(jì)方案之一就是利用消息隊(duì)列,對(duì)于秒殺系統(tǒng)的秒殺操作進(jìn)行異步處理,將秒殺操作發(fā)布一個(gè)消息到消息隊(duì)列中,這樣所有用戶(hù)的秒殺行為就形成了一個(gè)先進(jìn)先出的隊(duì)列,只有前面先添加到消息隊(duì)列中的用戶(hù)才能搶購(gòu)商品成功。從隊(duì)列中消費(fèi)消息進(jìn)行庫(kù)存變更的線(xiàn)程是個(gè)單線(xiàn)程,因此對(duì)于db的操作不會(huì)存在沖突,不需要加鎖操作。

另外一種優(yōu)化方式可以參考golang的GMP模型,將庫(kù)存分成多份,分別加載到服務(wù)server的本地,這樣多機(jī)之間在對(duì)庫(kù)存變更的時(shí)候就避免了鎖的競(jìng)爭(zhēng)。如果本地server是單進(jìn)程的,因此也可以形成一種無(wú)鎖化架構(gòu);如果是多進(jìn)程的,需要對(duì)本地庫(kù)存加鎖后在進(jìn)行變更,但是將庫(kù)存分散到server本地,降低了鎖的粒度,提高整個(gè)服務(wù)性能。

6.順序?qū)?/h4>

mysql的InnoDB存儲(chǔ)引擎在創(chuàng)建主鍵時(shí)通常會(huì)建議使用自增主鍵,而不是使用uuid,最主要的原因是InnoDB底層采用B+樹(shù)用來(lái)存儲(chǔ)數(shù)據(jù),每個(gè)葉子結(jié)點(diǎn)是一個(gè)數(shù)據(jù)頁(yè),存儲(chǔ)多條數(shù)據(jù)記錄,頁(yè)面內(nèi)的數(shù)據(jù)通過(guò)鏈表有序存儲(chǔ),數(shù)據(jù)頁(yè)間通過(guò)雙向鏈表存儲(chǔ)。由于uuid是無(wú)序的,有可能會(huì)插入到已經(jīng)空間不足的數(shù)據(jù)頁(yè)中間,導(dǎo)致數(shù)據(jù)頁(yè)分裂成兩個(gè)新的數(shù)據(jù)頁(yè)以便插入新數(shù)據(jù),影響整體寫(xiě)入性能。

此外mysql中的寫(xiě)入過(guò)程并不是每次將修改的數(shù)據(jù)直接寫(xiě)入到磁盤(pán)中,而是修改內(nèi)存中buffer pool內(nèi)存儲(chǔ)的數(shù)據(jù)頁(yè),將數(shù)據(jù)頁(yè)的變更記錄到undolog和binlog日志中,保證數(shù)據(jù)變更不丟失,每次記錄log都是追加寫(xiě)到日志文件尾部,順序?qū)懭氲酱疟P(pán)。對(duì)數(shù)據(jù)進(jìn)行變更時(shí)通過(guò)順序?qū)憀og,避免隨機(jī)寫(xiě)磁盤(pán)數(shù)據(jù)頁(yè),提升寫(xiě)入性能,這種將隨機(jī)寫(xiě)轉(zhuǎn)變?yōu)轫樞驅(qū)懙乃枷朐诤芏嘀虚g件中都有所體現(xiàn)。

kakfa中的每個(gè)分區(qū)是一個(gè)有序不可變的消息隊(duì)列,新的消息會(huì)不斷的添加的partition的尾部,每個(gè)partition由多個(gè)segment組成,一個(gè)segment對(duì)應(yīng)一個(gè)物理日志文件,kafka對(duì)segment日志文件的寫(xiě)入也是順序?qū)憽m樞驅(qū)懭氲暮锰幨潜苊饬舜疟P(pán)的不斷尋道和旋轉(zhuǎn)次數(shù),極大的提高了寫(xiě)入性能。

順序?qū)懼饕獣?huì)應(yīng)用在存在大量磁盤(pán)I/O操作的場(chǎng)景,日常工作中創(chuàng)建mysql表時(shí)選擇自增主鍵,或者在進(jìn)行數(shù)據(jù)庫(kù)數(shù)據(jù)同步時(shí)順序讀寫(xiě)數(shù)據(jù),避免底層頁(yè)存儲(chǔ)引擎的數(shù)據(jù)頁(yè)分裂,也會(huì)對(duì)寫(xiě)入性能有一定的提升。

7.分片化

redis對(duì)于命令的執(zhí)行過(guò)程是單線(xiàn)程的,單機(jī)有著很好的讀寫(xiě)性能,但是單機(jī)的機(jī)器容量跟連接數(shù)畢竟有限,因此單機(jī)redis必然會(huì)存在讀寫(xiě)上限跟存儲(chǔ)上限。redis集群的出現(xiàn)就是為了解決單機(jī)redis的讀寫(xiě)性能瓶頸問(wèn)題,redis集群是將數(shù)據(jù)自動(dòng)分片到多個(gè)節(jié)點(diǎn)上,每個(gè)節(jié)點(diǎn)負(fù)責(zé)數(shù)據(jù)的一部分,每個(gè)節(jié)點(diǎn)都可以對(duì)外提供服務(wù),突破單機(jī)redis存儲(chǔ)限制跟讀寫(xiě)上限,提高整個(gè)服務(wù)的高并發(fā)能力。除了官方推出的集群模式,代理模式codis等也是將數(shù)據(jù)分片到不同節(jié)點(diǎn),codis將多個(gè)完全獨(dú)立的redis節(jié)點(diǎn)組成集群,通過(guò)codis轉(zhuǎn)發(fā)請(qǐng)求到某一節(jié)點(diǎn),來(lái)提高服務(wù)存儲(chǔ)能力和讀寫(xiě)性能。

同樣的kafka中每個(gè)topic也支持多個(gè)partition,partition分布到多個(gè)broker上,減輕單臺(tái)機(jī)器的讀寫(xiě)壓力,通過(guò)增加partition數(shù)量可以增加消費(fèi)者并行消費(fèi)消息,提高kafka的水平擴(kuò)展能力和吞吐量。

新聞每日會(huì)生產(chǎn)大量的圖文跟視頻數(shù)據(jù),底層是通過(guò)tdsql存儲(chǔ),可以分采分片化的存儲(chǔ)思想,將圖文跟視頻或者其他介質(zhì)存儲(chǔ)到不同的數(shù)據(jù)庫(kù)或者數(shù)據(jù)表中,同一種介質(zhì)每日的生產(chǎn)量也會(huì)很大,這時(shí)候就可以對(duì)同一種介質(zhì)拆分成多個(gè)數(shù)據(jù)表,進(jìn)一步提高數(shù)據(jù)庫(kù)的存儲(chǔ)量跟吞吐量。另外一種角度去優(yōu)化存儲(chǔ)還可以將冷熱數(shù)據(jù)分離,最新的數(shù)據(jù)采用性能好的機(jī)器存儲(chǔ),之前老數(shù)據(jù)訪問(wèn)量低,采用性能差的機(jī)器存儲(chǔ),節(jié)省成本。

在微服務(wù)重構(gòu)過(guò)程中,需要進(jìn)行數(shù)據(jù)同步,將總庫(kù)中存儲(chǔ)的全量數(shù)據(jù)通過(guò)kafka同步到內(nèi)容微服務(wù)新的存儲(chǔ)中,預(yù)期同步qps高達(dá)15k。由于kafka的每個(gè)partition只能通過(guò)一個(gè)消費(fèi)者消費(fèi),要達(dá)到預(yù)期qps,因此需要?jiǎng)?chuàng)建750+partition才能夠?qū)崿F(xiàn),但是kafka的partition過(guò)多會(huì)導(dǎo)致rebalance很慢,影響服務(wù)性能,成本和可維護(hù)行都不高。采用分片化的思想,可以將同一個(gè)partition中的數(shù)據(jù),通過(guò)一個(gè)消費(fèi)者在內(nèi)存中分片到多個(gè)channel上,不同的channel對(duì)應(yīng)的獨(dú)立協(xié)程進(jìn)行消費(fèi),多協(xié)程并發(fā)處理消息提高消費(fèi)速度,消費(fèi)成功后寫(xiě)入到對(duì)應(yīng)的成功channel,由統(tǒng)一的offsetMaker線(xiàn)程消費(fèi)成功消息進(jìn)行offset提交,保證消息消費(fèi)的可靠性。

避免請(qǐng)求

為提升寫(xiě)入性能,mysql在寫(xiě)入數(shù)據(jù)的時(shí)候,對(duì)于在bufferpool中的數(shù)據(jù)頁(yè),直接修改bufferpool的數(shù)據(jù)頁(yè)并寫(xiě)redolog;對(duì)于不在內(nèi)存中的數(shù)據(jù)頁(yè)并不會(huì)立刻將磁盤(pán)中的數(shù)據(jù)頁(yè)加載到bufferpool中,而是僅僅將變更記錄在緩沖區(qū),等后續(xù)讀取磁盤(pán)上的數(shù)據(jù)頁(yè)到bufferpool中時(shí)會(huì)進(jìn)行數(shù)據(jù)合并,需要注意的是對(duì)于非唯一索引才會(huì)采用這種方式,對(duì)于唯一索引寫(xiě)入的時(shí)候需要每次都將磁盤(pán)上的數(shù)據(jù)讀取到bufferpool才能判斷該數(shù)據(jù)是否已存在,對(duì)于已存在的數(shù)據(jù)會(huì)返回插入失敗。

另外mysql查詢(xún)例如select * from table where name = 'xiaoming' 的查詢(xún),如果name字段存在二級(jí)索引,由于這個(gè)查詢(xún)是*,表示需要所在行的所有字段,需要進(jìn)行回表操作,如果僅需要id和name字段,可以將查詢(xún)語(yǔ)句改為select id , name from tabler where name = 'xiaoming' ,這樣只需要在name這個(gè)二級(jí)索引上就可以查到所需數(shù)據(jù),避免回表操作,減少一次I/O,提升查詢(xún)速度。

web應(yīng)用中可以使用緩存、合并css和js文件等,避免或者減少http請(qǐng)求,提升頁(yè)面加載速度跟用戶(hù)體驗(yàn)。

在日常移動(dòng)端開(kāi)發(fā)應(yīng)用中,對(duì)于多tab的數(shù)據(jù),可以采用懶加載的方式,只有用戶(hù)切換到新的tab之后才會(huì)發(fā)起請(qǐng)求,避免很多無(wú)用請(qǐng)求。服務(wù)端開(kāi)發(fā)隨著版本的迭代,有些功能字段端上已經(jīng)不展示,但是服務(wù)端依然會(huì)返回?cái)?shù)據(jù)字段,對(duì)于這些不需要的數(shù)據(jù)字段可以從數(shù)據(jù)源獲取上就做下線(xiàn)處理,避免無(wú)用請(qǐng)求。另外在數(shù)據(jù)獲取時(shí)可以對(duì)請(qǐng)求參數(shù)的合法性做準(zhǔn)確的校驗(yàn),例如請(qǐng)求投票信息時(shí),運(yùn)營(yíng)配置的投票ID可能是“” 或者“0”這種不合法參數(shù),如果對(duì)請(qǐng)求參數(shù)不進(jìn)行校驗(yàn),可能會(huì)存在很多無(wú)用I/O請(qǐng)求。另外在函數(shù)入口處通常會(huì)請(qǐng)求用戶(hù)的所有實(shí)驗(yàn)參數(shù),只有在實(shí)驗(yàn)期間才會(huì)用到實(shí)驗(yàn)參數(shù),在實(shí)驗(yàn)下線(xiàn)后并沒(méi)有下線(xiàn)ab實(shí)驗(yàn)平臺(tái)的請(qǐng)求,可以在非實(shí)驗(yàn)期間下線(xiàn)這部分請(qǐng)求,提升接口響應(yīng)速度。

8.池化

golang作為現(xiàn)代原生支持高并發(fā)的語(yǔ)言,池化技術(shù)在它的GMP模型就存在很大的應(yīng)用。對(duì)于goroutine的銷(xiāo)毀就不是用完直接銷(xiāo)毀,而是放到P的本地空閑隊(duì)列中,當(dāng)下次需要?jiǎng)?chuàng)建G的時(shí)候會(huì)從空閑隊(duì)列中直接取一個(gè)G復(fù)用即可;同樣的對(duì)于M的創(chuàng)建跟銷(xiāo)毀也是優(yōu)先從全局隊(duì)列中獲取或者釋放。此外golang中sync.pool可以用來(lái)保存被重復(fù)使用的對(duì)象,避免反復(fù)創(chuàng)建和銷(xiāo)毀對(duì)象帶來(lái)的消耗以及減輕gc壓力。

mysql等數(shù)據(jù)庫(kù)也都提供連接池,可以預(yù)先創(chuàng)建一定數(shù)量的連接用于處理數(shù)據(jù)庫(kù)請(qǐng)求。當(dāng)請(qǐng)求到來(lái)時(shí),可以從連接池中選擇空閑連接來(lái)處理請(qǐng)求,請(qǐng)求結(jié)束后將連接歸還到連接池中,避免連接創(chuàng)建和銷(xiāo)毀帶來(lái)的開(kāi)銷(xiāo),提升數(shù)據(jù)庫(kù)性能。

在日常工作中可以創(chuàng)建線(xiàn)程池用來(lái)處理請(qǐng)求,在請(qǐng)求到來(lái)時(shí)同樣的從鏈接池中選擇空閑的線(xiàn)程來(lái)處理請(qǐng)求,處理結(jié)束后歸還到線(xiàn)程池中,避免線(xiàn)程創(chuàng)建帶來(lái)的消耗,在web框架等需要高并發(fā)的場(chǎng)景下非常常見(jiàn)。

9.異步處理

異步處理在數(shù)據(jù)庫(kù)中同樣應(yīng)用廣泛,例如redis的bgsave,bgrewriteof就是分別用來(lái)異步保存RDB跟AOF文件的命令,bgsave執(zhí)行后會(huì)立刻返回成功,主線(xiàn)程fork出一個(gè)線(xiàn)程用來(lái)將內(nèi)存中數(shù)據(jù)生成快照保存到磁盤(pán),而主線(xiàn)程繼續(xù)執(zhí)行客戶(hù)端命令;redis刪除key的方式有del跟unlink兩種,對(duì)于del命令是同步刪除,直接釋放內(nèi)存,當(dāng)遇到大key時(shí),刪除操作會(huì)讓redis出現(xiàn)卡頓的問(wèn)題,而unlink是異步刪除的方式,執(zhí)行后對(duì)于key只做不可達(dá)的標(biāo)識(shí),對(duì)于內(nèi)存的回收由異步線(xiàn)程回收,不阻塞主線(xiàn)程。

mysql的主從同步支持異步復(fù)制、同步復(fù)制跟半同步復(fù)制。異步復(fù)制是指主庫(kù)執(zhí)行完提交的事務(wù)后立刻將結(jié)果返回給客戶(hù)端,并不關(guān)心從庫(kù)是否已經(jīng)同步了數(shù)據(jù);同步復(fù)制是指主庫(kù)執(zhí)行完提交的事務(wù),所有的從庫(kù)都執(zhí)行了該事務(wù)才將結(jié)果返回給客戶(hù)端;半同步復(fù)制指主庫(kù)執(zhí)行完后,至少一個(gè)從庫(kù)接收并執(zhí)行了事務(wù)才返回給客戶(hù)端。有多種主要是因?yàn)楫惒綇?fù)制客戶(hù)端寫(xiě)入性能高,但是存在丟數(shù)據(jù)的風(fēng)險(xiǎn),在數(shù)據(jù)一致性要求不高的場(chǎng)景下可以采用,同步方式寫(xiě)入性能差,適合在數(shù)據(jù)一致性要求高的場(chǎng)景使用。    此外對(duì)于kafka的生產(chǎn)者跟消費(fèi)者都可以采用異步的方式進(jìn)行發(fā)送跟消費(fèi)消息,但是采用異步的方式有可能會(huì)導(dǎo)致出現(xiàn)丟消息的問(wèn)題。對(duì)于異步發(fā)送消息可以采用帶有回調(diào)函數(shù)的方式,當(dāng)發(fā)送失敗后通過(guò)回調(diào)函數(shù)進(jìn)行感知,后續(xù)進(jìn)行消息補(bǔ)償。

在做服務(wù)性能優(yōu)化中,發(fā)現(xiàn)之前的一些監(jiān)控上報(bào),曝光上報(bào)等操作都在主流程中,可以將這部分功能做異步處理,降低接口的時(shí)延。此外用戶(hù)發(fā)布新聞后,會(huì)將新聞寫(xiě)入到個(gè)人頁(yè)索引,對(duì)圖片進(jìn)行加工處理,標(biāo)題進(jìn)行審核,或者給用戶(hù)增加活動(dòng)積分等操作,都可以采用異步處理,這里的異步處理是將發(fā)送消息這個(gè)動(dòng)作發(fā)送消息到消息隊(duì)列中,不同的場(chǎng)景消費(fèi)消息隊(duì)列中的消息進(jìn)行各自邏輯的處理,這種設(shè)計(jì)保證了寫(xiě)入性能,也解耦不同場(chǎng)景業(yè)務(wù)邏輯,提高系統(tǒng)可維護(hù)性。

總結(jié)

本文主要總結(jié)進(jìn)行服務(wù)性能優(yōu)化的幾種方式,每一種方式在我們常用的中間件中都有所體現(xiàn),我想這也是我們常說(shuō)多學(xué)習(xí)這些中間件的意義,學(xué)習(xí)它們不僅僅是學(xué)會(huì)如何去使用它們,也是學(xué)習(xí)它們底層優(yōu)秀的設(shè)計(jì)思想,理解為什么要這樣設(shè)計(jì),這種設(shè)計(jì)有什么好處,后續(xù)我們?cè)诩軜?gòu)選型或者做服務(wù)性能優(yōu)化時(shí)都會(huì)有一定的幫助。此外性能優(yōu)化方式也給出了具體的落地實(shí)踐,

希望通過(guò)實(shí)際的應(yīng)用例子加強(qiáng)對(duì)這種優(yōu)化方式的理解。此外要做服務(wù)性能優(yōu)化,還是要從自身服務(wù)架構(gòu)出發(fā),分析服務(wù)調(diào)用鏈耗時(shí)分布跟cpu消耗,優(yōu)化有問(wèn)題的rpc調(diào)用和函數(shù)。

責(zé)任編輯:趙寧寧 來(lái)源: 騰訊技術(shù)工程
相關(guān)推薦

2010-04-22 17:27:22

Oracle性能

2016-08-24 16:23:36

服務(wù)架構(gòu)

2022-02-16 14:10:51

服務(wù)器性能優(yōu)化Linux

2021-11-29 11:13:45

服務(wù)器網(wǎng)絡(luò)性能

2017-02-05 17:33:59

前端優(yōu)化Web性能

2011-07-03 19:58:34

SEO

2024-06-05 11:29:54

微服務(wù)監(jiān)控工具

2010-07-26 16:35:34

Perl性能

2024-08-06 16:31:32

2010-07-26 12:50:45

Perl性能

2023-11-18 19:46:07

GPU架構(gòu)

2022-05-05 09:27:31

Linux服務(wù)器優(yōu)化

2022-09-26 09:19:38

服務(wù)器優(yōu)化

2023-07-13 17:05:33

物聯(lián)網(wǎng)物聯(lián)網(wǎng)設(shè)備

2025-02-20 09:27:46

2014-10-28 16:11:37

AndroidApp性能優(yōu)化

2017-06-22 08:58:06

2023-10-17 14:35:22

人工智能AI

2011-08-01 10:49:12

服務(wù)器

2012-12-24 09:55:15

JavaJava WebJava優(yōu)化
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)