一個(gè)慢查詢凍結(jié)整個(gè)請(qǐng)求,線程堆積、內(nèi)存飆升、用戶盯著加載動(dòng)畫——這是作者多年寫Java應(yīng)用的常態(tài)。直到遇見Project Reactor,數(shù)據(jù)流、并發(fā)和錯(cuò)誤處理的方式被徹底改寫。
核心類型:Mono與Flux的邊界在哪
![]()
Project Reactor的兩個(gè)基礎(chǔ)類型幾乎覆蓋所有業(yè)務(wù)場景。Mono是"一個(gè)值或沒有"的容器,F(xiàn)lux承載"零到多個(gè)"的事件流。
作者的經(jīng)驗(yàn)法則:查單個(gè)用戶用Mono,查訂單列表用Flux。新手常犯的錯(cuò)誤是過度包裝——把什么都塞進(jìn)Flux,或者用Mono包列表。
組合查詢的寫法變得簡潔。zipWith讓兩個(gè)異步操作并行執(zhí)行,結(jié)果就緒后自動(dòng)合并為UserProfile。作者過去用CompletableFuture手寫同步邏輯,現(xiàn)在Reactor代勞協(xié)調(diào)。關(guān)鍵認(rèn)知:管道是惰性的,沒有訂閱就不會(huì)執(zhí)行。
背壓:消費(fèi)者說了算的流量控制
背壓(backpressure)的本質(zhì)是消費(fèi)者告訴生產(chǎn)者"慢點(diǎn),我跟不上了"。沒有它,快生產(chǎn)者會(huì)淹沒慢消費(fèi)者,內(nèi)存被緩沖撐爆或觸發(fā)超時(shí)。
Reactor提供三種策略:緩沖、丟棄、取最新。選擇取決于對(duì)數(shù)據(jù)丟失的容忍度。
事件流不能丟數(shù)據(jù)時(shí),用onBackpressureBuffer設(shè)上限,溢出時(shí)記錄警告并丟棄最舊數(shù)據(jù)。股票行情只關(guān)心最新價(jià),onBackpressureLatest直接丟棄中間值——這個(gè)場景下,舊價(jià)格就是噪音。
錯(cuò)誤處理:從崩潰到優(yōu)雅降級(jí)
阻塞代碼里一個(gè)異常可能拖垮整個(gè)請(qǐng)求鏈。Reactor把錯(cuò)誤變成流的一部分,用操作符就地處理。
onErrorReturn提供默認(rèn)值,onErrorResume切換到備用流,retryWhen按策略重試。作者特別強(qiáng)調(diào):別在訂閱者的lambda里寫try-catch,那會(huì)破壞響應(yīng)式鏈的可組合性。
重試不是無腦循環(huán)。配合Retry.backoff()指定最大次數(shù)、延遲和抖動(dòng),避免雪崩時(shí)加劇系統(tǒng)壓力。
![]()
調(diào)度器:線程切換的精確控制
默認(rèn)情況下所有操作在同一線程執(zhí)行。publishOn和改變執(zhí)行上下文,但行為截然不同。
publishOn影響其后的所有操作,適合鏈中某段需要切換線程的場景。subscribeOn影響整個(gè)訂閱過程,從源頭改變執(zhí)行環(huán)境。作者常見模式:用subscribeOn(Schedulers.boundedElastic())包裝阻塞調(diào)用(如JDBC),避免占用事件循環(huán)線程。
IO密集型任務(wù)用boundedElastic,CPU密集型用parallel,定時(shí)任務(wù)用single。選錯(cuò)調(diào)度器比不用還糟——線程競爭會(huì)抵消響應(yīng)式的性能收益。
冷流與熱流:訂閱時(shí)機(jī)的權(quán)力游戲
冷流(Cold Publisher)為每個(gè)訂閱者重新發(fā)射數(shù)據(jù),熱流(Hot Publisher)廣播給所有訂閱者。作者用share()或publish().refCount()將冷流轉(zhuǎn)熱,多個(gè)訂閱者共享同一數(shù)據(jù)源。
實(shí)時(shí)儀表盤的典型場景:后端持續(xù)推送數(shù)據(jù),多個(gè)前端連接接入。用冷流每個(gè)訂閱者獨(dú)立查庫,數(shù)據(jù)庫壓力隨連接數(shù)線性增長;熱流只需一次查詢,結(jié)果廣播分發(fā)。
但熱流有代價(jià):晚到的訂閱者錯(cuò)過歷史數(shù)據(jù)。replay()緩存指定數(shù)量或時(shí)間窗口的數(shù)據(jù),新訂閱者先收到緩存再實(shí)時(shí)跟進(jìn)。
性能數(shù)字:從噩夢到流水線的真實(shí)收益
作者未給出具體基準(zhǔn)測試數(shù)據(jù),但描述了架構(gòu)層面的質(zhì)變:線程數(shù)從"每個(gè)請(qǐng)求一個(gè)"降至固定的事件循環(huán)線程池,內(nèi)存占用因背壓控制而可預(yù)測,錯(cuò)誤被隔離在操作符層面而非級(jí)聯(lián)崩潰。
這些技術(shù)不是銀彈。團(tuán)隊(duì)需要理解延遲、吞吐量、資源利用率的權(quán)衡,需要改變"順序執(zhí)行、立即返回"的思維慣性。但當(dāng)阻塞代碼成為瓶頸時(shí),這五個(gè)技巧提供了系統(tǒng)性的改造路徑——從Mono/Flux的類型選擇,到背壓策略的取舍,再到調(diào)度器的精確投放,最終形成可組合、可觀測、可容錯(cuò)的數(shù)據(jù)管道。
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.