拆分的方法有多種,例如將原來主服務(wù)器上多個(gè)數(shù)據(jù)庫拆分到不同物理服務(wù)器的數(shù)據(jù)庫實(shí)例中。在一個(gè)MySQL數(shù)據(jù)庫中可能包含多個(gè)邏輯數(shù)據(jù)庫,在某個(gè)MySQL節(jié)點(diǎn)中存在多個(gè)邏輯數(shù)據(jù)庫,該節(jié)點(diǎn)不是一臺單一的MySQL數(shù)據(jù)庫服務(wù)器,而是MySQL數(shù)據(jù)庫集群,而且其中的所有數(shù)據(jù)庫中數(shù)據(jù)是一致的。
拆分的方法是將該節(jié)點(diǎn)中的不同數(shù)據(jù)庫拆分到不同的節(jié)點(diǎn)上。假設(shè)節(jié)點(diǎn)1中原本存在產(chǎn)品庫、銷售庫、倉儲庫,可以將其進(jìn)行拆分,讓節(jié)點(diǎn)1中只包含產(chǎn)品庫,讓節(jié)點(diǎn)2只包含銷售庫,讓節(jié)點(diǎn)3只包含倉庫庫。這樣,就將原來節(jié)點(diǎn)1的寫壓力分擔(dān)到了三個(gè)節(jié)點(diǎn)上,大大減輕了MySQL節(jié)點(diǎn)一的負(fù)擔(dān),提高了數(shù)據(jù)庫的運(yùn)行效率。
這種拆分方式的特點(diǎn)是實(shí)現(xiàn)起來比較簡單,適用于不允許跨庫查詢的情況。只要對拆分后的數(shù)據(jù)庫重新配置連接,即可讓其正常運(yùn)轉(zhuǎn)。其缺點(diǎn)是無法分擔(dān)針對單個(gè)數(shù)據(jù)庫的寫壓力。例如,銷售庫承擔(dān)了主要的寫壓力,別的數(shù)據(jù)庫讀寫的壓力很輕,那么這樣的拆分就意義不大。
為此,可以將原來數(shù)據(jù)庫中的表分離到不同節(jié)點(diǎn)中的不同數(shù)據(jù)庫中。在一個(gè)數(shù)據(jù)庫中會存在很多表,分別存儲不同類型的數(shù)據(jù)。例如對于節(jié)點(diǎn)1中的產(chǎn)品庫來說,可能包含衣服表、鞋帽表、食品表等,根據(jù)實(shí)際的分析,發(fā)現(xiàn)寫壓力主要集中在衣服表和食品表中,那么可以將這兩個(gè)表拆分到不同的數(shù)MySQL節(jié)點(diǎn)中。這樣,不同的節(jié)點(diǎn)只承受的只是原來數(shù)據(jù)庫中部分寫壓力。
我們還可以使用數(shù)據(jù)表的水平拆分加以應(yīng)對。水平拆分即對數(shù)據(jù)庫進(jìn)行分片處理,對一個(gè)數(shù)據(jù)庫中的相關(guān)表進(jìn)行水平拆分,存放到不同實(shí)例的數(shù)據(jù)庫中。在大多數(shù)情況下,MySQL的分庫分表就是指的該種方式。
在實(shí)際的項(xiàng)目規(guī)劃中,如果沒有必要最好不要進(jìn)行分片處理。當(dāng)相關(guān)業(yè)務(wù)正常運(yùn)行時(shí),如果數(shù)據(jù)庫的并發(fā)操作沒有達(dá)到臨界值,就貿(mào)然對其進(jìn)行分片,反倒變得難以維護(hù),對運(yùn)維產(chǎn)生不利影響。為了提高運(yùn)維效能,應(yīng)該首先考慮通過性能調(diào)優(yōu)或者提高應(yīng)用程序以及數(shù)據(jù)庫設(shè)計(jì)水平,來推遲分片操作。
例如,對于上述產(chǎn)品庫中的衣服表來說,當(dāng)需要對其進(jìn)行分片時(shí),假設(shè)在節(jié)點(diǎn)1上只存在一個(gè)數(shù)據(jù)庫,其中只包含該數(shù)據(jù)表,經(jīng)過分片處理后,會形成多個(gè)相同表結(jié)構(gòu)的衣服表,這些表可能分布在不同的節(jié)點(diǎn)上。在對數(shù)據(jù)庫進(jìn)行分片前,需要充分考慮到可能涉及到的問題。
如何選擇分區(qū)鍵決定了如何對數(shù)據(jù)庫進(jìn)行分片,以及分片后如何查詢數(shù)據(jù)。分區(qū)鍵選擇的是否合適,直接決定了分區(qū)后數(shù)據(jù)庫的性能。在選擇分區(qū)鍵時(shí),要盡可能的盡量避免發(fā)生跨分片查詢的情況。因?yàn)樵谶@種情況下,應(yīng)用程序必須對多個(gè)分片進(jìn)行查詢后才可以合并查詢的結(jié)果信息,其效率甚至比分片前還要低。
例如,對于一個(gè)論壇來說,一個(gè)用戶可能在不同的板塊發(fā)布多篇帖子。如果以板塊的ID作為分區(qū)鍵,那么在查詢某個(gè)用戶時(shí),就會跨所有的分區(qū)進(jìn)行查詢,才能得到該用戶的所有帖子信息。如果以用戶的ID為分區(qū)鍵,可以保證同一個(gè)用戶的帖子全部在一個(gè)分片中,這樣查詢起來就更加快捷。
分區(qū)鍵的選擇要盡可能讓各個(gè)分片中的數(shù)據(jù)保持平均分布。之所以進(jìn)行數(shù)據(jù)庫分片,是為了降低主數(shù)據(jù)庫的寫負(fù)載。如果分片后,大量的寫操作依然集中在某個(gè)分片中,就沒有必要進(jìn)行分片。
對于一個(gè)在線訂單庫來說,如果以買家的ID為分區(qū)鍵,并且采用ID范圍來分片的話,就必須保證選擇的ID非常合理,大部分活躍的買家是否被分到了一個(gè)段中。如果分片后,所有的查詢都包含該分區(qū)鍵,使用哈希函數(shù)進(jìn)行分區(qū),無疑是最好的分區(qū)方式。
不管對于任何應(yīng)用程序來說,往往只有少量的數(shù)據(jù)表需要進(jìn)行分片處理,即只有少數(shù)的表才會被頻繁的寫入數(shù)據(jù)。
對于其他數(shù)據(jù)表來說,在分片后,可以在每個(gè)分片中存儲一份相同的數(shù)據(jù)。這就要求這些表數(shù)據(jù)量較小,不會被經(jīng)常更新,而且這些表經(jīng)常會被和分區(qū)表在一起進(jìn)行關(guān)聯(lián)查詢,這樣在每一個(gè)分片中存儲一份冗余的數(shù)據(jù)表,可以提高查詢的效能。
當(dāng)然,為了避免繁瑣的定期維護(hù)操作,可以將無需分片的數(shù)據(jù)表統(tǒng)一存儲在一個(gè)額外的節(jié)點(diǎn)中,讓整個(gè)MySQL集群不存在冗余問題。如果分片的表和這些表進(jìn)行關(guān)聯(lián)查詢,就必須在應(yīng)用程序中進(jìn)行設(shè)置,對兩類數(shù)據(jù)表進(jìn)行分別查詢并進(jìn)行合并處理。因此,該方法的查詢效率較低。在節(jié)點(diǎn)上部署分片時(shí),并不是在一個(gè)節(jié)點(diǎn)上只能部署一個(gè)分片,而是有很多種方式可以選擇。最簡單的方式是每個(gè)分片使用單一的數(shù)據(jù)庫,數(shù)據(jù)庫的名稱也保持一致。即每個(gè)數(shù)據(jù)庫的結(jié)構(gòu)需要和原來單一實(shí)例上的數(shù)據(jù)庫結(jié)構(gòu)相同。
也可以將多個(gè)分片表存儲在一個(gè)數(shù)據(jù)庫中,需要在對應(yīng)的表名稱上加入分片號作為后綴,來進(jìn)行明確的區(qū)分。
此外,還可以在每一個(gè)節(jié)點(diǎn)中部署多個(gè)數(shù)據(jù)庫,每個(gè)數(shù)據(jù)庫包含一個(gè)或者分片。之后按照上述方法對相關(guān)的數(shù)據(jù)庫和分片表進(jìn)行區(qū)分。在一個(gè)節(jié)點(diǎn)中存儲多個(gè)數(shù)據(jù)庫實(shí)例的方法,也可以實(shí)現(xiàn)分片處理。
不管采用哪一種方法,相關(guān)的應(yīng)用程序必須進(jìn)行必要的調(diào)整,來匹配所采用的分片方式。如果在錯(cuò)誤的分片中查詢數(shù)據(jù),或者將數(shù)據(jù)寫入錯(cuò)誤的分片,就會造成管理上的混亂。