1. 程式人生 > >資料庫中介軟體MyCat

資料庫中介軟體MyCat

什麼是MyCat?

檢視官網的介紹是這樣說的

  • 一個徹底開源的,面向企業應用開發的大資料庫叢集
  • 支援事務、ACID、可以替代MySQL的加強版資料庫
  • 一個可以視為MySQL叢集的企業級資料庫,用來替代昂貴的Oracle叢集
  • 一個融合記憶體快取技術、NoSQL技術、HDFS大資料的新型SQL Server
  • 結合傳統資料庫和新型分散式資料倉庫的新一代企業級資料庫產品
  • 一個新穎的資料庫中介軟體產品

主要特性

  • 支援SQL92標準
  • 支援MySQL、Oracle、DB2、SQL Server、PostgreSQL等DB的常見SQL語法
  • 遵守Mysql原生協議,跨語言,跨平臺,跨資料庫的通用中介軟體代理。
  • 基於心跳的自動故障切換,支援讀寫分離,支援MySQL主從,以及galera cluster叢集。
  • 支援Galera for MySQL叢集,Percona Cluster或者MariaDB cluster
  • 基於Nio實現,有效管理執行緒,解決高併發問題。
  • 支援資料的多片自動路由與聚合,支援sum,count,max等常用的聚合函式,支援跨庫分頁。
  • 支援單庫內部任意join,支援跨庫2表join,甚至基於caltlet的多表join。
  • 支援通過全域性表,ER關係的分片策略,實現了高效的多表join查詢。
  • 支援多租戶方案。
  • 支援分散式事務(弱xa)。
  • 支援XA分散式事務(1.6.5)。
  • 支援全域性序列號,解決分散式下的主鍵生成問題。
  • 分片規則豐富,外掛化開發,易於擴充套件。
  • 強大的web,命令列監控。
  • 支援前端作為MySQL通用代理,後端JDBC方式支援Oracle、DB2、SQL Server 、 mongodb 、巨杉。
  • 支援密碼加密
  • 支援服務降級
  • 支援IP白名單
  • 支援SQL黑名單、sql注入攻擊攔截
  • 支援prepare預編譯指令(1.6)
  • 支援非堆記憶體(Direct Memory)聚合計算(1.6)
  • 支援PostgreSQL的native協議(1.6)
  • 支援mysql和oracle儲存過程,out引數、多結果集返回(1.6)
  • 支援zookeeper協調主從切換、zk序列、配置zk化(1.6)
  • 支援庫內分表(1.6)
  • 叢集基於ZooKeeper管理,線上升級,擴容,智慧優化,大資料處理(2.0開發版)

下載及安裝

到官網根據系統型別進行下載:http://mycat.io/

將下載檔案解壓,目錄如下:

各個目錄簡要說明:

bin:啟動目錄
catlet: 擴充套件功能
conf:配置檔案目錄
server.xml:是Mycat伺服器引數調整和使用者授權的配置檔案
schema.xml:是邏輯庫定義和表以及分片定義的配置檔案
rule.xml: 是分片規則的配置檔案,分片規則的具體一些引數資訊單獨存放為檔案,也在這個目錄下,配置檔案修改需要重啟MyCAT
log4j.xml: 日誌存放在logs/log中,每天一個檔案,日誌的配置是在conf/log4j.xml中,根據自己的需要可以調整輸出級別為debug,debug級別下,會輸出更多的資訊,方便排查問題
autopartition-long.txt,partition-hash-int.txt,sequence_conf.properties, sequence_db_conf.properties 分片相關的id分片規則配置檔案
lib:jar包目錄
logs :日誌目錄

進入bin目錄,通過管理員身份開啟DOS視窗,分別執行命令:

mycat install

mycat start

這樣就可以啟動mycat了。

核心配置

server.xml : 設定賬號、引數等

schema.xml : 物理資料庫和資料庫表的配置

rule.xml : 分片(分庫分表)規則

關於配置的詳細介紹可以參考 https://www.cnblogs.com/joylee/p/7513038.html 或者官網 http://www.mycat.io/document/mycat-definitive-guide.pdf

示例

首次認識mycat,最容易是從示例著手去了解,比如此次示例是結合mysql完成資料的分庫分表,進行橫向擴充套件。

首先需要準備幾個mysql的伺服器,通過docker構建,具體怎麼可以參考網上,大致步驟如下:

   1、下載mysql映象: docker pull mysql
   2、啟動容器:docker run -di -p 32768:3306 --name mysql1 -e MYSQL_ROOT_PASSWORD=123456 mysql ,輸入容器id
   3、通過容器id進入容器,docker exec -it <id> /bin/bash
   4、進入mysql:mysql -u root -p -> 123456
   5、新增遠端連線使用者與密碼:GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456';
   6、許可權:flush privileges;

如果不出意外則可以連線,因為我是通過本地虛擬機器安裝docker,預設埠192.168.99.100。現在根據下載的映象啟動3個容器,修改不同的埠。

通過客戶端工具分別連線以上三個資料庫,並且建表:

建立資料庫:TESTDB

建表:

CREATE TABLE `employee` (
  `id` int(11) NOT NULL,
  `name` varchar(56) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1、修改server.xml配置檔案

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

        <!-- 連線時用這個名字,比如 jdbc:mysql://localhost:8066/TESTDB -->
        <property name="schemas">TESTDB</property>
    </user>

2、修改schema.xml

    <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100">

        <table name="employee" primaryKey="ID" dataNode="dn1,dn2,dn3"  rule="mod-long" />

    </schema>
    <!-- name節點名,與上對應;dataHost:真實資料庫配置;database:資料庫表配置 -->
    <dataNode name="dn1" dataHost="host1" database="TESTDB" />
    <dataNode name="dn2" dataHost="host2" database="TESTDB" />
    <dataNode name="dn3" dataHost="host3" database="TESTDB" />

    <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select 1</heartbeat>
        <writeHost host="hostS1" url="192.168.99.100:32768" user="root" password="123456" />
    </dataHost>
    <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select 1</heartbeat>
        <writeHost host="hostS2" url="192.168.99.100:32769" user="root" password="123456" />
    </dataHost>
    <dataHost name="host3" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select 1</heartbeat>
        <writeHost host="hostS3" url="192.168.99.100:39770" user="root" password="123456" />
    </dataHost>

3、修改rule.xml

上面<table>配置了rule="mod-long",在rule.xml有相關的描述,修改下面引數,與上面dataNode數量對應

    <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
        <!-- how many data nodes -->
        <property name="count">3</property>
    </function>

這樣mycat的配置就完成了,由於修改了配置,我們將mycat重啟,進入bin,mycat restart。

測試

由於之前使用了mybatis-plus+springboot的專案,所有就用了這個:

application-mycat.properties:

mybatis-plus.mapper-locations=classpath*:com/sucl/sbmp/*/mapper/**Mapper.xml
mybatis-plus.type-aliases-package=com.sucl.sbmp.*.entity
mybatis-plus.global-config.refresh=true
#mybatis-plus.global-config.db-config.db-type=mysql
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.cache-enabled=false


mp.datasource.driver-class-name=com.mysql.jdbc.Driver
mp.datasource.url=jdbc:mysql://localhost:8066/TESTDB?useUnicode=true&useSSL=false&characterEncoding=utf8
mp.datasource.username=root
mp.datasource.password=123456
mp.datasource.validation-query=select '1'
mp.datasource.testOnBorrow=true

實體:

@Data
public class Employee {

    @TableId(type = IdType.INPUT)
    private long id;

    @TableField(value = "name")
    private String name;
}

mapper:

public interface EmployeeMapper extends BaseMapper<Employee> {

}

service:

@Service
@Transactional
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper,Employee> implements EmployeeService {

}

測試:

@ActiveProfiles("mycat")
@RunWith(SpringRunner.class)
@SpringBootTest
public class SbmpTest {
    @Autowired
    private EmployeeService employeeService;

    @Transactional
    @Rollback(false)
    @Test
    public void save(){
        List<Employee> employees = new ArrayList<>();
        for(int i=0;i<100;i++){
            Employee employee = new Employee();
            employee.setId(i);
            employee.setName("name"+i);
            employees.add(employee);
        }
        employeeService.saveBatch(employees);
    }

    @Test
    public void get(){
        List<Employee> employees = employeeService.list(null);
        employees.stream().forEach(System.out::println);
    }

}

分別執行兩個方法,會根據id在三個資料庫中分別插入資料:

查詢時則可以檢視三個表