Mycat基礎(chǔ)

基于 Mycat 1.6.7.3 版本

為什么要分庫分表

1、數(shù)據(jù)庫性能瓶頸的出現(xiàn)
1)對于應(yīng)用來說孝冒,如果數(shù)據(jù)庫性能出現(xiàn)問題啤挎,要么是無法獲取連接,是因為在高并發(fā)的情況下連接數(shù)不夠了
2)要么是操作數(shù)據(jù)變慢票罐,數(shù)據(jù)庫處理數(shù)據(jù)的效率除了問題
3)要么是存儲出現(xiàn)問題,比如單機存儲的數(shù)據(jù)量太大了泞边,存儲的問題也可能會導(dǎo)致性能的問題

歸根結(jié)底都是受到了硬件的限制该押,比如 CPU,內(nèi)存阵谚,磁盤蚕礼,網(wǎng)絡(luò)等等烟具,但是我們優(yōu)化肯定不可能直接從擴展硬件入手,因為帶來的收益和成本投入比例太低了

2奠蹬、數(shù)據(jù)庫優(yōu)化方案對比
1)SQL與索引
SQL 語句是在我們的應(yīng)用端編寫的朝聋,第一步,我們可以在程序中對 SQL 語句進行優(yōu)化囤躁,最終的目標(biāo)是用到索引冀痕,這個是容易的也是最常用的優(yōu)化手段

2)表與存儲引擎
第二步,數(shù)據(jù)是存放在表里面的狸演,表又是以不同的格式存放在存儲引擎中的言蛇,所以我們可以選用特定的存儲引擎,或者對表進行分區(qū)宵距,對表結(jié)構(gòu)進行拆分或者冗余處理腊尚,或者對表結(jié)構(gòu)比如字段的定義進行優(yōu)化

3)架構(gòu)
第三步,對于數(shù)據(jù)庫的服務(wù)消玄,我們可以對它的架構(gòu)進行優(yōu)化
如果只有一臺數(shù)據(jù)庫的服務(wù)器跟伏,我們可以運行多個實例丢胚,做集群的方案翩瓜,做負(fù)載均衡
或者基于主從復(fù)制實現(xiàn)讀寫分離,讓寫的服務(wù)都訪問 master 服務(wù)器携龟,讀的請求都訪問從服務(wù)器兔跌,slave 服務(wù)器自動 master 主服務(wù)器同步數(shù)據(jù)
或者在數(shù)據(jù)庫前面加一層緩存,達到減少數(shù)據(jù)庫的壓力峡蟋,提升訪問速度的目的

為了分散數(shù)據(jù)庫服務(wù)的存儲壓力和訪問壓力坟桅,我們也可以把不同的數(shù)據(jù)分布到不同的服務(wù)節(jié)點,這個就是分庫分表(scale out)

主從(replicate)和分片(shard)的區(qū)別:
主從 通過數(shù)據(jù)冗余實現(xiàn)高可用蕊蝗,和實現(xiàn)讀寫分離
分片 通過拆分?jǐn)?shù)據(jù)分散存儲和訪問壓力

4)配置
第四步仅乓,是數(shù)據(jù)庫配置的優(yōu)化,比如連接數(shù)蓬戚,緩沖區(qū)大小等等夸楣,優(yōu)化配置的目的都是為了更高效地利用硬件

5)操作系統(tǒng)與硬件
第五步,操作系統(tǒng)和硬件的優(yōu)化
從上往下子漩,成本收益比慢慢地在增加豫喧,所以肯定不是查詢一慢就堆硬件,堆硬件叫做向上的擴展(scale up)

3幢泼、架構(gòu)演進與分庫分表
1)單應(yīng)用單數(shù)據(jù)庫
案例:我們公司采購了一個消費金融核心系統(tǒng)紧显,這個是一個典型的單體架構(gòu)的應(yīng)用,單體架構(gòu)應(yīng)用的特點就是所有的代碼都在一個工程里面缕棵,打成一個 war 包部署到 tomcat孵班,最后運行在一個進程中

這套消費金融的核心系統(tǒng)涉兽,用的是 Oracle 的數(shù)據(jù)庫,初始化以后有幾百張表篙程,比如客戶信息表花椭、賬戶表、商戶表房午、產(chǎn)品表矿辽、放款表、還款表


image.png

為了適應(yīng)業(yè)務(wù)的發(fā)展郭厌,我們這一套系統(tǒng)不停地在修改袋倔,代碼量越來越大,系統(tǒng)變得越來越臃腫折柠。為了優(yōu)化系統(tǒng)宾娜,我們搭集群,負(fù)載均衡扇售,加緩存前塔,優(yōu)化數(shù)據(jù)庫,優(yōu)化業(yè)務(wù)代碼系統(tǒng)承冰,但是都應(yīng)對不了系統(tǒng)的訪問壓力

這個時候系統(tǒng)拆分就勢在必行了华弓,我們把以前這一套采購的核心系統(tǒng)拆分出來很多的子系統(tǒng),比如提單系統(tǒng)困乒、商戶管理系統(tǒng)寂屏、信審系統(tǒng)、合同系統(tǒng)娜搂、代扣系統(tǒng)迁霎、催收系統(tǒng),所有的系統(tǒng)都依舊共用一套 Oracle 數(shù)據(jù)庫

2)多應(yīng)用單數(shù)據(jù)庫
對代碼進行了解耦百宇,職責(zé)進行了拆分考廉,生產(chǎn)環(huán)境出現(xiàn)問題的時候,可以快速地排查和解決

image.png

這種多個子系統(tǒng)共用一個 DB 的架構(gòu)携御,會出現(xiàn)一些問題:

所有的業(yè)務(wù)系統(tǒng)都共用一個 DB昌粤,無論是從性能還是存儲的角度來說,都是滿足不了需求的因痛,隨著我們的業(yè)務(wù)繼續(xù)膨脹婚苹,我們又會增加更多的系統(tǒng)來訪問核心數(shù)據(jù)庫,但是一個物理數(shù)據(jù)庫能夠支撐的并發(fā)量是有限的鸵膏,所有的業(yè)務(wù)系統(tǒng)之間還會產(chǎn)生競爭膊升,最終會導(dǎo)致應(yīng)用的性能下降,甚至拖垮業(yè)務(wù)系統(tǒng)

3)多應(yīng)用獨立數(shù)據(jù)庫
我們必須要對各個子系統(tǒng)的數(shù)據(jù)庫也做一個拆分谭企,這個時候每個業(yè)務(wù)系統(tǒng)都有了自己的數(shù)據(jù)庫廓译,不同的業(yè)務(wù)系統(tǒng)就可以用不同的存儲方案


image.png

分庫其實是我們在解決系統(tǒng)性能問題的過程中评肆,對系統(tǒng)進行拆分的時候帶來的一個必然的結(jié)果,現(xiàn)在的微服務(wù)架構(gòu)也是一樣的非区,只拆應(yīng)用不拆分?jǐn)?shù)據(jù)庫瓜挽,不能解決根本的問題

4)什么時候分表
當(dāng)我們對原來一個數(shù)據(jù)庫的表做了分庫以后,其中一些表的數(shù)據(jù)還在以一個非痴鞒瘢快的速度在增長久橙,這個時候查詢也已經(jīng)出現(xiàn)了非常明顯的效率下降

在分庫之后,還需要進一步進行分表管怠,當(dāng)然淆衷,我們最開始想到的可能是在一個數(shù)據(jù)庫里面拆分?jǐn)?shù)據(jù),分區(qū)或者分表渤弛,到后面才是切分到多個數(shù)據(jù)庫中

分表主要是為了減少單張表的大小祝拯,解決單表數(shù)據(jù)量帶來的性能問題


image.png

分庫分表會提升系統(tǒng)的復(fù)雜度,如果在近期或者未來一段時間內(nèi)必須要解決存儲和性能的問題她肯,就不要去做超前設(shè)計和過度設(shè)計佳头,就像我們搭建項目,從快速實現(xiàn)的角度來說晴氨,肯定是從單體項目起步的康嘉,在業(yè)務(wù)豐富完善之前,也用不到微服務(wù)架構(gòu)

如果我們創(chuàng)建的表結(jié)構(gòu)合理瑞筐,字段不是太多凄鼻,并且索引創(chuàng)建正確的情況下腊瑟,單張表存儲幾千萬的數(shù)據(jù)是完全沒有問題的聚假,這個還是以應(yīng)用的實際情況為準(zhǔn),當(dāng)然我們也會對未來一段時間的業(yè)務(wù)發(fā)展做一個預(yù)判

分庫分表的類型和特點

從維度來說分成兩種闰非,一種是垂直膘格,一種是水平

垂直切分:基于表或字段劃分,表結(jié)構(gòu)不同财松。我們有單庫的分表瘪贱,也有多庫的分庫
水平切分:基于數(shù)據(jù)劃分,表結(jié)構(gòu)相同辆毡,數(shù)據(jù)不同菜秦,也有同庫的水平切分和多庫的切分

image.png

1、垂直切分
垂直分表有兩種舶掖,一種是單庫的球昨,一種是多庫的

1)單庫垂直分表
單庫分表,比如:商戶信息表眨攘,拆分成基本信息表主慰,聯(lián)系方式表嚣州,結(jié)算信息表,附件表等

2)多庫垂直分表
多庫垂直分表就是把原來存儲在一個庫的不同的表共螺,拆分到不同的數(shù)據(jù)庫

比如:消費金融核心系統(tǒng)數(shù)據(jù)庫该肴,有很多客戶相關(guān)的表,這些客戶相關(guān)的表藐不,全部單獨存放到客戶的數(shù)據(jù)庫里面匀哄,合同,放款雏蛮,風(fēng)控相關(guān)的業(yè)務(wù)表也是一樣的

image.png

當(dāng)我們對原來的一張表做了分庫的處理拱雏,如果某些業(yè)務(wù)系統(tǒng)的數(shù)據(jù)還是有一個非常快的增長速度底扳,比如說還款數(shù)據(jù)庫的還款歷史表铸抑,數(shù)據(jù)量達到了幾個億,這個時候硬件限制導(dǎo)致的性能問題還是會出現(xiàn)衷模,所以從這個角度來說垂直切分并沒有從根本上解決單庫單表數(shù)據(jù)量過大的問題鹊汛,在這個時候,我們還需要對我們的數(shù)據(jù)做一個水平的切分

2阱冶、水平切分
當(dāng)我們的客戶表數(shù)量已經(jīng)到達數(shù)千萬甚至上億的時候刁憋,單表的存儲容量和查詢效率都會出現(xiàn)問題,我們需要進一步對單張表的數(shù)據(jù)進行水平切分木蹬,水平切分的每個數(shù)據(jù)庫的表結(jié)構(gòu)都是一樣的至耻,只是存儲的數(shù)據(jù)不一樣,比如每個庫存儲 2000 萬的數(shù)據(jù)

水平切分也可以分成兩種镊叁,一種是單庫的尘颓,一種是多庫的

1)單庫水平分表
銀行的交易流水表,所有進出的交易都需要登記這張表晦譬,因為絕大部分時候客戶都是查詢當(dāng)天的交易和一個月以內(nèi)的交易數(shù)據(jù)疤苹,所以我們根據(jù)使用頻率這張表拆分成三張表
當(dāng)天表:只存儲當(dāng)天的數(shù)據(jù)
當(dāng)月表:在夜間運行一個定時任務(wù),前一天的數(shù)據(jù)敛腌,全部遷移到當(dāng)月表卧土,用的是 insert into select,然后 delete
歷史表:同樣是通過定時任務(wù)像樊,把登記時間超過 30 天的數(shù)據(jù)尤莺,遷移到 history歷史表(歷史表的數(shù)據(jù)非常大,我們按照月度生棍,每個月建立分區(qū))

注意颤霎,跟分區(qū)一樣,這種方式雖然可以一定程度解決單表查詢性能的問題,但是并不能解決單機存儲瓶頸的問題

2)多庫水平分表
比如客戶表捷绑,我們拆分到多個庫存儲韩脑,表結(jié)構(gòu)是完全一樣的


image.png

一般我們說的分庫分表都是跨庫的分表

3、分庫分表帶來的問題
1)跨庫關(guān)聯(lián)查詢
比如:查詢在合同信息的時候要關(guān)聯(lián)客戶數(shù)據(jù)粹污,由于是合同數(shù)據(jù)和客戶數(shù)據(jù)是在不同的數(shù)據(jù)庫段多,那么我們肯定不能直接使用 join 的這種方式去做關(guān)聯(lián)查詢

有幾種主要的解決方案:
a)字段冗余
比如:我們查詢合同庫的合同表的時候需要關(guān)聯(lián)客戶庫的客戶表,我們可以直接把一些經(jīng)常關(guān)聯(lián)查詢的客戶字段放到合同表壮吩,通過這種方式避免跨庫關(guān)聯(lián)查詢的問題

b)數(shù)據(jù)同步
比如:商戶系統(tǒng)要查詢產(chǎn)品系統(tǒng)的產(chǎn)品表进苍,我們干脆在商戶系統(tǒng)創(chuàng)建一張產(chǎn)品表,通過 ETL 或者其他方式定時同步產(chǎn)品數(shù)據(jù)

c)全局表(廣播表)
比如:銀行的行名鸭叙、行號信息被很多業(yè)務(wù)系統(tǒng)用到觉啊,如果我們放在核心系統(tǒng),每個系統(tǒng)都要去關(guān)聯(lián)查詢沈贝,這個時候我們可以在所有的數(shù)據(jù)庫都存儲相同的基礎(chǔ)數(shù)據(jù)

d)ER 表(綁定表)
我們有些表的數(shù)據(jù)是存在邏輯的主外鍵關(guān)系的杠人,比如訂單表order_info,存的是匯總的商品數(shù)宋下,商品金額嗡善;訂單明細(xì)表order_detail,是每個商品的價格学歧,個數(shù)等等罩引,或者叫做從屬關(guān)系,父表和子表的關(guān)系枝笨,他們之間會經(jīng)常有關(guān)聯(lián)查詢的操作袁铐,如果父表的數(shù)據(jù)和子表的數(shù)據(jù)分別存儲在不同的數(shù)據(jù)庫,跨庫關(guān)聯(lián)查詢也比較麻煩

能不能把父表和數(shù)據(jù)和從屬于父表的數(shù)據(jù)落到一個節(jié)點上呢横浑?
比如: order_id=1001 的數(shù)據(jù)在 node1剔桨,它所有的明細(xì)數(shù)據(jù)也放到 node1;order_id=1002 的數(shù)據(jù)在 node2伪嫁,它所有的明細(xì)數(shù)據(jù)都放到 node2领炫,這樣在關(guān)聯(lián)查詢的時候依然是在一個數(shù)據(jù)庫

通過合理的數(shù)據(jù)分布避免跨庫關(guān)聯(lián)查詢,實際上在我們的業(yè)務(wù)中张咳,也是盡量不要用跨庫關(guān)聯(lián)查詢,如果出現(xiàn)了這種情況似舵,就要分析一下業(yè)務(wù)或者數(shù)據(jù)拆分是不是合理

e)系統(tǒng)層組裝
在不同的數(shù)據(jù)庫節(jié)點把符合條件數(shù)據(jù)的數(shù)據(jù)查詢出來脚猾,然后重新組裝,返回給客戶端

2)分布式事務(wù)
案例:在一個貸款的流程里面砚哗,合同系統(tǒng)登記了數(shù)據(jù)龙助,放款系統(tǒng)也必須生成放款記錄,如果兩個動作不是同時成功或者同時失敗,就會出現(xiàn)數(shù)據(jù)一致性的問題提鸟,如果在一個數(shù)據(jù)庫里面军援,我們可以用本地事務(wù)來控制,但是在不同的數(shù)據(jù)庫里面就不行了称勋,所以分布式環(huán)境里面的事務(wù)胸哥,我們也需要通過一些方案來解決

分布式系統(tǒng)的基礎(chǔ)是 CAP 理論
C (一致性)Consistency:對某個指定的客戶端來說,讀操作能返回最新的寫操作赡鲜,對于數(shù)據(jù)分布在不同節(jié)點上的數(shù)據(jù)來說空厌,如果在某個節(jié)點更新了數(shù)據(jù),那么在其他節(jié)點如果都能讀取到這個最新的數(shù)據(jù)银酬,那么就稱為強一致嘲更,如果有某個節(jié)點沒有讀取到,那就是分布式不一致

A (可用性)Availability:非故障的節(jié)點在合理的時間內(nèi)返回合理的響應(yīng)(不是錯誤和超時的響應(yīng))揩瞪,可用性的兩個關(guān)鍵一個是合理的時間赋朦,一個是合理的響應(yīng)
合理的時間:指的是請求不能無限被阻塞,應(yīng)該在合理的時間給出返回
合理的響應(yīng):指的是系統(tǒng)應(yīng)該明確返回結(jié)果并且結(jié)果是正確的

P (分區(qū)容錯性)Partition tolerance:當(dāng)出現(xiàn)網(wǎng)絡(luò)分區(qū)后李破,系統(tǒng)能夠繼續(xù)工作北发,比如,這里集群有多臺機器喷屋,有臺機器網(wǎng)絡(luò)出現(xiàn)了問題琳拨,但是這個集群仍然可以正工作

CAP 三者是不能共有的,只能同時滿足其中兩點屯曹,基于 AP狱庇,我們又有了 BASE 理論

基本可用(Basically Available):分布式系統(tǒng)在出現(xiàn)故障時,允許損失部分可用功能恶耽,保證核心功能可用
軟狀態(tài)(Soft state):允許系統(tǒng)中存在中間狀態(tài)密任,這個狀態(tài)不影響系統(tǒng)可用性,這里指的是 CAP 中的不一致
最終一致(Eventually consistent):最終一致是指經(jīng)過一段時間后偷俭,所有節(jié)點數(shù)據(jù)都將會達到一致

分布式事務(wù)有幾種常見的解決方案:
a)全局事務(wù)(比如 XA 兩階段提交浪讳;應(yīng)用、事務(wù)管理器(TM)涌萤、資源管理器(DB))淹遵,例如 Atomikos
b)基于可靠消息服務(wù)的分布式事務(wù)

image.png

c)柔性事物TCC(Try-Confirm-Cancel)tcc-transaction
image.png

d)最大努力通知,通過消息中間件向其他系統(tǒng)發(fā)送消息(重復(fù)投遞+定期校對)

3)排序负溪、翻頁透揣、函數(shù)計算問題
跨節(jié)點多庫進行查詢時,會出現(xiàn) limit 分頁川抡,order by 排序的問題
比如:有兩個節(jié)點辐真,節(jié)點 1 存的是奇數(shù) id=1,3,5,7,9……;節(jié)點 2 存的是偶數(shù) id=2,4,6,8,10……
執(zhí)行 select * from user order by id limit 0,10

需要在兩個節(jié)點上各取出 10 條,然后合并數(shù)據(jù)侍咱,重新排序

max耐床、min、sum楔脯、count 之類的函數(shù)在進行計算的時候撩轰,也需要先在每個分片上執(zhí)行相應(yīng)的函數(shù),然后將各個分片的結(jié)果集進行匯總和再次計算淤年,最終將結(jié)果返回

4)全局主鍵避重問題
MySQL 的數(shù)據(jù)庫里面字段有一個自增的屬性钧敞,Oracle 也有 Sequence 序列,如果是一個數(shù)據(jù)庫麸粮,那么可以保證 ID 是不重復(fù)的溉苛,但是水平分表以后,每個表都按照自己的規(guī)律自增弄诲,肯定會出現(xiàn) ID 重復(fù)的問題愚战,這個時候我們就不能用本地自增的方式了

幾種常見的解決方案:
a)UUID(Universally Unique Identifier 通用唯一識別碼)
UUID 標(biāo)準(zhǔn)形式包含 32 個 16 進制數(shù)字,分為 5 段齐遵,形式為 8-4-4-4-12 的 36 個字符寂玲,例如:c4e7956c-16e7-422c-4509-d733803e289a9

name Length(Bytes) Length(Hex Digits) Contents
time_low 4 8 integer giving the low 32 bits of the time
time_mid 2 4 integer giving the middle 16 bits of the time
time_hi_and_version 2 4 4-bit "version" in the most significant bits,followed by the high 12 bits of the time
clock_seq_hi_and_res clock_seq_low 2 4 1-3 bit "variant" in the most significant bits,followed by the 13-15 bit clock sequence
node 6 12 the 48-bit node id

解析:xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
M 表示 UUID 版本,目前只有五個版本梗摇,即只會出現(xiàn) 1拓哟,2,3,4,5
數(shù)字 N 的一至三個最高有效位表示 UUID 變體纺腊,目前只會出現(xiàn) 8,9违诗,a,b 四種情況

1疮蹦、基于時間和 MAC 地址的 UUID
2诸迟、基于第一版卻更安全的 DCE UUID
3、基于 MD5 散列算法的 UUID
4愕乎、基于隨機數(shù)的 UUID——用的最多阵苇,JDK 里面是 4
5、基于 SHA1 散列算法的 UUID

UUID 是主鍵是最簡單的方案妆毕,本地生成慎玖,性能高,沒有網(wǎng)絡(luò)耗時笛粘,但缺點也很明顯,由于 UUID 非常長,會占用大量的存儲空間薪前;另外润努,作為主鍵建立索引和基于索引進行查詢時都會存在性能問題,在 InnoDB 中示括,UUID 的無序性會引起數(shù)據(jù)位置頻繁變動铺浇,導(dǎo)致分頁

b)數(shù)據(jù)庫
把序號維護在數(shù)據(jù)庫的一張表中。這張表記錄了全局主鍵的類型垛膝、位數(shù)鳍侣、起始值,當(dāng)前值吼拥,當(dāng)其他應(yīng)用需要獲得全局 ID 時倚聚,先** for update 鎖行,取到值+1 后并且更新后返回凿可,并發(fā)性比較差**

c)Redis
基于 Redis 的INT 自增的特性惑折,使用批量的方式降低數(shù)據(jù)庫的寫壓力,每次獲取一段區(qū)間的 ID 號段枯跑,用完之后再去數(shù)據(jù)庫獲取惨驶,可以大大減輕數(shù)據(jù)庫的壓力

d)雪花算法 Snowflake(64bit)


Snowflake.png

核心思想:
aa)使用 41bit 作為毫秒數(shù),可以使用 69 年
bb)10bit 作為機器的 ID(5bit 是數(shù)據(jù)中心敛助,5bit 的機器 ID)粗卜,支持 1024 個節(jié)點
cc)12bit 作為毫秒內(nèi)的流水號(每個節(jié)點在每毫秒可以產(chǎn)生 4096 個 ID)
dd)最后還有一個符號位,永遠(yuǎn)是 0

優(yōu)點:毫秒數(shù)在高位纳击,生成的 ID 整體上按時間趨勢遞增续扔;不依賴第三方系統(tǒng),穩(wěn)定性和效率較高评疗,理論上 QPS 約為409.6w/s(10002^12)测砂,并且整個分布式系統(tǒng)內(nèi)不會產(chǎn)生 ID 碰撞*;可根據(jù)自身業(yè)務(wù)靈活分配 bit 位

缺點:強依賴機器時鐘百匆,如果時鐘回?fù)?/strong>砌些,則可能導(dǎo)致生成 ID 重復(fù)

4、多數(shù)據(jù)源 / 讀寫數(shù)據(jù)源的解決方案
SQL 執(zhí)行經(jīng)過的流程:
DAO—Mapper(ORM)—JDBC—代理—數(shù)據(jù)庫服務(wù)

1)客戶端DAO層
比如: DAO 層加匈,在我們連接到某一個數(shù)據(jù)源之前存璃,我們先根據(jù)配置的分片規(guī)則,判斷需要連接到哪些節(jié)點雕拼,再建立連接

Spring 中提供了一個抽象類 AbstractRoutingDataSource纵东,可以實現(xiàn)數(shù)據(jù)源的動態(tài)切換

利用SSM框架實現(xiàn)步驟:
a)aplication.properties 定義多個數(shù)據(jù)源
b)創(chuàng)建@TargetDataSource 注解
c)創(chuàng)建 DynamicDataSource 繼承 AbstractRoutingDataSource
d)多數(shù)據(jù)源配置類 DynamicDataSourceConfig
e)創(chuàng)建切面類 DataSourceAspect,對添加了@TargetDataSource 注解的類進行攔截設(shè)置數(shù)據(jù)源
f)在 啟 動 類 上 自 動 裝 配 數(shù) 據(jù) 源 配 置@Import({DynamicDataSourceConfig.class})
g)在 實 現(xiàn) 類 上 加 上 注 解 啥寇, 如 @TargetDataSource(name =DataSourceNames.SECOND)偎球,調(diào)用

DAO層實現(xiàn)的優(yōu)點:
不需要依賴 ORM 框架洒扎,即使替換了 ORM 框架也不受影響,實現(xiàn)簡單(不需要解析 SQL 和路由規(guī)則)衰絮,可以靈活地定制

缺點:不能復(fù)用袍冷,不能跨語言

2)ORM框架層
比如:我們用 MyBatis 連接數(shù)據(jù)庫,也可以指定數(shù)據(jù)源猫牡,我們可以基于 MyBatis 插件的攔截機制(攔截 query 和 update 方法)胡诗,實現(xiàn)數(shù)據(jù)源的選擇
例子:
https://github.com/colddew/shardbatis
https://docs.jboss.org/hibernate/stable/shards/reference/en/html_single/

3)驅(qū)動層
不管是MyBatis還是Hibernate,還是Spring的JdbcTemplate淌友,本質(zhì)上都是對JDBC的封裝煌恢,所以第三層就是驅(qū)動層,比如: Sharding-JDBC震庭,就是對 JDBC 的對象進行了封裝

JDBC 的核心對象:
DataSource:數(shù)據(jù)源
Connection:數(shù)據(jù)庫連接
Statement:語句對象
ResultSet:結(jié)果集

只要對這幾個對象進行封裝或者攔截或者代理瑰抵,就可以實現(xiàn)分片的操作

4)代理層
前面三種都是在客戶端實現(xiàn)的,也就是說不同的項目都要做同樣的改動归薛,不同的編程語言也有不同的實現(xiàn)

代理層谍憔,比如 Mycat 和 Sharding-Proxy,都是屬于這一層

5)數(shù)據(jù)庫服務(wù)
最后一層就是在數(shù)據(jù)庫服務(wù)上實現(xiàn)主籍,也就是服務(wù)層习贫,某些特定的數(shù)據(jù)庫或者數(shù)據(jù)庫的特定版本可以實現(xiàn)這個功能

Mycat概念與配置

官網(wǎng):http://www.mycat.io/
Mycat 概要介紹:https://github.com/MyCATApache/Mycat-Server
入門指南: https://github.com/MyCATApache/Mycat-doc/tree/master/%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97

1、Mycat 的介紹與核心概念
1)基本介紹
歷史:從阿里cobar 升級而來千元,由開源組織維護苫昌,2.0正在開發(fā)中

定位:運行在應(yīng)用和數(shù)據(jù)庫之間,可以當(dāng)做一個 MySQL 服務(wù)器使用幸海,實現(xiàn)對 MySQL數(shù)據(jù)庫的分庫分表祟身,也可以通過 JDBC 支持其他的數(shù)據(jù)庫

image.png

Mycat的關(guān)鍵特性:
1、可以當(dāng)做一個 MySQL 數(shù)據(jù)庫來使用
2物独、支持 MySQL 之外的數(shù)據(jù)庫袜硫,通過 JDBC 實現(xiàn)
3、解決了我們提到的所有問題挡篓,多表 join婉陷、分布式事務(wù)、全局序列號官研、翻頁排序
4秽澳、支持 ZK 配置,帶監(jiān)控 mycat-web
5戏羽、2.0 正在開發(fā)中

2)核心概念


image.png

專有名詞解析:
主機/實例:物理主機担神,一臺服務(wù)器,一個數(shù)據(jù)庫服務(wù)始花,一個 3306 端口
物理數(shù)據(jù)庫:真實的數(shù)據(jù)庫妄讯,例如 101孩锡、102、103 的 gpcat 數(shù)據(jù)庫
物理表:真實的表捞挥,例如 101浮创、102忧吟、103 的 gpcat 數(shù)據(jù)庫的 order_info 表
分片:將原來單個數(shù)據(jù)庫的數(shù)據(jù)切分后分散存儲在不同的數(shù)據(jù)庫節(jié)點
分片節(jié)點:分片以后數(shù)據(jù)存儲的節(jié)點
分片鍵:分片依據(jù)的字段砌函,例如 order_info 表以 id 為依據(jù)分片,id 就是分片鍵,通常是主鍵
分片算法:分片的規(guī)則讹俊,例如隨機仍劈、取模、范圍寡壮、哈希、枚舉以及各種組合算法
邏輯表:相對于物理表这溅,是分片表聚合后的結(jié)果,對于客戶端來說跟真實的表沒有區(qū)別
邏輯數(shù)據(jù)庫:對于物理數(shù)據(jù)庫棒仍,是數(shù)據(jù)節(jié)點聚合后的結(jié)果莫其,例如 vincentshopping

下載解壓Mycat:http://dl.mycat.io/

linux:
wget http://dl.mycat.io/1.6.7.3/20190927161129/Mycat-server-1.6.7.3-release-20190927161129-linux.tar.gz
tar -xzvf Mycat-server-1.6.7.3-release-20190927161129-linux.tar.gz

解壓之后5個目錄講解:
bin :啟動目錄
catlet :空目錄
conf :配置目錄
lib :jar包依賴
logs :日志目錄

2乱陡、Mycat 配置詳解
主要的配置文件 有:server.xml、schema.xml胳徽、rule.xml 和具體的分片配置文件

1)server.xml
包含系統(tǒng)配置信息
system 標(biāo)簽:例如字符集膜廊、線程數(shù)爪瓜、心跳铆铆、分布式事務(wù)開關(guān)等等
user 標(biāo)簽:配置登錄用戶和權(quán)限

<user name="root" defaultAccount="true">
    <property name="password">123456</property>
    <property name="schemas">vincent</property>
</user>

mycat 對稱碼加密:
java -cp Mycat-server-1.6.7.3-release.jar io.mycat.util.DecryptUtil 0:root:123456

2)schema.xml
schema 在 MySQL 里面跟數(shù)據(jù)庫是等價的

schema.xml 包括邏輯庫薄货、表、分片規(guī)則柄慰、分片節(jié)點和數(shù)據(jù)源坐搔,可以定義多個 schema

這里面有三個主要的標(biāo)簽(table概行、dataNode凳忙、dataHost):

<table/>

表名和庫名最好都用小寫

<!--定義了邏輯表禽炬,以及邏輯表分布的節(jié)點和分片規(guī)則:-->
<schema name="vincentmall" checkSQLschema="false" sqlMaxLimit="100">
    <!-- 范圍分片 -->
    <table name="customer" primaryKey="id" dataNode="dn1,dn2,dn3" rule="rang-long-cust" />
    <!-- 取模分片 -->
    <table name="order_info" dataNode="dn1,dn2,dn3" rule="mod-long-order" >
        <!-- ER 表 -->
        <childTable name="order_detail" primaryKey="id" joinKey="order_id" parentKey="order_id"/>
    </table>
    <!-- 全局表 -->
    <table name="student" primaryKey="sid" type="global" dataNode="dn1,dn2,dn3" />
</schema>

參數(shù)解釋:
primaryKey:指定該邏輯表對應(yīng)真實表的主鍵瞎抛。MyCat 會緩存主鍵(通過 primaryKey 屬性配置)與具體 dataNode 的信息桐臊,當(dāng)分片規(guī)則(rule)使用非主鍵進行分片時断凶,那么在使用主鍵進行查詢時,MyCat 就會通過緩存先確定記錄在哪個 dataNode 上肿男,然后再在該 dataNode 上執(zhí)行查詢舶沛,如果沒有緩存/緩存并沒有命中的話如庭,還是會發(fā)送語句給所有的 dataNode
dataNode:數(shù)據(jù)分片的節(jié)點
autoIncrement:自增長(全局序列)坪它,true 代表主鍵使用自增長策略
type:全局表:global往毡。其他:不配置

<dataNode/>

<dataNode name="dn1" dataHost="host1" database="vincentcat" />
數(shù)據(jù)節(jié)點與物理數(shù)據(jù)庫的對應(yīng)關(guān)系

<dataHost/>

配置物理主機的信息开瞭,readhost 是從屬于 writehost 的

<dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql"
dbDriver="native" switchType="1" slaveThreshold="100">
    <heartbeat>select user()</heartbeat>
    <!-- can have multi write hosts -->
    <writeHost host="hostM1" url="localhost:3306" user="root" password="123456">
        <!-- can have multi read hosts -->
        <readHost host="hostS2" url="192.168.8.146:3306" user="root" password="xxx"/>
    </writeHost>
    <writeHost host="hostS1" url="localhost:3316" user="root" password="123456"/>
    <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>

參數(shù)解析:
balance(0挎狸,1,2冬筒,3):負(fù)載的配置舞痰,決定 select 語句的負(fù)載
0:不開啟讀寫分離機制响牛,所有讀操作都發(fā)送到當(dāng)前可用的 writeHost 上
1:所有讀操作都隨機發(fā)送到當(dāng)前的 writeHost 對應(yīng)的 readHost 和備用的 writeHost
2:所有的讀操作都隨機發(fā)送到所有的 writeHost,readHost 上
3:所有的讀操作都只發(fā)送到 writeHost 的 readHost 上

writeType(0呀打,1):讀寫分離的配置贬丛,決定 update豺憔、delete恭应、insert 語句的負(fù)載
0:所有寫操作都發(fā)送到可用的 writeHost 上(默認(rèn)第一個昼榛,第一個掛了以后發(fā)到第二個)
1:所有寫操作都隨機的發(fā)送到 writeHost

switchType(-1褒纲,1莺掠,2彻秆,3):主從切換配置
-1:表示不自動切換
1:默認(rèn)值唇兑,表示自動切換
2:基于 MySQL 主從同步的狀態(tài)決定是否切換,心跳語句為 show slave status
3:基于MySQL galary cluster的切換機制(適合集群) (1.4.1)扎附,心跳語句為 show status like 'wsrep%'

3)rule.xml
定義了分片規(guī)則和算法
分片規(guī)則:

<tableRule name="rang-long-cust">
    <rule>
        <columns>id</columns>
        <algorithm>func-rang-long-cust</algorithm>
    </rule>
</tableRule>

分片算法:

<function name="func-rang-long-cust" class="io.mycat.route.function.AutoPartitionByLong">
    <property name="mapFile">rang-long-cust.txt</property>
</function>

<!--分片配置:rang-long-cust.txt-->
10001-20000=1
0-10000=0
20001-100000=2

4)ZK配置
Mycat 也支持 ZK 配置(用于管理配置和生成全局 ID)留夜,執(zhí)行 bin 目錄下init_zk_data.sh碍粥,會自動將 zkconf 下的所有配置文件上傳到 ZK(先拷貝到這個目錄)

cd /usr/local/soft/mycat/conf
#通配符復(fù)制
cp *.txt *.xml *.properties zkconf/
?
cd /usr/local/soft/mycat/bin
#執(zhí)行
./init_zk_data.sh

啟用ZK配置:

mycat/conf/myid.properties

loadZk=true
zkURL=127.0.0.1:2181
clusterId=010
myid=01001
clusterSize=1
clusterNodes=mycat_gp_01
#server booster ; booster install on db same server,will reset all minCon to 2
type=server
boosterDataHosts=dataHost1

存在問題:
如果執(zhí)行 init_zk_data.sh 腳本報錯的話钦讳,代表未寫入成功愿卒,此時不要啟用 ZK配置并重啟掘猿,否則本地文件會被覆蓋

啟動時如果 loadzk=true 啟動時稠通,會自動從 zk 下載配置文件覆蓋本地配置

解決:在這種情況下如果修改配置改橘,需要先修改 conf 目錄的配置飞主,copy 到 zkconf碌识,再執(zhí)行上傳

5)啟動停止
進入到mycat/bin 目錄筏餐,啟動mycat之前必須要先啟動物理數(shù)據(jù)庫

啟動:./mycat start
停止:./mycat stop
重啟:./mycat restart
查看狀態(tài):./mycat status
前臺運行:./mycat console

linux 命令窗口連接:
mysql -uroot -p123456 -h 192.168.8.151 -P8066 cattest

3魁瞪、Mycat 分片驗證
數(shù)據(jù)庫可以用:explain 來看路由結(jié)果

建表驗證:

CREATE TABLE `customer` (
    `id` int(11) DEFAULT NULL,
    `name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `order_info` (
    `order_id` int(11) NOT NULL COMMENT '訂單 ID',
    `uid` int(11) DEFAULT NULL COMMENT '用戶 ID',
    `nums` int(11) DEFAULT NULL COMMENT '商品數(shù)量',
    `state` int(2) DEFAULT NULL COMMENT '訂單狀態(tài)',
    `create_time` datetime DEFAULT NULL ON UPDATE     CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
    `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
    PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `order_detail` (
    `order_id` int(11) NOT NULL COMMENT '訂單號',
    `id` int(11) NOT NULL COMMENT '訂單詳情',
    `goods_id` int(11) DEFAULT NULL COMMENT '貨品 ID',
    `price` decimal(10,2) DEFAULT NULL COMMENT '價格',
    `is_pay` int(2) DEFAULT NULL COMMENT '支付狀態(tài)',
    `is_ship` int(2) DEFAULT NULL COMMENT '是否發(fā)貨',
    `status` int(2) DEFAULT NULL COMMENT '訂單詳情狀態(tài)',
    PRIMARY KEY (`order_id`,`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `student` (
    `sid` int(8) NOT NULL AUTO_INCREMENT,
    `name` varchar(255) DEFAULT NULL,
    `qq` varchar(255) DEFAULT NULL,
    PRIMARY KEY (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

schema.xml

<table name="customer" dataNode="dn1,dn2,dn3" rule="rang-long-cust" primaryKey="id"/>
<table name="order_info" dataNode="dn1,dn2,dn3" rule="mod-long-order">
    <childTable name="order_detail" joinKey="order_id" parentKey="order_id" primaryKey="id"/>
</table>
<table name="student" dataNode="dn1,dn2,dn3" primaryKey="sid" type="global"/>

數(shù)據(jù)節(jié)點配置:

<dataNode name="dn1" dataHost="host1" database="cat"/>
<dataNode name="dn2" dataHost="host2" database="cat"/>
<dataNode name="dn3" dataHost="host3" database="cat"/>

<dataHost balance="0" maxCon="1000" minCon="10" name="host1" writeType="0" switchType="1"
slaveThreshold="100" dbType="mysql" dbDriver="native">
    <heartbeat>select user()</heartbeat>
    <writeHost host="hostM1" url="192.168.8.146:3306" password="123456" user="root"/>
</dataHost>
?
<dataHost balance="0" maxCon="1000" minCon="10" name="host2" writeType="0" switchType="1"
slaveThreshold="100" dbType="mysql" dbDriver="native">
    <heartbeat>select user()</heartbeat>
    <writeHost host="hostM1" url="192.168.8.150:3306" password="123456" user="root"/>
</dataHost>
?
<dataHost balance="0" maxCon="1000" minCon="10" name="host3" writeType="0" switchType="1"
slaveThreshold="100" dbType="mysql" dbDriver="native">
    <heartbeat>select user()</heartbeat>
    <writeHost host="hostM1" url="192.168.8.151:3306" password="123456" user="root"/>
</dataHost>

流程:schema——rule.xml——分片配置

1)范圍分片

<tableRule name="rang-long-cust">
    <rule>
        <columns>id</columns>
        <algorithm>rang-long-cust</algorithm>
    </rule>
</tableRule>

<function name="rang-long-cust" class="io.mycat.route.function.AutoPartitionByLong">
    <property name="mapFile">rang-long-cust.txt</property>
</function>

<!--customer表,按照rang-long-cust.txt中定義的id范圍去進行分片辅髓,分別插入到不同的database中-->
INSERT INTO `customer` (`id`, `name`) VALUES (6666, '趙先生');
INSERT INTO `customer` (`id`, `name`) VALUES (7777, '錢先生');
INSERT INTO `customer` (`id`, `name`) VALUES (16666, '孫先生');
INSERT INTO `customer` (`id`, `name`) VALUES (17777, '李先生');
INSERT INTO `customer` (`id`, `name`) VALUES (26666, '周先生');
INSERT INTO `customer` (`id`, `name`) VALUES (27777, '吳先生');

2)取模分片(ER表)

<!-- order_info 表-->
<tableRule name="mod-long-order">
    <rule>
        <columns>order_id</columns>
        <algorithm>mod-long</algorithm>
    </rule>
</tableRule>

<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
    <property name="count">3</property>
</function>

INSERT INTO `order_info` (`order_id`, `uid`, `nums`, `state`, `create_time`, `update_time`) VALUES (1, 1000001, 1, 2,
'2019-9-23 14:35:37', '2019-9-23 14:35:37');
INSERT INTO `order_info` (`order_id`, `uid`, `nums`, `state`, `create_time`, `update_time`) VALUES (2, 1000002, 1, 2,
'2019-9-24 14:35:37', '2019-9-24 14:35:37');
INSERT INTO `order_info` (`order_id`, `uid`, `nums`, `state`, `create_time`, `update_time`) VALUES (3, 1000003, 3, 1,
'2019-9-25 11:35:49', '2019-9-25 11:35:49');

<!-- order_detail表 -->
INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (3, 20180001,
85114752, 19.99, 1, 1, 1);
INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (1, 20180002,
25411251, 1280.00, 1, 1, 0);
INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (1, 20180003,
62145412, 288.00, 1, 1, 2);
INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (2, 20180004,
21456985, 399.00, 1, 1, 2);
INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (2, 20180005,
21457452, 1680.00, 1, 1, 2);
INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (2, 20180006,
65214789, 9999.00, 1, 1, 3);

3)全局表

<!--student表-->
<table name="student" dataNode="dn1,dn2,dn3" primaryKey="sid" type="global"/>

INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (1, '黑白', '166669999');
INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (2, 'AV 哥', '466669999');
INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (3, '最強菜鳥', '368828888');
INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (4, '加載中', '655556666');
INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (5, '貓老公', '265286999');
INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (6, '一個人的精彩', '516895555');

4猎莲、Mycat 全局ID
配置文件 server.xml sequnceHandlerType值:
0 文件 1 數(shù)據(jù)庫 2 本地時間戳 3 ZK
<property name="sequnceHandlerType">0</property>

1)文件方式
配置 conf/sequence_conf.properties

CUSTOMER.HISIDS=
CUSTOMER.MINID=10000001
CUSTOMER.MAXID=20000000
CUSTOMER.CURID=10000001

語法:
select next value for MYCATSEQ_CUSTOMER
eg:
INSERT INTOcustomer(id,name) VALUES (next value for MYCATSEQ_CUSTOMER, 'vincent');

優(yōu)點:本地加載著洼,讀取速度較快
缺點:當(dāng) Mycat 重新發(fā)布后身笤,配置文件中的 sequence 需要替換液荸,Mycat 不能做集群部署

2)數(shù)據(jù)庫方式
<property name="sequnceHandlerType">1</property>

配置: sequence_db_conf.properties

<!--把這張表創(chuàng)建在 146 上娇钱,所以是 dn1-->
#sequence stored in datanode
GLOBAL=dn1
CUSTOMER=dn1

在第一個數(shù)據(jù)庫節(jié)點上創(chuàng)建 MYCAT_SEQUENCE 表:

DROP TABLE IF EXISTS MYCAT_SEQUENCE;
CREATE TABLE MYCAT_SEQUENCE (
    name VARCHAR(50) NOT NULL,
    current_value INT NOT NULL,
    increment INT NOT NULL DEFAULT 1,
    remark varchar(100),
PRIMARY KEY(name)) ENGINE=InnoDB;

可以在 schema.xml 配置文件中配置這張表,供外部訪問:
<table name="mycat_sequence" dataNode="dn1" autoIncrement="true" primaryKey="id"></table>

創(chuàng)建存儲過程——獲取當(dāng)前的sequence的值:

DROP FUNCTION IF EXISTS `mycat_seq_currval`;
DELIMITER ;;
CREATE DEFINER=`root`@`%` FUNCTION `mycat_seq_currval`(seq_name VARCHAR(50)) RETURNS varchar(64)
CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
SET retval="-999999999,null";
SELECT concat(CAST(current_value AS CHAR),",",CAST(increment AS CHAR) ) INTO retval FROM
MYCAT_SEQUENCE WHERE name = seq_name;
RETURN retval ;
END
;;
DELIMITER ;

創(chuàng)建存儲過程——獲取下一個sequence的值

DROP FUNCTION IF EXISTS `mycat_seq_nextval`;
DELIMITER ;;
CREATE DEFINER=`root`@`%` FUNCTION `mycat_seq_nextval`(seq_name VARCHAR(50)) RETURNS varchar(64)
CHARSET latin1
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = current_value + increment WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END
;;
DELIMITER ;

創(chuàng)建存儲過程煤蹭,設(shè)置sequence

DROP FUNCTION IF EXISTS `mycat_seq_setval`;
DELIMITER ;;
CREATE DEFINER=`root`@`%` FUNCTION `mycat_seq_setval`(seq_name VARCHAR(50), value INTEGER)
RETURNS varchar(64) CHARSET latin1
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = value
WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END
;;
DELIMITER ;

插入數(shù)據(jù):

INSERT INTO MYCAT_SEQUENCE(name,current_value,increment,remark) VALUES ('GLOBAL', 1, 100,'');
INSERT INTO MYCAT_SEQUENCE(name,current_value,increment,remark) VALUES ('ORDERS', 1, 100,'訂單表使用');

測試:
select next value for MYCATSEQ_ORDERS

3)本地時間戳方式
ID= 64 位二進制 (42(毫秒) + 5(機器 ID) + 5(業(yè)務(wù)編碼) + 12(重復(fù)累加) 常挚,長度為18 位
<property name="sequnceHandlerType">2</property>

配置文件:sequence_time_conf.properties

#sequence depend on TIME
WORKID=01
DATAACENTERID=01

驗證:select next value for MYCATSEQ_GLOBAL

4)ZK方式
修改 conf/myid.properties

設(shè)置 loadZk=true(啟動時會從 ZK 加載配置奄毡,一定要注意備份配置文件秧倾,并且先用 bin/init_zk_data.sh,把配置文件寫入到 ZK

<property name="sequnceHandlerType">3</property>

配置文件:sequence_distributed_conf.properties

# 代表使用 zk
INSTANCEID=ZK
# 與 myid.properties 中的 CLUSTERID 設(shè)置的值相同
CLUSTERID=010

復(fù)制配置文件:

cd /usr/local/soft/mycat/conf
cp *.txt *.xml *.properties zkconf/
chown -R zkconf/

cd /usr/local/soft/mycat/bin
./init_zk_data.sh

驗證:select next value for MYCATSEQ_GLOBAL

5)使用
schema.xml 的 table 標(biāo)簽上配置 autoIncrement="true"那先,不需要獲取和指定序列的情況下售淡,就可以使用全局 ID 了

Mycat監(jiān)控與日志查看

1揖闸、監(jiān)控
1)命令行監(jiān)控
連接到管理端口 9066汤纸,必須要帶 IP
mysql -uroot -h127.0.0.1 -p123456 -P9066

查看全部命令:
mysql>show @@help;

命令 作用
show @@server 查看服務(wù)器狀態(tài)贮泞,包括占用內(nèi)存等
show @@database 查看數(shù)據(jù)庫
show @@datanode 查看數(shù)據(jù)節(jié)點
show @@datasource 查看數(shù)據(jù)源
show @@connection 該命令用于獲取 Mycat 的前端連接狀態(tài),即應(yīng)用與 mycat 的連接
show @@backend 查看后端連接狀態(tài)
show @@cache 查看緩存使用情況 SQLRouteCache:sql 路由緩存TableID2DataNodeCache : 緩存表主鍵與分片對應(yīng)關(guān)系 ER_SQL2PARENTID :緩存 ER 分片中子表與父表關(guān)系
reload @@config 重新加載基本配置令蛉,使用這個命令時 mycat服務(wù)不可用
show @@sysparam 參看參數(shù)
show @@sql.high 執(zhí)行頻率高的 SQL
show @@sql.slow 慢 SQL 設(shè)置慢 SQL 的命令:reload @@sqlslow=5 ;

2)命令行監(jiān)控mycat-web監(jiān)控

Mycat-eye 是 mycat 提供的一個監(jiān)控工具珠叔,它依賴于 ZK运杭,本地必須要運行一個 ZK辆憔,必須先啟動 ZK

安裝Zookeeper:

#創(chuàng)建目錄
mkdir -p /usr/local/soft/zookeeper
cd /usr/local/soft/zookeeper

#下載解壓
wget https://archive.apache.org/dist/zookeeper/zookeeper-3.4.9/zookeeper-3.4.9.tar.gz
tar -zxvf zookeeper-3.4.9.tar.gz
cd zookeeper-3.4.9
mkdir data
mkdir logs

#修改配置文件
cd conf
cp zoo_sample.cfg zoo.cfg

#修改zoo.cfg
# 數(shù)據(jù)文件夾
dataDir=/usr/local/services/zookeeper/zookeeper-3.4.9/data

# 日志文件夾
dataLogDir=/usr/local/services/zookeeper/zookeeper-3.4.9/logs

#配置環(huán)境變量
vim /etc/profile

#尾部追加  zk env
export ZOOKEEPER_HOME=/usr/local/soft/zookeeper/zookeeper-3.4.9/
export PATH=$ZOOKEEPER_HOME/bin:$PATH
export PATH

#編譯生效
source /etc/profile

#啟動zk
cd ../bin
zkServer.sh start

#查看狀態(tài)
zkServer.sh status

安裝mycat-web:

#下載mycat-web
cd /usr/local/soft
wget http://dl.mycat.io/mycat-web-1.0/Mycat-web-1.0-SNAPSHOT-20170102153329-linux.tar.gz
tar -xzvf Mycat-web-1.0-SNAPSHOT-20170102153329-linux.tar.gz

#啟動mycat-web
cd mycat-web
#后臺啟動
nohup ./start.sh &

停止:kill start.jar 相關(guān)的進程

訪問端口:8082
http://192.168.8.151:8082/mycat/

配置: mycat server.xml

<!-- 1 為開啟實時統(tǒng)計熊榛、0 為關(guān)閉 -->
<property name="useSqlStat">1</property>

修改之后要重啟 mycat 服務(wù)生效

2玄坦、日志
log4j 的 level 配置要改成 debug

1)wrapper.log日志
wrapper 日志:mycat 啟動煎楣,停止择懂,添加為服務(wù)等都會記錄到此日志文件困曙,如果系統(tǒng)環(huán)境配置錯誤或缺少配置時慷丽,導(dǎo)致 Mycat 無法啟動要糊,可以通過查看 wrapper.log 定位具體錯誤原因

2)mycat.log日志
mycat.log 為 mycat 主要日志文件杨耙,記錄了啟動時分配的相關(guān) buffer 信息,數(shù)據(jù)源連接信息宣脉,連接池塑猖,動態(tài)類加載信息等等

conf/log4j2.xml 文件中進行相關(guān)配置羊苟,如保留個數(shù)蜡励,大小凉倚,字符集稽寒,日志文件大小

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末杏糙,一起剝皮案震驚了整個濱河市宏侍,隨后出現(xiàn)的幾起案子漫蛔,更是在濱河造成了極大的恐慌旧蛾,老刑警劉巖锨天,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搂赋,死亡現(xiàn)場離奇詭異脑奠,居然都是意外死亡宋欺,警方通過查閱死者的電腦和手機齿诞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來但汞,“玉大人特占,你說我怎么就攤上這事是目“媚桑” “怎么了嗤疯?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵戏罢,是天一觀的道長龟糕。 經(jīng)常有香客問我讲岁,道長缓艳,這世上最難降的妖魔是什么阶淘? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上珠闰,老公的妹妹穿的比我還像新娘伏嗜。我一直安慰自己承绸,他們只是感情好军熏,可當(dāng)我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布均践。 她就那樣靜靜地躺著彤委,像睡著了一般焦影。 火紅的嫁衣襯著肌膚如雪斯辰。 梳的紋絲不亂的頭發(fā)上椒涯,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機與錄音湖苞,去河邊找鬼财骨。 笑死隆箩,一個胖子當(dāng)著我的面吹牛捌臊,可吹牛的內(nèi)容都是我干的理澎。 我是一名探鬼主播寇荧,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼揩抡,長吁一口氣:“原來是場噩夢啊……” “哼殴玛!你這毒婦竟也來了捅膘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤滚粟,失蹤者是張志新(化名)和其女友劉穎寻仗,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凡壤,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年亚侠,在試婚紗的時候發(fā)現(xiàn)自己被綠了曹体。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡硝烂,死狀恐怖箕别,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情滞谢,我是刑警寧澤串稀,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站狮杨,受9級特大地震影響母截,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜橄教,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一清寇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧护蝶,春花似錦华烟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春比吭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背姨涡。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工衩藤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人涛漂。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓赏表,卻偏偏與公主長得像,于是被迫代替她去往敵國和親匈仗。 傳聞我的和親對象是個殘疾皇子瓢剿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容