日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁(yè) > > 架構(gòu)師社區(qū)
[導(dǎo)讀]最近,因?yàn)樵黾恿艘恍╋L(fēng)控措施,導(dǎo)致新人拼團(tuán)訂單接口的QPS、TPS下降了約5%~10%,這還了得!

作者:浪漫先生

來(lái)源:uejin.im/post/6854573218322513933



# 前言


最近,因?yàn)樵黾恿艘恍╋L(fēng)控措施,導(dǎo)致新人拼團(tuán)訂單接口的QPS、TPS下降了約5%~10%,這還了得!


首先,快速解釋一下【新人拼團(tuán)】活動(dòng):


業(yè)務(wù)簡(jiǎn)介:顧名思義,新人拼團(tuán)是由新用戶發(fā)起的拼團(tuán),如果拼團(tuán)成功,系統(tǒng)會(huì)自動(dòng)獎(jiǎng)勵(lì)新用戶一張滿15.1元減15的平臺(tái)優(yōu)惠券。這相當(dāng)于是無(wú)門檻優(yōu)惠了。每個(gè)用戶僅有一次機(jī)會(huì)。新人拼團(tuán)活動(dòng)的最大目的主要是為了拉新。


新用戶判斷標(biāo)準(zhǔn):是否有支付成功的訂單 ? 不是新用戶 : 是新用戶。


當(dāng)前問(wèn)題:由于像這種優(yōu)惠力度較大的活動(dòng)很容易被羊毛黨、黑產(chǎn)盯上。因此,我們完善了訂單風(fēng)控系統(tǒng),讓黑產(chǎn)無(wú)處遁形!然而由于需要同步調(diào)用風(fēng)控系統(tǒng),導(dǎo)致整個(gè)下單接口的的QPS、TPS的指標(biāo)皆有下降,從性能的角度來(lái)看,【新人拼團(tuán)下單接口】無(wú)法滿足性能指標(biāo)要求。因此CTO指名點(diǎn)姓讓我?guī)ь^沖鋒……沖啊!


# 問(wèn)題分析


風(fēng)控系統(tǒng)的判斷一般分為兩種:在線同步分析和離線異步分析。在實(shí)際業(yè)務(wù)中,這兩者都是必要的。在線同步分析可以在下單入口處就攔截掉風(fēng)險(xiǎn),而離線異步分析可以提供更加全面的風(fēng)險(xiǎn)判斷基礎(chǔ)數(shù)據(jù)和風(fēng)險(xiǎn)監(jiān)控能力。


最近我們對(duì)在線同步這塊的風(fēng)控規(guī)則進(jìn)行了加強(qiáng)和優(yōu)化,導(dǎo)致整個(gè)新人拼團(tuán)下單接口的執(zhí)行鏈路更長(zhǎng),從而導(dǎo)致TPS和QPS這兩個(gè)關(guān)鍵指標(biāo)下降。


# 解決思路


要提升性能,最簡(jiǎn)單粗暴的方法是加服務(wù)器!然而,無(wú)腦加服務(wù)器無(wú)法展示出一個(gè)出色的程序員的能力。CTO說(shuō)了,要加服務(wù)器可以,買服務(wù)器的錢從我工資里面扣……


在測(cè)試環(huán)境中,我們簡(jiǎn)單的通過(guò)使用StopWatch來(lái)簡(jiǎn)單分析,偽代碼如下:

@Transactional(rollbackFor = Exception.class)public CollageOrderResponseVO colleageOrder(CollageOrderRequestVO request) { StopWatch stopWatch = new StopWatch();  stopWatch.start("調(diào)用風(fēng)控系統(tǒng)接口"); // 調(diào)用風(fēng)控系統(tǒng)接口, http調(diào)用方式 stopWatch.stop();  stopWatch.start("獲取拼團(tuán)活動(dòng)信息"); //  // 獲取拼團(tuán)活動(dòng)基本信息. 查詢緩存 stopWatch.stop();  stopWatch.start("獲取用戶基本信息"); // 獲取用戶基本信息。http調(diào)用用戶服務(wù) stopWatch.stop();  stopWatch.start("判斷是否是新用戶"); // 判斷是否是新用戶。查詢訂單數(shù)據(jù)庫(kù) stopWatch.stop();  stopWatch.start("生成訂單并入庫(kù)"); // 生成訂單并入庫(kù) stopWatch.stop();  // 打印task報(bào)告 stopWatch.prettyPrint();  // 發(fā)布訂單創(chuàng)建成功事件并構(gòu)建響應(yīng)數(shù)據(jù) return new CollageOrderResponseVO();}


執(zhí)行結(jié)果如下:

StopWatch '新人拼團(tuán)訂單StopWatch': running time = 1195896800 ns---------------------------------------------ns % Task name---------------------------------------------014385000 021% 調(diào)用風(fēng)控系統(tǒng)接口010481800 010% 獲取拼團(tuán)活動(dòng)信息013989200 015% 獲取用戶基本信息028314600 030% 判斷是否是新用戶028726200 024% 生成訂單并入庫(kù)


在測(cè)試環(huán)境整個(gè)接口的執(zhí)行時(shí)間在1.2s左右。其中最耗時(shí)的步驟是【判斷是否是新用戶】邏輯。這是我們重點(diǎn)優(yōu)化的地方(實(shí)際上,也只能針對(duì)這點(diǎn)進(jìn)行優(yōu)化,因?yàn)槠渌襟E邏輯基本上無(wú)優(yōu)化空間了)。


# 確定方案


在這個(gè)接口中,【判斷是否是新用戶】的標(biāo)準(zhǔn)是是用戶是否有支付成功的訂單。因此開(kāi)發(fā)人員想當(dāng)然的根據(jù)用戶ID去訂單數(shù)據(jù)庫(kù)中查詢。我們的訂單主庫(kù)的配置如下:

拼團(tuán)活動(dòng)遇黑產(chǎn)?搭進(jìn)去了8臺(tái)服務(wù)器...


這配置還算豪華吧。然而隨著業(yè)務(wù)的積累,訂單主庫(kù)的數(shù)據(jù)早就突破了千萬(wàn)級(jí)別了,雖然會(huì)定時(shí)遷移數(shù)據(jù),然而訂單量突破千萬(wàn)大關(guān)的周期越來(lái)越短……(分庫(kù)分表方案是時(shí)候提上議程了,此次場(chǎng)景暫不討論分庫(kù)分表的內(nèi)容)而用戶ID雖然是索引,但畢竟不是唯一索引。因此查詢效率相比于其他邏輯要更耗時(shí)。


通過(guò)簡(jiǎn)單分析可以知道,其實(shí)只需要知道這個(gè)用戶是否有支付成功的訂單,至于支付成功了幾單我們并不關(guān)心。因此此場(chǎng)景顯然適合使用redis的bitmap數(shù)據(jù)結(jié)構(gòu)來(lái)解決。在支付成功方法的邏輯中,我們簡(jiǎn)單加一行代碼來(lái)設(shè)置bitmap:

// 說(shuō)明:key表示用戶是否存在支付成功的訂單標(biāo)記// userId是long類型String key = "order:f:paysucc"; redisTemplate.opsForValue().setBit(key,?userId, true);

通過(guò)這一番改造,在下單時(shí)【判斷是否是新用戶】的核心代碼就不需要查庫(kù)了,而是改為:

Boolean paySuccFlag = redisTemplate.opsForValue().getBit(key, userId);if (paySuccFlag != null && paySuccFlag) { // 不是新用戶,業(yè)務(wù)異常}


修改之后,在測(cè)試環(huán)境的測(cè)試結(jié)果如下:

StopWatch '新人拼團(tuán)訂單StopWatch': running time = 82207200 ns---------------------------------------------ns % Task name---------------------------------------------014113100 017% 調(diào)用風(fēng)控系統(tǒng)接口010193800 012% 獲取拼團(tuán)活動(dòng)信息013965900 017% 獲取用戶基本信息014532800 018% 判斷是否是新用戶029401600??036%??生成訂單并入庫(kù)


測(cè)試環(huán)境下單時(shí)間變成了0.82s,主要性能損耗在生成訂單入庫(kù)步驟,這里涉及到事務(wù)和數(shù)據(jù)庫(kù)插入數(shù)據(jù),因此是合理的。接口響應(yīng)時(shí)長(zhǎng)縮短了31%!相比生產(chǎn)環(huán)境的性能效果更明顯……接著舞!


# 晴天霹靂


這次的優(yōu)化效果十分明顯,想著CTO該給我加點(diǎn)績(jī)效了吧,不然我工資要被扣完了呀~


一邊這樣想著,一邊準(zhǔn)備生產(chǎn)環(huán)境灰度發(fā)布。發(fā)完版之后,準(zhǔn)備來(lái)個(gè)葛優(yōu)躺好好休息一下,等著測(cè)試妹子驗(yàn)證完就下班走人。然而在我躺下不到1分鐘的時(shí)間,測(cè)試妹子過(guò)來(lái)緊張的跟我說(shuō):“接口報(bào)錯(cuò)了,你快看看!”What?


當(dāng)我打開(kāi)日志一看,立馬傻眼了。報(bào)錯(cuò)日志如下:

io.lettuce.core.RedisCommandExecutionException: ERR bit offset is not an integer or out of rangeat io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:135) ~[lettuce-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:108) ~[lettuce-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]at io.lettuce.core.protocol.AsyncCommand.completeResult(AsyncCommand.java:120) ~[lettuce-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]at io.lettuce.core.protocol.AsyncCommand.complete(AsyncCommand.java:111) ~[lettuce-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]at io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:654) ~[lettuce-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:614) ~[lettuce-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]…………


bit offset is not an integer or out of range。這個(gè)錯(cuò)誤提示已經(jīng)很明顯:我們的offset參數(shù)out of range。為什么會(huì)這樣呢?我不禁開(kāi)始思索起來(lái):redis bitmap的底層數(shù)據(jù)結(jié)構(gòu)實(shí)際上是string類型,redis對(duì)于string類型有最大值限制不得超過(guò)512M,即2^32次方byte…………我靠?。?!


# 恍然大悟


由于測(cè)試環(huán)境歷史原因,userId的長(zhǎng)度都是8位的,最大值99999999,假設(shè)offset就取這個(gè)最大值。那么在bitmap中,bitarray=999999999=2^29byte。因此setbit沒(méi)有報(bào)錯(cuò)。


而生產(chǎn)環(huán)境的userId,經(jīng)過(guò)排查發(fā)現(xiàn)用戶中心生成ID的規(guī)則變了,導(dǎo)致以前很老的用戶的id長(zhǎng)度是8位的,新注冊(cè)的用戶id都是18位的。以測(cè)試妹子的賬號(hào)id為例:652024209997893632 = 2^59byte,這顯然超出了redis的最大值要求。不報(bào)錯(cuò)才怪!


緊急回退版本,灰度發(fā)布失敗~還好,CTO念我不知道以前的這些業(yè)務(wù)規(guī)則,放了我一馬~該死,還想著加績(jī)效,沒(méi)有扣績(jī)效就是萬(wàn)幸的了!


本次事件暴露出幾個(gè)非常值得注意的問(wèn)題,值得反思:


  • 懂技術(shù)體系,還要懂業(yè)務(wù)體系


    對(duì)于bitmap的使用,我們是非常熟悉的,對(duì)于多數(shù)高級(jí)開(kāi)發(fā)人員而言,他們的技術(shù)水平也不差,但是因?yàn)椴煌瑯I(yè)務(wù)體系的變遷而無(wú)法評(píng)估出精準(zhǔn)的影響范圍,導(dǎo)致無(wú)形的安全隱患。本次事件就是因?yàn)闆](méi)有了解到用戶中心的ID規(guī)則變化以及為什么要變化從而導(dǎo)致問(wèn)題發(fā)生。

  • 預(yù)生產(chǎn)環(huán)境的必要性和重要性


    導(dǎo)致本次問(wèn)題的另一個(gè)原因,就是因?yàn)闆](méi)有預(yù)生產(chǎn)環(huán)境,導(dǎo)致無(wú)法真正模擬生產(chǎn)環(huán)境的真實(shí)場(chǎng)景,如果能有預(yù)生產(chǎn)環(huán)境,那么至少可以擁有生產(chǎn)環(huán)境的基礎(chǔ)數(shù)據(jù):用戶數(shù)據(jù)、活動(dòng)數(shù)據(jù)等。很大程度上能夠提前暴露問(wèn)題并解決。從而提升正式環(huán)境發(fā)版的效率和質(zhì)量。

  • 敬畏心


    要知道,對(duì)于一個(gè)大型的項(xiàng)目而言,任何一行代碼其背后都有其存在的價(jià)值:正所謂存在即合理。別人不會(huì)無(wú)緣無(wú)故這樣寫。如果你覺(jué)得不合理,那么需要通過(guò)充分的調(diào)研和了解,確定每一個(gè)參數(shù)背后的意義和設(shè)計(jì)變更等。以盡可能降低犯錯(cuò)的幾率。


# 后記


通過(guò)此次事件,本來(lái)想著優(yōu)化能夠提升接口效率,從而不需要加服務(wù)器。這下好了,不僅生產(chǎn)環(huán)境要加1臺(tái)服務(wù)器以臨時(shí)解決性能指標(biāo)不達(dá)標(biāo)的問(wèn)題,還要另外加7臺(tái)服務(wù)器用于預(yù)生產(chǎn)環(huán)境的搭建!因?yàn)閎itmap,搭進(jìn)去了8臺(tái)服務(wù)器。痛并值得。接著奏樂(lè),接著舞~~~


免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動(dòng)電源

在工業(yè)自動(dòng)化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動(dòng)力設(shè)備,其驅(qū)動(dòng)電源的性能直接關(guān)系到整個(gè)系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動(dòng)勢(shì)抑制與過(guò)流保護(hù)是驅(qū)動(dòng)電源設(shè)計(jì)中至關(guān)重要的兩個(gè)環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動(dòng)性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動(dòng)電源

LED 驅(qū)動(dòng)電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個(gè)照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動(dòng)電源易損壞的問(wèn)題卻十分常見(jiàn),不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問(wèn)題,需從設(shè)計(jì)、生...

關(guān)鍵字: 驅(qū)動(dòng)電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動(dòng)電源的公式,電感內(nèi)電流波動(dòng)大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動(dòng)電源

電動(dòng)汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動(dòng)汽車的核心技術(shù)之一是電機(jī)驅(qū)動(dòng)控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動(dòng)系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動(dòng)汽車的動(dòng)力性能和...

關(guān)鍵字: 電動(dòng)汽車 新能源 驅(qū)動(dòng)電源

在現(xiàn)代城市建設(shè)中,街道及停車場(chǎng)照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢(shì)逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動(dòng)電源 LED

LED通用照明設(shè)計(jì)工程師會(huì)遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動(dòng)電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動(dòng)電源的電磁干擾(EMI)問(wèn)題成為了一個(gè)不可忽視的挑戰(zhàn)。電磁干擾不僅會(huì)影響LED燈具的正常工作,還可能對(duì)周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來(lái)解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動(dòng)電源

開(kāi)關(guān)電源具有效率高的特性,而且開(kāi)關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動(dòng)電源

關(guān)鍵字: LED 驅(qū)動(dòng)電源 開(kāi)關(guān)電源

LED驅(qū)動(dòng)電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動(dòng)LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動(dòng)電源
關(guān)閉