柚子快報(bào)激活碼778899分享:什么是中間件?
柚子快報(bào)激活碼778899分享:什么是中間件?
文章目錄
為什么需要中間件?中間件生態(tài)漫談數(shù)據(jù)庫中間件讀寫分離分庫分表引進(jìn)數(shù)據(jù)庫中間件MyCat 服務(wù)端代理模式ShardingJDBC 客戶端代理模式
總結(jié)
IT 系統(tǒng)從單體應(yīng)用逐漸向分布式架構(gòu)演變,高并發(fā)、高可用、高性能、分布式等話題變得異?;馃?,中間件也在這一時(shí)期如雨后春筍般涌現(xiàn)出來,那到底什么是中間件呢?存在哪些類型的中間件呢?同一類型的中間件,我們該怎么選擇?
為什么需要中間件?
先來說說什么是中間件,我認(rèn)為中間件是游離于業(yè)務(wù)需求之外,專門為了處理項(xiàng)目中涉及高可用、高性能、高并發(fā)等技術(shù)需求而引入的一個(gè)個(gè)技術(shù)組件。它的一個(gè)重要作用就是能夠?qū)崿F(xiàn)業(yè)務(wù)代碼與技術(shù)功能之間解耦合。
這么說是不是還有點(diǎn)抽象?在這里定義里,我提到了業(yè)務(wù)需求和技術(shù)需求,關(guān)于這兩個(gè)詞我需要再解釋一下。
業(yè)務(wù)需求,籠統(tǒng)地說就是特定用戶的特定訴求。以我們快遞行業(yè)為例:人與人之間需要跨城市傳遞物品,逢年過節(jié)我們需要給遠(yuǎn)方的親人寄禮物,這就是所謂的業(yè)務(wù)需求。
技術(shù)需求,就是隨著業(yè)務(wù)的不斷擴(kuò)展,形成規(guī)模效應(yīng)后帶來的使用上的需求。例如上面提到的寄件服務(wù),原先只需要服務(wù) 1 萬個(gè)客戶,用戶體驗(yàn)非常好,但現(xiàn)在需要服務(wù)幾個(gè)億的用戶,用戶在使用的過程中就會出現(xiàn)卡頓、系統(tǒng)異常等問題,因此產(chǎn)生可用性、穩(wěn)定性方面的技術(shù)訴求。
為了解決各式各樣的業(yè)務(wù)和技術(shù)訴求,代碼量會越來越多。如果我們?nèi)螒{業(yè)務(wù)代碼與技術(shù)類代碼沒有秩序地糾纏在一起,系統(tǒng)會變得越來越不可維護(hù),運(yùn)營成本也會成指數(shù)級增加,故障頻發(fā),最終直接導(dǎo)致項(xiàng)目建設(shè)失敗。
怎么解決這個(gè)問題呢?計(jì)算機(jī)領(lǐng)域有一個(gè)非常經(jīng)典的分層架構(gòu)思想,還有這樣一句話“計(jì)算機(jī)領(lǐng)域任何一個(gè)問題都可以通過分層來解決,如果不行,那就再增加一層?!币胱屜到y(tǒng)做得越來越好,我們通常會基于分層的架構(gòu)思想引入一個(gè)中間層,專門來解決可用性、穩(wěn)定性、高性能方面的技術(shù)類訴求,這個(gè)中間層就是中間件,這也正是“中間件”這個(gè)詞的來源。
中間件生態(tài)漫談
明白了中間件的內(nèi)涵,我們再來看看市面上有哪些中間件。我在開篇詞中已經(jīng)提到過了,中間件的種類繁多,我整理了一版分布式架構(gòu)體系中常見的中間件,你可以先打開圖片仔細(xì)看一看。
特別是對互聯(lián)網(wǎng)主流分布式架構(gòu)體系的研讀,我發(fā)現(xiàn)微服務(wù)中間件、消息中間件、定時(shí)調(diào)度的使用頻率極高,在解決分布式架構(gòu)相關(guān)問題中是排頭兵,具有無可比擬的普適性。這三者的設(shè)計(jì)理念和案例能對分布式、高可用和高并發(fā)等理念實(shí)現(xiàn)全覆蓋。
微服務(wù) 具體而言,作為軟件架構(gòu)從單體應(yīng)用向分布式演進(jìn)出現(xiàn)的第一個(gè)新名詞,微服務(wù)涉及分布式領(lǐng)域中服務(wù)注冊、服務(wù)動態(tài)發(fā)現(xiàn)、RPC 調(diào)用、負(fù)載均衡、服務(wù)聚合等核心技術(shù),而 Dubbo 在微服務(wù)領(lǐng)域是當(dāng)仁不讓的王者。所以在微服務(wù)這一部分,我們會以 Dubbo 為例進(jìn)行實(shí)戰(zhàn)演練。 消息中間件 隨著微服務(wù)的蓬勃發(fā)展,系統(tǒng)的復(fù)雜度越來越高,加上互聯(lián)網(wǎng)秒殺、雙十一、618 等各種大促活動層出不窮,我們急切需要對系統(tǒng)解耦和應(yīng)對突發(fā)流量的解決辦法,這時(shí)候消息中間件應(yīng)運(yùn)而生了,它同樣成為我們架構(gòu)設(shè)計(jì)工作中最常用的工具包。常用的消息中間件包括 RocketMQ、Kafka,它們在適用性上有所不同,如何保障消息中間件的穩(wěn)定性是一大挑戰(zhàn)。 定時(shí)調(diào)度 而定時(shí)調(diào)度呢?我們既可以認(rèn)為它是個(gè)技術(shù)需求,也可以認(rèn)為它是一個(gè)業(yè)務(wù)類需求,通過研讀 ElasticJob、XXL-Job 等定時(shí)調(diào)度框架,可以很好地提升我們對業(yè)務(wù)需求的架構(gòu)設(shè)計(jì)能力。
數(shù)據(jù)庫中間件
數(shù)據(jù)庫中間件應(yīng)該是我們接觸得最早也是最為常見的中間件,在引入數(shù)據(jù)庫中間件之前,由于單體應(yīng)用向分布式架構(gòu)演進(jìn)的過程中單表日數(shù)據(jù)急速增長,單個(gè)數(shù)據(jù)庫的節(jié)點(diǎn)很容易成為系統(tǒng)瓶頸,無法提供穩(wěn)定的服務(wù)。因此,為了解決可用性問題,在技術(shù)架構(gòu)領(lǐng)域通常有如下兩種解決方案:
讀寫分離分庫分表
我們先分別解析下這兩個(gè)方案。最后再來看一看,引入數(shù)據(jù)庫中間件給技術(shù)帶來的簡化。
讀寫分離
這是我在沒有接觸中間件之前,在一個(gè)項(xiàng)目中使用過的方案: 這個(gè)方案的實(shí)現(xiàn)要點(diǎn)有三個(gè)。
第一,在編寫業(yè)務(wù)接口時(shí),要通過在接口上添加注解來指示運(yùn)行時(shí)應(yīng)該使用的數(shù)據(jù)源。例如,@SlaveofDB 表示使用 Slave 數(shù)據(jù)庫,@MasterOfDB 表示使用主庫。
第二,當(dāng)用戶發(fā)起請求時(shí),要先經(jīng)過一個(gè)攔截器獲取用戶請求的具體接口,然后使用反射機(jī)制獲取該方法上的注解。舉個(gè)例子,如果存在 @SlaveofDB,則往線程上下文環(huán)境中存儲一個(gè)名為 dbType 的變量,賦值為 slave,表示走從庫;如果存在 @MasterOfDB,則存儲為 master,表示走主庫。
第三,在 Dao 層采用 Spring 提供的路由選擇機(jī)制,繼承自 AbastractRoutingDataSource。應(yīng)用程序啟動時(shí)自動注入兩個(gè)數(shù)據(jù)源 (master-slave),采用 key-value 鍵值對的方式存儲。在真正需要獲取鏈接時(shí),根據(jù)上下文環(huán)境中存儲的數(shù)據(jù)庫類型,從內(nèi)部持有的 dataSourceMap 中獲取對應(yīng)的數(shù)據(jù)源,從而實(shí)現(xiàn)數(shù)據(jù)庫層面的讀寫分離。
總結(jié)一下,讀寫分離的思路就是通過降低寫入節(jié)點(diǎn)的負(fù)載,將耗時(shí)的查詢類請求轉(zhuǎn)發(fā)到從節(jié)點(diǎn),從而有效提升寫入的性能。
但是,當(dāng)業(yè)務(wù)量不斷增加,單個(gè)數(shù)據(jù)庫節(jié)點(diǎn)已無法再滿足業(yè)務(wù)需求時(shí),我們就要對數(shù)據(jù)進(jìn)行切片,分庫分表的技術(shù)思想就應(yīng)運(yùn)而生了。
分庫分表
分庫分表是負(fù)載均衡在數(shù)據(jù)庫領(lǐng)域的應(yīng)用,主要的原理你可以參考下面這張圖。 簡單說明一下。分庫分表主要是通過引入多個(gè)寫入節(jié)點(diǎn)來緩解數(shù)據(jù)壓力的。因此,在接受寫入請求后,負(fù)載均衡算法會將數(shù)據(jù)路由到其中一個(gè)節(jié)點(diǎn)上,多個(gè)節(jié)點(diǎn)共同分擔(dān)數(shù)據(jù)寫入請求,降低單個(gè)節(jié)點(diǎn)的壓力,提升擴(kuò)展性,解決單節(jié)點(diǎn)的性能瓶頸。
不過,要實(shí)現(xiàn)數(shù)據(jù)庫層面的分庫分表還是存在一定技術(shù)難度的。因?yàn)榉謳旆直砗妥x寫分離一樣,最終要解決的都是如何選擇數(shù)據(jù)源的問題。所以在分庫分表方案中,首先我們要有兩個(gè)算法。
一個(gè)分庫字段和分庫算法,即在進(jìn)行數(shù)據(jù)查詢、數(shù)據(jù)寫入時(shí),根據(jù)分庫字段的值算出要路由到哪個(gè)數(shù)據(jù)庫實(shí)例上;一個(gè)分表字段和分表算法,即在進(jìn)行數(shù)據(jù)查詢、數(shù)據(jù)寫入時(shí),根據(jù)分表字段的值算出要路由到哪個(gè)表上。
不管是上面的分庫、還是分表都需要解決一個(gè)非常關(guān)鍵的問題:SQL 解析。你可以看下面這張圖。
如果訂單庫的分庫字段設(shè)置為 order_no,要想正確執(zhí)行這條 SQL 語句,我們首先要解析這條 SQL 語句,提取 order_no 的字段值,再根據(jù)分庫算法 (負(fù)載均衡算法) 計(jì)算應(yīng)該發(fā)送到哪一個(gè)具體的庫上執(zhí)行。
SQL 語句語法非常復(fù)雜,要實(shí)現(xiàn)一套高性能的 SQL 解析引擎絕非易事,如果按照上面我提供的解決方案,將會帶來幾個(gè)明顯的弊端。
技術(shù)需求會污染業(yè)務(wù)代碼,維護(hù)成本高
在業(yè)務(wù)控制器中需要使用注解來聲明讀寫分離按相關(guān)的規(guī)則進(jìn)行,隨著業(yè)務(wù)控制的不斷增加、或者讀寫分離規(guī)則的變化,我們需要對系統(tǒng)所有注解進(jìn)行修改,但業(yè)務(wù)邏輯其實(shí)并沒有改變。這就造成兩者之間相互影響,后期維護(hù)成本較高。
技術(shù)實(shí)現(xiàn)難度大,極大增加開發(fā)成本
由于 SQL 語句的格式太復(fù)雜、太靈活,如果不是數(shù)據(jù)庫專業(yè)人才,很難全面掌握 SQL 語法。在這樣的情況下,你寫出的 SQL 解析引擎很難覆蓋所有的場景,容易出現(xiàn)遺漏最終導(dǎo)致故障的發(fā)生;這也給產(chǎn)品的性能帶來極大挑戰(zhàn)。
那怎么辦呢?其實(shí),我們完全可以使用業(yè)界大神的開源作品來解決問題,這就要說到數(shù)據(jù)庫中間件了。
引進(jìn)數(shù)據(jù)庫中間件
技術(shù)類訴求往往是相通的,極具普適性,為了解決上面的通病,根據(jù)分層的架構(gòu)理念,我們通常會引入一個(gè)中間層,專門解決數(shù)據(jù)庫方面的技術(shù)類需求
MyCat 和 ShardingJDBC/ShardingSphere 是目前市面最主流的兩個(gè)數(shù)據(jù)庫中間件,二者各有優(yōu)勢。
MyCat 服務(wù)端代理模式
先來看下 MyCat 代理數(shù)據(jù)庫。它的工作模式可以用下面這張圖概括:
面對應(yīng)用程序,MyCat 會偽裝成一個(gè)數(shù)據(jù)庫服務(wù)器 (例如 MySQL 服務(wù)端)。它會根據(jù)各個(gè)數(shù)據(jù)庫的通信協(xié)議,從二進(jìn)制請求中根據(jù)協(xié)議進(jìn)行解碼,然后提取 SQL,并根據(jù)配置的分庫分表、讀寫分離規(guī)則計(jì)算出需要發(fā)送到哪個(gè)物理數(shù)據(jù)庫。
隨后,面對真實(shí)的數(shù)據(jù)庫資源,MyCat 會偽裝成一個(gè)數(shù)據(jù)庫客戶端。它會根據(jù)通信協(xié)議將 SQL 語句封裝成二進(jìn)制流,發(fā)送請求到真實(shí)的物理資源,真實(shí)的物理數(shù)據(jù)庫收到請求后解析請求并進(jìn)行對應(yīng)的處理,再將結(jié)果層層返回到應(yīng)用程序。
這種架構(gòu)的優(yōu)勢是它對業(yè)務(wù)代碼無任何侵入性,應(yīng)用程序只需要修改項(xiàng)目中數(shù)據(jù)庫的連接配置就可以了,而且使用簡單,易于推廣。同時(shí)它也有劣勢:
存在性能損耗
數(shù)據(jù)庫中間件需要對應(yīng)用程序發(fā)送過來的請求進(jìn)行解碼并計(jì)算路由,隨后它還要再次對請求進(jìn)行編碼并轉(zhuǎn)發(fā)到真實(shí)的數(shù)據(jù)庫,這就增加了性能開銷。
高度中心化,數(shù)據(jù)庫中間件容易成為性能瓶頸
數(shù)據(jù)庫中間件需要處理所有的數(shù)據(jù)庫請求,返回結(jié)果都需要在數(shù)據(jù)庫中進(jìn)行聚合,雖然減少了后端數(shù)據(jù)庫的壓力,但中間件本身很容易成為系統(tǒng)的瓶頸,擴(kuò)展能力受到一定制約
代理層實(shí)現(xiàn)復(fù)雜,普適性差
數(shù)據(jù)庫中間件本身的實(shí)現(xiàn)比較復(fù)雜,需要適配市面上各主流數(shù)據(jù)庫,例如 MySQL、Oracle 等,通用性大打折扣。
ShardingJDBC 客戶端代理模式
下面我們再來看下 ShardingJDBC 客戶端代理數(shù)據(jù)庫。ShardingJDBC 的工作模式如下圖所示:
ShardingJDBC 主要實(shí)現(xiàn)的是 JDBC 協(xié)議。實(shí)現(xiàn) JDBC 協(xié)議,其實(shí)主要是面向 java.sql.Datasource、Connection、ResultSet 等對象編程。它通常以客戶端 Jar 包的方式嵌入到業(yè)務(wù)系統(tǒng)中,ShardingjJDBC 根據(jù)分庫分表的配置信息,初始化一個(gè) ShardingJdbcDatasource 對象,隨后解析 SQL 語句來提取分庫、分表字段值,再根據(jù)配置的路由規(guī)則選擇正確的后端真實(shí)數(shù)據(jù)庫,最后,ShardingJDBC 用各種類型數(shù)據(jù)庫的驅(qū)動包將 SQL 發(fā)送到真實(shí)的物理數(shù)據(jù)庫上。
我們同樣來分析一下這個(gè)方案的優(yōu)缺點(diǎn)。
主要的優(yōu)勢有如下幾點(diǎn):
無性能損耗
ShardingJDBC 使用的是基于客戶端的代理模式,不需要對 SQL 進(jìn)行編碼解碼等操作,只要根據(jù) SQL 語句進(jìn)行路由選擇就可以了,沒有太多性能損耗。
無單點(diǎn)故障,擴(kuò)展性強(qiáng)
ShardingJDBC 以 Jar 包的形式存在于項(xiàng)目中,其分布式特性隨著應(yīng)用的增加而增加,擴(kuò)展性極強(qiáng)。
基于JDBC協(xié)議,可無縫支持各主流數(shù)據(jù)庫
JDBC 協(xié)議是應(yīng)用程序與關(guān)系型數(shù)據(jù)庫交互的業(yè)界通用標(biāo)準(zhǔn),市面上所有關(guān)系型數(shù)據(jù)庫都天然支持 JDBC,故不存在兼容性問題。
當(dāng)然缺點(diǎn)也很明顯,對于分庫分表,它沒有一個(gè)統(tǒng)一的視圖,運(yùn)維類成本較高。舉個(gè)例子,如果訂單表被分成了 1024 個(gè)表,這時(shí)候如果你想根據(jù)訂單編號去查詢數(shù)據(jù),必須人為計(jì)算出這條數(shù)據(jù)存在于哪個(gè)庫的哪個(gè)表中,然后再去對應(yīng)的庫上執(zhí)行 SQL 語句。
為了解決 ShardingJDBC 存在的問題,官方提供了 ShardingSphere,其工作機(jī)制基于代理模式,與 MyCat 的設(shè)計(jì)理念一致,作為數(shù)據(jù)庫的代理層,提供統(tǒng)一的數(shù)據(jù)聚合層,可以有效彌補(bǔ) ShardingJDBC 在運(yùn)維層面的缺陷,因此項(xiàng)目通常采用 ShardingDBC 的編程方式,然后再搭建一套 ShardingSphere 供數(shù)據(jù)查詢。
在沒有 ShardingSphere 之前,使用 MyCat 也有一定優(yōu)勢。MyCat 對業(yè)務(wù)代碼無侵入性,接入成本也比較低。但 ShardingSphere 彌補(bǔ)了 ShardingJDBC 對運(yùn)維的不友好,而且它的性能損耗低、擴(kuò)展性強(qiáng)、支持各類主流數(shù)據(jù)庫,可以說相比 MyCat 已經(jīng)占有明顯的優(yōu)勢了。
所以如果要在實(shí)踐生產(chǎn)中選擇數(shù)據(jù)庫中間件,我更加推薦 ShardingJDBC。
除了上面的原因,從資源利用率和社區(qū)活躍度的角度講,首先,MyCat 的“前身”是阿里開源的 Cobar,是數(shù)據(jù)庫中間件的開山鼻祖,技術(shù)架構(gòu)稍顯古老,而 ShardingJDBC 在設(shè)計(jì)之初就可以規(guī)避 MyCat 的固有缺陷,摒棄服務(wù)端代理模式。代理模式需要額外的機(jī)器搭建 MyCat 進(jìn)程,引入了新的進(jìn)程,勢必需要增加硬件資源的投入。
其次,ShardingJDBC 目前已經(jīng)是 Apache 的頂級項(xiàng)目,它的社區(qū)活躍度也是 MyCat 無法比擬的。一個(gè)開源項(xiàng)目社區(qū)越活躍,尋求幫助后問題得到解決的概率就會越大,越多人使用,系統(tǒng)中存在的 Bug 也更容易被發(fā)現(xiàn)、被修復(fù),這就使得中間件本身的穩(wěn)定性更有保障。
總結(jié)
通過剛才的學(xué)習(xí),我們知道了中間件的概念,它是為了解決系統(tǒng)中的技術(shù)需求,將技術(shù)需求與業(yè)務(wù)需求進(jìn)行解耦,讓我們專注于業(yè)務(wù)代碼開發(fā)的一個(gè)個(gè)技術(shù)組件。中間件的存在,就是為了解決高并發(fā)、高可用性、高性能等各領(lǐng)域的技術(shù)難題。
在項(xiàng)目中,合理引用中間件能極大提升我們系統(tǒng)的穩(wěn)定性、可用性,但同時(shí)也會提升系統(tǒng)維護(hù)的復(fù)雜度,對我們的技術(shù)能力提出了更高的要求,我們必須要熟練掌握項(xiàng)目中引用的各種中間件,深入理解其工作原理、實(shí)現(xiàn)細(xì)節(jié),提高對中間件的駕馭能力,否則一旦運(yùn)用不當(dāng),很可能給系統(tǒng)帶來災(zāi)難性的故障。
柚子快報(bào)激活碼778899分享:什么是中間件?
相關(guān)文章
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。