天天看點

Mycat(實踐篇 - 基于PostgreSQL的水準切分、主從複制、讀寫分離)

寫在前面

  Mycat作為獨立的資料庫中間件,我們隻需要進行相關的配置,就可以非常友善的幫我們實作水準切分、垂直切分、讀寫分離等功能,但PostgreSQL的主從複制需要我們通過其它方式實作。這裡假設我們已經搭建好相關的環境,下面就開始我們的實踐吧!

準備環境

  • PostgreSQL(Version : 10.1)主從環境搭建
  • 對應資料庫建立(以下例子中使用的都是預設存在的postgres資料庫,可以不用額外添加)

配置server.xml

<user name="postgresmycat">
                <property name="password">postgresmycat</property>
                <property name="schemas">postgresmycats</property>
        </user>
           

配置schema.xml

<schema name="postgresmycats" checkSQLschema="false" sqlMaxLimit="100">
                <table name="tb_user" dataNode="mydn3,mydn4" rule="user-mod-long" />
                <table name="tb_student" dataNode="mydn3,mydn4" rule="student-mod-long" />
        </schema>

        <dataNode name="mydn3" dataHost="myhost3" database="postgres" />
        <dataNode name="mydn4" dataHost="myhost4" database="postgres" />

        <!-- 這裡的dbDriver使用jdbc的方式來連接配接,用native方式似乎目前還不太相容,試過了好像不可以 -->
        <dataHost name="myhost3" maxCon="100" minCon="10" balance="3" writeType="0" dbType="postgresql" dbDriver="jdbc">
                <heartbeat>select user</heartbeat><!-- 注意這裡的心跳檢測指令跟mysql的有點不同 -->
                <writeHost host="hostM3" url="jdbc:postgresql://localhost:5432/postgres" user="postgres" password="xxx">
                        <readHost host="hostS3" url="jdbc:postgresql://localhost:5433/postgres" user="postgres" password="xxx"/>
                </writeHost>
        </dataHost>

        <dataHost name="myhost4" maxCon="100" minCon="10" balance="3" writeType="0" dbType="postgresql" dbDriver="jdbc">
                <heartbeat>select user</heartbeat>
                <writeHost host="hostM4" url="jdbc:postgresql://localhost:5434/postgres" user="postgres" password="xxx" >
                        <readHost host="hostS4" url="jdbc:postgresql://localhost:5435/postgres" user="postgres" password="xxx"/>
                </writeHost>
        </dataHost>
           

dbDriver 屬性

  指定連接配接後端資料庫使用的 Driver,目前可選的值有 native 和 jdbc。使用 native 的話,因為這個值執行的

是二進制的 mysql 協定,是以可以使用 mysql 和 maridb。其他類型的資料庫則需要使用 JDBC 驅動來支援

引述《Mycat權威指南》裡面的原話:

從 1.6 版本開始支援 postgresql 的 native 原始協定。

如果使用 JDBC 的話需要将符合 JDBC4 标準的驅動 JAR 包放到 MYCAT\lib 目錄下,并檢查驅動 JAR 包中

包括如下目錄結構的檔案:META-INF\services\java.sql.Driver。在這個檔案内寫上具體的 Driver 類名,例如:

com.mysql.jdbc.Driver。

  是以,具體的解決方案就是找一個postgresql的jar包,然後丢到mycat的lib目錄下,不然就會出現啟動失敗或者連接配接不到postgre資料庫的異常情況。本例中用到的jar包是:

postgresql-42.1.4.jar

配置rule.xml

<tableRule name="user-mod-long">
                <rule>
                        <columns>id</columns>
                        <algorithm>mod-long</algorithm>
                </rule>
        </tableRule>
       <tableRule name="student-mod-long">
                <rule>
                        <columns>user_id</columns>
                        <algorithm>mod-long</algorithm>
                </rule>
        </tableRule>

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

  修改了配置檔案後,别忘了重新開機Mycat,如果有異常出現,請通過檢視logs目錄下的日志檔案進行排查。

項目搭建(SpringBoot + JPA)

  • 準備:首次建表,設定application.yml中的spring.jpa.hibernate.ddl-auto屬性為:create(JPA自動建表解決方案,使用update的話在連接配接mycat的時候會報找不到表的錯誤)。之後似乎必須更改為:none,否則使用其它屬性都會報錯(這裡Mysql與PostgreSQL不同,似乎是一個未解決的bug,這也就意味着以後新增字段都要手動連上資料庫進行添加了...)
  • 添加application.yml(注意了,這裡都是用連mysql的方式去配置,Mycat會在後端做好對其它資料庫的連接配接):
spring:
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update
      naming:
        strategy: org.hibernate.cfg.ImprovedNamingStrategy
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL5Dialect
  datasource:
    url: jdbc:mysql://localhost:8066/postgresmycats?characterEncoding=UTF-8&useSSL=false&autoReconnect=true&rewriteBatchedStatements=true
    username: postgresmycat
    password: postgresmycat
           
  • 添加User Entity
@Entity
@Table(name = "tb_user")
@Data
public class User {

    @Id
    private Long id;

    private String name;

    private Integer gender;

}
           
  • 添加Student Entity
@Entity
@Table(name = "tb_student")
@Data
public class Student {

    @Id
    private Long id;

    private String name;

    @Column(unique = true)
    private Long userId;

}
           
  • 添加UserDao
public interface UserDao extends JpaRepository<User, Long> {

    Page<User> findByNameLike(String name, Pageable pageable);

}
           
  • 添加StudentDao
public interface StudentDao extends JpaRepository<Student, Long> {

    Page<User> findByNameLike(String name, Pageable pageable);

}
           

項目測試

  1. 測試添加
@Test
public void testAdd() {
        for (long i = 0; i < 30; i++) {
            User user = new User();
            user.setId(i);
            user.setName("李四" + i);
            user.setGender(i % 2 == 0 ? 1 : 0);
            userDao.save(user);

            Student student = new Student();
            student.setId(System.currentTimeMillis() + i);
            student.setName("李四學生" + i);
            student.setUserId(i);
            studentDao.save(student);
        }
}
           

測試結果:資料按id取模的方式劃分到了兩個資料庫中,同時從庫同步了主庫的資料

Mycat(實踐篇 - 基于PostgreSQL的水準切分、主從複制、讀寫分離)

水準切分(id取模)

  1. 測試模糊查詢+分頁
@Test
public void testFind() {
        Pageable pageable = new PageRequest(0, 10, Sort.Direction.ASC, "id");
        List<User> userList = userDao.findByNameLike("%李四1%", pageable).getContent();
        userList.forEach(System.out::println);

        Pageable pageable2 = new PageRequest(0, 10, Sort.Direction.ASC, "userId");
        List<Student> studentList = studentDao.findByNameLike("%李四學生2%", pageable2).getContent();
        studentList.forEach(System.out::println);
}
           

測試結果:按照模糊比對及id升序的方式輸出結果

Mycat(實踐篇 - 基于PostgreSQL的水準切分、主從複制、讀寫分離)

測試結果:讀操作都走了從庫

Mycat(實踐篇 - 基于PostgreSQL的水準切分、主從複制、讀寫分離)

讀寫分離,讀都走了從庫

  1. 删除及修改請自行測試

Mycat系列

Mycat(入門篇) Mycat(配置篇) Mycat(實踐篇 - 基于Mysql的水準切分、主從複制、讀寫分離) Mycat(實踐篇 - 基于PostgreSQL的水準切分、主從複制、讀寫分離)

參考連結

Mycat官網 Mycat從零開始 Mycat權威指南 GitHub:Mycat-Server Wiki:Mycat-Server Issues:Mycat-Server mysql中間件研究(Atlas,Cobar,TDDL) mysql中間件研究(Atlas,Cobar,TDDL,Mycat,Heisenberg,Oceanus,Vitess,OneProxy)