国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

微服務架構:利用事件驅動實現最終一致性

開發 架構
微服務中,不同模塊之間使用的數據庫是不同的,不同模塊之間部署的服務去也有可能是不用的,那么分區容錯是無法避免的,因為服務之間的調用不能保證百分百的沒問題,所以系統設計必須考慮這種情況。

 事務一致性

首先,我們來回顧一下ACID原則:

  • Atomicity:原子性,改變數據狀態要么是一起完成,要么一起失敗
  • Consistency:一致性,數據的狀態是完整一致的
  • Isolation:隔離線,即使有并發事務,互相之間也不影響
  • Durability:持久性, 一旦事務提交,不可撤銷

在單體應用中,我們可以利用關系型數據庫的特性去完成事務一致性,但是一旦應用往微服務發展,根據業務拆分成不用的模塊,而且每個模塊的數據庫已經分離開了,這時候,我們要面對的就是分布式事務了,需要自己在代碼里頭完成ACID了。比較流行的解決方案有:兩階段提交、補償機制、本地消息表(利用本地事務和MQ)、MQ的事務消息(RocketMQ)。

[[278930]]

CAP定理

1998年,加州大學的計算機科學家 Eric Brewer 提出,分布式系統有三個指標。

  • Consistency:一致性
  • Availability:可用性
  • Partition tolerance:分區容錯

Eric Brewer 說,這三個指標不可能同時做到。這個結論就叫做 CAP 定理。

微服務中,不同模塊之間使用的數據庫是不同的,不同模塊之間部署的服務去也有可能是不用的,那么分區容錯是無法避免的,因為服務之間的調用不能保證百分百的沒問題,所以系統設計必須考慮這種情況。因此,我們可以認為CAP的P總是成立的,剩下的C和A無法同時做到。

實際上根據分布式系統中CAP原則,當P(分區容忍)發生的時候,強行追求C(一致性),會導致(A)可用性、吞吐量下降,此時我們一般用最終一致性來保證我們系統的AP能力。當然不是放棄C,而是放棄強一致性,而且在一般情況下CAP都能保證,只是在發生分區容錯的情況下,我們可以通過最終一致性來保證數據一致。

事件驅動實現最終一致性

事件驅動架構在領域對象之間通過異步的消息來同步狀態,有些消息也可以同時發布給多個服務,在消息引起了一個服務的同步后可能會引起另外消息,事件會擴散開。嚴格意義上的事件驅動是沒有同步調用的。

例子:

在電商里面,用戶下單必須根據庫存來確定訂單是否成交。

項目架構:SpringBoot2+Mybatis+tk-Mybatis+ActiveMQ【因為小例子,不做成Spring Cloud架構】

首先,我們來看看正常的服務之間調用:

 

微服務架構:利用事件驅動實現最終一致性

 

代碼:

  1. @Override 
  2. @Transactional(rollbackFor = Exception.class) 
  3. public Result placeOrder(OrderQuery query) { 
  4.  Result result = new Result(); 
  5.  // 先遠程調用Stock-Service去減少庫存 
  6.  RestTemplate restTemplate = new RestTemplate(); 
  7.  //請求頭 
  8.  HttpHeaders headers = new HttpHeaders(); 
  9.  headers.setContentType(MediaType.APPLICATION_JSON); 
  10.  //封裝成一個請求對象 
  11.  HttpEntity entity = new HttpEntity(query, headers); 
  12.  // 同步調用庫存服務的接口 
  13.  Result stockResult = restTemplate.postForObject("http://127.0.0.1:8081/stock/reduceStock",entity,Result.class); 
  14.  if (stockResult.getCode() == Result.ResultConstants.SUCCESS){ 
  15.  Order order = new Order(); 
  16.  BeanUtils.copyProperties(query,order); 
  17.  order.setOrderStatus(1); 
  18.  Integer insertCount = orderMapper.insertSelective(order); 
  19.  if (insertCount == 1){ 
  20.  result.setMsg("下單成功"); 
  21.  }else { 
  22.  result.setMsg("下單失敗"); 
  23.  } 
  24.  }else { 
  25.  result.setCode(Result.ResultConstants.FAIL); 
  26.  result.setMsg("下單失?。?quot;+stockResult.getMsg()); 
  27.  } 
  28.  return result; 

我們可以看到,這樣的服務調用的弊端多多:

1、訂單服務需同步等待庫存服務的返回結果,接口結果返回延誤。2、訂單服務直接依賴于庫存服務,只要庫存服務崩了,訂單服務不能再正常運行。3、訂單服務需考慮并發問題,庫存最后可能為負。

下面開始利用事件驅動實現最終一致性

1、在訂單服務新增訂單后,訂單的狀態是“已開啟”,然后發布一個Order Created事件到消息隊列上

 

微服務架構:利用事件驅動實現最終一致性

 

代碼:

  1. @Transactional(rollbackFor = Exception.class) 
  2. public Result placeOrderByMQ(OrderQuery query) { 
  3.  Result result = new Result(); 
  4.  // 先創建訂單,狀態為下單0 
  5.  Order order = new Order(); 
  6.  BeanUtils.copyProperties(query,order); 
  7.  order.setOrderStatus(0); 
  8.  Integer insertCount = orderMapper.insertSelective(order); 
  9.  if (insertCount == 1){ 
  10.  // 發送 訂單消息 
  11.  MqOrderMsg mqOrderMsg = new MqOrderMsg(); 
  12.  mqOrderMsg.setId(order.getId()); 
  13.  mqOrderMsg.setGoodCount(query.getGoodCount()); 
  14.  mqOrderMsg.setGoodName(query.getGoodName()); 
  15.  mqOrderMsg.setStockId(query.getStockId()); 
  16.  jmsProducer.sendOrderCreatedMsg(mqOrderMsg); 
  17.  // 此時的訂單只是開啟狀態 
  18.  result.setMsg("下單成功"); 
  19.  } 
  20.  return result; 

2、庫存服務在監聽到消息隊列OrderCreated中的消息,將庫存表中商品的庫存減去下單數量,然后再發送一個Stock Locked事件給消息隊列。

 

微服務架構:利用事件驅動實現最終一致性

 

代碼:

  1. /** 
  2.  * 接收下單消息 
  3.  * @param message 接收到的消息 
  4.  * @param session 上下文 
  5.  */ 
  6. @JmsListener(destination = ORDER_CREATE,containerFactory = "myListenerContainerFactory"
  7. @Transactional(rollbackFor = Exception.class) 
  8. public void receiveOrderCreatedMsg(Message message, Session session){ 
  9.  try { 
  10.  if (message instanceof ActiveMQObjectMessage){ 
  11.  MqStockMsg result = new MqStockMsg(); 
  12.  ActiveMQObjectMessage objectMessage=(ActiveMQObjectMessage)message; 
  13.  MqOrderMsg msg = (MqOrderMsg)objectMessage.getObject(); 
  14.  Integer updateCount = stockMapper.updateNumByStockId(msg.getStockId(),msg.getGoodCount()); 
  15.  if (updateCount >= 1){ 
  16.  result.setSuccess(true); 
  17.  result.setOrderId(msg.getId()); 
  18.  }else { 
  19.  result.setSuccess(false); 
  20.  } 
  21.  // 手動ack,使消息出隊列,不然會不斷消費 
  22.  message.acknowledge(); 
  23.  // 發送庫存鎖定消息到MQ 
  24.  jmsProducer.sendStockLockedMsg(result); 
  25.  } 
  26.  } catch (JMSException e) { 
  27.  log.error("接收訂單創建消息報錯:"+e.getMessage()); 
  28.  } 

仔細的朋友可能會看到:message.acknowledge(),即手動確認消息。因為在保證庫存服務的邏輯能正常執行后再確認消息已消費,可以保證消息的投遞可靠性,萬一在庫存服務執行時報出異常,我們可以做到重新消費該下單消息。

3、訂單服務接收到Stock Locked事件,將訂單的狀態改為“已確認”

 

微服務架構:利用事件驅動實現最終一致性

 

代碼:

  1. /** 
  2.  * 判斷是否還有庫存,有庫存更新訂單狀態為1,無庫存更新訂單狀態為2,并且通知用戶(WebSocket) 
  3.  * @param message 
  4.  */ 
  5. @JmsListener(destination = STOCK_LOCKED,containerFactory = "myListenerContainerFactory"
  6. @Transactional(rollbackFor = Exception.class) 
  7. public void receiveStockLockedMsg(Message message, Session session){ 
  8.  try { 
  9.  if (message instanceof ActiveMQObjectMessage){ 
  10.  ActiveMQObjectMessage objectMessage=(ActiveMQObjectMessage)message; 
  11.  MqStockMsg msg = (MqStockMsg)objectMessage.getObject(); 
  12.  if (msg.isSuccess()){ 
  13.  Order updateOrder = new Order(); 
  14.  updateOrder.setId(msg.getOrderId()); 
  15.  updateOrder.setOrderStatus(1); 
  16.  orderMapper.updateByPrimaryKeySelective(updateOrder); 
  17.  log.info("訂單【"+msg.getOrderId()+"】下單成功"); 
  18.  }else { 
  19.  Order updateOrder = new Order(); 
  20.  updateOrder.setId(msg.getOrderId()); 
  21.  updateOrder.setOrderStatus(2); 
  22.  orderMapper.updateByPrimaryKeySelective(updateOrder); 
  23.  // 通知用戶庫存不足,訂單被取消 
  24.  log.error("訂單【"+msg.getOrderId()+"】因庫存不足被取消"); 
  25.  } 
  26.  // 手動ack,使消息出隊列,不然會不斷消費 
  27.  message.acknowledge(); 
  28.  } 
  29.  } catch (JMSException e) { 
  30.  log.error("接收庫存鎖定消息報錯:"+e.getMessage()); 
  31.  } 

同樣,這里我們也是會利用手動確認消息來保證消息的投遞可靠性。

至此,已經全部搞定了。我們看一下和正常的服務調用對比如何:

1、訂單服務不再直接依賴于庫存服務,而是將下單事件發送到MQ中,讓庫存監聽。

2、訂單服務能真正的作為一個模塊獨立運行。

3、解決了并發問題,而且MQ的隊列處理效率非常的高。

但是也存在下面的問題:

1、用戶體驗改變了:因為使用事件機制,訂單是立即生成的,可是很有可能過一會,系統會提醒你沒貨了。。這就像是排隊搶購一樣,排著排著就被通知沒貨了,不用再排隊了。

2、數據庫可能會存在很對沒有完成下單的訂單。

最后,如果真的要考慮用戶體驗,并且不想數據庫存在很多不必要的數據,該怎么辦?

那就把訂單服務和庫存服務聚合在一起吧。解決當前的問題應當是首先要考慮的,我們設計微服務的目的是本想是解決業務并發量。而現在面臨的卻是用戶體驗的問題,所以架構設計也是需要妥協的。

最主要是,我們是經過思考和分析的,每個方案能做到哪種程度,能應用到哪種場景。正所謂,技術要和實際場景結合,我們不能為了追求新技術而生搬硬套。

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2020-02-25 23:39:11

架構運維技術

2021-07-26 06:33:42

CRDT數據CAP

2019-01-15 17:58:03

微服務架構數據

2023-11-22 12:55:59

微服務架構數據庫

2019-12-17 08:40:33

微服務架構數據

2019-09-05 08:43:34

微服務分布式一致性數據共享

2024-06-04 09:51:48

2023-12-27 14:23:10

微服務數據存儲

2022-07-21 06:54:28

微服務系統RocketMQ

2017-07-25 14:38:56

數據庫一致性非鎖定讀一致性鎖定讀

2020-11-24 09:03:41

一致性MySQLMVCC

2025-05-13 08:44:26

2022-12-14 08:23:30

2017-07-02 16:28:06

MySQL數據庫集群

2017-05-19 15:00:05

session架構web-server

2021-11-01 21:15:54

微服務系統數據

2022-11-10 07:49:09

hash算法代碼

2023-06-07 08:10:29

2016-12-19 18:41:09

哈希算法Java數據

2021-06-16 08:33:02

分布式事務ACID
點贊
收藏

51CTO技術棧公眾號

免费人成精品欧美精品| 亚洲人成电影| av动漫精品一区二区| 在线精品视频一区二区三四| av动漫在线播放| 一道在线中文一区二区三区| 日韩av影院在线观看| 免费在线看黄网站| 成年网站在线播放| 国产不卡免费视频| 成人午夜激情| 久久精品亚洲一区二区三区浴池| 亚洲日韩第一页| 欧美影院精品一区| 黄色小说在线播放| 亚洲视频免费在线观看| 国产树林野战在线播放| 一本到12不卡视频在线dvd| 久久九九亚洲综合| 欧美一卡二卡| 欧美一二三区精品| 无人视频在线观看免费| 国产精品视频免费| 久久久久久www| 久久永久免费| 一本一本a久久| 最新日韩欧美| 91大片在线观看| 色琪琪久久se色| 亚洲性日韩精品一区二区| 色戒汤唯在线观看| 欧美视频一区二区三区四区 | 精品欧美乱码久久久久久1区2区| 丁香资源影视免费观看| 要久久电视剧全集免费| 欧美亚洲国产免费| 精品69视频一区二区三区Q| 欧美激情区在线播放| 四虎影视成人精品国库在线观看| 奇米一区二区三区av| 国产91aaa| 午夜一级久久| 欧美12av| 麻豆国产欧美日韩综合精品二区 | 日韩午夜激情av| 黄色软件视频在线观看| 在线看片第一页欧美| 国产一区二区三区免费在线 | 二区三区不卡| 久久久久久久一区二区三区| 成人午夜av| 日韩久久久久久久| 99国产精品久久久久久久久久久 | 久久亚洲一级片| 日本24小时在线高清视频| 欧美亚洲免费在线一区| aa国产成人| 欧美高清激情视频| 免费日韩在线观看| 99视频精品在线| 美臀av在线| 亚洲精品不卡在线| 国产aⅴ精品一区二区四区| 国产成一区二区| 麻豆精品在线播放| 女生裸体视频网站免费观看| 日韩精品一区二区三区在线观看 | 奇米色欧美一区二区三区| 国产精品日韩二区| 91在线精品一区二区| 清纯唯美亚洲色图| 日韩亚洲欧美中文在线| 99久久精品费精品国产风间由美| 日本一区视频在线| 国产精品每日更新在线播放网址| 在线观看免费版| 欧美激情成人在线视频| 久久国产精品亚洲77777| 成人三级av| 亚洲美女在线观看| 91精品精品| 91视频免费版污| 精品国产乱码久久久久久图片 | 99热在线观看免费| 日韩精品一区二区在线观看| 日韩有码av| 亚洲制服中文| 精品福利视频导航| 视频一区日韩| 中文字幕中文字幕一区三区| 大伊人狠狠躁夜夜躁av一区| 久久av网站| 国产高清免费在线| 色女孩综合影院| 久久久久97| 无码粉嫩虎白一线天在线观看 | 日韩主播视频在线| 女人被男人躁得好爽免费视频 | 一区二区三区入口| 亚洲国产成人爱av在线播放| 欧美电影免费播放| 波多野结衣天堂| 亚洲性生活视频| 久久中文在线| 四虎影视精品成人| 欧美影院在线播放| 成人少妇影院yyyy| 欧美色图天堂| 国产精品免费一区二区三区在线观看| 中文字幕欧美日韩一区| 成人深夜福利| 成人在线观看www| 欧美乱妇15p| 色综合久久中文| av 日韩 人妻 黑人 综合 无码| 美女搞黄视频在线观看| 国产亚洲福利社区| 久久国产精品99久久人人澡| 亚洲第一视频| 国产高清视频一区三区| 欧美—级在线免费片| 日韩美女在线| 糖心vlog在线免费观看| 亚洲国产成人精品一区二区| 日韩福利电影在线| 色黄网站在线观看| 日本不卡久久| 欧美成人精品二区三区99精品| 亚洲午夜极品| 91看片在线观看| 精品视频第一区| 在线不卡中文字幕播放| 国产视频亚洲| 国产精品久久久久久福利| 精品国产一二| 欧美精品乱码久久久久久| 一本一本久久| av电影高清在线观看| 亚洲国产日韩欧美| 亚洲片国产一区一级在线观看| 国产福利91精品一区二区三区| 欧美大片免费高清观看| 美女扒开大腿让男人桶 | 川上优的av在线一区二区| 国产私拍一区| 日韩午夜在线观看视频| 夜夜爽av福利精品导航| 欧美巨大xxxx做受沙滩| 一级毛片在线播放| 色999日韩欧美国产| 国产999精品久久久久久绿帽| 国产精品va在线播放| 欧美一二三视频| 国产乱人伦偷精品视频免下载| 日本xxxxxxx免费视频| 91精品国产91久久久久福利| 亚洲激情图片小说视频| 欧美区日韩区| segui88久久综合| 一区二区三区加勒比av| 亚州av乱码久久精品蜜桃| 日本a级在线| 欧美三级午夜理伦三级老人| 日韩在线视频观看| 亚洲欧美自拍偷拍色图| 一区二区视频欧美| 中文不卡1区2区3区| 无码少妇一区二区三区芒果| 国产精品福利在线| 91精品国产综合久久蜜臀| 成人一区二区在线观看| 欧美人与牛zoz0性行为| 黄色网页在线看| 日韩avxxx| 亚洲va欧美va国产综合剧情| 精品电影一区二区| 国产精品麻豆久久久| 女人天堂亚洲aⅴ在线观看| 超级碰碰不卡在线视频| 草草草在线视频| 99久久自偷自偷国产精品不卡| 日韩欧美区一区二| 国产三级欧美三级日产三级99| 日韩欧美自拍| av免费不卡| 日本搞黄视频| 久久久99国产精品免费| 日韩有码在线播放| 日韩欧美aaa| 26uuu亚洲综合色| 日韩视频中文| 欧美韩一区二区| 阿v视频在线观看| 黑料吃瓜在线观看| 欧美黄色免费网址| 国产精品久久久久免费| 久久中文字幕在线| 日韩一区二区在线观看| 亚洲自拍偷拍网站| 久久亚洲一区二区三区明星换脸|