国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

這篇具有很好參考價值的文章主要介紹了一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

服務(wù)冪等性架構(gòu)設(shè)計

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

  • 作者: 博學(xué)谷狂野架構(gòu)師
  • GitHub:GitHub地址 (有我精心準備的130本電子書PDF)

只分享干貨、不吹水,讓我們一起加油!??

防重表實現(xiàn)冪等

對于防止數(shù)據(jù)重復(fù)提交,還有一種解決方案就是通過防重表實現(xiàn)。

防重表的實現(xiàn)思路也非常簡單,首先創(chuàng)建一張表作為防重表,同時在該表中建立一個或多個字段的唯一索引作為防重字段,用于保證并發(fā)情況下,數(shù)據(jù)只有一條。在向業(yè)務(wù)表中插入數(shù)據(jù)之前先向防重表插入,如果插入失敗則表示是重復(fù)數(shù)據(jù)。

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

為什么不用悲觀鎖

對于防重表的解決方案,可能有人會說為什么不使用悲觀鎖,悲觀鎖在使用的過程中也是會發(fā)生死鎖的。

悲觀鎖是通過鎖表的方式實現(xiàn)的,假設(shè)現(xiàn)在一個用戶A訪問表A(鎖住了表A),然后試圖訪問表B;

另一個用戶B訪問表B(鎖住了表B),然后試圖訪問表A。 這時對于用戶A來說,由于表B已經(jīng)被用戶B鎖住了,所以用戶A必須等到用戶B釋放表B才能訪問。

同時對于用戶B來說,由于表A已經(jīng)被用戶A鎖住了,所以用戶B必須等到用戶A釋放表A才能訪問。此時死鎖就已經(jīng)產(chǎn)生了。

閱讀專業(yè)類書籍是Java程序員必備的學(xué)習方式之一。通過不斷學(xué)習和積累,可以不斷提高自己的技術(shù)能力和職業(yè)水平,實現(xiàn)職業(yè)發(fā)展的目標。

非常建議大家注重閱讀,并選擇一些有深度、有價值的書籍不斷提升自己的技術(shù)水平和能力。這些書籍包括Java編程語言、數(shù)據(jù)結(jié)構(gòu)和算法、面向?qū)ο笤O(shè)計、設(shè)計模式、框架原理與應(yīng)用等等。

對于一位2-3年的Java程序員來說,閱讀專業(yè)類書籍是更加的重要,因為它們可以幫助你擴展技術(shù)廣度和深度,提高你的技術(shù)能力和職業(yè)水平。以下是我給這些程序員的一些建議:

學(xué)會尋找優(yōu)秀的書籍:在選擇書籍時,要選擇那些被廣泛認可和推薦的經(jīng)典書籍??梢酝ㄟ^搜索網(wǎng)上的書籍推薦列表,向其他經(jīng)驗豐富的程序員請教,或者參考公司內(nèi)部的學(xué)習計劃,來找到好的書籍。
閱讀有關(guān)設(shè)計模式和架構(gòu)的書籍:對于Java程序員來說,掌握設(shè)計模式和架構(gòu)原則是非常重要的。可以選擇閱讀《設(shè)計模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》、《大話設(shè)計模式》、《Java程序員修煉之道》等書籍來深入學(xué)習。
學(xué)習新的技術(shù)和框架:Java技術(shù)不斷發(fā)展,新的技術(shù)和框架也不斷涌現(xiàn)。因此,Java程序員應(yīng)該定期閱讀有關(guān)新技術(shù)和框架的書籍,比如Spring、Spring Boot、MyBatis、Netty等。
學(xué)習算法和數(shù)據(jù)結(jié)構(gòu):算法和數(shù)據(jù)結(jié)構(gòu)是編程基礎(chǔ),掌握這些知識可以提高代碼的質(zhì)量和效率。可以選擇閱讀《算法》、《算法導(dǎo)論》等書籍來學(xué)習算法和數(shù)據(jù)結(jié)構(gòu)。
參考開源項目和源代碼:閱讀開源項目和源代碼是非常有益的,可以學(xué)習到其他程序員的編碼技巧和設(shè)計思路??梢赃x擇一些知名的開源項目,如Spring、MyBatis等來進行學(xué)習。
當然,我也知道,光是建議是不足以激發(fā)大家學(xué)習的動力的,所以,書也我也幫大家整理好了,把飯喂到嘴里了,我只能幫你到這里了,剩下的就靠你自己了。

以下這份包含46本Java程序員必備經(jīng)典的書單(豆瓣評分8分+),是我花費一個月時間整理的:GitHub:GitHub地址

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

唯一主鍵實現(xiàn)冪等

數(shù)據(jù)庫唯一主鍵的實現(xiàn)主要是利用數(shù)據(jù)庫中主鍵唯一約束的特性,一般來說唯一主鍵比較適用于“插入”時的冪等性,其能保證一張表中只能存在一條帶該唯一主鍵的記錄。

使用數(shù)據(jù)庫唯一主鍵完成冪等性時需要注意的是,該主鍵一般來說并不是使用數(shù)據(jù)庫中自增主鍵,而是使用分布式 ID 充當主鍵,這樣才能能保證在分布式環(huán)境下 ID 的全局唯一性。

對于一些后臺系統(tǒng),并發(fā)量并不高的情況下,對于冪等的實現(xiàn)非常簡單,通過這種思想即可完成冪等控制。

適用場景

  • 插入操作
  • 刪除操作

使用限制

  • 需要生成全局唯一主鍵 ID;

主要流程

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

主要流程如下:

  1. 客戶端執(zhí)行創(chuàng)建請求,調(diào)用服務(wù)端接口。
  2. 服務(wù)端執(zhí)行業(yè)務(wù)邏輯,生成一個分布式 ID,將該 ID 充當待插入數(shù)據(jù)的主鍵,然 后執(zhí)數(shù)據(jù)插入操作,運行對應(yīng)的 SQL 語句。
  3. 服務(wù)端將該條數(shù)據(jù)插入數(shù)據(jù)庫中,如果插入成功則表示沒有重復(fù)調(diào)用接口。如果拋出主鍵重復(fù)異常,則表示數(shù)據(jù)庫中已經(jīng)存在該條記錄,返回錯誤信息到客戶端。

在業(yè)務(wù)執(zhí)行前,先判斷是否已經(jīng)操作過,如果沒有則執(zhí)行,否則判斷為重復(fù)操作。

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

效果演示

在并發(fā)下訪問時,因為是基于id進行判斷,那id值就必須要保證在多次提交時,需要唯一。訪問流程如下:

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

 @Override
@Transactional(rollbackFor = Exception.class)
public String addOrder(Order order) {

    order.setCreateTime(new Date());
    order.setUpdateTime(new Date());

    //查詢
    Order orderResult = orderMapper.selectByPrimaryKey(order.getId());

    Optional<Order> orderOptional = Optional.ofNullable(orderResult);
    if (orderOptional.isPresent()){

        return "repeat request";
    }

    int result = orderMapper.insert(order);
    if (result != 1){
        return "fail";
    }

    return "success";
}

對于上述功能實現(xiàn),在并發(fā)下,并不能完成冪等性控制。通過jemeter測試,模擬50個并發(fā),可以發(fā)現(xiàn),插入了重復(fù)數(shù)據(jù)。產(chǎn)生了臟數(shù)據(jù)。

要解決這個問題,非常簡單,在數(shù)據(jù)庫層面添加唯一索引即可,將id設(shè)置為唯一索引,也是最容易想到的方式,一旦id出現(xiàn)重復(fù),就會出現(xiàn)異常,避免了臟數(shù)據(jù)的發(fā)生也可以解決永久性冪等。但該方案無法用于分庫分表情況,其只適用于單表情況。

樂觀鎖實現(xiàn)冪等性

數(shù)據(jù)庫樂觀鎖方案一般只能適用于執(zhí)行更新操作的過程,我們可以提前在對應(yīng)的數(shù)據(jù)表中多添加一個字段,充當當前數(shù)據(jù)的版本標識。

這樣每次對該數(shù)據(jù)庫該表的這條數(shù)據(jù)執(zhí)行更新時,都會將該版本標識作為一個條件,值為上次待更新數(shù)據(jù)中的版本標識的值。

適用操作

  • 更新操作

使用限制

  • 需要數(shù)據(jù)庫對應(yīng)業(yè)務(wù)表中添加額外字段

問題拋出

扣減庫存數(shù)據(jù)錯誤

通過jemeter進行測試,可以發(fā)現(xiàn)。當模擬一萬并發(fā)時,最終的庫存數(shù)量是錯誤的。這主要是因為當多線程訪問時,一個線程讀取到了另外線程未提交的數(shù)據(jù)造成。

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

synchronized失效問題

對于現(xiàn)在的問題,暫不考慮秒殺設(shè)計、隊列請求串行化等,只考慮如何通過鎖進行解決,要通過鎖解決的話,那最先想到的可能是synchronized。

根據(jù)synchronized定義,當多線程并發(fā)訪問時,會對當前加鎖的方法產(chǎn)生阻塞,從而保證線程安全,避免臟數(shù)據(jù)。但是,真的能如預(yù)期的一樣嗎?

 @Service
public class StockServiceImpl implements StockService {

    @Autowired
    private StockMapper stockMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized int lessInventory(String goodsId, int num) {
        return stockMapper.lessInventory(goodsId, num);
    }
}

當前已經(jīng)在在方法上添加了synchronized,對當前方法對象進行了鎖定。 通過Jemeter,模擬一萬并發(fā)對其進行訪問。可以發(fā)現(xiàn),仍然出現(xiàn)了臟數(shù)據(jù)。

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

事務(wù)導(dǎo)致鎖失效

該問題的產(chǎn)生原因,就在于在方法上synchronized搭配使用了@Transactional

首先synchronized鎖定的是當前方法對象,而@Transactional會對當前方法進行AOP增強,動態(tài)代理出一個代理對象,在方法執(zhí)行前開啟事務(wù),執(zhí)行后提交事務(wù)。

所以synchronized@Transactional其實操作的是兩個不同的對象,換句話說就是@Transactional的事務(wù)操作并不在synchronized鎖定范圍之內(nèi)。

假設(shè)A線程執(zhí)行完扣減庫存方法,會釋放鎖并提交事務(wù)。但A線程釋放鎖但還沒提交事務(wù)前,B線程執(zhí)行扣減庫存方法,B線程執(zhí)行后,和A線程一起提交事務(wù),就出現(xiàn)了線程安全問題,造成臟數(shù)據(jù)的出現(xiàn)。

樂觀鎖保證冪等

基于版本號實現(xiàn)

MySQL樂觀鎖是基于數(shù)據(jù)庫完成分布式鎖的一種實現(xiàn),實現(xiàn)的方式有兩種:

  • 基于版本號
  • 基于條件

但是實現(xiàn)思想都是基于MySQL的行鎖思想來實現(xiàn)的。

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

  1. 修改數(shù)據(jù)表,添加version字段,默認值為0
  2. 修改StockMapper添加基于版本修改數(shù)據(jù)方法
 @Update("update tb_stock set amount=amount-#{num},version=version+1 where goods_id=#{goodsId} and version=#{version}")
int lessInventoryByVersion(@Param("goodsId") String goodsId,@Param("num") int num,@Param("version") int version);
  1. 測試模擬一萬并發(fā)進行數(shù)據(jù)修改,此時可以發(fā)現(xiàn)當前版本號從0變?yōu)?,且?guī)齑媪空_。

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

基于條件實現(xiàn)

通過版本號控制是一種非常常見的方式,適合于大多數(shù)場景。

但現(xiàn)在庫存扣減的場景來說,通過版本號控制就是多人并發(fā)訪問購買時,查詢時顯示可以購買,但最終只有一個人能成功,這也是不可以的。其實最終只要商品庫存不發(fā)生超賣就可以。那此時就可以通過條件來進行控制。

  1. 修改StockMapper
 @Update("update tb_stock set amount=amount-#{num} where goods_id=#{goodsId} and amount-#{num}>=0")
int lessInventoryByVersionOut(@Param("goodsId") String goodsId,@Param("num") int num);
  1. 修改StockController
 @PutMapping("/lessInventoryByVersionOut/{goodsId}/{num}")
public String lessInventoryByVersionOut(@PathVariable("goodsId") String goodsId,@PathVariable("num") int num){

    int result = stockService.lessInventoryByVersionOut(goodsId, num);
    if (result == 1){
        System.out.println("購買成功");
        return "success";
    }

    System.out.println("購買失敗");
    return "fail";
}
  1. 通過jemeter進行測試,可以發(fā)現(xiàn)當多人并發(fā)扣減庫存時,控制住了商品超賣的問題。

樂觀鎖實現(xiàn)冪等性

在系統(tǒng)中,不光要保證客戶端訪問的冪等性,同時還要保證服務(wù)間冪等。

比較常見的情況,當服務(wù)間進行調(diào)用時,因為網(wǎng)絡(luò)抖動等原因出現(xiàn)超時,則很有可能出現(xiàn)數(shù)據(jù)錯誤。此時在分布式環(huán)境下,就需要通過分布式事務(wù)或分布式鎖來保證數(shù)據(jù)的一致性。分布式鎖的解決方案中MySQL樂觀鎖就是其中一種實現(xiàn)。

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

feign超時重試效果演示

以上圖為例,當客戶端要生成訂單時,可以基于token機制保證生成訂單的冪等性,接著訂單生成成功后,還會基于feign調(diào)用庫存服務(wù)進行庫存扣減,此時則很有可能出現(xiàn),庫存服務(wù)執(zhí)行扣減庫存成功,但是當結(jié)果返回時,出現(xiàn)網(wǎng)絡(luò)抖動超時了,那么上游的訂單服務(wù)則很有可能會發(fā)起重試,此時如果不進行扣減庫存的冪等性保證的話,則出現(xiàn)扣減庫存執(zhí)行多次。

那可以先來演示當下游服務(wù)出現(xiàn)延遲,上游服務(wù)基于feign進行重試的效果。

  1. 當前是order調(diào)用feign,所以在order中會存在feignConfigure配置類,用于配置超時時間與重試次數(shù)。
 /**
 * 自定義feign超時時間、重試次數(shù)
 * 默認超時為10秒,不會進行重試。
 */
@Configuration
public class FeignConfigure {

    //超時時間,時間單位毫秒
    public static int connectTimeOutMillis = 5000;
    public static int readTimeOutMillis = 5000;

    @Bean
    public Request.Options options() {
        return new Request.Options(connectTimeOutMillis, readTimeOutMillis);
    }

    //自定義重試次數(shù)
    @Bean
    public Retryer feignRetryer(){
        Retryer retryer = new Retryer.Default(100, 1000, 4);
        return retryer;
    }
}
  1. stock服務(wù)的StockController中demo方法會延遲六秒。

    通過這種方式模擬超時效果。此時在order中調(diào)用stock服務(wù),可以發(fā)現(xiàn),order服務(wù)會對stock服務(wù)調(diào)用四次。

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

這里就演示了服務(wù)間調(diào)用超時的效果,當下游服務(wù)超時,上游服務(wù)會進行重試。

服務(wù)調(diào)用超時庫存多次扣減

根據(jù)上述演示,當下游服務(wù)超時,上游服務(wù)就會進行重試。

那么結(jié)合當前的業(yè)務(wù)場景,當用戶下單成功去調(diào)用庫存服務(wù)扣減庫存時, 如果庫存服務(wù)執(zhí)行扣減庫存成功但返回結(jié)果超時,則上游訂單服務(wù)就會重試,再次進行扣減庫存,此時就會出現(xiàn)同一訂單商品庫存被多次扣減。

  1. 在訂單服務(wù)中生成訂單,并調(diào)用庫存服務(wù)扣減庫存
 @Idemptent
@PostMapping("/genOrder")
public String genOrder(@RequestBody Order order){

    String orderId = String.valueOf(idWorker.nextId());
    order.setId(orderId);
    order.setCreateTime(new Date());
    order.setUpdateTime(new Date());
    int result = orderService.addOrder(order);

    if (result != 1){
        System.out.println("fail");
        return "fail";
    }

    //生成訂單詳情信息
    List<String> goodsIdArray = JSON.parseArray(order.getGoodsIds(), String.class);

    goodsIdArray.stream().forEach(goodsId->{
        //插入訂單詳情
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setId(String.valueOf(idWorker.nextId()));
        orderDetail.setGoodsId(goodsId);
        orderDetail.setOrderId(orderId);
        orderDetail.setGoodsName("heima");
        orderDetail.setGoodsNum(1);
        orderDetail.setGoodsPrice(1);
        orderDetailService.addOrderDetail(orderDetail);

        //扣減庫存(不考慮鎖)
        stockFeign.reduceStockNoLock(goodsId, orderDetail.getGoodsNum());

    });


    return "success";
}
  1. 庫存服務(wù)直接基于商品信息進行庫存扣減
 @Update("update tb_stock set amount=amount-#{num} where goods_id=#{goodsId}")
int reduceStockNoLock(@Param("goodsId") String goodsId,@Param("num") Integer num);
 @PutMapping("/reduceStockNoLock/{goodsId}/{num}")
public String reduceStockNoLock(@PathVariable("goodsId") String goodsId,
                                    @PathVariable("num") Integer num) throws InterruptedException {

        System.out.println("reduce stock");
        int result = stockService.reduceStockNoLock(goodsId, num);

        if (result != 1){
            return "reduce stock fail";
        }

        //延遲
        TimeUnit.SECONDS.sleep(6000);
        return "reduce stock success";
    }
  1. 執(zhí)行生成訂單扣減庫存,此時可以發(fā)現(xiàn)扣減庫存方法被執(zhí)行多次,并且?guī)齑鏀?shù)量也被扣減了多次
 {"totalNum":1,"payMoney":1,"goodsIds":"['1271700536000909313']"}

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

樂觀鎖解決服務(wù)間重試保證冪等
  1. 修改StockMapper,添加樂觀鎖控制控制庫存
 @Update("update tb_stock set version=version+1,amount=amount-#{num} where goods_id=#{goodsId} and version=#{version} and amount-#{num}>=0")
int reduceStock(@Param("goodsId") String goodsId,@Param("num") Integer num,@Param("version") Integer version);
  1. 修改StockController,添加樂觀鎖扣減庫存方法
 /**
     * 樂觀鎖扣減庫存
     * @param goodsId
     * @param num
     * @param version
     * @return
     */
@PutMapping("/reduceStock/{goodsId}/{num}/{version}")
public int reduceStock(@PathVariable("goodsId") String goodsId,
                       @PathVariable("num") Integer num,
                       @PathVariable("version") Integer version) throws InterruptedException {

    System.out.println("exec reduce stock");
    int result = stockService.reduceStock(goodsId, num, version);
    if (result != 1){
        //扣減失敗
        return result;
    }
    //延遲
    TimeUnit.SECONDS.sleep(6000);
    return result;
}
  1. 測試,可以發(fā)現(xiàn)雖然發(fā)生多次重試,但是庫存只會被扣減成功一次。保證了服務(wù)間的冪等性。
ps:order服務(wù)出現(xiàn)異常,是因為order服務(wù)會超時重試四次,但stock服務(wù)的延遲每一次都是超過超時時間的,所以最終在order服務(wù)才會出現(xiàn)read timeout異常提示。

消息冪等

在系統(tǒng)中當使用消息隊列時,無論做哪種技術(shù)選型,有很多問題是無論如何也不能忽視的,如:消息必達、消息冪等等。本章節(jié)以典型的RabbitMQ為例,講解如何保證消息冪等的可實施解決方案,其他MQ選型均可參考。

消息重試演示

消息隊列的消息冪等性,主要是由MQ重試機制引起的。

因為消息生產(chǎn)者將消息發(fā)送到MQ-Server后,MQ-Server會將消息推送到具體的消息消費者。假設(shè)由于網(wǎng)絡(luò)抖動或出現(xiàn)異常時,MQ-Server根據(jù)重試機制就會將消息重新向消息消費者推送,造成消息消費者多次收到相同消息,造成數(shù)據(jù)不一致。

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

在RabbitMQ中,消息重試機制是默認開啟的,但只會在consumer出現(xiàn)異常時,才會重復(fù)推送。在使用中,異常的出現(xiàn)有可能是由于消費方又去調(diào)用第三方接口,由于網(wǎng)絡(luò)抖動而造成異常,但是這個異常有可能是暫時的。所以當消費者出現(xiàn)異常,可以讓其重試幾次,如果重試幾次后,仍然有異常,則需要進行數(shù)據(jù)補償。

數(shù)據(jù)補償方案:當重試多次后仍然出現(xiàn)異常,則讓此條消息進入死信隊列,最終進入到數(shù)據(jù)庫中,接著設(shè)置定時job查詢這些數(shù)據(jù),進行手動補償。

本節(jié)中以consumer消費異常為演示主體,因此需要修改RabbitMQ配置文件。

修改配置文件

修改consumer一方的配置文件

 # 消費者監(jiān)聽相關(guān)配置
    listener:
      simple:
        retry:
          # 開啟消費者(程序出現(xiàn)異常)重試機制,默認開啟并一直重試
          enabled: true
          # 最大重試次數(shù)
          max-attempts: 5
          # 重試間隔時間(毫秒)
          initial-interval: 3000
設(shè)置消費異常

當consumer消息監(jiān)聽類中添加異常,最終接受消息時,可以發(fā)現(xiàn),消息在接收五次后,最終出現(xiàn)異常。

消息冪等解決

要保證消息冪等性的話,其實最終要解決的就是保證多次操作,造成的影響是相同的。那么其解決方案的思路與服務(wù)間冪等的思路其實基本都是一致的。

  1. 消息防重表,解決思路與服務(wù)間冪等的防重表一致。
  2. redis:利用redis防重。

這兩種方案是最常見的解決方案。其實現(xiàn)思路其實都是一致的。

一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!

代碼實現(xiàn)

修改OrderController
 /**
     * 此處為了方便演示,不做基礎(chǔ)添加數(shù)據(jù)庫操作
     * @return
     */
@PostMapping("/addOrder")
public String addOrder(){

    String uniqueKey = String.valueOf(idWorker.nextId());

    MessageProperties messageProperties = new MessageProperties();
    messageProperties.setMessageId(uniqueKey);
    messageProperties.setContentType("text/plain");
    messageProperties.setContentEncoding("utf-8");
    Message message = new Message("1271700536000909313".getBytes(),messageProperties);
    rabbitTemplate.convertAndSend(RabbitMQConfig.REDUCE_STOCK_QUEUE,message);

    return "success";
}
修改stockApplication
 @Bean
public JedisPool jedisPool(){
    return new JedisPool("192.168.200.150",6379);
}
新增消息監(jiān)聽類
 @Component
public class ReduceStockListener {

    @Autowired
    private StockService stockService;

    @Autowired
    private JedisPool jedisPool;

    @Autowired
    private StockFlowService stockFlowService;

    @RabbitListener(queues = RabbitMQConfig.REDUCE_STOCK_QUEUE)
    @Transactional
    public void receiveMessage(Message message){

        //獲取消息id
        String messageId = message.getMessageProperties().getMessageId();

        Jedis jedis = jedisPool.getResource();

        System.out.println(messageId);
        try {

            //redis鎖去重校驗
            if (!"OK".equals(jedis.set(messageId, messageId, "NX", "PX", 300000))){
                System.out.println("重復(fù)請求");
                return;
            }

            //mysql狀態(tài)校驗
            if (!(stockFlowService.findByFlag(messageId).size() == 0)){
                System.out.println("數(shù)據(jù)已處理");
                return;
            }

            String goodsId = null;
            try {
                //獲取消息體中g(shù)oodsId
                goodsId = new String(message.getBody(),"utf-8");
                stockService.reduceStock(goodsId,messageId);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            int nextInt = new Random().nextInt(100);
            System.out.println("隨機數(shù):"+nextInt);
            if (nextInt%2 ==0){
                int i= 1/0;
            }


        } catch (RuntimeException e) {
            //解鎖
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            jedis.eval(script, Collections.singletonList(messageId), Collections.singletonList(messageId));
            System.out.println("出現(xiàn)異常了");
            System.out.println(messageId+":釋放鎖");
            throw e;
        }
    }
}

消息緩沖區(qū)

對于RabbitMQ的使用,默認情況下,每條消息都會進行分別的ack通知,消費完一條后,再來消費下一條。但是這樣就會造成大量消息的阻塞情況。所以為了提升消費者對于消息的消費速度,可以增加consumer數(shù)據(jù)或者對消息進行批量消費。MQ接收到producer發(fā)送的消息后,不會直接推送給consumer。而是積攢到一定數(shù)量后,再進行消息的發(fā)送。 這種方式的實現(xiàn),可以理解為是一種緩沖區(qū)的實現(xiàn),提升了消息的消費速度,但是會在一定程度上舍棄結(jié)果返回的實時性。

對于批量消費來說,也是需要考慮冪等的。對于冪等性的解決方案,沿用剛才的思路即可解決。

本文由傳智教育博學(xué)谷狂野架構(gòu)師教研團隊發(fā)布。

如果本文對您有幫助,歡迎關(guān)注點贊;如果您有任何建議也可留言評論私信,您的支持是我堅持創(chuàng)作的動力。

轉(zhuǎn)載請注明出處!文章來源地址http://www.zghlxwxcb.cn/news/detail-424835.html

到了這里,關(guān)于一次說透,4大服務(wù)性冪等場景架構(gòu)設(shè)計方案!的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包