一、核心概念
傳統將數據集中存儲在單一節點的解決方案的不足:
1.性能:由于關系型數據庫大多采用B+樹索引,在數據量超過閾值情況下,索引深度的增加也將使得磁盤訪問IO次數增加,進而導致查詢性能得下降,同時高并發請求也使得集中式數據庫成為系統最大瓶頸
2.可用性:
3.運維:當單一數據庫實例得數據達到閾值之后,數據得備份和恢復的時間成本都會隨著數據量大小而愈發不可控
數據分片是指:按照某個維度將存放在單一數據庫中的數據分散存放在多個數據庫或表中以達到提升性能瓶頸以及可用性的效果。數據分片分為垂直分片和水平分片
垂直分片:按照業務拆分的方式稱為垂直分片,又稱縱向拆分,核心理念是專庫專用。垂直拆分可以緩解數據量和訪問量帶來的問題,但是無法根治
水平分片:又稱為橫向分片,不根據業務邏輯劃分,而是通過某個字段(某些字段)根據某種規則將數據分散至多個庫或表中,每個分片僅包含數據的一部分。
1.1數據分片核心概念
1.1.1SQL
- 邏輯表
- 真實表
- 數據節點
- 綁定表
如果主表和子表之間不設置為綁定表,則查詢過程將呈現為笛卡兒積關聯,否則子表和主表在進行路由時,所有的路由計算將只使用主表的策略
1.1.2分片
- 分片鍵
用于分片的數據庫字段 - 分片算法
1.精確分片算法:PreciseShardingAlgorithm,用于處理使用單一鍵作為分片鍵的與In進行分片的場景,配合StandardShardingStrategy使用
2.復合分片:對應ComplexKeysShardingAlgorithm,用于處理使用多鍵作為分片鍵進行分片的場景,配合ComplexShardingStrategy使用
3.范圍分片:對應RangeShardingAlgorithm,用于處理使用單一鍵作為 分片鍵的BETWEEN AND、>、<、<=、>=進行分片的場景,配合StandardShardingStrategy使用
4.Hint分片:對應HintShardingAlgorithm,用于處理使用Hint行分片的場景,配置配合HintShardingStrategy使用
- 分片策略
包含分片鍵和分片算法
1.標準分片策略:對應StandardShardingStrategy。提供對SQL語句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持
2.復合分片策略
3.行表達式分片策略,只支持單分片鍵。
4.Hint分片策略
5.不分片策略
1.2 數據分片內核剖析
二、代碼實踐
2.1 準備工作
2.1.1 建庫建表
ds0
CREATE DATABASE `ds0`;
USE `ds0`;
CREATE TABLE `user0` (
`user_id` BIGINT(20) NOT NULL,
`user_name` VARCHAR(200) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
CREATE TABLE `user1` (
`user_id` BIGINT(20) NOT NULL,
`user_name` VARCHAR(200) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
ds1
CREATE DATABASE `ds1`;
USE `ds1`;
CREATE TABLE `user0` (
`user_id` BIGINT(20) NOT NULL,
`user_name` VARCHAR(200) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
CREATE TABLE `user1` (
`user_id` BIGINT(20) NOT NULL,
`user_name` VARCHAR(200) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
2.1.2 引入pom
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.0</version>
</dependency>
2.2 代碼實踐
2.2.1 配置指導(這里通過properties配置進行示例)
2.2.1.1 分庫分表多數據源信息配置
spring.shardingsphere.datasource.names= #數據源名稱,多數據源以逗號分隔
spring.shardingsphere.datasource.<data-source-name>.type= #數據庫連接池類名稱
spring.shardingsphere.datasource.<data-source-name>.driver-class-name= #數據庫驅動類名
spring.shardingsphere.datasource.<data-source-name>.url= #數據庫url連接
spring.shardingsphere.datasource.<data-source-name>.username= #數據庫用戶名
spring.shardingsphere.datasource.<data-source-name>.password= #數據庫密碼
spring.shardingsphere.datasource.<data-source-name>.xxx= #數據庫連接池的其它屬性
2.2.1.2 分片策略和分片算法配置
配置具體表的數據節點
spring.shardingsphere.sharding.tables.<logic-table-name>.actual-data-nodes= #由數據源名 + 表名組成,以小數點分隔。多個表以逗號分隔,支持inline表達式。缺省表示使用已知數據源與邏輯表名稱生成數據節點,用于廣播表(即每個庫中都需要一個同樣的表用于關聯查詢,多為字典表)或只分庫不分表且所有庫的表結構完全一致的情況
為表和庫分別配置分片策略和算法:
共有四種策略可以配置,分庫和分表各自只能選其一進行配置
- 單分片鍵
spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.standard.sharding-column= #分片列名稱
spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.standard.precise-algorithm-class-name= #精確分片算法類名稱,用于=和IN。該類需實現PreciseShardingAlgorithm接口并提供無參數的構造器
spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.standard.range-algorithm-class-name= #范圍分片算法類名稱,用于BETWEEN,可選。該類需實現RangeShardingAlgorithm接口并提供無參數的構造器
- 多分片鍵的復合分片
spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.complex.sharding-columns= #分片列名稱,多個列以逗號分隔
spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.complex.algorithm-class-name= #復合分片算法類名稱。該類需實現ComplexKeysShardingAlgorithm接口并提供無參數的構造器
- 行表達式分片
spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.inline.sharding-column= #分片列名稱
spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.inline.algorithm-expression= #分片算法行表達式,需符合groovy語法
- Hint分片策略
spring.shardingsphere.sharding.tables.<logic-table-name>.database-strategy.hint.algorithm-class-name= #Hint分片算法類名稱。該類需實現HintShardingAlgorithm接口并提供無參數的構造器
配置未設置分片規則的表路由的默認數據源以及默認分庫和分表的策略
spring.shardingsphere.sharding.default-data-source-name= #未配置分片規則的表將通過默認數據源定位
spring.shardingsphere.sharding.default-database-strategy.xxx= #默認數據庫分片策略,同分庫策略
spring.shardingsphere.sharding.default-table-strategy.xxx= #默認表分片策略,同分表策略
2.2.1.3 配置綁定表和廣播表
binding-tables和broadcast-tables為集合
spring.shardingsphere.sharding.binding-tables[0]= #綁定表規則列表
spring.shardingsphere.sharding.binding-tables[1]= #綁定表規則列表
spring.shardingsphere.sharding.binding-tables[x]= #綁定表規則列表
spring.shardingsphere.sharding.broadcast-tables[0]= #廣播表規則列表
spring.shardingsphere.sharding.broadcast-tables[1]= #廣播表規則列表
spring.shardingsphere.sharding.broadcast-tables[x]= #廣播表規則列表
2.2.1.4 其他配置
- 配置分布式自增主鍵策略
spring.shardingsphere.sharding.tables.<logic-table-name>.key-generator.column= #自增列名稱,缺省表示不使用自增主鍵生成器
spring.shardingsphere.sharding.tables.<logic-table-name>.key-generator.type= #自增列值生成器類型,缺省表示使用默認自增列值生成器。可使用用戶自定義的列值生成器或選擇內置類型:SNOWFLAKE/UUID
spring.shardingsphere.sharding.tables.<logic-table-name>.key-generator.props.<property-name>= #屬性配置, 注意:使用SNOWFLAKE算法,需要配置worker.id與max.tolerate.time.difference.milliseconds屬性。若使用此算法生成值作分片值,建議配置max.vibration.offset屬性
- 配置開啟顯示SQL解析過程
spring.shardingsphere.props.sql.show= #是否開啟SQL顯示,默認值: false
2.2.2 分庫分表配置實戰(Yaml配置方式)
這里分庫和分表的分片策略均采用行表達式,分片算法均為針對user_id 對2進行取模路由
spring:
shardingsphere:
#配置數據源名稱,多數據源以逗號進行分隔
datasource:
names: ds0,ds1
#配置各個數據源的基本信息
ds0:
# type:數據庫連接池名稱
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/ds0?serverTimezone=UTC
username: root
password: 1234
ds1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/ds1?serverTimezone=UTC
username: root
password: 1234
sharding:
tables:
user:
actual-data-nodes: ds$->{0..1}.user$->{0..1}
# 配置分庫策略
database-strategy:
inline:
sharding-column: user_id #配置分片鍵名稱
algorithm-expression: ds$->{user_id % 2} #配置分片算法行表達式
# 配置分表策略
table-strategy:
inline:
sharding-column: user_id #配置分片鍵名稱
algorithm-expression: user$->{user_id % 2} #配置分片算法行表達式
props:
sql:
show: true
2.2.2 分庫分表配置實戰(Java代碼配置方式)
真實業務中肯定很多業務表需要進行分表,當然不可能每張表都通過yaml方式去配置,所以最終可能還是需要通過java代碼進行分庫分表的配置。下述代碼功能將和上述yaml的配置相同。
pom
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>4.0.1</version>
</dependency>
配置代碼
@Configuration
public class ShardingDataSourceConfiguration {
@Bean
public DataSource getShardingDataSource() throws SQLException {
ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
// 獲取user表的分片規則配置
TableRuleConfiguration userInfoTableRuleConfiguration = getUserInfoTableRuleConfiguration();
shardingRuleConfig.getTableRuleConfigs().add(userInfoTableRuleConfiguration);
return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, new Properties());
}
/**
* 配置真實數據源
* @return 數據源map
*/
private Map<String, DataSource> createDataSourceMap() {
Map<String, DataSource> dataSourceMap = new HashMap<>();
DruidDataSource druidDataSource1 = new DruidDataSource();
druidDataSource1.setUrl("jdbc:mysql://localhost:3306/ds0?serverTimezone=UTC");
druidDataSource1.setUsername("root");
druidDataSource1.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource1.setPassword("1234");
DruidDataSource druidDataSource2 = new DruidDataSource();
druidDataSource2.setUrl("jdbc:mysql://localhost:3306/ds1?serverTimezone=UTC");
druidDataSource2.setUsername("root");
druidDataSource2.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource2.setPassword("1234");
dataSourceMap.put("ds0",druidDataSource1);
dataSourceMap.put("ds1",druidDataSource2);
return dataSourceMap;
}
/**
* 配置user表的分片規則
*
* @return ser表的分片規則配置對象
*/
private TableRuleConfiguration getUserInfoTableRuleConfiguration() {
// 為user表配置數據節點
TableRuleConfiguration ruleConfiguration = new TableRuleConfiguration("user", "ds${0..1}.user${0..1}");
// 設置分片鍵
String shardingKey = "user_id";
// 為user表配置分庫分片策略及分片算法
ruleConfiguration.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration(shardingKey, "ds${user_id % 2}"));
// 為user表配置分表分片策略及分片算法
ruleConfiguration.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration(shardingKey, "user${user_id % 2}"));
return ruleConfiguration;
}
}
完整實戰代碼github:https://github.com/xiaomaomiao/ShardingSphereDemo.git
2.3、踩坑記錄
1.ShardingShpere配合Druid數據源啟動報錯
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.