<div class="entry-content">
<h1></h1>
背景
公司有一個業務場景,數據庫的修改需要同步到Elasticsearch里,但是該場景的修改頻率有點高,經常會出現一條記錄短時間內多次的變化,如果每次變化都作為一次ES同步任務,那ES肯定是受不住的。
思路
通過估算請求規模,主要有如下2方面的解決思路:
- 高頻變化去重:因為同一條記錄短時間內多次變化,其實同步一次最終的狀態即可,所以可以考慮犧牲一定的實時性,在一定時間窗口內做變化通知的去重。
- 批量導入:每條記錄變化作為獨立請求推送給ES,實際上遠不如多條記錄批量推送ES的吞吐要高。
方案
- 在線去重:因為在線業務本身是高頻的,所以需要一個高頻的存儲介質來實現去重,想到redis的set/zset數據結構。
- 離線批量:利用離線JOB定時的將一段時間內去重的變動集合推送給ES,其核心問題在於在線set集合如何離線化,保證互不影響。
整體架構如下:
假設變動的是用戶的積分等高頻資產信息,那么在線部分一旦數據庫發生變動,則將用戶uid向zset_w在線集合寫入,可以實現實時去重。
離線JOB則首先檢查zset_r離線集合是否有剩余變動任務未處理,若zset_r集合為空則執行redis的rename操作將在線集合zset_w重命名為zset_r,這個過程對redis來說是原子性的。
此后離線JOB繼續處理zset_r中已經去重的變化uid集合,而在線部分繼續向新的zset_w集合添加最新變動的uid即可,如此往復。
優化
隨着在線高頻變更量的增多,該方案可以實施橫向擴展,即准備N對(zset_w、zset_r)並令在線部分按uid打散流量,從而可以為每一對zset啟動獨立的離線JOB,實現並行處理。
鑒於在線部分操作redis異常導致通知丟失,可以通過長周期的全庫離線補償實現,在此不做說明。
結論
該業務場景的思想本質包含了2點:
- 流式轉批量 換取更高的吞吐。
- 大問題拆小 實現橫向的擴展。
總是思考是否有更簡單的方案,做到簡單可依賴。