唯品會(huì)億級(jí)網(wǎng)關(guān)分享-語(yǔ)音轉(zhuǎn)文字版本

先說(shuō)標(biāo)題中的億級(jí)網(wǎng)關(guān),我的角度時(shí)用戶(hù)量是億級(jí),訪問(wèn)量按小時(shí)算是時(shí)百億級(jí)別以上,主要是api網(wǎng)關(guān),也做了老程序php反向代理,區(qū)別點(diǎn)為是否存在頁(yè)面,是否需要通配。

我們定位為:高性能,高可用,可擴(kuò)展,可管理,可治理,安全的網(wǎng)關(guān)產(chǎn)品,作為唯品會(huì)所有流量的入口
網(wǎng)關(guān)價(jià)值:所有中心化控制點(diǎn)都可以統(tǒng)一控制

我們底層技術(shù)選型從servlet到akka到netty,servlet就跳過(guò),底層性能模型差太多

線(xiàn)程模型使用netty的boss worker,目前所有業(yè)務(wù)的處理由于不會(huì)阻塞住worker線(xiàn)程,都跑在worker上。

目前性能數(shù)據(jù)為在12核的機(jī)器上,1k payload大小的請(qǐng)求http請(qǐng)求,后端服務(wù)為rpc為9萬(wàn) http為7萬(wàn)多。瓶頸在cpu上
線(xiàn)程模型,我們進(jìn)一步合并了后端請(qǐng)求調(diào)用的woker線(xiàn)程池跟接受請(qǐng)求線(xiàn)程池,考慮連接池可以讓一個(gè)請(qǐng)求的worker線(xiàn)程處理,跟發(fā)送到后端的請(qǐng)求線(xiàn)程處理在一個(gè)worker上,這樣性能會(huì)提高8%-10%,因?yàn)樯倭艘淮吻袚Q。

比如說(shuō)是http到http, 后端http的話(huà)就是一個(gè)連接池,拿連接的時(shí)候,怎么判斷拿連接就是當(dāng)前線(xiàn)程所在的連接,很多連接就可能分在不同的worker上,需要一個(gè)標(biāo)志位,這個(gè)標(biāo)志位可能可以選擇線(xiàn)程ID或者是線(xiàn)程特點(diǎn)的一個(gè)東西去做一個(gè)標(biāo)志位,優(yōu)先拿這個(gè),如果沒(méi)有我再去拿其他的。也看你的模型,http這種非雙工到后端會(huì)需要連接數(shù),可以均勻的分在這個(gè)24個(gè)模塊線(xiàn)程上. 如果是rpc,可能一兩條連接打天下,就需要盡量不切換或者多創(chuàng)建連接的代價(jià)達(dá)到不切換。

插件化方式需要不在worker線(xiàn)程上運(yùn)行,做到隔離問(wèn)題不影響,包含類(lèi)的隔離與線(xiàn)程池隔離,目前想采用共享線(xiàn)程池+獨(dú)立線(xiàn)程池分配模式,先使用共享,沒(méi)有可用則獨(dú)立使用一個(gè)小的線(xiàn)程池。

netty這塊來(lái)調(diào)優(yōu)實(shí)踐
除了worker線(xiàn)程切換的優(yōu)化,線(xiàn)程安全與共享的方式做了一些事,可以讓非安全的代碼在線(xiàn)程內(nèi)共享,類(lèi)似threadlocal,但我們用的netty的fastthreadlocal,更快更好,底層用的是數(shù)組,而且減少了對(duì)象的創(chuàng)建,服用了對(duì)象對(duì)gc也更友好
netty里比如stringbuild等都這么共享使用,我們代碼用到也是直接參考netty的用法。

netty有一個(gè)平臺(tái)類(lèi),可以直接使用,由于我們是jdk7,用這個(gè)netty copy了jdk8采有的一些類(lèi),比如hashmap的優(yōu)化,可以直接用,包括包含mpsc這類(lèi)

整個(gè)網(wǎng)關(guān)不會(huì)出現(xiàn)任何一處有鎖或者有卡的問(wèn)題,日志也是全異步,如果一定有鎖,比如說(shuō)我涉及到一些多個(gè)線(xiàn)程去做共享狀態(tài)改變,那我們就有準(zhǔn)確性的問(wèn)題,要求必須準(zhǔn)確,盡量通cas的方式來(lái)搞定,而不是說(shuō)強(qiáng)行加鎖,是不會(huì)做一個(gè)強(qiáng)行加鎖,通常用自旋方式來(lái)把這一塊解決掉,整個(gè)性能是比較好的。

使用netty的native epoll 性能更優(yōu),只需要很簡(jiǎn)單的更改幾個(gè)類(lèi)名就可以。
這塊性能話(huà)我們測(cè)下來(lái)其實(shí)是有一個(gè)提升的,就是CPU會(huì)稍微低一點(diǎn)點(diǎn),性能沒(méi)有太明顯,就CPU稍微比平時(shí)負(fù)載會(huì)低一點(diǎn)。

bytebuf的問(wèn)題。netty在就是官方文檔當(dāng)時(shí)有幾種對(duì)比,但根據(jù)你使用場(chǎng)景可以自己跑一下,比如你需要解包并且轉(zhuǎn)換所有包內(nèi)容,那么堆外不一定有優(yōu)勢(shì)。我們是混合場(chǎng)景,選擇堆外。
boss線(xiàn)程數(shù)根據(jù)端口數(shù)決定,我們只監(jiān)聽(tīng)一個(gè),不需要設(shè)置cpu的一半,走這個(gè)到處都有的最佳實(shí)踐。當(dāng)然如果你設(shè)置一半,其實(shí)也不會(huì)用到,這個(gè)可以看netty源碼邏輯。

就netty我我們目前的話(huà)大部分都是說(shuō) 拿到完整的http做業(yè)務(wù)處理,但是我們其實(shí)有很多可以前置,不需要解析完整的http。比如說(shuō),我們的通常是一次請(qǐng)求,或者是我們的一些非法請(qǐng)求,包括限流防刷這種非法的教練,我們其實(shí)只需要根據(jù)ITP的一個(gè)請(qǐng)求函和請(qǐng)求頭,我們就可以做一個(gè)判斷,并不需要把它完整地拆包,我們就可以提前判斷。這塊呢就需要我們把netty的這塊http的解析重寫(xiě),netty本身對(duì)http是一個(gè)狀態(tài)機(jī)的方式解析。

就說(shuō)我們通常在做優(yōu)化的時(shí)候,你到底優(yōu)化哪個(gè)代碼,是去一段段扣代碼還是怎么弄,我覺(jué)得還是不要扣代碼,扣代碼這個(gè)價(jià)值點(diǎn)很難找,就是說(shuō)你可能覺(jué)得這塊可能是不是怎么樣更好,我是利用一個(gè)string拼,然后我如果換一個(gè)方式是不是性能更好?可能效果并不是那么明顯。
還是盡量用工具,用工具從系統(tǒng)底層到整個(gè)jvm部分最好是能貫通起來(lái),貫通起來(lái)也方便于排查問(wèn)題。整個(gè)如果把這塊是從系統(tǒng)底層到j(luò)vm層,整個(gè)通了之后,你排查問(wèn)題的速度也比較快,然后定位問(wèn)題比較快。
比如說(shuō)火焰圖,我們跑其實(shí)是會(huì)跑到火焰圖數(shù)據(jù)的。我們性能測(cè)試是會(huì)看一下跑出來(lái)的是不是符合我們的預(yù)期。第一個(gè)就是說(shuō)系統(tǒng)函數(shù)底層的調(diào)動(dòng)是否符合我們的預(yù)期,系統(tǒng)上的一個(gè)開(kāi)銷(xiāo),然后到j(luò)vm方法棧上的一個(gè)消耗,這塊比如說(shuō)比較簡(jiǎn)單的作用,谷歌的火焰圖這個(gè)工具,netfilx火焰圖的生成,jvm上就得采樣,就你可以設(shè)置采樣頻率,,采樣下來(lái)之后會(huì)拿會(huì)拿到一個(gè)詳細(xì)的一個(gè)圖。

就會(huì)看到我們整個(gè)網(wǎng)關(guān)跑出來(lái)一個(gè)結(jié)果,當(dāng)然這里面又有細(xì)節(jié),怎么看火焰圖的問(wèn)題了,快速識(shí)別一些性能問(wèn)題。
下面還有java 自帶。最近不是這個(gè)jmc比較火嘛,就說(shuō)這jmc開(kāi)源之后把團(tuán)隊(duì)給裁了。就是jmc這塊自帶的一個(gè)分析工具,他其實(shí)也會(huì)到一個(gè)消耗,是整個(gè)的一個(gè)方法調(diào)用,你會(huì)看到哪一塊消耗CPU比較多,但JMC的話(huà)是覺(jué)得沒(méi)有火焰圖這么比較直觀點(diǎn),看你分析哪些問(wèn)題,各有特點(diǎn)?;鹧鎴D可能就更多的在系統(tǒng)函數(shù)上,jvm都可以做到就是整個(gè)都可以看到整個(gè)。

剩下就說(shuō)我在寫(xiě)代碼的時(shí)候,比如說(shuō)一個(gè)選擇,比如說(shuō)上周的一個(gè)例子,就是我們?cè)谧鲞@種base64的一個(gè)轉(zhuǎn)碼的過(guò)程當(dāng)中,我們可能一些特殊需求需要轉(zhuǎn),那我現(xiàn)在有這么多工具類(lèi),那我到底用哪個(gè)工具的性能更好呢?我們通常做法是寫(xiě)一個(gè)單元測(cè)試來(lái)跑一下、測(cè)一下,但是這種單元測(cè)試很不可靠,因?yàn)檫@種單元測(cè)試跟最終你去jvm運(yùn)行跑代碼其實(shí)區(qū)別還是很大,首先他會(huì)沒(méi)有去做編譯優(yōu)化,有很多問(wèn)題。
java官方也是推薦直接基準(zhǔn)測(cè)試,用基準(zhǔn)測(cè)試來(lái)測(cè)它到底性能怎么樣,但是這種基準(zhǔn)測(cè)試寫(xiě)的話(huà),最好去把官方的demo讀一遍,它里面其實(shí)有很多坑,比如說(shuō)你很容易寫(xiě)一個(gè)for循環(huán)在里面,for循環(huán)還很容易被優(yōu)化掉。 還有就是你解決測(cè)試的時(shí)候,其實(shí)最后值并不返回,他去跑的時(shí)候就會(huì)把優(yōu)化掉,
系統(tǒng)就會(huì)去跑一塊代碼,就認(rèn)為最后這個(gè)值根本沒(méi)有用到,沒(méi)用到優(yōu)化就全部蓋掉,全部蓋掉之后,跑出來(lái)你會(huì)發(fā)現(xiàn)系統(tǒng)數(shù)據(jù)很好,但是實(shí)際并不是這個(gè)樣子。所以的話(huà)這塊有很多坑,寫(xiě)他之前最好去把官方的demo通讀一遍,會(huì)避免很多東西,他的demo也比較詳盡,避免很多錯(cuò)誤的一個(gè)寫(xiě)法。我后面附了一個(gè)日常的demo吧,這可能就是上周我們跑64的一個(gè)demo寫(xiě)的。比如剛才的坑,就說(shuō)明這樣去運(yùn)行的時(shí)候,其實(shí)并沒(méi)有返回就不會(huì)處理,它其實(shí)提供一種方式上處理,就是你把它消費(fèi)掉,這塊的話(huà)會(huì)跑一個(gè)性能數(shù)據(jù)出來(lái),最終結(jié)果會(huì)是這樣的一個(gè)情況。 這樣話(huà)就會(huì)看到那到底選擇哪一個(gè)比較好,比如說(shuō)我們每秒的調(diào)動(dòng)次數(shù),那可能下來(lái)發(fā)現(xiàn)確實(shí)JDK8自帶的這個(gè)性能比較好一點(diǎn)。

下面聊到這個(gè)GC優(yōu)化與排查。Gc優(yōu)化,其實(shí)對(duì)網(wǎng)關(guān)來(lái)說(shuō)很難容忍這個(gè)gc問(wèn)題,因?yàn)樘貏e是高并發(fā)的情況下,比如說(shuō)在上做促銷(xiāo)的時(shí)候,流量很大的情況下,由于網(wǎng)關(guān)發(fā)生gc導(dǎo)致整個(gè)超時(shí)了是很大一個(gè)問(wèn)題,所以我們?cè)趃c上盡量控制頻率,我們大概現(xiàn)在的情況下是我們能控制到是說(shuō)一個(gè)月一次cms gc,但是要想網(wǎng)關(guān)其實(shí)流量很大,每天都有流量過(guò)來(lái),這種大促、更別說(shuō)這種搶購(gòu)之類(lèi)導(dǎo)致的一些流量。所以我們?cè)谶@塊做了很多一些優(yōu)化,就是整個(gè)控制它的一個(gè)頻率,后面會(huì)講到。
然后的話(huà)是我們一些常見(jiàn)的踩坑的問(wèn)題,比如說(shuō)我們會(huì)遇到這種熔斷、指標(biāo)統(tǒng)計(jì)上的一個(gè)踩坑。這可能這一塊的話(huà),比如說(shuō)熔斷分方法的熔斷和服務(wù)器的。大家都知道壟斷會(huì)要寫(xiě)這個(gè)計(jì)數(shù)器,計(jì)數(shù)器我們可能要統(tǒng)計(jì)容納多少秒內(nèi)失敗次數(shù)等于多少的話(huà),比如說(shuō)我定義是十秒內(nèi)失敗次數(shù)——請(qǐng)求數(shù)(就有幾個(gè)維度)請(qǐng)求十次,十秒內(nèi)連續(xù)失敗,或者按幾個(gè)維度來(lái)吧,失敗率是60%,我就認(rèn)為這個(gè)服務(wù)不好,應(yīng)該壟斷。
這樣的話(huà)就會(huì)導(dǎo)致我們其實(shí)會(huì)去統(tǒng)計(jì)很多這種指標(biāo),這種指標(biāo)就會(huì)帶來(lái)一個(gè)問(wèn)題,就是說(shuō)我們的統(tǒng)計(jì)量太大。比如說(shuō)我們當(dāng)時(shí)是API網(wǎng)關(guān)其實(shí)就是一個(gè)一個(gè)API沒(méi)有什么問(wèn)題,但我們現(xiàn)在反向代理就會(huì)帶來(lái)這個(gè)問(wèn)題,因?yàn)榉聪虼砩婕耙粋€(gè)通配,后面的這個(gè)方法很多,所以這個(gè)帶來(lái)問(wèn)題就是熔斷上統(tǒng)計(jì)會(huì)導(dǎo)致我們內(nèi)存的一個(gè)爆掉。指標(biāo)統(tǒng)計(jì)這個(gè)容量上,也是反向代理的時(shí)候也會(huì)遇到一個(gè)問(wèn)題,因?yàn)槲覀兤鋵?shí)請(qǐng)求的url是很多的,無(wú)數(shù)的url過(guò)來(lái),我們?nèi)ソy(tǒng)計(jì)的話(huà),最后遇到這個(gè)問(wèn)題,我們通常會(huì)統(tǒng)計(jì)1秒鐘、10秒鐘這種各種的一個(gè)指標(biāo),或者說(shuō)1分鐘5分鐘,這種都會(huì)帶來(lái)一個(gè)問(wèn)題。
包括這塊順帶再說(shuō)一下kafka,包括我們用到kafka,這個(gè)坑是跳不過(guò)去的,原生代碼里面自帶的這個(gè)采樣,采樣的話(huà)他會(huì)統(tǒng)計(jì)1分鐘5分鐘15分鐘,但是我們網(wǎng)關(guān)流量很大的情況下,這個(gè)根據(jù)jvm的一個(gè)原理,就是說(shuō)我肯定首先對(duì)象進(jìn)入這個(gè)年輕帶,他年輕帶里面就是倒騰幾次,就老年代。流量很大,我們這塊這ygc就會(huì)特別頻繁,他就很快進(jìn)入老年代,但很快進(jìn)入老年代,就會(huì)帶來(lái)這個(gè)問(wèn)題。
那就就相當(dāng)于它的統(tǒng)計(jì)指標(biāo)全部在老年代堆積。堆積之后,關(guān)鍵是它采樣就說(shuō),可能我采樣指標(biāo)是1分鐘5分鐘15分鐘,old區(qū)直線(xiàn)增長(zhǎng),就會(huì)觸發(fā)我們的cms gc,這塊我們最后的一個(gè)時(shí)間我們就直接把這塊代碼干掉,因?yàn)槲覀兤鋵?shí)沒(méi)有辦法統(tǒng)計(jì)資料,不用統(tǒng)計(jì)指標(biāo),我們不想它這個(gè)給我們帶來(lái)的問(wèn)題

這塊也是old區(qū)的一個(gè)問(wèn)題,就是說(shuō)我們當(dāng)時(shí)之前是15天左右發(fā)生一次,上線(xiàn)之后發(fā)現(xiàn)每天穩(wěn)定增長(zhǎng)400兆,就去排查這個(gè)問(wèn)題,反查發(fā)現(xiàn)kafka的一個(gè)問(wèn)題,反查之后發(fā)現(xiàn)里面有數(shù)據(jù)結(jié)構(gòu)里面有個(gè)跳表,我們反查了一下代碼發(fā)現(xiàn)只有kafka在用,然后這塊就跟蹤到kafka,因?yàn)橐呀?jīng)找到這個(gè)到底是誰(shuí)關(guān)聯(lián)它。這個(gè)反查到了之后發(fā)現(xiàn)是kafka的問(wèn)題,我們做了一個(gè)空實(shí)驗(yàn)之后,發(fā)現(xiàn)這個(gè)其實(shí)問(wèn)題就解決掉,就回到我們?cè)饶莻€(gè)頻率上。
說(shuō)到這個(gè)日志,我們剛才說(shuō)的日志其實(shí)是權(quán)益部的一個(gè)輸出日志,這塊我們是按log4j2的一個(gè)方式處理,就是二點(diǎn)幾的版本,但我們?cè)谟玫臅r(shí)候2.6還沒(méi)出來(lái),但是后面2.6出來(lái)是很推薦大家試一下,因?yàn)檫@塊還做什么gc優(yōu)化,它號(hào)稱(chēng)是減少了很多gc問(wèn)題,我們測(cè)下來(lái)也是基本上gc耗時(shí)也會(huì)有明顯的一個(gè)降低。

這一塊的話(huà)是說(shuō)我們當(dāng)時(shí)上線(xiàn)的時(shí)候,我們其實(shí)沒(méi)有設(shè)cms gc到底什么時(shí)候觸發(fā)的,比如說(shuō)都是區(qū),可能通常大家會(huì)設(shè)置到說(shuō)75%就觸發(fā)了,然后不設(shè)置,我們覺(jué)得這塊讓jvm去做可能更好一點(diǎn),就說(shuō)我們不知道什么時(shí)候觸發(fā)是合理值,既然我們不知道就讓jvm來(lái)自己來(lái)做自己來(lái)做動(dòng)態(tài)調(diào)整。但發(fā)現(xiàn)一個(gè)問(wèn)題,就是現(xiàn)網(wǎng)上的資料都說(shuō),包括我們?nèi)プx這個(gè)幾本jvm的書(shū),他們也都會(huì)說(shuō),這個(gè)JDK你不設(shè)的話(huà),它默認(rèn)是68%處發(fā)這個(gè)cms到我線(xiàn)上上線(xiàn)之后發(fā)現(xiàn)并不是什么,我們92%才觸發(fā),我們就看一下我們jdk的一個(gè)版本,我們版本是7,我們就拿了一個(gè)open jdk的原代碼,就算了一下,算出來(lái),確實(shí)是92%出發(fā)。
這塊我舉這個(gè)例子意思說(shuō),看到這種問(wèn)題,其實(shí)通過(guò)這個(gè)代碼是很容易找的,我們直接可以對(duì)你的jdk版本拉下來(lái)之后去找,并不需要去相信說(shuō)我去查各種資料,發(fā)現(xiàn)沒(méi)有,到底是多少觸發(fā),這塊直接代碼里面很明顯,其實(shí)也不復(fù)雜,就是雖然說(shuō)C++這種代碼,那我們其實(shí)只是從去找一些這種配置的話(huà),就很很容易快速識(shí)別的。代碼里面是沒(méi)有秘密的。

還有一個(gè)問(wèn)題就是說(shuō)高io導(dǎo)致jvm停頓的問(wèn)題,這種測(cè)試會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,說(shuō)我們?cè)谶B續(xù)壓測(cè)大概四五個(gè)小時(shí),就會(huì)發(fā)現(xiàn)我們的有些四個(gè)9的數(shù)據(jù),可能不上網(wǎng)看,四個(gè)9的數(shù)據(jù),可能會(huì)出現(xiàn)有一秒增加,其實(shí)我們大部分時(shí)間都是在一毫秒的一個(gè)范圍,但是發(fā)現(xiàn)有四個(gè)9會(huì)有一種一秒的特別長(zhǎng)的一個(gè)時(shí)間,覺(jué)得這可能是一個(gè)問(wèn)題,我們線(xiàn)上會(huì)這種其實(shí)不太能接受的,我們線(xiàn)上基本上時(shí)間都是經(jīng)過(guò)網(wǎng)絡(luò)的一個(gè)調(diào)動(dòng)后端返回這個(gè)時(shí)間,請(qǐng)求發(fā)起進(jìn)來(lái)出去的時(shí)間大概都在一兩毫秒。所以覺(jué)得這塊我們是不能接受這一點(diǎn),然后就去排查問(wèn)題,就發(fā)現(xiàn)這樣一個(gè)問(wèn)題說(shuō)高io導(dǎo)致jvm的停頓
一個(gè)是把gc日志并不直接放磁盤(pán)上,放在這里面放內(nèi)存文件系統(tǒng)上,然后必須加上這個(gè)參數(shù),因?yàn)閖vm在運(yùn)行,它會(huì)輸出、關(guān)聯(lián)操作好幾個(gè)文件,它有一個(gè)文件是你用一些jvm的命令做一些分析用的
后面我們就舉例子來(lái)講就做網(wǎng)關(guān)的時(shí)候,因?yàn)樽鲞@種對(duì)質(zhì)量要求比較高一點(diǎn)。因?yàn)槲覀冞@個(gè)承載的是一線(xiàn)流量,其實(shí)影響是非常大的,對(duì)性能也是要求很高,而且又涉及到我們這個(gè)改動(dòng)很頻繁。各種業(yè)務(wù)方可能有些需求點(diǎn)在我們這我們要去為他們做一些定制化的一些開(kāi)發(fā)。當(dāng)然可以用插件化來(lái)做,但是這塊其實(shí)有很多改動(dòng),所以就舉一些場(chǎng)景,到底應(yīng)該怎么做?
比如說(shuō)讓你來(lái)寫(xiě)網(wǎng)關(guān)的代碼你應(yīng)該考慮哪些點(diǎn)?比如說(shuō)我們通常做一些抽象,我們會(huì)用到一些通用技計(jì)數(shù)器,我們以這個(gè)場(chǎng)景來(lái)講,我們要去做一些考慮。這也是拿我們平時(shí)遇到一個(gè)點(diǎn)來(lái)發(fā)散的講,就說(shuō)網(wǎng)關(guān)到底哪些問(wèn)題?
我們通常會(huì)用一個(gè)通用計(jì)數(shù)器這種東西,因?yàn)槲覀儠?huì)做很多計(jì)數(shù),比如說(shuō)我們限流,后端的服務(wù):我們要保護(hù)后端服務(wù)我們來(lái)做限流,再比如說(shuō)我們要做防刷,我們可能要根據(jù)ip或者根據(jù)session各個(gè)維度來(lái)做防刷,做成保護(hù)安全上的一個(gè)東西,或者有一些技術(shù)上的一些需求,比如說(shuō)是熔斷,它其實(shí)也是一個(gè)技術(shù)上的需求,這種技術(shù)啊我怎么來(lái)做的?
可能想比較簡(jiǎn)單,它就Java自帶的這個(gè)原子類(lèi)的這種cs,我就直接上面加就可以。其實(shí)也會(huì)有問(wèn)題,原子類(lèi)它的維度比較單一。來(lái)看這樣一個(gè)實(shí)現(xiàn),其實(shí)它這里面就有一個(gè)是計(jì)數(shù)的一個(gè)概念,還有一個(gè)時(shí)間的概念,這兩個(gè)概念我們就需要用時(shí)輪的方式來(lái)實(shí)現(xiàn)。那時(shí)間輪的方式就會(huì)帶來(lái)一個(gè)問(wèn)題,用時(shí)間輪的話(huà)我就要有一個(gè)清晰的概念在里面,包括時(shí)間輪怎么快速去查找,比如說(shuō)你看時(shí)間輪列表的話(huà),性能上一個(gè)問(wèn)題,包括考慮我用時(shí)間輪怎么去避免產(chǎn)生GC或者一系列的問(wèn)題。
我們這塊要實(shí)現(xiàn)一個(gè)滑動(dòng)窗口的一個(gè)時(shí)間輪。那就首先第一個(gè)就是選擇,到底是提前清理的話(huà),就使用時(shí)清理,提前清理怎么去清理這樣一個(gè)問(wèn)題。我們的最后選擇是說(shuō)我們使用時(shí)清理。

這樣一個(gè)統(tǒng)計(jì)的話(huà),那么實(shí)現(xiàn)上首先用數(shù)組去實(shí)現(xiàn),做對(duì)應(yīng)上的一個(gè)映射,數(shù)組里面的對(duì)象,但是這就涉及到我們要怎么去清理它?我們并不我們?nèi)绻苯蛹右话焰i去清理,比如說(shuō)我們每次去鎖住,它就是每個(gè)線(xiàn)程都會(huì)遇到這個(gè)鎖,這個(gè)性能會(huì)降很低。所以我們是用一個(gè)自旋鎖的方式,因?yàn)槲覀兤鋵?shí)是不停的請(qǐng)求進(jìn)來(lái),我們?nèi)プ孕涂梢粤?,自旋一下就可以,這塊時(shí)間的話(huà)性能是比較好的。
然后這塊還有一個(gè)問(wèn)題,就是說(shuō)那我們那JDK8在后面供應(yīng)對(duì)象是明顯的比前面這個(gè)cas一個(gè)原生對(duì)象性能高很多了,但為什么不用后面這個(gè),這就是一個(gè)內(nèi)存上的問(wèn)題。比如說(shuō)用前面說(shuō)用度量工具測(cè),測(cè)完之后發(fā)現(xiàn)前面完全滿(mǎn)足我們的需求,因?yàn)楹竺娴脑?huà)確實(shí)性能會(huì)好,但是后面的內(nèi)存又會(huì)高很多。大概在60萬(wàn)的對(duì)象,后面是45兆,前面是一點(diǎn)幾兆,就這種內(nèi)存上的一個(gè)對(duì)比,我們可能內(nèi)存上接受不了這個(gè)。
包括這種對(duì)象,我用完之后我要清理掉,對(duì)象清理掉之后,它就會(huì)帶來(lái)gc問(wèn)題,我這個(gè)對(duì)象已經(jīng)在新生代里面倒騰了幾次,因?yàn)榱髁亢艽?,容量很大的時(shí)候,我就不停的ygc。ygc幾次我就進(jìn)老年帶,那去的時(shí)候又會(huì)帶來(lái)老年代這個(gè)對(duì)象增加,清理掉,解除這個(gè)關(guān)聯(lián)關(guān)系之后,老一代又會(huì)直線(xiàn)增加,我們想控制1月一次的cms這個(gè)目標(biāo)給它很難達(dá)成了。所以這塊就是我們的作用這樣一個(gè)需求就有很多點(diǎn)需要考慮。
有相關(guān)的一些點(diǎn)考慮到之后,我們還要把它做成一個(gè)抽象工具,就是說(shuō)要用的話(huà),我們直接調(diào)就可以做,這些考慮點(diǎn)全部在里面,而并不是說(shuō)我們每個(gè)人去實(shí)現(xiàn)一套,
再說(shuō)一個(gè)非常有意思的一個(gè)GC場(chǎng)景,其實(shí)我們有些技術(shù)場(chǎng)景,我們會(huì)用到這種lru的方式我們?nèi)ソy(tǒng)計(jì),因?yàn)椴粔蛴谩1热缯f(shuō)我們要統(tǒng)計(jì)一些東西,我們只能用最近最常使用的一個(gè)算法去做,但是這就會(huì)帶來(lái)幾個(gè)問(wèn)題。我們?nèi)绻阉O(shè)置很大,準(zhǔn)確性倒是挺高的,準(zhǔn)確性提高了之后,GC問(wèn)題就來(lái)了,如果我設(shè)小了,但是又準(zhǔn)確性不夠,那我多小合適了,這個(gè)需要根據(jù)流量來(lái)。
這個(gè)問(wèn)題呢可以進(jìn)一步抽象,其實(shí)會(huì)帶來(lái)很多問(wèn)題,就是說(shuō)那這個(gè)問(wèn)題進(jìn)一步抽象到說(shuō)所有能熬過(guò)ygc到了老年帶,并且把它反復(fù)創(chuàng)建問(wèn)題解除,其實(shí)都會(huì)有這個(gè)老年帶增長(zhǎng)的一個(gè)問(wèn)題。
比如說(shuō)我們可能像廣泛的一些日常這種使用,如你在開(kāi)發(fā)日常代碼的話(huà),肯定會(huì)涉及到連接池,這是一個(gè)比較常見(jiàn)的例子。就說(shuō)你的連接池會(huì)設(shè)有一個(gè)共享連接,共享連接的話(huà),幾次ygc后也會(huì)進(jìn)入老年帶。進(jìn)入老年帶之后,會(huì)有配置一些參數(shù)去把這些共享連接給關(guān)掉動(dòng)態(tài)變化數(shù)量,檢查閑置連接啥的,會(huì)清理掉,這個(gè)對(duì)象就在老年帶里待著了。但是在老年帶里的連接數(shù)發(fā)現(xiàn)不夠又會(huì)去創(chuàng)建它,創(chuàng)建之后就會(huì),于是這個(gè)隨著流量不停的在老年帶里面創(chuàng)建對(duì)象,就會(huì)帶來(lái)這個(gè)問(wèn)題。

最后一點(diǎn)呢就是說(shuō)我們寫(xiě)了這么多代碼之后,發(fā)現(xiàn)一些規(guī)律性的東西,盡可能復(fù)用對(duì)象,盡快釋放對(duì)象。
如我們?cè)趧?chuàng)建一個(gè)對(duì)象的話(huà),能復(fù)用盡量復(fù)用,比如說(shuō)我們用了一些計(jì)數(shù)器,我們移除的時(shí)候,其實(shí)放在一個(gè)隊(duì)列上,我們要?jiǎng)?chuàng)建什么首先從隊(duì)列上去取。隊(duì)列沒(méi)有,我們?cè)儆靡粋€(gè)就是減少這種垃圾對(duì)象地方創(chuàng)建。

netty而且還是很有參考價(jià)值,如果你把源碼過(guò)一遍的話(huà),可能很有很多想象不到的點(diǎn),會(huì)對(duì)你有些價(jià)值。
盡量狀態(tài)無(wú)鎖,如果一定狀態(tài),先走共享。先走線(xiàn)程內(nèi)共享,就是模塊內(nèi)的一個(gè)共享,模塊的共享之后,如果說(shuō)發(fā)現(xiàn)還是解決不了問(wèn)題,那你沒(méi)辦法,你只能cas,那cas,我盡量選擇小的一把鎖,怎么小怎么來(lái),而并不是我加一把大的讀寫(xiě)鎖或者怎么樣,我可能做一個(gè)循環(huán)做一個(gè)自選鎖來(lái)做。
最后一點(diǎn),這里比較重要,就是說(shuō)在寫(xiě)作代碼,因?yàn)榫W(wǎng)關(guān)的代碼這塊,入口流量,如果有問(wèn)題會(huì)影響很?chē)?yán)重。當(dāng)然我們通過(guò)一些發(fā)布的方式可以避免,但這塊的話(huà)就是說(shuō)你在寫(xiě)的話(huà),盡量了解你代碼你寫(xiě)的每一行代碼背后的邏輯。里面內(nèi)部到底是怎么運(yùn)行,再用這種基準(zhǔn)測(cè)試去度量,度量你的代碼到底有多少的性能損耗,到底是怎樣的
我的這塊分享就完了!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 該文章為轉(zhuǎn)載,原文章請(qǐng)點(diǎn)擊 1. 背景 1.1. Netty 3.X系列版本現(xiàn)狀 根據(jù)對(duì)Netty社區(qū)部分用戶(hù)的調(diào)...
    Pramyness閱讀 2,155評(píng)論 1 14
  • 在一個(gè)方法內(nèi)部定義的變量都存儲(chǔ)在棧中,當(dāng)這個(gè)函數(shù)運(yùn)行結(jié)束后,其對(duì)應(yīng)的棧就會(huì)被回收,此時(shí),在其方法體中定義的變量將不...
    Y了個(gè)J閱讀 4,585評(píng)論 1 14
  • 遠(yuǎn)方 我眺望 你閃爍的光芒 讓我癡迷
    亦能飄零久閱讀 249評(píng)論 0 2
  • 出處:京東APP 亮點(diǎn):當(dāng)輸入期望價(jià)格時(shí),自動(dòng)關(guān)聯(lián)提示折扣力度。 應(yīng)用:點(diǎn)評(píng)管家APP,表單設(shè)置時(shí),可以借鑒這種設(shè)...
    令狐沖521閱讀 645評(píng)論 0 50
  • 一、2017年夢(mèng)想清單 [工作]: 1. 完成大學(xué)里的學(xué)習(xí)任務(wù),達(dá)到平均成績(jī)80%及以上 2.學(xué)習(xí)編程,基本掌握p...
    米哈_ab4c閱讀 238評(píng)論 1 0

友情鏈接更多精彩內(nèi)容