當(dāng)前位置:首頁 > 公眾號精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]最近,因為增加了一些風(fēng)控措施,導(dǎo)致新人拼團訂單接口的QPS、TPS下降了約5%~10%,這還了得!

作者:浪漫先生

來源:uejin.im/post/6854573218322513933



# 前言


最近,因為增加了一些風(fēng)控措施,導(dǎo)致新人拼團訂單接口的QPS、TPS下降了約5%~10%,這還了得!


首先,快速解釋一下【新人拼團】活動:


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


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


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


# 問題分析


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


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


# 解決思路


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


在測試環(huán)境中,我們簡單的通過使用StopWatch來簡單分析,偽代碼如下:

@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("獲取拼團活動信息"); //  // 獲取拼團活動基本信息. 查詢緩存 stopWatch.stop();  stopWatch.start("獲取用戶基本信息"); // 獲取用戶基本信息。http調(diào)用用戶服務(wù) stopWatch.stop();  stopWatch.start("判斷是否是新用戶"); // 判斷是否是新用戶。查詢訂單數(shù)據(jù)庫 stopWatch.stop();  stopWatch.start("生成訂單并入庫"); // 生成訂單并入庫 stopWatch.stop();  // 打印task報告 stopWatch.prettyPrint();  // 發(fā)布訂單創(chuàng)建成功事件并構(gòu)建響應(yīng)數(shù)據(jù) return new CollageOrderResponseVO();}


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

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


在測試環(huán)境整個接口的執(zhí)行時間在1.2s左右。其中最耗時的步驟是【判斷是否是新用戶】邏輯。這是我們重點優(yōu)化的地方(實際上,也只能針對這點進行優(yōu)化,因為其他步驟邏輯基本上無優(yōu)化空間了)。


# 確定方案


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

拼團活動遇黑產(chǎn)?搭進去了8臺服務(wù)器...


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


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

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

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

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


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

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


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


# 晴天霹靂


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


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


當(dāng)我打開日志一看,立馬傻眼了。報錯日志如下:

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。這個錯誤提示已經(jīng)很明顯:我們的offset參數(shù)out of range。為什么會這樣呢?我不禁開始思索起來:redis bitmap的底層數(shù)據(jù)結(jié)構(gòu)實際上是string類型,redis對于string類型有最大值限制不得超過512M,即2^32次方byte…………我靠?。?!


# 恍然大悟


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


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


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


本次事件暴露出幾個非常值得注意的問題,值得反思:


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


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

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


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

  • 敬畏心


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


# 后記


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


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

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

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉