一、背景
本篇文章以解決實際需求的問題的角度進行切入,探討了如果使用布隆過濾器快速丟棄無效請求,降低了系統的負載以及不必要的流量。
我們都知道布隆過濾器是以占用內存小,同時也能夠實現快速的過濾從而滿足我們的需求,本篇文章就不仔細展開說明布隆過濾器的工作原理,具體工作原理可以參考下面這篇博客。
Redis布隆過濾器的原理和應用場景,解決緩存穿透 - 知乎
二、實際要解決的問題
面臨問題:在我們的日常工作中,我們通常是負責某個系統,例如訂單系統、預約系統、保險系統等等,在一整個業務流程中,我們只是負責某一業務系統,我們都會有自己的上下游,以預約系統為例,訂單系統(下游)根據預約單號查詢預約系統是否有預約,從而處理對應邏輯,但并不是所有的訂單都是有預約的,大部分的訂單是沒有的,對于我預約系統來說,訂單系統大部分的查詢都是無效的,但是如果我只是使用數據庫的前提下,大部分的請求還是打到了我的數據庫,如圖所示
這種情況下,如果訂單系統的請求量非常大,那對我們預約的系統壓力以及數據庫的壓力會比較大,那么我們將如何解決我們的系統壓力以及數據庫的壓力呢?
三、解決方案
剛才說到,訂單系統有大量的訂單,但是不是每個訂單都需要預約,大部分單號對預約系統來說都是無效的請求,所以這個業務場景我們就可以考慮用布隆過濾器對無效的請求進行過濾。
具體怎么做呢,我們可以在數據庫和預約系統之間增加布隆過濾器,增加了布隆過濾器那同時也必須增加布隆過濾器的數據初始化。我們可以這樣設計,如下圖所示
- 在數據流入的時候增加布隆布隆過濾器的寫入
????????關鍵代碼:BloomFilterUtils.addValue
/*** @author chen* @description 下單后處理* @param orderNo 訂單號* @date: 2024/3/3 9:42*/private void afterOrderHandle(String orderNo) {//redisTemplate.opsForValue().setBit("test-key",10,true);//通過這種方式實現,需要自己使用hash算法計算對應位數組下標位置(不推薦)//推薦使用redisson開箱即用的RBloomFilter//加載到布隆過濾器BloomFilterUtils.addValue(BloomFilterEnum.TB_ORDER_BLOOM_FILTER.getBloomFilterName(),orderNo);log.info("#加載完畢#");//其他操作.....}
- 在下游訂單系統查詢預約系統時增加通過訂單號查詢布隆過濾器進行過濾,能夠快速的對上游請求進行快速過濾
關鍵代碼:BloomFilterUtils.isContains
/*** @author chen* @description 訂單查詢* @param reqVO 請求入參* @date: 2024/3/3 9:59* @return com.redis.bloom.filter.data.vo.resp.OrderSearchRespVO*/public OrderSearchRespVO orderSearch(OrderSearchReqVO reqVO) {String orderNo = reqVO.getOrderNo();if(!BloomFilterUtils.isContains(BloomFilterEnum.TB_ORDER_BLOOM_FILTER.getBloomFilterName(),orderNo)){log.info("布隆過濾器不存在#則代表數據庫一定不存在,則直接返回空,不進行數據庫查詢#orderNo={}",reqVO.getOrderNo());return null;}QueryWrapper<TbOrder> queryWrapper = new QueryWrapper<>();queryWrapper.eq("order_no",reqVO.getOrderNo());//查詢數據庫List<TbOrder> tbOrders = tbOrderMapper.selectList(queryWrapper);if(CollectionUtil.isEmpty(tbOrders)){return null;}TbOrder tbOrder = tbOrders.get(0);//使用MapStruct復制對象返回,不暴漏數據庫對象給前端OrderSearchRespVO respVO = TbOrderCopyMapper.INSTANCE.createOrderSearchRespVO(tbOrder);return respVO;}
四、總結
- 針對此場景、布隆過濾器有著小而實用的特點,可以利用較小的內存擋住大部分的請求,從而降低系統壓力和數據庫壓力
- 布隆過濾器不僅針對此場景有使用的地方,同時也可以針對緩存穿透也是有很大用處,大大降低數據庫的壓力
- 這里僅僅只是記錄了布隆過濾器特定場景,目前也是我在工作中用的最多的場景,優化效果顯著
五、源代碼
redis-bloom-filter: 1、這里介紹了簡單的布隆過濾器的用法以及實戰場景
感興趣的朋友可以拉下代碼進行項目運行,只需要把redis配置更換即可