读写分离怎么实现_项目中如何实现读写分离?怎么配置?
上篇文章中,在兩個 windows 系統的電腦上安裝了最新版?8.0.21 MySQL 數據庫,并且配置了主從。MySQL如何配置讀寫分離?
主從復制的原理思想也很簡單,就是從庫不斷地同步主庫的改動,保持與主庫數據一致;應用僅在從庫中讀數據。
在項目中,使用讀寫分離本質上就是,增加數據庫服務器資源 + 網絡帶寬,來分攤對數據庫的讀寫請求,從而提高了性能和可用性。主從復制實現讀寫分離最大的缺點就是從庫同步到主庫的數據存在延遲,網絡不好的時候,延遲比較嚴重。
解決了數據庫怎么配的問題,繼續探索一下,項目中如何實現讀寫分離。
在我們平時開發中,一般不會自己去控制 select 請求從從庫拿 Connection,insert、delete、update 請求從主庫拿 Connection。當然也有這么干,就是把讀寫請求按規則命名方法,然后根據方法名通過反射統一處理請求不同的庫。
大部分企業在項目中是使用中間件去實現讀寫分離的,如 mycat、atlas、dbproxy、cetus、Sharding-JDBC......,每種中間件各有優缺點。
Sharding-JDBC 是 apache 旗下的 ShardingSphere 中的一款產品,輕量,引入 jar 即可完成讀寫分離的需求,可以理解為增強版的 JDBC,現在被使用的較多。
既然數據庫主從環境準備好了,那就搭建項目玩一把。
maven 依賴的庫
<dependency> <groupId>org.apache.shardingspheregroupId> <artifactId>sharding-jdbc-coreartifactId> <version>4.1.1version>dependency><dependency> <groupId>com.zaxxergroupId> <artifactId>HikariCPartifactId> <version>3.4.5version>dependency><dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <version>8.0.21version>dependency>參照官網文檔配置與修改讀寫分離的 demo 程序
獲取數據源的工具類
package constxiong;import com.zaxxer.hikari.HikariDataSource;/** * 獲取 DataSource 工具類,使用了 Hikari 數據庫連接池 */import javax.sql.DataSource;public final class DataSourceUtil { private static final int PORT = 3306; /** * 通過 Hikari 數據庫連接池創建 DataSource * @param ip * @param username * @param password * @param dataSourceName * @return */ public static DataSource createDataSource(String ip, String username, String password, String dataSourceName) { HikariDataSource result = new HikariDataSource(); result.setDriverClassName(com.mysql.jdbc.Driver.class.getName()); result.setJdbcUrl(String.format("jdbc:mysql://%s:%s/%s?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8", ip, PORT, dataSourceName)); result.setUsername(username); result.setPassword(password); return result; }}測試 Sharding-JDBC 讀寫分離
主庫:172.31.32.184
從庫:172.31.32.234
觀察通過 Sharding-JDBC 獲取的 DataSource 是否會自動寫入到主庫,從庫是否主動同步,從庫同步數據的延遲時間
測試代碼
package constxiong;import org.apache.shardingsphere.api.config.masterslave.MasterSlaveRuleConfiguration;import org.apache.shardingsphere.shardingjdbc.api.MasterSlaveDataSourceFactory;import javax.sql.DataSource;import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.time.LocalTime;import java.util.*;/** * 測試 ShardingSphere 讀寫分離 * 主庫:172.31.32.184 * 從庫:172.31.32.234 * * 觀察通過 ShardingSphere 獲取的 DataSource 是否會自動寫入到主庫,從庫是否主動同步,從庫同步數據的延遲時間 */public class Test { //主庫 DataSource private static DataSource dsSlave = DataSourceUtil.createDataSource("172.31.32.234", "root", "constxiong@123", "constxiong"); //從庫 DataSource private static DataSource dsMaster = DataSourceUtil.createDataSource("172.31.32.184", "root", "constxiong@123", "constxiong"); public static void main(String[] args) throws SQLException { //啟動線程打印主庫與從庫當前 cuser 數據量與時間,觀察從庫同步數據延遲 printMasterAndSlaveData(); //從 ShardingSphere 獲取 DataSource,出入數據,觀察插入數據的庫是否為主庫 DataSource ds = getMasterSlaveDataSource(); Connection conn = ds.getConnection(); Statement stt = conn.createStatement(); stt.execute("insert into cuser values(2, 'fj')"); } /** * 啟動線程打印,兩個主從庫 cuser 表的信息、數據量、當前時間 * @throws SQLException */ private static void printMasterAndSlaveData() throws SQLException { Connection masterConn = dsMaster.getConnection(); Connection slaveConn = dsSlave.getConnection(); new Thread(() -> { while (true) { try { System.out.println("------master------" + LocalTime.now()); print(masterConn); System.out.println("------slave------" + LocalTime.now()); print(slaveConn); } catch (SQLException e) { } } }).start(); } private static void print(Connection conn) throws SQLException { Statement statement = conn.createStatement(); statement.execute("select * from cuser"); ResultSet rs = statement.getResultSet(); int count = 0; while (rs.next()) { int id = rs.getInt("id"); String name = rs.getString("name"); System.out.println(id + "-" + name); count++; } System.out.println("total: " + count); } /** * 設置 ShardingSphere 的主從庫 * @return * @throws SQLException */ private static DataSource getMasterSlaveDataSource() throws SQLException { MasterSlaveRuleConfiguration masterSlaveRuleConfig = new MasterSlaveRuleConfiguration("ds_master_slave", "ds_master", Arrays.asList("ds_slave")); return MasterSlaveDataSourceFactory.createDataSource(createDataSourceMap(), masterSlaveRuleConfig, new Properties()); } /** * 用 主從庫的 DataSource 構造 map * @return */ private static Map<String, DataSource> createDataSourceMap() { Map<String, DataSource> result = new HashMap<>(); result.put("ds_master", dsMaster); result.put("ds_slave", dsSlave); return result; }}分析延遲信息
數據默認配置的情況,在內網從庫同步的時間延遲,在 200ms 左右,當然這個統計是不精確的,只是看個大概情況。
為了更能看出 Sharding-JDBC 原汁原味的作用,這里并未使用 Spring。結合使用 Spring、Spring Boot 使用 Sharding-JDBC 的配置與代碼示例,官網中也已給出,可參照文檔實現。
參考文檔:
https://shardingsphere.apache.org/document/legacy/4.x/document/en/manual/sharding-jdbc/configuration/config-java/#read-write-split
https://shardingsphere.apache.org/document/legacy/4.x/document/en/manual/sharding-jdbc/usage/read-write-splitting/
代碼上傳至:
https://github.com/ConstXiong/toy/tree/master/demo/shardingsphere-read-write-split
面試題均收錄于小程序
留言區
總結
以上是生活随笔為你收集整理的读写分离怎么实现_项目中如何实现读写分离?怎么配置?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cpu功耗排行_2020 主流手机处理器
- 下一篇: 电脑有两个硬盘怎么选择启动 电脑启动时如