激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - java開發(fā)微服務架構設計消息隊列的水有多深

java開發(fā)微服務架構設計消息隊列的水有多深

2022-03-03 12:48飄渺Jam Java教程

今天我們說說消息隊列的問題,來帶大家探一探消息隊列的水有多深,希望看完本文大家在引入消息隊列的時候先想一想,是不是一定要引入?引入消息隊列后產(chǎn)生的問題能不能解決

很多人在做架構設計時往往會“過度設計”,簡單問題復雜化,上來就引一堆中間件,我想大概原因主要有下面兩點:

為了秀(學)技術而架構
我們常說技術是為業(yè)務服務的,不能為了技術而技術,為了秀技術引入一堆復雜架構這是要不得的。

考慮問題不全面,或者說廣度不夠,不知道如何簡單化
舉個栗子,假設有一個高并發(fā)的用戶平臺需要處理注冊(寫)及登錄查詢(讀)功能,在數(shù)據(jù)庫層做了主從同步。為了解決主從同步延時問題引入了一個Redis,想實現(xiàn)寫主庫的時候同時寫Redis,然后讀的時候直接讀Redis,這就避免了主從延時同步問題。這就是典型的考慮問題不全面,這樣雖然能解決主從延時問題,但是又會導致雙寫事務的產(chǎn)生,那為什么不直接把主從同步的方式改成強同步復制呢,這樣不是直接保證了一致性嗎?
那你可能會說改成強同步復制不是會增加響應時間進而影響系統(tǒng)吞吐量嗎,那咱還可以對用戶做個分庫,多做幾個主從同步出來不就可以了嗎?

誒誒誒,跑題了,今天咱不是說消息隊列嗎?

哦,言歸正傳。今天我們說說消息隊列的問題,希望看完本文大家在引入消息隊列的時候先想一想,是不是一定要引入?引入消息隊列后產(chǎn)生的問題能不能解決?

 

消息隊列的作用

在微服務開發(fā)中我們經(jīng)常會引入消息中間件實現(xiàn)業(yè)務解耦,執(zhí)行異步操作, 現(xiàn)在讓我們來看看使用消息中間件的好處和弊端。

首先需要肯定是使用消息組件有很多好處,其中最核心的三個是:解耦、異步、削峰。

  • 解耦:客戶端只要講請求發(fā)送給特定的通道即可,不需要感知接收請求實例的情況。
  • 異步:將消息寫入消息隊列,非必要的業(yè)務邏輯以異步的方式運行,加快響應速度。
  • 削峰:消息中間件在消息被消費之前一直緩存消息,消息處理端可以按照自己處理的并發(fā)量從消息隊列中慢慢處理消息,不會一瞬間壓垮業(yè)務。

當然消息中間件并不是銀彈,引入消息機制后也會有如下一些弊端:

  • 潛在的性能瓶頸:消息代理可能會存在性能瓶頸。幸運的是目前主流的消息中間件都支持高度的橫向擴展。
  • 潛在的單點故障:消息代理的高可用性至關重要,否則系統(tǒng)整體的可靠性將受到影響,幸運的是大多數(shù)消息中間件都是高可用的。
  • 額外的操作復雜性:消息系統(tǒng)是一個必須獨立安裝、配置和運維的系統(tǒng)組件,增加了運維的復雜度。

這些弊端我們借助消息中間件本身提供的擴展、高可用能力可以解決,但是要真正用好消息中間件我們還需要關注可能會遇到的一些設計難題。

 

消息隊列的設計難題

處理并發(fā)和順序消息

在生產(chǎn)環(huán)境中為了提高消息處理的能力以及應用程序的吞吐量,一般會將消費者部署多個實例節(jié)點。那么帶來的挑戰(zhàn)就是如何確保每個消息只被處理一次,并且是按照他們的發(fā)送順序來處理的。

例如:假設有3個相同的接收方實例從同一個點對點通道讀取消息,發(fā)送方按順序發(fā)布了 Order Created、Order Updated 和 Order Cancelled 這3個事件消息。簡單的消息實現(xiàn)可能就會同事講每個消息給不同的接收方。若由于網(wǎng)絡問題導致延遲,消息可能沒有按照他們發(fā)出時的順序被處理,這將導致奇怪的行為,服務實例可能在另一個服務器處理 Order Created 消息之前處理 Order Cancelled消息。

Kafka 使用的解決方案是使用分片(分區(qū))通道。整體解決方案分為三個部分:

  • 一個主題通道由多個分片組成,每個分片的行為類似一個通道。
  • 發(fā)送方在消息頭部指定分片鍵如orderId,Kafka使用分片鍵將消息分配給特定的分片。
  • 將接收方的多個實例組合在一起,并將他們視為相同的邏輯接收方(消費者組)。kafka將每個分片分配給單個接收器,它在接收方啟動和關閉時重新分配分片。

java開發(fā)微服務架構設計消息隊列的水有多深

如上圖所示,每個Order事件消息都將orderId作為其分片鍵。特定訂單的每個事件都發(fā)布到同一個分片。而且該分片中的消息始終由同一個接收方實例讀取,因此這樣就能夠保證按順序處理這些消息。

處理重復消息

引入消息架構必須要解決的另一個挑戰(zhàn)是處理重復消息。在理想情況下,消息代理應該只傳遞一次消息,但保證消息有且僅有一次的消息傳遞的成本通常很高。相反,很多消息組件承諾至少保證成功傳遞一次消息。

在正常情況下,消息組件只會傳遞一次消息。但是當客戶端、網(wǎng)絡或消息組件故障可能導致消息被多次傳遞。假設客戶端在處理消息后發(fā)送確認消息前,他的數(shù)據(jù)庫崩潰了,這時消息組件將再次發(fā)送未確認的消息,在數(shù)據(jù)庫重新啟動時向該客戶端發(fā)送。

處理重復消息有以下兩種不同的方法:

編寫冪等消息處理程序

跟蹤消息并丟棄重復項

編寫冪等消息處理器

如果應用程序處理消息的邏輯是滿足冪等的,那么重復消息就是無害的。程序的冪等性是指,即使這個應用被相同輸入?yún)?shù)多次重復調(diào)用時,也不會產(chǎn)生額外的效果。例如:取消一個已經(jīng)取消的訂單,就是一個冪等性操作。同樣,創(chuàng)建一個已經(jīng)存在的訂單操作也必是這樣。滿足冪等的消息處理程序可以被放心的執(zhí)行多次,只要消息組件在傳遞消息時保持相同的消息順序。

但是不幸的是,應用程序通常不是冪等的。或者你現(xiàn)在正在使用的消息組件在重新傳遞消息時不會保留排序。重復或無序消息可能會導致錯誤。在這種情況下,你需要編寫跟蹤消息并丟棄重復消息的消息處理程序。

跟蹤消息并丟棄重復消息

考慮一個授權消費者信用卡的消息處理程序。它必須為每個訂單僅執(zhí)行一次信用卡授權操作。這段應用程序每次調(diào)用時都會產(chǎn)生不同的效果。如果重復消息導致消息處理程序多次執(zhí)行該邏輯,則應用程序的行為將不正確。執(zhí)行此類應用程序邏輯的消息處理程序必須通過檢測和丟棄重復消息而讓它成為冪等的。

一個簡單的解決方案是消息接收方使用 message id 跟蹤他已處理的消息并丟棄任何重復項。例如,在數(shù)據(jù)庫表中存儲它消費的每條消息的 message id。

java開發(fā)微服務架構設計消息隊列的水有多深

當接收方處理消息時,它將消息的 message id 作為創(chuàng)建和變更業(yè)務實體的事務的一部分記錄在數(shù)據(jù)表里。如上圖所示,接收方將包含message id 的行插入 PROCESSED_MESSAGE表。如果消息是重復的,則INSERT將失敗,接收方可以選擇丟棄該消息。

另一個解決方案是消息處理程序在應用程序表,而不是專門表中記錄 message id。當時用具有受限事務模型的NoSQL數(shù)據(jù)庫時,此方法特別有用,因為 NoSQL數(shù)據(jù)庫通常不支持將針對兩個表的更新作為數(shù)據(jù)庫事務。

處理事務性消息

服務通常需要在更新數(shù)據(jù)庫的事務中發(fā)布消息,數(shù)據(jù)庫更新和消息發(fā)送都必須在事務中進行,否則服務可能會更新數(shù)據(jù)庫然后在發(fā)送消息之前崩潰。

如果服務不以原子方式執(zhí)行者兩個操作,則類似的故障可能使系統(tǒng)處于不一致狀態(tài)。

接下來我們看一下常用的保證事務消息的兩種解決方案,最后再看看現(xiàn)代消息組件RocketMQ的事務性消息解決方案。

使用數(shù)據(jù)庫表作為消息隊列

如果你的應用程序正在使用關系型數(shù)據(jù)庫,要保證數(shù)據(jù)的更新和消息發(fā)送之間的事務可以直接使用事務性發(fā)件箱模式,Transactional Outbox。

java開發(fā)微服務架構設計消息隊列的水有多深

此模式使用數(shù)據(jù)庫表作為臨時消息隊列。如上圖所示,發(fā)送消息的服務有個OUTBOX數(shù)據(jù)表,在進行INSERT、UPDATE、DELETE 業(yè)務操作時也會給OUTBOX數(shù)據(jù)表INSERT一條消息記錄,這樣可以保證原子性,因為這是基于本地的ACID事務。

OUTBOX表充當臨時消息隊列,然后我們在引入一個消息中繼(MessageRelay)的服務,由他從OUTBOX表中讀取數(shù)據(jù)并發(fā)布消息到消息組件。

消息中繼的實現(xiàn)可以很簡單,只需要通過定時任務定期從OUTBOX表中拉取最新未發(fā)布的數(shù)據(jù),獲取到數(shù)據(jù)后將數(shù)據(jù)發(fā)送給消息組件,最后將完成發(fā)送的消息從OUTBOX表中刪除即可。

使用事務日志發(fā)布事件

另外一種保證事務性消息的方式是基于數(shù)據(jù)庫的事務日志,也就是所謂的數(shù)據(jù)變更捕獲,Change Data Capture,簡稱CDC。

一般數(shù)據(jù)庫在數(shù)據(jù)發(fā)生變更的時候都會記錄事務日志(Transaction Log),比如MySQL的binlog。事務日志可以簡單的理解成數(shù)據(jù)庫本地的一個文件隊列,它主要記錄按時間順序發(fā)生的數(shù)據(jù)庫表變更記錄。

這里我們利用alibaba開源的組件canal結合MySQL來說明下這種模式的工作原理。

更多操作說明可以參考官方文檔:https://github.com/alibaba/canal

canal工作原理

canal 模擬 MySQL slave 的交互協(xié)議,把自己偽裝成一個MySQL的 slave節(jié)點 ,向 MySQL master 發(fā)送dump 協(xié)議;

MySQL master 收到 dump 請求,開始推送 binary log 給 slave (即 canal );

canal 解析 binary log 對象(原始為 byte 流),然后可以將解析后的數(shù)據(jù)直接發(fā)送給消息組件。

RocketMQ事務消息解決方案

Apache RocketMQ在4.3.0版中已經(jīng)支持分布式事務消息,RocketMQ采用了2PC的思想來實現(xiàn)了提交事務消息,同時增加一個補償邏輯來處理二階段超時或者失敗的消息,如下圖所示。

java開發(fā)微服務架構設計消息隊列的水有多深

RocketMQ實現(xiàn)事務消息主要分為兩個階段:正常事務的發(fā)送及提交、事務信息的補償流程。

整體流程為:

正常事務發(fā)送與提交階段
1、生產(chǎn)者發(fā)送一個半消息給MQServer(半消息是指消費者暫時不能消費的消息)
2、服務端響應消息寫入結果,半消息發(fā)送成功
3、開始執(zhí)行本地事務
4、根據(jù)本地事務的執(zhí)行狀態(tài)執(zhí)行Commit或者Rollback操作

事務信息的補償流程
1、如果MQServer長時間沒收到本地事務的執(zhí)行狀態(tài)會向生產(chǎn)者發(fā)起一個確認回查的操作請求
2、生產(chǎn)者收到確認回查請求后,檢查本地事務的執(zhí)行狀態(tài)
3、根據(jù)檢查后的結果執(zhí)行Commit或者Rollback操作
補償階段主要是用于解決生產(chǎn)者在發(fā)送Commit或者Rollback操作時發(fā)生超時或失敗的情況。

在生產(chǎn)者使用RocketMQ發(fā)送事務消息的時候我們也會借鑒第一種方案即自建一張事務日志表,然后在執(zhí)行本地事務的時候同時生成一條事務日志記錄,讓本地事務與日志事務在同一個方法中,同時添加 @Transactional 注解,保證兩個操作事務是一個原子操作。這樣如果事務日志表中有這個本地事務的信息,那就代表本地事務執(zhí)行成功,需要Commit,相反如果沒有對應的事務日志,則表示沒執(zhí)行成功,需要Rollback。

孩砸,看完這篇文章,消息隊列你能把握住了嗎?

以上就是java開發(fā)之微服務架構消息隊列的水有多深的詳細內(nèi)容,更多關于微服務架構消息隊列的資料請關注服務器之家其它相關文章!

原文鏈接:https://jianzh5.blog.csdn.net/article/details/117018102

延伸 · 閱讀

精彩推薦
  • Java教程利用Java8 Optional如何避免空指針異常詳解

    利用Java8 Optional如何避免空指針異常詳解

    Optional可以讓你的代碼具有可讀性,且會避免出現(xiàn)空指針異常。 下面這篇文章主要給大家介紹了關于利用Java8 Optional如何避免空指針異常的相關資料,文中...

    劉亞濤6472021-03-18
  • Java教程例舉fastJson和jackson轉(zhuǎn)json的區(qū)別

    例舉fastJson和jackson轉(zhuǎn)json的區(qū)別

    今天小編就為大家分享一篇關于例舉fastJson和jackson轉(zhuǎn)json的區(qū)別,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編...

    執(zhí)筆記憶的空白11732021-06-21
  • Java教程淺談Mybatis SqlSession執(zhí)行流程

    淺談Mybatis SqlSession執(zhí)行流程

    本文主要介紹了淺談Mybatis SqlSession執(zhí)行流程,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧...

    Java有貨6902021-10-03
  • Java教程Java練手小項目實現(xiàn)一個項目管理系統(tǒng)

    Java練手小項目實現(xiàn)一個項目管理系統(tǒng)

    讀萬卷書不如行萬里路,只學書上的理論是遠遠不夠的,只有在實戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用Java實現(xiàn)一個項目管理系統(tǒng),大家可以在...

    空山新雨后~10222022-02-24
  • Java教程Java反射機制的講解

    Java反射機制的講解

    今天小編就為大家分享一篇關于Java反射機制的講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    yangyongUestc4382021-07-31
  • Java教程我從jdk1.8升級到jdk11所遇到的坑都有這些

    我從jdk1.8升級到jdk11所遇到的坑都有這些

    這篇文章主要介紹了從jdk1.8升級到jdk11將會遇到的一些坑,本文給大家分享解決方案對大家的學習或工作具有參考借鑒價值,對jdk1.8升級到jdk11相關知識感興...

    AI碼師5042021-11-22
  • Java教程Java的方法和this關鍵字如何理解與應用

    Java的方法和this關鍵字如何理解與應用

    Java語言中的“方法”(Method)在其他語言當中也可能被稱為“函數(shù)”(Function)。對于一些復雜的代碼邏輯,如果希望重復使用這些代碼,并且做到“隨時...

    spring小楊11272022-02-15
  • Java教程java中ZXing 生成、解析二維碼圖片的小示例

    java中ZXing 生成、解析二維碼圖片的小示例

    ZXing 是一個開源 Java 類庫用于解析多種格式的 1D/2D 條形碼,這篇文章主要介紹了java中ZXing 生成、解析二維碼圖片的小示例 ,有興趣的可以了解一下。...

    靜默虛空2282020-07-27
主站蜘蛛池模板: 午夜精品久久久久久久96蜜桃 | 午夜色片 | 激情综合在线 | 色网站综合 | 日韩视频一区二区三区四区 | 黄污网站在线 | 中文字幕一二区 | 色黄视频免费观看 | 国产亚洲精品影达达兔 | 久久国产精品二国产精品中国洋人 | 九九视屏 | 九草在线视频 | 亚洲午夜在线观看 | 热99re久久免费视精品频软件 | 亚洲精品久久久久久 | 啪啪激情 | 亚洲视频在线网 | a视频在线免费观看 | 特片网久久| 大学生一级毛片在线视频 | 91短视频网页版 | 国产精品免费久久久久久 | 91精品久久久久久久久久久 | 可以看逼的视频 | 日日摸夜夜骑 | 亚洲少妇诱惑 | 欧美精品成人一区二区三区四区 | 国产一区二区久久精品 | 国产在线欧美日韩 | 久久久久久久久成人 | 欧美不卡| 性片网站 | 欧美成人午夜一区二区三区 | 一区二区三区黄色 | 国产毛片aaa一区二区三区视频 | 亚洲一区二区不卡视频 | 国产91九色视频 | 欧美成人久久 | 成人免费福利视频 | 欧美性色黄大片www 成人免费网站在线观看 | 国产高潮国产高潮久久久91 |