目录
1、了解分库分表的概念和原理
随着数据库的使用,在面对大量数据的存储,单机性能没法解决问题的情况下,就需要考虑分库分表。
1.1 分库的场景
分库一般是单机有性能瓶颈,一般来说IO瓶颈和CPU瓶颈,在单机数据量太大时,无法应对,网络贷款不够,需要多个节点进行负载,这个时候就需要分库。
IO瓶颈一般在面临大数据查询的时候,返回的数据过多,产生大量的IO,单机无法支撑
CPU瓶颈在做一些复杂操作的时候,比如group by ,order by的时候,需要大量cpu运算的时候,
1.2 分表的场景
分表一般是因为单表数据量过多,查询慢,新增也慢,一般来说单表数据不超过2000w,在1000w的时候就要拆份额
1.3 数据库拆分的两种方式
垂直拆分:根据业务维度,将一张表中的字段拆分成不同的几张表
水平拆分: 将一个表根据分片算法,将数据拆分成好几张表结构相同的表
1.4 分库分表的技术方案
1.4.1 客户端主动访问不同数据库
客户端知道数据在哪个地方,直接操作多个多数据,这也就是多数据源
1.4.2 服务端应用进行分开查询
应用下层直接操作分割,技术实现就是sharding-jdbc
1.4.3 中间件进行分开查询
不直接连接到数据源,而是连接到中间件,分库分表的逻辑在中间件实现,技术实现就是mycat
1.5 分片策略
1.5.1 按照哈希切片
对数据库的某个字段进行来求哈希,再除以分片总数后取模,取模后相同的数据为一个分片,这样将数据分成多个分片的方法叫做哈希分片
1.5.2 按时间分表
根据业务时间或者插入时间
1.5.3 按数据区间分表
根据业务数据的范围进行分表
1.6 分库分表存在的问题
我们发现垂直拆分和水平拆分具有共同点:
存在分布式事务问题
存在跨节点join的问题
存在跨节点合并排序、分页的问题
存在多数据源管理的问题
2、Sharding-jdbc 的架构和配置
sharding jdbc 主要是为了解决数据分片和读写分离,使用sharding jdbc 应用可以透明的访问多个数据源和数据表。
2.1 sharding jdbc的架构
Sharding-jdbc 系统架构分成5个部分:SQL解析,SQL路由,SQL改写,SQL执行,结果集归并
2.2 sharding jdbc 概念
2.2.1 逻辑表
水平拆分的数据表的总称。例:订单数据表根据主键尾数拆分为10张表,分别是 torder0 、 torder1 到torder9 ,他们的逻辑表名为 t_order 。
2.2.2 真实表
在分片的数据库中真实存在的物理表。即上个示例中的 torder0 到 torder9 。
2.2.3 数据节点
数据分片的最小物理单元。由数据源名称和数据表组成,例:ds0.torder_0 。
2.3 show me the code
2.3.1 引用
创建一个springboot项目,这个没难度,一路next就好
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid}</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
2.3.2 配置application.properties
这是一个比较全的例子,主从配置,分库,分表
分库 ms单库分库分为 ms0库 和 ms1库。
分表 tab_user单表分为tab_user0表 和 tab_user1表。
读写分离 数据写入ms0库 和 ms1库,数据读取 sl0库 和 sl1库。
server.port=8088
#指定mybatis信息
mybatis.config-location=classpath:mybatis-config.xml
#打印sql
spring.shardingsphere.props.sql.show=true
spring.shardingsphere.datasource.names=master0,slave0,master1,slave1
spring.shardingsphere.datasource.master0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master0.url=jdbc:mysql://localhost:3306/ms0?characterEncoding=utf-8
spring.shardingsphere.datasource.master0.username=root
spring.shardingsphere.datasource.master0.password=root
spring.shardingsphere.datasource.slave0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.slave0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave0.url=jdbc:mysql://localhost:3306/sl0?characterEncoding=utf-8
spring.shardingsphere.datasource.slave0.username=root
spring.shardingsphere.datasource.slave0.password=root
spring.shardingsphere.datasource.master1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master1.url=jdbc:mysql://localhost:3306/ms1?characterEncoding=utf-8
spring.shardingsphere.datasource.master1.username=root
spring.shardingsphere.datasource.master1.password=root
spring.shardingsphere.datasource.slave1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.slave1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave1.url=jdbc:mysql://localhost:3306/sl1?characterEncoding=utf-8
spring.shardingsphere.datasource.slave1.username=root
spring.shardingsphere.datasource.slave1.password=root
#根据年龄分库
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=age
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=master$->{age % 2}
#根据id分表
spring.shardingsphere.sharding.tables.tab_user.actual-data-nodes=master$->{0..1}.tab_user$->{0..1}
spring.shardingsphere.sharding.tables.tab_user.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.tab_user.table-strategy.inline.algorithm-expression=tab_user$->{id % 2}
#指定master0为主库,slave0为它的从库
spring.shardingsphere.sharding.master-slave-rules.master0.master-data-source-name=master0
spring.shardingsphere.sharding.master-slave-rules.master0.slave-data-source-names=slave0
#指定master1为主库,slave1为它的从库
spring.shardingsphere.sharding.master-slave-rules.master1.master-data-source-name=master1
spring.shardingsphere.sharding.master-slave-rules.master1.slave-data-source-names=slave1
2.3.3正常的操作数据库就行
@RestController
public class UserController {
@Autowired
private UserService userService;
/**
* 模拟插入数据
*/
List<User> userList = Lists.newArrayList();
/**
* 初始化插入数据
*/
@PostConstruct
private void getData() {
userList.add(new User(1L,"小A", "女", 3));
userList.add(new User(2L,"小B", "男", 31));
userList.add(new User(3L,"小C", "女", 11));
userList.add(new User(4L,"小D", "男", 44));
userList.add(new User(5L,"小E", "女", 62));
}
/**
* @Description: 批量保存用户
*/
@PostMapping("save-user")
public Object saveUser() {
return userService.insertForeach(userList);
}
/**
* @Description: 获取用户列表
*/
@GetMapping("list-user")
public Object listUser() {
return userService.list();
}
}
2.3.4 验证下
写入的数据在主库
读出的数据在从库
3、总结
MySQL在面对大数据量、高并发、读写分离、横向扩展、地域分布等情况时,都需要进行分库分表。
只要能满足需求,拆分规则越简单越好
能不搞这些就不搞这些
自媒体写作变现一本通:450万粉丝矩阵主理人、十点读书签约写作讲师手把手教你写作变现实战经验,有方法,有理论,有实践,让写作变现变得简单!
450万粉丝矩阵主理人经验总结,手把手教你写作变现。
当当自营购买链接:http://product.dangdang.com/29511376.html