[04][03][01] Mycat 基礎

為什么要分庫分表

數(shù)據(jù)庫性能瓶頸的出現(xiàn)

對于應用來說,如果數(shù)據(jù)庫性能出現(xiàn)問題,要么是無法獲取連接,是因為在高并發(fā)的情況下連接數(shù)不夠了.要么是操作數(shù)據(jù)變慢,數(shù)據(jù)庫處理數(shù)據(jù)的效率除了問題.要么是存儲出現(xiàn)問題,比如單機存儲的數(shù)據(jù)量太大了,存儲的問題也可能會導致性能的問題
歸根結底都是受到了硬件的限制,比如 CPU,內存,磁盤,網(wǎng)絡等等.但是我們優(yōu)化肯定不可能直接從擴展硬件入手,因為帶來的收益和成本投入比例太比
所以我們先來分析一下,當我們處理數(shù)據(jù)出現(xiàn)無法連接,或者變慢的問題的時候,我們可以從哪些層面入手

數(shù)據(jù)庫優(yōu)化方案對比

數(shù)據(jù)庫優(yōu)化有很多層面

SQL 與索引

因為 SQL 語句是在我們的應用端編寫的,所以第一步,我們可以在程序中對 SQL 語句進行優(yōu)化,最終的目標是用到索引.這個是容易的也是最常用的優(yōu)化手段

表與存儲引擎

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

架構

第三步,對于數(shù)據(jù)庫的服務,我們可以對它的架構進行優(yōu)化
如果只有一臺數(shù)據(jù)庫的服務器,我們可以運行多個實例,做集群的方案,做負載均衡
或者基于主從復制實現(xiàn)讀寫分離,讓寫的服務都訪問 master 服務器,讀的請求都訪問從服務器,slave 服務器自動 master 主服務器同步數(shù)據(jù)
或者在數(shù)據(jù)庫前面加一層緩存,達到減少數(shù)據(jù)庫的壓力,提升訪問速度的目的
為了分散數(shù)據(jù)庫服務的存儲壓力和訪問壓力,我們也可以把不同的數(shù)據(jù)分布到不同的服務節(jié)點,這個就是分庫分表(scaleout)

注意主從(replicate)和分片(shard)的區(qū)別:

  • 主從通過數(shù)據(jù)冗余實現(xiàn)高可用,和實現(xiàn)讀寫分離
  • 分片通過拆分數(shù)據(jù)分散存儲和訪問壓力

配置

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

操作系統(tǒng)與硬件

最后一步操作系統(tǒng)和硬件的優(yōu)化
從上往下,成本收益比慢慢地在增加.所以肯定不是查詢一慢就堆硬件,堆硬件叫做向上的擴展(scaleup)

什么時候才需要分庫分表呢?我們的評判標準是什么?
如果是數(shù)據(jù)量的話,一張表存儲了多少數(shù)據(jù)的時候,才需要考慮分庫分表?
如果是數(shù)據(jù)增長速度的話,每天產(chǎn)生多少數(shù)據(jù),才需要考慮做分庫分表?
如果是應用的訪問情況的話,查詢超過了多少時間,有多少請求無法獲取連接,才需要分庫分表?這是一個值得思考的問題

架構演進與分庫分表

單應用單數(shù)據(jù)庫

2013 年的時候,我們公司采購了一個消費金融核心系統(tǒng),這個是一個典型的單體架構的應用.同學們應該也很熟悉,單體架構應用的特點就是所有的代碼都在一個工程里面,打成一個 war 包部署到 tomcat,最后運行在一個進程中
這套消費金融的核心系統(tǒng),用的是 Oracle 的數(shù)據(jù)庫,初始化以后有幾百張表,比如客戶信息表,賬戶表,商戶表,產(chǎn)品表,放款表,還款表等等


為了適應業(yè)務的發(fā)展,我們這一套系統(tǒng)不停地在修改,代碼量越來越大,系統(tǒng)變得越來越臃腫.為了優(yōu)化系統(tǒng),我們搭集群,負載均衡,加緩存,優(yōu)化數(shù)據(jù)庫,優(yōu)化業(yè)務代碼系統(tǒ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ù)庫

多應用單數(shù)據(jù)庫

對代碼進行了解耦,職責進行了拆分,生產(chǎn)環(huán)境出現(xiàn)問題的時候,可以快速地排查和解決


這種多個子系統(tǒng)共用一個 DB 的架構,會出現(xiàn)一些問題
第一個就是所有的業(yè)務系統(tǒng)都共用一個 DB,無論是從性能還是存儲的角度來說,都是滿足不了需求的.隨著我們的業(yè)務繼續(xù)膨脹,我們又會增加更多的系統(tǒng)來訪問核心數(shù)據(jù)庫,但是一個物理數(shù)據(jù)庫能夠支撐的并發(fā)量是有限的,所有的業(yè)務系統(tǒng)之間還會產(chǎn)生競爭,最終會導致應用的性能下降,甚至拖垮業(yè)務系統(tǒng)

多應用獨立數(shù)據(jù)庫

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


所以,分庫其實是我們在解決系統(tǒng)性能問題的過程中,對系統(tǒng)進行拆分的時候帶來的一個必然的結果.現(xiàn)在的微服務架構也是一樣的,只拆應用不拆分數(shù)據(jù)庫,不能解決根本的問題

什么時候分表?

當我們對原來一個數(shù)據(jù)庫的表做了分庫以后,其中一些表的數(shù)據(jù)還在以一個非常快的速度在增長,這個時候查詢也已經(jīng)出現(xiàn)了非常明顯的效率下降
所以,在分庫之后,還需要進一步進行分表.當然,我們最開始想到的可能是在一個數(shù)據(jù)庫里面拆分數(shù)據(jù),分區(qū)或者分表,到后面才是切分到多個數(shù)據(jù)庫中
分表主要是為了減少單張表的大小,解決單表數(shù)據(jù)量帶來的性能問題


我們需要清楚的是,分庫分表會提升系統(tǒng)的復雜度,如果在近期或者未來一段時間內必須要解決存儲和性能的問題,就不要去做超前設計和過度設計.就像我們搭建項目,從快速實現(xiàn)的角度來說,肯定是從單體項目起步的,在業(yè)務豐富完善之前,也用不到微服務架構
如果我們創(chuàng)建的表結構合理,字段不是太多,并且索引創(chuàng)建正確的情況下,單張表存儲幾千萬的數(shù)據(jù)是完全沒有問題的,這個還是以應用的實際情況為準.當然我們也會對未來一段時間的業(yè)務發(fā)展做一個預判

分庫分表的類型和特點

從維度來說分成兩種,一種是垂直,一種是水平
垂直切分:基于表或字段劃分,表結構不同.我們有單庫的分表,也有多庫的分庫
水平切分:基于數(shù)據(jù)劃分,表結構相同,數(shù)據(jù)不同,也有同庫的水平切分和多庫的切分


垂直切分

垂直分表有兩種,一種是單庫的,一種是多庫的

單庫垂直分表

單庫分表,比如:商戶信息表,拆分成基本信息表,聯(lián)系方式表,結算信息表,附件表等等

多庫垂直分表

多庫垂直分表就是把原來存儲在一個庫的不同的表,拆分到不同的數(shù)據(jù)庫
比如:消費金融核心系統(tǒng)數(shù)據(jù)庫,有很多客戶相關的表,這些客戶相關的表,全部單獨存放到客戶的數(shù)據(jù)庫里面.合同,放款,風控相關的業(yè)務表也是一樣的



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

水平切分

當我們的客戶表數(shù)量已經(jīng)到達數(shù)千萬甚至上億的時候,單表的存儲容量和查詢效率都會出現(xiàn)問題,我們需要進一步對單張表的數(shù)據(jù)進行水平切分.水平切分的每個數(shù)據(jù)庫的表結構都是一樣的,只是存儲的數(shù)據(jù)不一樣,比如每個庫存儲1000萬的數(shù)據(jù)
水平切分也可以分成兩種,一種是單庫的,一種是多庫的

單庫水平分表

銀行的交易流水表,所有進出的交易都需要登記這張表,因為絕大部分時候客戶都是查詢當天的交易和一個月以內的交易數(shù)據(jù),所以我們根據(jù)使用頻率把這張表拆分成三張表:
當天表:只存儲當天的數(shù)據(jù)
當月表:在夜間運行一個定時任務,前一天的數(shù)據(jù),全部遷移到當月表.用的是 insertintoselect,然后 delete
歷史表:同樣是通過定時任務,把登記時間超過 30 天的數(shù)據(jù),遷移到 history 歷史表(歷史表的數(shù)據(jù)非常大,我們按照月度,每個月建立分區(qū))

費用表:
消費金融公司跟線下商戶合作,給客戶辦理了貸款以后,消費金融公司要給商戶返費用,或者叫提成,每天都會產(chǎn)生很多的費用的數(shù)據(jù).為了方便管理,我們每個月建立一張費用表,例如 fee_detail_201901……fee_detail_201912
但是注意,跟分區(qū)一樣,這種方式雖然可以一定程度解決單表查詢性能的問題,但是并不能解決單機存儲瓶頸的問題

多庫水平分表

另一種是多庫的水平分表.比如客戶表,我們拆分到多個庫存儲,表結構是完全一樣的


一般我們說的分庫分表都是跨庫的分表
既然分庫分表能夠幫助我們解決性能的問題,那我們是不是馬上動手去做,甚至在項目設計的時候就先給它分幾個庫呢?先冷靜一下,我們來看一下分庫分表會帶來哪些問題,也就是我們前面說的分庫分表之后帶來的復雜性

多案分庫分表帶來的問題

跨庫關聯(lián)查詢

比如查詢在合同信息的時候要關聯(lián)客戶數(shù)據(jù),由于是合同數(shù)據(jù)和客戶數(shù)據(jù)是在不同的數(shù)據(jù)庫,那么我們肯定不能直接使用 join 的這種方式去做關聯(lián)查詢
我們有幾種主要的解決方案:

  • 字段冗余:比如我們查詢合同庫的合同表的時候需要關聯(lián)客戶庫的客戶表,我們可以直接把一些經(jīng)常關聯(lián)查詢的客戶字段放到合同表,通過這種方式避免跨庫關聯(lián)查詢的問題
  • 數(shù)據(jù)同步:比如商戶系統(tǒng)要查詢產(chǎn)品系統(tǒng)的產(chǎn)品表,我們干脆在商戶系統(tǒng)創(chuàng)建一張產(chǎn)品表,通過 ETL 或者其他方式定時同步產(chǎn)品數(shù)據(jù)
  • 全局表(廣播表):比如行名行號信息被很多業(yè)務系統(tǒng)用到,如果我們放在核心系統(tǒng),每個系統(tǒng)都要去關聯(lián)查詢,這個時候我們可以在所有的數(shù)據(jù)庫都存儲相同的基礎數(shù)據(jù)
  • ER 表(綁定表)
    我們有些表的數(shù)據(jù)是存在邏輯的主外鍵關系的,比如訂單表 order_info,存的是匯總的商品數(shù),商品金額;訂單明細表 order_detail,是每個商品的價格,個數(shù)等等.或者叫做從屬關系,父表和子表的關系.他們之間會經(jīng)常有關聯(lián)查詢的操作,如果父表的數(shù)據(jù)和子表的數(shù)據(jù)分別存儲在不同的數(shù)據(jù)庫,跨庫關聯(lián)查詢也比較麻煩.所以我們能不能把父表和數(shù)據(jù)和從屬于父表的數(shù)據(jù)落到一個節(jié)點上呢?
    比如 order_id=1001 的數(shù)據(jù)在 node1,它所有的明細數(shù)據(jù)也放到 node1;order_id=1002 的數(shù)據(jù)在 node2,它所有的明細數(shù)據(jù)都放到 node2,這樣在關聯(lián)查詢的時候依然是在一個數(shù)據(jù)庫
    上面的思路都是通過合理的數(shù)據(jù)分布避免跨庫關聯(lián)查詢,實際上在我們的業(yè)務中,也是盡量不要用跨庫關聯(lián)查詢,如果出現(xiàn)了這種情況,就要分析一下業(yè)務或者數(shù)據(jù)拆分是不是合理.如果還是出現(xiàn)了需要跨庫關聯(lián)的情況,那我們就只能用最后一種辦法
  • 系統(tǒng)層組裝:在不同的數(shù)據(jù)庫節(jié)點把符合條件數(shù)據(jù)的數(shù)據(jù)查詢出來,然后重新組裝,返回給客戶端

分布式事務

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

復習一下.分布式系統(tǒng)的基礎是 CAP 理論

  • C(一致性)Consistency:對某個指定的客戶端來說,讀操作能返回最新的寫操作.對于數(shù)據(jù)分布在不同節(jié)點上的數(shù)據(jù)來說,如果在某個節(jié)點更新了數(shù)據(jù),那么在其他節(jié)點如果都能讀取到這個最新的數(shù)據(jù),那么就稱為強一致,如果有某個節(jié)點沒有讀取到,那就是分布式不一致
  • A(可用性)Availability:非故障的節(jié)點在合理的時間內返回合理的響應(不是錯誤和超時的響應).可用性的兩個關鍵一個是合理的時間,一個是合理的響應.合理的時間指的是請求不能無限被阻塞,應該在合理的時間給出返回.合理的響應指的是系統(tǒng)應該明確返回結果并且結果是正確的
  • P(分區(qū)容錯性)Partitiontolerance:當出現(xiàn)網(wǎng)絡分區(qū)后,系統(tǒng)能夠繼續(xù)工作.打個比方,這里集群有多臺機器,有臺機器網(wǎng)絡出現(xiàn)了問題,但是這個集群仍然可以正工作

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

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

分布式事務有幾種常見的解決方案:

  • 全局事務(比如 XA 兩階段提交;應用,事務管理器(TM),資源管理器(DB)),例如 Atomikos

  • 基于可靠消息服務的分布式事務


  • 柔性事務 TCC(Try-Confirm-Cancel)tcc-transaction


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

排序,翻頁,函數(shù)計算問題

跨節(jié)點多庫進行查詢時,會出現(xiàn) limit 分頁,orderby 排序的問題.比如有兩個節(jié)點,節(jié)點 1 存的是奇數(shù) id=1,3,5,7,9……;節(jié)點 2 存的是偶數(shù) id=2,4,6,8,10……
執(zhí)行 select*fromuser_infoorderbyidlimit0,10
需要在兩個節(jié)點上各取出10條,然后合并數(shù)據(jù),重新排序
max,min,sum,count 之類的函數(shù)在進行計算的時候,也需要先在每個分片上執(zhí)行相應的函數(shù),然后將各個分片的結果集進行匯總和再次計算,最終將結果返回

全局主鍵避重問題

MySQL 的數(shù)據(jù)庫里面字段有一個自增的屬性,Oracle 也有 Sequence 序列.如果是一個數(shù)據(jù)庫,那么可以保證 ID 是不重復的,但是水平分表以后,每個表都按照自己的規(guī)律自增,肯定會出現(xiàn) ID 重復的問題,這個時候我們就不能用本地自增的方式了
我們有幾種常見的解決方案:

UUID(Universally Unique Identifier 通用唯一識別碼)

UUID 標準形式包含 32 個 16 進制數(shù)字,分為 5 段,形式為 8-4-4-4-12 的 36 個字符,例如:c4e7956c-03e7-472c-8909-d733803e79a9

Name Length(Bytes) Length(HexDigits) Contents
time_low 4 8 integergivingthelow32bitsofthetime
time_mid 2 4 integergivingthemiddle16bitsofthetime
time_hi_and_version 2 4 4-bit"version"inthemostsignificantbits,followedbythehigh12bitsofthetime
clock_seq_hi_and_resclock_seq_low 2 4 1-3bit"variant"inthemostsignificantbits,followedbythe13-15bitclocksequence
node 6 12 the48-bitnodeid

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

  • 基于時間和 MAC 地址的 UUID
  • 基于第一版卻更安全的 DCEUUID
  • 基于 MD5 散列算法的 UUID
  • 基于隨機數(shù)的 UUID——用的最多,JDK 里面是 4
  • 基于 SHA1 散列算法的 UUID

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

數(shù)據(jù)庫

把序號維護在數(shù)據(jù)庫的一張表中.這張表記錄了全局主鍵的類型,位數(shù),起始值,當前值.當其他應用需要獲得全局 ID 時,先 forupdate 鎖行,取到值+1 后并且更新后返回.并發(fā)性比較差

Redis

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

雪花算法 Snowflake(64bit)

核心思想:

  • 使用 41bit 作為毫秒數(shù),可以使用 69 年
  • 10bit 作為機器的 ID(5bit 是數(shù)據(jù)中心,5bit 的機器 ID),支持 1024 個節(jié)點
  • 12bit 作為毫秒內的流水號(每個節(jié)點在每毫秒可以產(chǎn)生 4096 個 ID)
  • 最后還有一個符號位,永遠是0

代碼:snowflake.SnowFlakeTest

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

不足就在于:強依賴機器時鐘,如果時鐘回撥,則可能導致生成 ID 重復

當我們對數(shù)據(jù)做了切分,分布在不同的節(jié)點上存儲的時候,是不是意味著會產(chǎn)生多個數(shù)據(jù)源?既然有了多個數(shù)據(jù)源,那么在我們的項目里面就要配置多個數(shù)據(jù)源
現(xiàn)在問題就來了,我們在執(zhí)行一條 SQL 語句的時候,比如插入,它應該是在哪個數(shù)據(jù)節(jié)點上面執(zhí)行呢?又比如查詢,如果只在其中的一個節(jié)點上面,我怎么知道在哪個節(jié)點,是不是要在所有的數(shù)據(jù)庫節(jié)點里面都查詢一遍,才能拿到結果?
那么,從客戶端到服務端,我們可以在哪些層面解決這些問題呢?

多數(shù)據(jù)源/讀寫數(shù)據(jù)源的解決方案

我們先要分析一下 SQL 執(zhí)行經(jīng)過的流程
DAO——Mapper(ORM)——JDBC——代理——數(shù)據(jù)庫服務

客戶端 DAO 層

第一個就是在我們的客戶端的代碼,比如 DAO 層,在我們連接到某一個數(shù)據(jù)源之前,我們先根據(jù)配置的分片規(guī)則,判斷需要連接到哪些節(jié)點,再建立連接
Spring 中提供了一個抽象類 AbstractRoutingDataSource,可以實現(xiàn)數(shù)據(jù)源的動態(tài)切換

SSM 工程:spring-boot-dynamic-data-source-master
步驟:

  • aplication.properties 定義多個數(shù)據(jù)源
  • 創(chuàng)建@TargetDataSource 注解
  • 創(chuàng)建 DynamicDataSource 繼承 AbstractRoutingDataSource
  • 多數(shù)據(jù)源配置類 DynamicDataSourceConfig
  • 創(chuàng)建切面類 DataSourceAspect,對添加了@TargetDataSource 注解的類進行攔截設置數(shù)據(jù)源
  • 在啟動類上自動裝配數(shù)據(jù)源配置@Import({DynamicDataSourceConfig.class})
  • 在實現(xiàn)類上加上注解,如@TargetDataSource(name=DataSourceNames.SECOND),調用

在 DAO 層實現(xiàn)的優(yōu)勢:不需要依賴 ORM 框架,即使替換了 ORM 框架也不受影響.實現(xiàn)簡單(不需要解析 SQL 和路由規(guī)則),可以靈活地定制
缺點:不能復用,不能跨語言

ORM 框架層

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

驅動層

不管是 MyBatis 還是 Hibernate,還是 Spring 的 JdbcTemplate,本質上都是對 JDBC 的封裝,所以第三層就是驅動層.比如 Sharding-JDBC,就是對 JDBC 的對象進行了封裝.JDBC 的核心對象:
DataSource:數(shù)據(jù)源
Connection:數(shù)據(jù)庫連接
Statement:語句對象
ResultSet:結果集

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

代理層

前面三種都是在客戶端實現(xiàn)的,也就是說不同的項目都要做同樣的改動,不同的編程語言也有不同的實現(xiàn),所以我們能不能把這種選擇數(shù)據(jù)源和實現(xiàn)路由的邏輯提取出來,做成一個公共的服務給所有的客戶端使用呢?
這個就是第四層,代理層.比如 Mycat 和 Sharding-Proxy,都是屬于這一層

數(shù)據(jù)庫服務

最后一層就是在數(shù)據(jù)庫服務上實現(xiàn),也就是服務層,某些特定的數(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

Mycat 介紹與核心概念

基本介紹

歷史:從阿里 cobar 升級而來,由開源組織維護,2.0 正在開發(fā)中
定位:運行在應用和數(shù)據(jù)庫之間,可以當做一個 MySQL 服務器使用,實現(xiàn)對 MySQL 數(shù)據(jù)庫的分庫分表,也可以通過 JDBC 支持其他的數(shù)據(jù)庫


Mycat 的關鍵特性(官網(wǎng)首頁)

  • 可以當做一個 MySQL 數(shù)據(jù)庫來使用
  • 支持 MySQL 之外的數(shù)據(jù)庫,通過 JDBC 實現(xiàn)
  • 解決了我們提到的所有問題,多表 join,分布式事務,全局序列號,翻頁排序
  • 支持 ZK 配置,帶監(jiān)控 mycat-web
  • 2.0正在開發(fā)中

核心概念

概念 含義
主機 物理主機,一臺服務器,一個數(shù)據(jù)庫服務,一個3306端口
物理數(shù)據(jù)庫真實的數(shù)據(jù)庫,例如 146,150,151 的 gpcat 數(shù)據(jù)庫
物理表 真實的表,例如 146,150,151 的 gpcat 數(shù)據(jù)庫的 order_info 表
分片 將原來單個數(shù)據(jù)庫的數(shù)據(jù)切分后分散存儲在不同的數(shù)據(jù)庫節(jié)點
分片節(jié)點分片以后數(shù)據(jù)存儲的節(jié)點
分片鍵 分片依據(jù)的字段,例如 order_info 表以 id 為依據(jù)分片,id 就是分片鍵,通常是主鍵
分片算法 分片的規(guī)則,例如隨機,取模,范圍,哈希,枚舉以及各種組合算法
邏輯表 相對于物理表,是分片表聚合后的結果,對于客戶端來說跟真實的表沒有區(qū)別
邏輯數(shù)據(jù)庫 相對于物理數(shù)據(jù)庫,是數(shù)據(jù)節(jié)點聚合后的結果,例如 catmall

下載,解壓 Mycat(有 Windows 版本,可以在本地數(shù)據(jù)庫測試)
http://dl.mycat.io/

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

Mycat 解壓以后有 5 個目錄:

目錄 作用
bin 啟動目錄
catlet 空目錄
conf 配置目錄
libjar 包依賴
logs 日志目錄

Mycat 配置詳解

主要的配置文件 server.xml,schema.xml,rule.xml 和具體的分片配置文件
坑非常多,配置錯誤會導致無法啟動,這個時候要看日志!
注意備份,不知道什么時候就跑不起來了……

server.xml

包含系統(tǒng)配置信息
system 標簽:例如字符集,線程數(shù),心跳,分布式事務開關等等
user 標簽:配置登錄用戶和權限

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

mycat 對密碼加密:

java -cp Mycat-server-1.6.7.3-release.jar io.mycat.util.DecryptUtil 0:root:123456

schema.xml

https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_schema
schema 在 MySQL 里面跟數(shù)據(jù)庫是等價的
schema.xml 包括邏輯庫,表,分片規(guī)則,分片節(jié)點和數(shù)據(jù)源,可以定義多個 schema
這里面有三個主要的標簽(table,dataNode,dataHost):

<table/>

表名和庫名最好都用小寫
定義了邏輯表,以及邏輯表分布的節(jié)點和分片規(guī)則:

<schema name="catmall" 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>
配置 作用
primaryKey 指定該邏輯表對應真實表的主鍵.MyCat 會緩存主鍵(通過 primaryKey 屬性配置)與具體 dataNode 的信息當分片規(guī)則(rule)使用非主鍵進行分片時,那么在使用主鍵進行查詢時,MyCat 就會通過緩存先確定記錄在哪個 dataNode 上,然后再在該 dataNode 上執(zhí)行查詢.如果沒有緩存/緩存并沒有命中的話,還是會發(fā)送語句給所有的 dataNode
dataNode 數(shù)據(jù)分片的節(jié)點
autoIncrement 自增長(全局序列),true 代表主鍵使用自增長策略
type 全局表:global.其他:不配置

<dataNode/>

<dataNode name="dn1" dataHost="host1" database="gpcat" />

數(shù)據(jù)節(jié)點與物理數(shù)據(jù)庫的對應關系

<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>

balance:負載的配置,決定 select 語句的負載

作用
0 不開啟讀寫分離機制,所有讀操作都發(fā)送到當前可用的 writeHost 上
1 所有讀操作都隨機發(fā)送到當前的 writeHost 對應的 readHost 和備用的 writeHost
2 所有的讀操作都隨機發(fā)送到所有的 writeHost,readHost 上
3 所有的讀操作都只發(fā)送到 writeHost 的 readHost 上

writeType:讀寫分離的配置,決定 update,delete,insert 語句的負載

作用
0 所有寫操作都發(fā)送到可用的 writeHost 上(默認第一個,第一個掛了以后發(fā)到第二個)
1 所有寫操作都隨機的發(fā)送到 writeHost

switchType:主從切換配置

作用
-1 表示不自動切換
1 默認值,表示自動切換
2 基于 MySQL 主從同步的狀態(tài)決定是否切換,心跳語句為 showslavestatus
3 基于 MySQLgalarycluster 的切換機制(適合集群)(1.4.1),心跳語句為 showstatuslike'wsrep%'

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

ZK 配置

https://www.cnblogs.com/leeSmall/p/9551038.html

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

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

cd /usr/local/soft/mycat/bin
./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í)行上傳


啟動停止

進入 mycat/bin 目錄(注意要先啟動物理數(shù)據(jù)庫):

操作 命令
啟動 ./mycatstart
停止 ./mycatstop
重啟 ./mycatrestart
查看狀態(tài) ./mycatstatus
前臺運行 ./mycatconsole

連接:

mysql -uroot -p123456 -h 192.168.8.151 -P8066 catmall

Mycat 分片驗證

explain 可以用來看路由結果
在三個數(shù)據(jù)庫中建表

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="gpcat"/>
<dataNode name="dn2" dataHost="host2" database="gpcat"/>
<dataNode name="dn3" dataHost="host3" database="gpcat"/>

<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——分片配置

范圍分片

<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

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, '吳先生');

取模分片(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);

全局表

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');

Mycat 全局 ID

Mycat 全局序列實現(xiàn)方式主要有 4 種:本地文件方式,數(shù)據(jù)庫方式,本地時間戳算法,ZK.也可以自定義業(yè)務序列
注意獲取全局 ID 的前綴都是:MYCATSEQ_

文件方式

配置文件 server.xmlsequnceHandlerType 值:0 文件 1 數(shù)據(jù)庫 2 本地時間戳 3ZK

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

文件方式,配置 conf/sequence_conf.properties

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

語法:selectnextvalueforMYCATSEQ_CUSTOMER

INSERT INTO `customer` (`id`, `name`)VALUES (next value for MYCATSEQ_CUSTOMER, 'qingshan');

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

數(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)建存儲過程——獲取當前 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)建存儲過程,設置 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 ;

插入記錄

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

本地時間戳方式

ID=64 位二進制(42(毫秒)+5(機器 ID)+5(業(yè)務編碼)+12(重復累加),長度為 18 位

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

配置文件 sequence_time_conf.properties

#sequence depend on TIME
WORKID=01
DATAACENTERID=01

驗證:selectnextvalueforMYCATSEQ_GLOBAL


ZK 方式

修改 conf/myid.properties
設置 loadZk=true(啟動時會從 ZK 加載配置,一定要注意備份配置文件,并且先用 bin/init_zk_data.sh,把配置文件寫入到 ZK)

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

配置文件:sequence_distributed_conf.properties

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

復制配置文件

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

驗證:selectnextvalueforMYCATSEQ_GLOBAL


使用

在 schema.xml 的 table 標簽上配置 autoIncrement="true",不需要獲取和指定序列的情況下,就可以使用全局 ID 了

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

監(jiān)控

命令行監(jiān)控

連接到管理端口 9066,注意必須要帶 IP

mysql -uroot -h127.0.0.1 -p123456 -P9066

全部命令:

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

命令行監(jiān)控 mycatweb 監(jiān)控

https://github.com/MyCATApache/Mycat-download/tree/master/mycat-web-1.0
Mycat-eye 是 mycat 提供的一個監(jiān)控工具,它依賴于 ZK
本地必須要運行一個 ZK,必須先啟動 ZK
參考:https://gper.club/articles/7e7e7f7ff7g59gc3g64

下載 mycat-web

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 &

停止:killstart.jar 相關的進程
訪問端口8082
http://192.168.8.151:8082/mycat/

mycatserver.xml 配置

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

重啟 mycat 服務生效

日志

log4j 的 level 配置要改成 debug

wrapper.log 日志

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

mycat.log 日志

mycat.log 為 mycat 主要日志文件,記錄了啟動時分配的相關 buffer 信息,數(shù)據(jù)源連接信息,連接池,動態(tài)類加載信息等等
在 conf/log4j2.xml 文件中進行相關配置,如保留個數(shù),大小,字符集,日志文件大小等

以 select 為例


?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 一、Mycat簡介 1.1 什么是Mycat Mycat是目前最流行的基于Java語言編寫的數(shù)據(jù)庫中間件,是一個實...
    AC編程閱讀 2,222評論 0 11
  • 基于 Mycat 1.6.7.3 版本 為什么要分庫分表 1、數(shù)據(jù)庫性能瓶頸的出現(xiàn)1)對于應用來說,如果數(shù)據(jù)庫性能...
    vincent浩哥閱讀 1,059評論 0 0
  • MySQL 主從復制 主從復制的含義 在 MySQL 多服務器的架構中,至少要有一個主節(jié)點(master),跟主節(jié)...
    悠娜的奶爸閱讀 260評論 0 1
  • 文章共 1796字,閱讀大約需要 4分鐘 ! 概 述 在如今海量數(shù)據(jù)充斥的互聯(lián)網(wǎng)環(huán)境下,分庫分表的意義我想在此處就...
    CodeSheep閱讀 2,005評論 0 63
  • MYCAT的主要作用: 1. MYCAT是實現(xiàn)了MySQL通信協(xié)議的一個分布式數(shù)據(jù)庫系統(tǒng)中間層。 數(shù)據(jù)庫中間層的作...
    呆叔么么閱讀 242評論 0 0

友情鏈接更多精彩內容