分布式存儲-ShardingSphere(讀寫分離&分布式事務)


分布式存儲-ShardingSphere(讀寫分離&分布式事務)

前面聊到ShardingSphere的一些配置和使用,但是作為一個數據庫中間件,它可以做的可不是僅僅進行分庫和分表。本篇想聊聊

  • 對mysql讀寫分離的支持
  • 它支持的分布式事務,默認的管理器是【Atomikos
  • 同時也會搭建一主一從的這樣一個mysql服務器【因為有至少兩個服務器是shardingshpher讀寫分離的前提】
  • 也會順便聊聊2pc,base,cap理論這些和分布式事務相關的理論。

mysql讀寫分離

我們在讀多寫少的場景下,對數據庫進行讀寫分離的好處有:

  • 減少共享鎖和排他鎖的競爭。
  • 減少服務器的壓力:當讀請求過多的時候,我們可以通過橫向擴充讀庫去減少數據庫的壓力。
  • 配置不同類型的數據庫:大部分情況下我們配置的是innodb(支持事務的操作)。而對於查詢我們就可以配置MyISAM引擎從而提升效率

mysql讀寫分離的配置【binlog】:

  • 當數據庫發生事務操作的時候,他就會把操作寫進一個日志中,
  • 然后slave節點中有一個io的線程定時發送一個read操作,
  • master會生成一個binlog,並且返回binlog給slave,
  • slave就會把得到的binlog寫在自己的relaylog中,然后用一個線程去執行

操作步驟:

【整體流程】

  • mater節點需要開啟binlog日志
  • slave節點需要指定某個binlog,以及從那個位置開始讀取
  • slave需要指定master節點的ip以及用戶名和密碼

【實際步驟】

【搭建兩台mysql服務器】(我使用的是mysql8.0):

  • 192.168.43.4【master】
  • 192.168.43.3 【slave】

【master節點開啟binlog】在mysql的配置文件中加上兩行代碼

  • log-bin=/var/lib/mysql/mysql-bin
  • server-id=1001
    • log-bin指的是你的logbin文件的位置,
    • server-id指的是你的這台mysql的唯一標識slave在讀取的時候需要知道這個東西
  • 然后重啟mysql,重啟后就發現logbin已經生成在了log-bin的目錄中
  • 或者使用sql查詢【show variables like 'log_bin%';】發現log-bin已經是on狀態了,這也證明已經開啟了

【在master節點創建一個用戶】:相當於一個白名單,只有這個用戶可以復制數據從master上

  • -- 創建用戶,其中repl表示用戶名, 192.168.43.3表示slave庫的ip地址,也就是只允許這個ip通過repl用戶訪問master庫
    • create user 'repl'@'192.168.43.3' identified with mysql_native_password by'123456';   
  • 授權 
    • -- replication slave 表示授權復制 -- *.* 表示所有的庫和表
    • grant replication slave on *.* to 'repl'@'192.168.43.3';
  • 刷新權限信息
    • flush privileges; 
【slave節點配置】:
首先在master節點,通過【show master status】了解master節點的狀態,把file的內容填寫到master-log-file中,把position填寫到master-log-pos中

【 連接master 】change master to master_host='192.168.43.4',master_user='repl',master_password='123456',master_log_file='binlog.000002',master_log_pos=855;

 查詢同步狀態:【show slave status\G】 當看見下面這兩個屬性都是yes就證明我們已經配置完

 【可能遇見的問題】:因為我是直接把虛擬機拷貝了一份,但是mysql的serverid是一致的,所以可能會出現上面的slave-io-running:no的情況,我們只需要把他的auto-confi中的id修改不一致即可。

測試】:當我們在master上新建一個數據庫的時候,slave上就會自動創建同樣的數據庫。同樣的,在新建表的時候,slave也會自動創建。至此主從配置配置和搭建完畢。

【binlog是什么】:查詢所有的binlog【show BINARY LOGS;】 查詢當前使用的binlog【SHOW BINLOG EVENTS in '這里就是使用show master status查詢出來的file'】。他其實就是把每一次的sql放在info中,slave拿過去進行解析后執行,就實現了和master一樣的效果了

 【主從同步延遲怎么辦?】:主節點和從節點進行通信那網絡延遲是無法被規避的,一般可能是

大事務或者節點過多而造成的數據同步延遲,這種情況下,我們可以通過【show slave status\G】中的這幾個字段判斷和主庫的延遲量,如果延遲過大我們直接強制走主庫。

 或者通過控制slave節點的數量,或者去做級聯,具體還是需要通過實際情況而定。

ShardingJDBC實現讀寫分離 

上面已經搭建了主從的這樣的mysql服務器,但是,當一個sql來訪問我們的服務端的時候,怎么判斷他走哪個節點呢?這個時候shardingSphere就為我們了干了這個事情。

【配置】

spring.shardingsphere.props.sql-show=true
spring.shardingsphere.datasource.names="write-ds,read-ds"
spring.shardingsphere.datasource.common.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.common.driver-class-name=com.mysql.jdbc.Driver

#寫庫配置
spring.shardingsphere.datasource.write-ds.jdbc-url=jdbc:mysql://192.168.43.4/readwritedb?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.write-ds.username=root
spring.shardingsphere.datasource.write-ds.password=123456

#讀庫配置
spring.shardingsphere.datasource.read-ds.jdbc-url=jdbc:mysql://192.168.43.3/readwritedb?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.read-ds.username=root
spring.shardingsphere.datasource.read-ds.password=123456

# db0這個名字隨意定義,就是一個邏輯庫的名字
spring.shardingsphere.rules.replica-query.data-sources.db0.primary-data-source-name=write-ds
spring.shardingsphere.rules.replica-query.data-sources.db0.replica-data-source-names=read-ds
spring.shardingsphere.rules.replica-query.load-balancers.db0.type=ROUND_ROBIN
#無任何意義
spring.shardingsphere.rules.replica-query.load-balancers.db0.props.test=test
View Code

測試插入一條數據

發現它走的是寫庫

 查詢一條數據

 發現它走的是讀庫

ShardingJDBC分布式事務

分庫分表解決了數據庫的壓力,可是,這就帶來了一個新的問題,分布式事務。當用戶點擊一個按鈕的時候,有可能是涉及到多個表的操作,但是,經過分庫分表后,這些表沒有在同一個數據庫中,那如何保證事務的一致性呢?這個時候就引出了全局事務。流程如下:

  • 在一個應用中,同時操作兩個數據庫的數據【當mysql收到需要操作某個數據庫的數據的時候他不能直接操作,因為這就變成了單個事務了】
  • 這個時候引入一個第三方【全局事務】,這個全局事務決定這兩個操作是同時成功還是失敗。
  • 當這兩個數據庫的操作都完成后【他們不會直接提交事務】,他們就會分別給全局事務一個消息,告訴全局事務他們是否操作成功還是失敗。
  • 一旦有一個節點的執行錯誤,這個全局事務就讓他們都回滾事務,否則才告知他們提交事務,這樣就能保證了事務的一致性

【問題】:我們這里肯定不能使用傳統的事務來做,因為使用全局事務他就會自動提交了,那這里就有一個XA協議

【XA協議】:是 X/Open 這個組織定義的一套分布式事務的標准中的一個協議,實際上這個組織提供三個角色和兩個協議,使用這些才能構建一個分布式事務的解決方案。

三個角色分別如下

AP(Application Program):表示應用程序,也可以理解成使用 DTP模型的程序
RM(Resource Manager):資源管理器, 這個資源可以是數據庫應用程序通過資源管理器對資源進行控制,資源管理器 必須實現XA定義的接口
TM(Transaction Manager):表示事務管理器, 負責協調和管理全局事務事務管理器控制整個全局事務,管理事務的生命周期,並且協調資源。 
兩個協議分別是:
【XA協議】:
TM用它來通知和協調相關RM事務的開始、結束、提交或回滾。目前Oracle、Mysql、DB2都提供了對XA的支持;
【TX協議】: 全局事務管理器與資源管理器之間通信的接口
工作流程:

 具體做法:

配置

spring.shardingsphere.props.sql-show=true
spring.shardingsphere.datasource.names="ds-0,ds-1"
spring.shardingsphere.datasource.common.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.common.driver-class-name=com.mysql.jdbc.Driver

#配置兩個數據源
spring.shardingsphere.datasource.ds-0.jdbc-url=jdbc:mysql://192.168.43.3/shard01?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.ds-0.username=root
spring.shardingsphere.datasource.ds-0.password=123456

spring.shardingsphere.datasource.ds-1.jdbc-url=jdbc:mysql://192.168.43.4/shard02?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.ds-1.username=root
spring.shardingsphere.datasource.ds-1.password=123456

#使用user_id作為分片鍵
spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-column=user_id
spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-algorithm-name=database-inline
spring.shardingsphere.rules.sharding.sharding-algorithms.database-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.database-inline.props.algorithm-expression=ds-$->{user_id % 2}

#主鍵生成規則
spring.shardingsphere.rules.sharding.tables.t_order.key-generate-strategy.column=order_id
spring.shardingsphere.rules.sharding.tables.t_order.key-generate-strategy.key-generator-name=snowflake


spring.shardingsphere.rules.sharding.key-generators.snowflake.type=SNOWFLAKE
spring.shardingsphere.rules.sharding.key-generators.snowflake.props.worker-id=123
View Code

在代碼中增加一個注解即可,我們測試在代碼中讓它報錯,看看事務會不會回滾

 @Override
    @Transactional(rollbackFor = Exception.class)
    @ShardingTransactionType(TransactionType.XA)
    public TOrder addOrder() {
        for (int i = 0; i <10 ; i++) {
            TOrder tOrder=new TOrder();
            tOrder.setAddressId(1);
            tOrder.setStatus("GLOBAL_TRANSACTION");
            tOrder.setUserId(random.nextInt(1000));
            //這里讓i等於4的時候報錯,看看會不會回滾
            
            if(i==4){
                int ex=1/0;
            }
            orderMapper.insert(tOrder);
        }
        return new TOrder();
    }
View Code

我們看見已經報錯了,並且數據沒有進入到數據庫

ShardingSphere 默認的 XA 事務管理器為 Atomikos,那他是如何實現多數據源頭的事務管理的呢?

實際上主要還是基於2pc的提交(一種一致性協議):

  • 表示事務管理器向每一個數據庫都發送執行命令的操作,每個數據庫就開始執行他們的操作,並且把執行的結果發送給事務管理器
  • 如果資源管理器【數據庫】有一個的發送結果是錯誤的,那資源管理器事務管理器就向數據庫發送事務回滾的要求,否則是發送讓他們都執行的要求。

分布式事務涉及問題

【XA事務存在的問題】
因為xa是屬於強一致性事務,因為在全局事務中,只要有任何一個RM出現異常,都會導致全局事務回滾,同時在第一階段的時候給數據庫發送請求的時候,會鎖定數據庫資源, 但是一旦網絡延遲了,那就要等待很久。
 
CAP理論】:這個理論告訴我們在分布式系統中,這三個只能滿足兩個。對於一個業務系統來說,【可用性】和【分區容錯性】是必須要滿足的兩個條件,並且這兩者是相輔相成的。我們必須保證系統可用,同時一個節點宕機,整個系統不能癱瘓。
  • C:Consistency 一致性 同一數據的多個副本是否實時相同。
  • A:Availability 可用性 可用性:一定時間內 & 系統返回一個明確的結果 則稱為該系統可用。
  • P:Partition tolerance 分區容錯性 將同一服務分布在多個系統中,從而保證某一個系統宕機,仍然有其他系統提供相同的服務
 【BASE理論】:
  • Basically Available(基本可用):允許在一定時間段,我們的數據不同步,比如說我master中的數據是5而slave節點的數據是2
  • Soft State(柔性狀態):允許系統在多個不同節點的數據副本存在數據延時。
  • Eventually Consistent(最終一致性):在最終的某個點的時候達到數據的最終一致性
對於base理論我們要做的就是【最終一致性】,這可以通過【重試機制】達到效果:比如說我們在注冊的時候,有一個贈送積分的功能,但是由於網絡或者其他原因失敗了,那我們可以把這個失敗的數據放在一個本地的消息表中,不斷的去跑這個消息然后進行重新贈送積分。


免責聲明!

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



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