相對(duì)于緩存服務(wù)器集群价认,數(shù)據(jù)存儲(chǔ)服務(wù)器集群對(duì)數(shù)據(jù)的持久性和可用性提出了更高的要求谦去。因?yàn)榫彺娌糠謥G失不會(huì)影響業(yè)務(wù)囱修,數(shù)據(jù)存儲(chǔ)服務(wù)器則必須保證數(shù)據(jù)的可靠存儲(chǔ)想诅。所以不能簡(jiǎn)單地使用一致性 Hash吠卷。
具體來(lái)說(shuō)锡垄,數(shù)據(jù)存儲(chǔ)集群伸縮性又分為兩種:
- 關(guān)系數(shù)據(jù)庫(kù)集群伸縮性
- NoSQL 數(shù)據(jù)庫(kù)集群伸縮性
關(guān)系數(shù)據(jù)庫(kù)集群的伸縮性設(shè)計(jì)
主流的關(guān)系型數(shù)據(jù)庫(kù)都支持?jǐn)?shù)據(jù)復(fù)制功能,我們可以利用這個(gè)功能對(duì)數(shù)據(jù)庫(kù)進(jìn)行簡(jiǎn)單伸縮祭隔。使用數(shù)據(jù)復(fù)制的 MySQL 集群伸縮性方案货岭。
在這種架構(gòu)中,數(shù)據(jù)庫(kù)寫(xiě)操作都在主服務(wù)器上疾渴,由主服務(wù)器將數(shù)據(jù)同步到集群中其他從服務(wù)器茴她,數(shù)據(jù)讀操作及數(shù)據(jù)分析等離線操作在從服務(wù)器上進(jìn)行。
除了主從讀寫(xiě)分離程奠,還可以使用數(shù)據(jù)分庫(kù)丈牢,即把不同的業(yè)務(wù)數(shù)據(jù)表部署在不同的數(shù)據(jù)庫(kù)集群上。使用這種方式的不足是:跨庫(kù)的表不能進(jìn)行關(guān)聯(lián)查詢(join)瞄沙。
在實(shí)際應(yīng)用中己沛,還會(huì)對(duì)一些數(shù)據(jù)量很大的單表進(jìn)行分片,即把一張表拆開(kāi)距境,分別存儲(chǔ)在多個(gè)數(shù)據(jù)庫(kù)中申尼。
目前比較成熟的支持?jǐn)?shù)據(jù)分片的分布式關(guān)系數(shù)據(jù)庫(kù)有開(kāi)源的 Amoeba 和 Cobar。它們有相似的架構(gòu)垫桂,這里以 Cobar 為例:
Cobar 是分布式關(guān)系數(shù)據(jù)庫(kù)的訪問(wèn)代理师幕,部署于應(yīng)用服務(wù)器和數(shù)據(jù)庫(kù)服務(wù)器之間,也可以非獨(dú)立部署(以 lib 的方式與應(yīng)用部署在一起)。應(yīng)用通過(guò) JDBC 訪問(wèn) Cobar 集群霹粥,Cobar 服務(wù)器依據(jù) SQL 和分庫(kù)規(guī)則來(lái)分解 SQL灭将,分發(fā)到 MySQL 集群中的不同數(shù)據(jù)庫(kù)實(shí)例上執(zhí)行(每個(gè)實(shí)例都部署為主從結(jié)構(gòu),保證數(shù)據(jù)高可用)后控。
前端通信模塊接收應(yīng)用發(fā)送過(guò)來(lái)的 SQL 請(qǐng)求(select * from users where userid in (12, 22, 23))后交與 SQL 解析模塊處理庙曙,SQL 解析模塊解析獲得 SQL 中的路由規(guī)則查詢條件(userid in (12, 22, 23))再轉(zhuǎn)交到 SQL 路由模塊。SQL 路由模塊根據(jù)路由配置的規(guī)則(userid 為偶數(shù)路由至數(shù)據(jù)庫(kù) A浩淘,為奇數(shù)路由至數(shù)據(jù)庫(kù) B)把 SQL 語(yǔ)句分解為多條 SQL(select * from users where userid in (12, 22)捌朴;select * from users where userid in (23);)轉(zhuǎn)交給 SQL 執(zhí)行代理模塊张抄,發(fā)送至數(shù)據(jù)庫(kù) A 和數(shù)據(jù)庫(kù) B 分別執(zhí)行砂蔽。
兩個(gè)數(shù)據(jù)庫(kù)把執(zhí)行的結(jié)果返回給 SQL 執(zhí)行代理模塊,再通過(guò)結(jié)果合并署惯,把兩個(gè)結(jié)果集合并為一個(gè)結(jié)果集左驾,最終返回給應(yīng)用。
Cobar 如何做集群的伸縮
Cobar 服務(wù)器可以看作是無(wú)狀態(tài)的應(yīng)用服務(wù)器泽台,所以可以直接使用負(fù)載均衡手段實(shí)現(xiàn)集群伸縮。而 MySQL 服務(wù)器中存儲(chǔ)著數(shù)據(jù)矾缓,所以要做數(shù)據(jù)遷移(把集群中原有的服務(wù)器中的數(shù)據(jù)遷移到新的服務(wù)器)怀酷,才能保證擴(kuò)容后數(shù)據(jù)一致負(fù)載均衡。
具體遷移哪些數(shù)據(jù)可以利用一致性 Hash 算法(即路由模塊使用一致性 Hash 算法進(jìn)行路由)嗜闻,盡量使要遷移的數(shù)據(jù)最少蜕依。因?yàn)檫w移數(shù)據(jù)需要遍歷數(shù)據(jù)庫(kù)中的每一條記錄(的索引),并重新進(jìn)行路由計(jì)算確定是否需要遷移琉雳,所以這會(huì)對(duì)數(shù)據(jù)庫(kù)造成一定的壓力样眠。而且還要解決遷移過(guò)程中的數(shù)據(jù)一致性、可訪問(wèn)性翠肘、遷移過(guò)程中服務(wù)器宕機(jī)時(shí)的可用性等問(wèn)題檐束。
實(shí)踐中,Cobar 服務(wù)器利用 MySQL 的數(shù)據(jù)同步功能進(jìn)行數(shù)據(jù)遷移束倍。遷移是以 Schema 為單位被丧。在 Cobar 集群初始化時(shí),為每一個(gè) MySQL 實(shí)例創(chuàng)建多個(gè) Schema绪妹。Schema 的個(gè)數(shù)依據(jù)業(yè)務(wù)遠(yuǎn)景的集群規(guī)模來(lái)估算甥桂,如果未來(lái)集群的最大規(guī)模為 1000 臺(tái)數(shù)據(jù)庫(kù)服務(wù)器,那么總的初始 Schema 數(shù)>= 1000邮旷。在擴(kuò)容的時(shí)候黄选,從每個(gè)服務(wù)器中遷移部分 Schema 到新服務(wù)器。因?yàn)檫w移是以 Schema 為單位婶肩,所以遷移過(guò)程可以使用 MySQL 同步機(jī)制:
同步完成后办陷,即新服務(wù)器中的 Schema 數(shù)據(jù)和原服務(wù)器中的 Schema 數(shù)據(jù)一致后貌夕,修改 Cobar 服務(wù)器的路由配置,把這些 Schema 的 IP 地址修改為新服務(wù)器的 IP 地址懂诗,最后刪除原服務(wù)器中被遷移的 Schema蜂嗽,完成 MySQL 集群擴(kuò)容。
在整個(gè)分布式關(guān)系數(shù)據(jù)庫(kù)的訪問(wèn)請(qǐng)求過(guò)程中殃恒,Cobar 服務(wù)器處理所消耗的時(shí)間很少植旧,時(shí)間主要還是花費(fèi)在 MySQL 數(shù)據(jù)庫(kù)服務(wù)器上。所以應(yīng)用通過(guò) Cobar 訪問(wèn)分布式關(guān)系數(shù)據(jù)庫(kù)的性能與直接訪問(wèn)關(guān)系數(shù)據(jù)庫(kù)是相當(dāng)?shù)睦胩疲虼丝梢詽M足網(wǎng)站在線業(yè)務(wù)的實(shí)時(shí)處理需求病附。事實(shí)上由于 Cobar 代替應(yīng)用程序連接數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)只需要維護(hù)更少的連接亥鬓,減少不必要的資源消耗(其實(shí)是代理層 Cobar 限制了數(shù)據(jù)庫(kù)的并發(fā)數(shù)完沪,比如代理只有 8 線程,同時(shí)的連接數(shù)就只有 8 個(gè)嵌戈,用完之后可以不釋放覆积。如果不限制線程并發(fā)的數(shù)量,則 CPU 的資源很快就被耗盡熟呛,每個(gè)線程執(zhí)行任務(wù)也會(huì)相當(dāng)緩慢宽档,因?yàn)?CPU 要把時(shí)間片分配給不同的線程對(duì)象,而且上下文切換也要耗時(shí)庵朝,最終造成系統(tǒng)運(yùn)行效率大幅降低)吗冤。
但 Cobar 路由后只能在單一數(shù)據(jù)庫(kù)實(shí)例上處理查詢請(qǐng)求,因此無(wú)法執(zhí)行跨庫(kù)關(guān)聯(lián)操作九府,當(dāng)然更不能進(jìn)行跨庫(kù)事務(wù)處理椎瘟。這是分布式數(shù)據(jù)庫(kù)的通病。
相比關(guān)系數(shù)據(jù)庫(kù)本身功能的強(qiáng)大侄旬,目前各類分布式關(guān)系數(shù)據(jù)庫(kù)解決方案都顯得簡(jiǎn)陋肺蔚,限制了關(guān)系數(shù)據(jù)庫(kù)某些功能的使用。但因?yàn)椴粩嘣鲩L(zhǎng)的海量數(shù)據(jù)存儲(chǔ)壓力儡羔,又不得不利用分布式關(guān)系數(shù)據(jù)庫(kù)的集群伸縮能力婆排,這時(shí)就必須從業(yè)務(wù)上回避分布式關(guān)系數(shù)據(jù)庫(kù)的各種缺點(diǎn):避免事務(wù)或利用事務(wù)補(bǔ)償機(jī)制代替數(shù)據(jù)庫(kù)事務(wù);分解數(shù)據(jù)訪問(wèn)邏輯避免 JOIN 操作等笔链。
NoSQL 數(shù)據(jù)庫(kù)集群的伸縮性設(shè)計(jì)
NoSQL 指的是非關(guān)系的段只、分布式數(shù)據(jù)庫(kù)設(shè)計(jì)模式。一般而言鉴扫,NoSQL 數(shù)據(jù)庫(kù)產(chǎn)品都放棄了關(guān)系數(shù)據(jù)庫(kù)的兩大重要基礎(chǔ):以關(guān)系代數(shù)為基礎(chǔ)的結(jié)構(gòu)化查詢語(yǔ)句(SQL)和事務(wù)一致性保證(ACID)赞枕。而強(qiáng)化其他一些大型網(wǎng)站更關(guān)注的特性:高可用性和可伸縮性。
目前應(yīng)用最廣泛的 NoSQL 產(chǎn)品是 Apache HBase。
HBase 的伸縮性主要依賴其可分裂的 HRegion 和可伸縮的分布式文件系統(tǒng) HDFS 實(shí)現(xiàn)炕婶。
HBase 中姐赡,數(shù)據(jù)以 HRegion 為單位進(jìn)行管理,也就是說(shuō)應(yīng)用程序如果想要訪問(wèn)一個(gè)數(shù)據(jù)柠掂,必須先找到 HRegion项滑,然后將數(shù)據(jù)讀寫(xiě)操作提交給 HRegion,由 HRegion 完成存儲(chǔ)層面的數(shù)據(jù)操作涯贞。每個(gè) HRegion 存儲(chǔ)一段 KEY 值區(qū)間 [key1,key2) 的數(shù)據(jù)枪狂。HRegionServer 是物理服務(wù)器,每個(gè) HRegionServer 上可以啟動(dòng)多個(gè) HRegion 實(shí)例宋渔。當(dāng)一個(gè) HRegion 寫(xiě)入的數(shù)據(jù)超過(guò)配置的閾值時(shí)州疾,HRegion 就會(huì)分裂為兩個(gè) HRegion,并將 HRegion 在整個(gè)集群中進(jìn)行遷移皇拣,以使 HRegionServer 達(dá)到負(fù)載均衡严蓖。
所有的 HRegion 信息(存儲(chǔ)的 Key 值區(qū)間、所在的 HRegionServer 地址氧急、訪問(wèn)端口號(hào)等)都記錄在 HMaster 服務(wù)器上颗胡。為了保證高可用,HBase 會(huì)啟動(dòng)多個(gè) HMaster吩坝,并通過(guò) ZooKeeper (一個(gè)支持分布式一致性的數(shù)據(jù)管理服務(wù))選舉出一個(gè)主服務(wù)器毒姨。應(yīng)用會(huì)通過(guò) ZooKeeper 獲得主 HMaster 的地址,輸入 Key 值獲得這個(gè) Key 所在的 HRegionServer 地址钾恢,然后請(qǐng)求 HRegionServer 上的 HRegion手素,獲得需要的數(shù)據(jù)鸳址。
寫(xiě)入過(guò)程也類似瘩蚪,需要先得到 HRegion 才能繼續(xù)操作。HRegion 會(huì)把數(shù)據(jù)存儲(chǔ)為多個(gè) HFile 格式的文件稿黍,這些文件使用 HDFS 分布式文件系統(tǒng)進(jìn)行存儲(chǔ)疹瘦,保證在整個(gè)集群內(nèi)分布并高可用。當(dāng)一個(gè) HRegion 中數(shù)據(jù)量太多時(shí)巡球,HRegion(連同 HFile)會(huì)分裂長(zhǎng)兩個(gè) HRegion言沐,并根據(jù)集群中服務(wù)器負(fù)載進(jìn)行遷移,如果集群中加入了新的服務(wù)器酣栈,也就是說(shuō)有了新的 HRegionServer险胰,由于其負(fù)載較低,也會(huì)把 HRegion 遷移過(guò)去并記錄到 HMaster 中矿筝,從而實(shí)現(xiàn) HBase 的線性伸縮起便。