mycat 概述


從開始接觸mycat,到現在為止也有三個多月的時間了,目前在測試環境中已經初步應用!大概可以總結一下了

mycat是一個數據庫中間件,也可以理解為是數據庫代理。在架構體系中是位於數據庫和應用層之間的一個組件,並且對於應用層是透明的,即數據庫感受不到mycat的存在,認為是直接連接的mysql數據庫(實際上是連接的mycat,mycat實現了mysql的原生協議)

mycat的三大功能:分表、讀寫分離、主從切換;mycat的主要功能也就是這三個了吧!??

1、分表

  對於數據量很大的表(千萬級以上),mysql性能會有很大下降,因此盡量控制在每張表的大小在百萬級別。對於數據量很大的一張表,可以考慮將這些記錄按照一定的規則放到不同的數據庫里面。這樣每個數據庫的數據量不是太大,性能也不會有太大損失。

  mycat自動會幫助我們實現分表功能,而對於應用層來說是透明的,即跟一張表沒有什么區別!

  mycat分表的實現:首先在mycat的scheme.xml中配置邏輯表,並且在配置中說明此表在哪幾個物理庫上。此邏輯表的名字與真實數據庫中的名字一致!然后需要配置分片規則,即按照什么邏輯分庫!分片規則有很多,選取以下幾個簡單說明:

  1、根據數據庫某字段的hash值片

  2、截取某字段的幾位數字,匹配分區號

  3、按照時間(年份分表)

  4、……

  分表的原則是盡量避免跨庫操作操作,跨庫操作會損失很多性能,mycat會對各個庫的結果集進行合並,另外就是要考慮擴展之后,盡量使最少量的數據遷移。

  分表規則很多,很靈活,並且在源碼基礎上修改分片規則也很容易!

  分表之后有什么弊端呢?

  使用存儲過程/函數就不太方便了,mycat本身不支持存儲過程,是通過注解的方式實現存儲過程的調用。並且在所有庫上都執行,將執行結果合並,並返回(mysql存儲過程返回結果最好使用select方式返回)。

  分表之后還有一個問題,就是自增ID的問題,在分庫場景下,如果使用mysql的自增主鍵,會導致各個庫中主鍵之間有重復。mycat使用內部的全局序列號解決這個問題;即插入數據的時候,mycat會自動的顯示的插入自增主鍵,使用的是全局序列號;

  需要在配置邏輯表的時候,配置上自增字段,自增屬性=true 這兩個屬性;

 <table name="fh_fullnote" primaryKey="FH_FULLNOTE_ID" autoIncrement="true" dataNode="dn1,dn2,dn3" rule="sharding-by-substring" />

  那么全局序列號存儲在什么地方呢?mycat是怎么去取的呢?

  全局序列號有兩種存儲方式:基於本地文件和基於數據庫的存儲;

  我們是采用基於數據庫的存儲方式,需要在數據庫中建立 mycat_sequence表

Create Table: CREATE TABLE `mycat_sequence` (
  `name` varchar(50) NOT NULL,
  `current_value` int(11) NOT NULL,
  `increment` int(11) NOT NULL DEFAULT '100',
  PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

  全局序列號就是存儲在這個表中;第一個是全局序列號的名,第二個是當前值,第三個是增量;即每次mycat會取出一批序列號(增量就是作用與此),用完之后再取;如果每次都取,在效率上會有損失。

  mycat取全局序列號是通過函數來取的,因此需要在數據庫上增加如下三個函數:

/******************************獲取函數當前值***********************************/

DELIMITER $$

USE `mycat1`$$

DROP FUNCTION IF EXISTS `mycat_seq_currval`$$

CREATE DEFINER=`root`@`%` FUNCTION `mycat_seq_currval`(seq_name VARCHAR(50)) RETURNS VARCHAR(64) CHARSET utf8
    DETERMINISTIC
BEGIN
    DECLARE retval VARCHAR(64);
    SET retval="-999999999,null";
        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 ;
/*******************************獲取下一批值***************************************/
DELIMITER $$

USE `mycat1`$$

DROP FUNCTION IF EXISTS `mycat_seq_nextval`$$

CREATE DEFINER=`root`@`%` FUNCTION `mycat_seq_nextval`(seq_name VARCHAR(50)) RETURNS VARCHAR(64) CHARSET utf8
BEGIN
    UPDATE MYCAT_SEQUENCE
    SET current_value = current_value + increment WHERE NAME = seq_name;
    RETURN mycat_seq_currval(seq_name);
    END$$

DELIMITER ;

/*******************************設定值***************************************/
DELIMITER $$

USE `mycat1`$$

DROP FUNCTION IF EXISTS `mycat_seq_setval`$$

CREATE DEFINER=`root`@`%` FUNCTION `mycat_seq_setval`(seq_name VARCHAR(50),VALUE INTEGER) RETURNS VARCHAR(64) CHARSET utf8
BEGIN
    UPDATE MYCAT_SEQUENCE
    SET current_value = VALUE
    WHERE NAME = seq_name;
    RETURN mycat_seq_currval(seq_name);
    END$$

DELIMITER ;

  一般來說,每一個表應該對應一個全局序列號;

  此對應關系在sequence_db_conf.properties配置;

  表名 = 全局序列號數據庫(dn1)

  2、讀寫分離

  經過統計發現,對數據庫的大量操作是讀操作,一般占到所有操作70%以上。所以做讀寫分離還是很有必要的,如果不做讀寫分離,那么從庫也是一種很大的浪費。

  mycat的讀寫分離也是在scheme.xml里面配置的。配置方式如下:

<writeHost host="hostM1" url="192.168.91.231:3306" user="root" password="123456">
      <!-- can have multi read hosts -->
      <readHost host="hostS2" url="192.168.91.232:3306" user="root" password="123456" />
</writeHost>

  值得注意的是,讀庫是附屬於寫庫的,如果寫庫掛掉之后,讀庫也就不能使用了。

  讀寫分離一般涉及到兩個問題:一個是讀操作的均衡,是全部走讀庫?還是部分走讀庫,部分讀寫庫?    另一個問題,如果同步不及時或者同步出錯,或者實時性要求較高,這種場景下,如何強制走寫庫?

  首先來看第一個問題,讀寫均衡問題:

  scheme.xml配置文件  dataHost標簽中有一個balance屬性,該屬性的不同值表示不同的含義:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM