Sharding-Jdbc學習筆記二之讀寫分離專案配置篇

DDF_YiChen發表於2020-10-10


mysql配置安裝及資料庫準備參考 上一篇

2. 專案配置

參考手冊

2.1 application.yml中配置

使用druid連線池, 經過測試, 如果要配置druid的filter還是保持和原來一樣的配置將這部分資訊配置在spring.datasource.druid下

現在使用了shardingsphere,所以其他連線具體資訊需要配置在spring.shardingsphere.datasource下

#######################################################讀寫分離配置###############################################################
 
# mysql master連線資訊
master.mysql.host: localhost
master.mysql.port: 3306
master.mysql.db: boot-quick
master.mysql.username: root
master.mysql.password: 123456
 
# mysql slave0連線資訊
slave0.mysql.host: localhost
slave0.mysql.port: 3307
slave0.mysql.db: boot-quick
slave0.mysql.username: root
slave0.mysql.password: 123456
 
# mysql slave0連線資訊
slave1.mysql.host: localhost
slave1.mysql.port: 3308
slave1.mysql.db: boot-quick
slave1.mysql.username: root
slave1.mysql.password: 123456
 
 
spring:
  main:
    allow-bean-definition-overriding: true
 
  # 經測試filter需要配置再datasource.druid下,而每個連線的資訊還是得配置在sharding-sphere下的datasource每個自己的
  datasource:
    druid:
      filter:
        stat:
          enabled: true
          log-slow-sql: true
          slow-sql-millis: 3000
        wall:
          enabled: true # 開啟WallFilter
          db-type: mysql
      ## 開啟內建監控介面 訪問路徑: /context-path/druid/index.html
      stat-view-servlet:
        enabled: true
        url-pattern: /druid/*
        reset-enable: true
        login-username: admin
        login-password: 123456
 
  shardingsphere:
    datasource:
      names: master,slave0,slave1
      # 配置資料來源
      master:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://${master.mysql.host}:${master.mysql.port}/${master.mysql.db}?useUnicode=true&characterEncoding=UTF8&useSSL=false&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&tinyInt1isBit=false
        username: ${master.mysql.username}
        password: ${master.mysql.password}
        initial-size: 5
        asyncInit: true
        max-active: 30
        min-idle: 10
        keep-alive: true
        max-wait: 60000
        use-unfair-lock: true
        time-between-eviction-runs-millis: 60000
        min-evictable-idle-time-millis: 600000
        validation-query: SELECT 1
        test-while-idle: true
        test-on-borrow: true
        test-on-return: false
        poolPreparedStatements: false
        max-open-prepared-statements: 20
      # 配置資料來源
      slave0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://${slave0.mysql.host}:${slave0.mysql.port}/${slave0.mysql.db}?useUnicode=true&characterEncoding=UTF8&useSSL=false&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&tinyInt1isBit=false
        username: ${slave0.mysql.username}
        password: ${slave0.mysql.password}
        initial-size: 5
        asyncInit: true
        max-active: 30
        min-idle: 10
        keep-alive: true
        max-wait: 60000
        use-unfair-lock: true
        time-between-eviction-runs-millis: 60000
        min-evictable-idle-time-millis: 600000
        validation-query: SELECT 1
        test-while-idle: true
        test-on-borrow: true
        test-on-return: false
        poolPreparedStatements: false
        max-open-prepared-statements: 20
      # 配置資料來源
      slave1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://${slave1.mysql.host}:${slave1.mysql.port}/${slave1.mysql.db}?useUnicode=true&characterEncoding=UTF8&useSSL=false&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&tinyInt1isBit=false
        username: ${slave1.mysql.username}
        password: ${slave1.mysql.password}
        initial-size: 5
        asyncInit: true
        max-active: 30
        min-idle: 10
        keep-alive: true
        max-wait: 60000
        use-unfair-lock: true
        time-between-eviction-runs-millis: 60000
        min-evictable-idle-time-millis: 600000
        validation-query: SELECT 1
        test-while-idle: true
        test-on-borrow: true
        test-on-return: false
        poolPreparedStatements: false
        max-open-prepared-statements: 20
 
    # 配置主從規則
    masterslave:
      # 從庫負載均衡演算法
      load-balance-algorithm-type: round_robin
      # 讀寫分離資料來源名稱
      name: ms
      # 主庫資料來源名稱, 從上面配置的資料來源中選擇
      master-data-source-name: master
      # 從庫資料來源名稱列表, 從上面配置的資料來源中選擇
      slave-data-source-names: slave0,slave1
 
    props:
      #  顯示sql具體資訊
      sql.show: true
 

3. 專案測試

專案搭建以及crud程式碼和單表操作沒有一點區別,因此測試程式碼省略

  • 插入測試從從庫查詢, 插入則操作主庫

  • 列表查詢測試, 查詢從從庫查詢資料

4. 錯誤彙總

  1. 在master刪除的資料,在slave節點不存在

    Could not execute Delete_rows event on table boot-quick.auth_user; Can't find record in 'auth_user', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log WIN-NQ0GCAPFCPP-bin.000017, end_log_pos 2234
    

    臨時解決,

    按照上面的錯誤先在主庫檢視binlog日誌後面要同步的數量

    SHOW BINLOG EVENTS in 'WIN-NQ0GCAPFCPP-bin.000017' from 2997;
    

    然後 進入到slave,先停下slave,然後跳過錯誤數量, 再重啟slave

    stop slave;
    set global sql_slave_skip_counter=1;
    start slave;
    

    永久解決, 根據錯誤程式碼(上面那段錯誤就包含了Error_code: 1032),在從庫配置檔案中跳過對應的錯誤

    slave-skip-errors=1032
    

5. 主從同步原理

  • 主節點

    1、當主節點上進行 insert、update、delete 操作時,會按照時間先後順序寫入到 binlog 中;
    2、當從節點連線到主節點時,主節點會建立一個叫做 binlog dump 的執行緒;

    3、一個主節點有多少個從節點,就會建立多少個 binlog dump 執行緒;

    4、當主節點的binlog 發生變化的時候,也就是進行了更改操作,binlog dump 執行緒就會通知從節點 (Push模式),並將相應的 binlog 內容傳送給從節點;

  • 從節點

    當開啟主從同步的時候,從節點會建立兩個執行緒用來完成資料同步的工作。

    I/O執行緒: 此執行緒連線到主節點,主節點上的 binlog dump 執行緒會將 binlog 的內容傳送給此執行緒。此執行緒接收到 binlog 內容後,再將內容寫入到本地的 relay log

    SQL執行緒: 該執行緒讀取 I/O 執行緒寫入的 relay log,並且根據 relay log 的內容對從資料庫做對應的操作。

專案通用配置和專案錯誤彙總

  • 預設連線未配置,剛開始使用的版本沒有這個問題,後來升到了4.1.1有這個問題

    Action:
    
    Consider the following:
        If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
        If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
    

    則需要在主啟動類上排除當前專案所依賴的連線池的自動配置類,如使用的druid

    @SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
    
  • datasource已定義

    Description:
    
    The bean 'dataSource', defined in class path resource [org/apache/shardingsphere/shardingjdbc/spring/boot/SpringBootConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceAutoConfigure.class] and overriding is disabled.
    
    Action:
    
    Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
    

    則按照上面的提示,加上配置

    spring:
      main:
        allow-bean-definition-overriding: true
    

相關文章