同步架構和異步架構的區別,你知道嗎?
就程序員而言,日后的職業發展可以走 3 個方向:專攻技術深度、轉團隊管理、晉升架構師。
成為一名優秀的架構師,是大多數技術人的追求。但資深架構師的出現幾率僅約為 0.3%。
如果想在 3-5 年后穩坐金字塔尖,必須有扎實的代碼功底和項目積累,也要意識地培養技術廣度和架構思維能力。多學習牛人經驗也可獲益良多。
圖片
1 同步調用
同步調用是指在請求發起后,調用方一直阻塞等待調用處理完成的過程。在所提供的例子中,客戶端代碼 ClientCode 需要執行發送郵件的操作 sendEmail,這會觸發對 EmailService 的調用。
EmailService 將調用 SmtpEmailAdapter 類來處理請求,而該類會通過 SMTP 和 TCP 協議調用遠程服務,將請求發送到遠程服務器。遠程服務器收到消息后,會執行一系列操作,然后將郵件發送出去,并返回結果。
Adapter 接收到返回后,再將結果返回給 EmailService。EmailService 收到返回結果后,再將其返回給 ClientCode。在整個 sendEmail 過程中,ClientCode 會一直阻塞等待最終調用結果的返回,以確定操作是成功還是失敗。由于這個等待過程是阻塞的,因此被稱為同步調用。
2 異步調用
異步調用與同步調用相反。在異步調用的過程中,以發送郵件的例子為例,用戶 ClientCode 調用 EmailService 后,EmailService 將調用請求發送到消息隊列,然后立即返回。
ClientCode 在收到返回后可以繼續向下處理,而不會繼續阻塞等待。實際上,消息被發送到隊列后,尚未被處理。在后續的消息消費階段,比 EmailService 的返回可能會稍晚一些。有一個消息隊列消費者 QueueConsumer 從消息隊列中取出消息,然后將其發送給 SmtpAdapter,即調用 SmtpAdapter。
處理邏輯與同步調用類似,SmtpAdapter 通過 SMTP 通信協議將消息發送到遠程服務器,執行郵件發送操作,通過 RemoteServer 進行處理。處理完成后,收到返回結果后通知消息隊列 Queue。
在這個過程中,客戶端的調用(即應用程序的調用)和實際的業務邏輯(發送郵件的操作)是異步的。在郵件發送操作的處理過程中,客戶端代碼已經返回,它可以繼續執行自己的后續操作,而不需要等待郵件的發送完成,這就是異步調用。
圖片
使用異步調用架構的主要手段之一是通過消息隊列來構建。以下是該架構的圖示:
- 消息生產者(Message Producer):負責產生消息并將其發送到消息隊列。消息生產者是異步的,它發送完消息后就可以繼續執行其他任務,而不必等待消息被處理。
- 消息隊列(Message Queue):用于存儲和傳遞消息。消息隊列作為中介,接收生產者發送的消息,并將其提供給消費者。常見的消息隊列系統包括 RabbitMQ、Apache Kafka、ActiveMQ 等。
- 消息消費者(Message Consumer):從消息隊列中獲取消息并進行相應的業務邏輯處理。與消息生產者一樣,消息消費者也是異步的,它可以在獲取消息后立即開始處理,而無需等待消息的產生。
使用消息隊列構建一個異步調用架構,你需要了解3種角色,一種是消息的生產者,一種是消息隊列,還有一種是消息的消費者。
消息的生產者是客戶端應用程序代碼的一部分,用來初始化異步調用處理流程。
在基于消息隊列的處理中,生產者的職責非常少,它要做的就是創建一個合法的消息,并把這個消息發送到消息隊列中,由應用開發者決定生產者的代碼在哪里執行,什么時候發送消息。
消息隊列是消息發送的目的地,也是消息發給消費者的一個緩沖區。實現消息隊列的方法有很多種,可以使用共享文件夾,也可以利用關系數據庫或者 NoSQL 系統。
然而,最主要且常見的做法是使用專門的分布式消息隊列服務器。這些消息隊列服務器被設計用于高效地存儲、傳遞和處理大量的異步消息。它們提供了可靠性、可伸縮性和高性能的特性,以滿足不同應用場景的需求。
一些流行的分布式消息隊列系統包括:
- RabbitMQ:一個開源的消息隊列系統,實現了高級消息隊列協議(AMQP)。
- Apache Kafka:分布式流處理平臺,具有高吞吐量和可持久性的特點。
- ActiveMQ:一個開源的消息和集成模式服務器,實現了Java Message Service(JMS)規范。
- Amazon SQS(Simple Queue Service):由亞馬遜提供的托管消息隊列服務。
- Redis:一種內存中數據結構存儲,也可用作消息代理。
業務架構的第三個重要角色就是消息的消費者。消息的消費者從消息隊列中接受并處理消息,消息的消費者也是由應用開發者實現的,但是它是一個異步處理的組件。
圖片
消息的消費者不需要知道生產者存在,它只依賴消息隊列中的消息。消息的消費者通常部署在獨立的服務器上,和消息的生產者完全隔離,并且可以通過添加硬件的方式進行伸縮。
圖片
點對點模型是一種消息傳遞模型,其中消費者和生產者只需知道消息隊列的名稱。在這種模型中,生產者將消息發送到消息隊列,而消息隊列的另一端有多個消費者競爭消費消息。
圖片
每個到達消息隊列的消息只會被路由到一個消費者,因此每個消費者看到的是全部消息的一個子集。
在這張圖中,有多個消息生產者和多個消息消費者。多個生產者將消息發送到消息隊列,而多個消費者在消息隊列中競爭性地消費消息。
每條消息只會被一個消費者消費,每個消費者只會消費消息隊列中的一部分消息。這種點對點的模型適用于需要確保每條消息只被一個接收者處理的場景,以及在消息生產者和消費者之間實現解耦的需求。
在發布訂閱模型中,消息可能被發送到不止一個消費者,生產者發送消息到一個主題,而不是隊列中。
消息被發布到主題后,就會被克隆給每一個訂閱它的消費者,每個消費者接收一份消息復制到自己的私有隊列。
消費者可以獨立于其他消費者使用自己訂閱的消息,消費者之間不會競爭消息。
常用的分布式消息隊列都支持發布訂閱模型,也就是說消息的發布訂閱模型是分布式消息隊列的一個功能特性。
圖片
兩種消息傳遞模型通常會根據業務需求和特點進行選擇。點對點模型適用于一些耗時較長、邏輯相對獨立的業務場景,例如發送郵件。因為發送郵件是一個比較耗時的操作,應用程序對于郵件發送是否成功并不太關心,而且發送郵件的邏輯相對獨立。在這種情況下,應用程序只需要把郵件消息放入消息隊列中就可以立即返回。消費者則只需從消息隊列中取出郵件消息進行處理,通過遠程服務器將郵件發送出去。由于每封郵件只需要被發送一次,因此消息只需要被一個消費者消費即可。
圖片
相反,對于一些需要多個消費者協同處理的、涉及多個步驟的業務,例如新用戶注冊,通常會選擇發布訂閱模型。新用戶注冊成功后,可能需要發送激活郵件、歡迎短信,將用戶注冊數據寫入數據庫,并將新用戶信息發送給關聯企業的系統,以實現一次注冊即可登錄多個關聯產品的需求。在這種情況下,可以使用按主題發布的方式,即發布訂閱模型。新用戶注冊消息可以發布到一個主題,多個消費者可以訂閱這個主題,分別處理不同的任務,如發送郵件、發送短信、寫入數據庫等。這種模型允許多個消費者同時對同一消息進行處理,實現了業務邏輯的解耦和靈活性的提高。