一、前言
開篇六連問,等咱們熟悉完再來真香也不遲,我們廢話少說,直接來暢游 Spring 響應式編程的世界。 二、響應式編程是啥?
有點抽象?沒有關系,老周這就來說道說道。核心的一點響應式編程是聲明式編程范式,對命令式編程進行替代的一個范例,這種替代的存在是因為響應式編程解決了命令式編程的限制。大多數開發(fā)者都是命令式編程起步的,你寫的代碼就是一行接一行的指令,按照它們的順序一次一條地出現。一個任務被執(zhí)行,程序就需要等到它執(zhí)行完了,才能執(zhí)行下一個任務。每一步,數據都需要完全獲取到了才能被處理,因此它需要作為一個整體來處理。 命令式編程有個最大的弊端是:當正在執(zhí)行的任務被阻塞了,特別是一個 IO 任務,例如將數據寫入到數據庫或從遠程服務器獲取數據,那么調用該任務的線程將無法做任何事情,直到任務完成。說白了,阻塞的線程就是一種浪費,在如今的環(huán)境,線程的資源是那么的寶貴。 相反,響應式編程是函數式和聲明式的。響應式編程涉及描述通過該數據流的 pipeline 或 stream,而不是描述的一組按順序執(zhí)行的步驟。響應式流處理數據時只要數據是可用的就進行處理,而不是需要將數據作為一個整體進行提供。 三、為啥要有響應式編程?我們上面也說了命令式編程會線程阻塞,而響應式編程是聲明式編程范式的,是對命令式編程進行替代的一個范例。 對于命令式編程的同步阻塞,其實業(yè)界是有一些處理方案的,比如在 Java 中,為了實現異步非阻塞,一般會采用回調和 Future 這兩種機制,但這兩種機制都存在一定局限性。 3.1 回調機制我們來看下面這個圖:
回調體現的是一種雙向的調用方式,實現了服務 A 和服務 B 之間的解耦。在這個 callback 回調方法中,回調的執(zhí)行是由任務的結果來觸發(fā)的,所以我們就可以異步來執(zhí)行某項任務,從而使得調用鏈路不發(fā)生任何的阻塞。 回調的最大問題是復雜性,一旦在執(zhí)行流程中包含了多層的異步執(zhí)行和回調,那么就會形成一種嵌套結構,給代碼的開發(fā)和調試帶來很大的挑戰(zhàn)。所以回調很難大規(guī)模地組合起來使用,因為很快就會導致代碼難以理解和維護,從而造成所謂的“回調地獄”問題。之前公司就遇到代碼“回調地獄”問題,十幾層的回調,后面的人進來維護估計會吐。 3.2 Future 機制我們再來看看 Future 這種機制,有一個需要處理的任務,然后把這個任務提交到 Future,Future 就會在一定時間內完成這個任務,而在這段時間內我們可以去做其他事情。下面我們來看看來自 Doug Lea 大神在 Java 中的 Future 接口設計:
如果想要恢復線程,就需要涉及加載和保存寄存器等一系列計算密集型的操作。因此,大量線程之間的相互協(xié)作同樣會導致資源利用效率低下。 3.3 響應式編程實現方法3.3.1 數據流與響應式數據流就是數據像水流一樣源源不斷的輸入過來,而系統(tǒng)的響應能力就體現在對這些數據流的即時響應過程上。我們可以不采用傳統(tǒng)的同步調用方式來處理數據,而是由處于數據庫上游的各層組件自動來執(zhí)行事件,從web到service再到dao層,這個過程就像水流一樣,整個數據傳遞鏈路都應該是采用事件驅動的方式來進行運作的,這個過程都應該是異步非阻塞的,這就是響應式編程的核心特點。 相較傳統(tǒng)開發(fā)所普遍采用的“拉”模式,在響應式編程下,基于事件的觸發(fā)和訂閱機制,這就形成了一種類似“推”的工作方式。說白了,就類似現在的 Kafka 等消息引擎,大部分都采用事件驅動的 pub/sub 模式的架構。這種模式的最大優(yōu)勢是生成事件和消費事件的過程是異步執(zhí)行的,意味著資源之間的競爭關系較少,故服務器的響應能力也就越高。 3.3.2 響應式宣言響應式宣言是一份構建現代云擴展架構的處方。這個框架主要使用消息驅動的方法來構建系統(tǒng),在形式上可以達到彈性和韌性,最后可以產生響應性的價值。所謂彈性和韌性,通俗來說就像是橡皮筋,彈性是指橡皮筋可以拉長,而韌性指在拉長后可以縮回原樣。
問題:消息驅動與上面提到的事件驅動有啥區(qū)別呢? 響應式宣言指出了兩者的區(qū)別:“消息驅動”中消息數據被送往明確的目的地址,有固定導向;“事件驅動”是事件向達到某個給定狀態(tài)的組件發(fā)出的信號,沒有固定導向,只有被觀察的數據。
下一篇老周會來說下響應式流的核心機制是什么?敬請期待~ |
|