基于 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)品表矿辽、放款表、還款表
為了適應(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)問題的時候,可以快速地排查和解決
這種多個子系統(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)就可以用不同的存儲方案
分庫其實是我們在解決系統(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ù)量帶來的性能問題
分庫分表會提升系統(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ù)不同菜秦,也有同庫的水平切分和多庫的切分
1、垂直切分
垂直分表有兩種舶掖,一種是單庫的球昨,一種是多庫的
1)單庫垂直分表
單庫分表,比如:商戶信息表眨攘,拆分成基本信息表主慰,聯(lián)系方式表嚣州,結(jié)算信息表,附件表等
2)多庫垂直分表
多庫垂直分表就是把原來存儲在一個庫的不同的表共螺,拆分到不同的數(shù)據(jù)庫
比如:消費金融核心系統(tǒng)數(shù)據(jù)庫该肴,有很多客戶相關(guān)的表,這些客戶相關(guān)的表藐不,全部單獨存放到客戶的數(shù)據(jù)庫里面匀哄,合同,放款雏蛮,風(fēng)控相關(guān)的業(yè)務(wù)表也是一樣的
當(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)是完全一樣的
一般我們說的分庫分表都是跨庫的分表
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ù)
c)柔性事物TCC(Try-Confirm-Cancel)tcc-transaction
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)
核心思想:
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ù)庫
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)核心概念
專有名詞解析:
主機/實例:物理主機担神,一臺服務(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 INTO
customer(
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ù)蜡励,大小凉倚,字符集稽寒,日志文件大小等