分库分表,sharding-jdbc

分库分表一定是为了支撑高并发、数据量大两个问题的

 

你了解哪些分库分表的中间件,各个中间件的优缺点是啥?然后你用过哪些分库分表的中间件。

比较常见的包括:

  • Cobar
  • TDDL
  • Atlas
  • Sharding-jdbc
  • Mycat

Cobar

阿里 b2b 团队开发和开源的,属于 proxy 层方案,就是介于应用服务器和数据库服务器之间。应用程序通过 JDBC 驱动访问 Cobar 集群,Cobar 根据 SQL 和分库规则对 SQL 做分解,然后分发到 MySQL 集群不同的数据库实例上执行。早些年还可以用,但是最近几年都没更新了,基本没啥人用,差不多算是被抛弃的状态吧。而且不支持读写分离、存储过程、跨库 join 和分页等操作。

Sharding-jdbc

当当开源的,属于 client 层方案,是 ShardingSphere 的 client 层方案, ShardingSphere 还提供 proxy 层的方案 Sharding-Proxy。确实之前用的还比较多一些,因为 SQL 语法支持也比较多,没有太多限制,而且截至 2019.4,已经推出到了 4.0.0-RC1 版本,支持分库分表、读写分离、分布式 id 生成、柔性事务(最大努力送达型事务、TCC 事务)。而且确实之前使用的公司会比较多一些(这个在官网有登记使用的公司,可以看到从 2017 年一直到现在,是有不少公司在用的),目前社区也还一直在开发和维护,还算是比较活跃,个人认为算是一个现在也可以选择的方案。

Mycat

基于 Cobar 改造的,属于 proxy 层方案,支持的功能非常完善,而且目前应该是非常火的而且不断流行的数据库中间件,社区很活跃,也有一些公司开始在用了。但是确实相比于 Sharding jdbc 来说,年轻一些,经历的锤炼少一些。

 

Sharding-jdbc 这种 client 层方案的优点在于不用部署,运维成本低,不需要代理层的二次转发请求,性能很高,但是如果遇到升级啥的需要各个系统都重新升级版本再发布,各个系统都需要耦合 Sharding-jdbc 的依赖;

Mycat 这种 proxy 层方案的缺点在于需要部署,自己运维一套中间件,运维成本高,但是好处在于对于各个项目是透明的,如果遇到升级之类的都是自己中间件那里搞就行了。

 

2、分库分表

1、分库分表有两种方式:垂直切分和水平切分
2、垂直切分:垂直分表和垂直分库。

垂直分表:大表分字段。垂直分库:按业务分库
3、水平切分:水平分表和水平分库
水平分库:判断某字段进入不同库

水平分表:分库分表问题

(1)跨节点连接查询问题(分页、排序)
(2)多数据源管理问题

 

而且这儿还有两种分库分表的方式:

  • 一种是按照 range 来分,就是每个库一段连续的数据,这个一般是按比如时间范围来的,但是这种一般较少用,因为很容易产生热点问题,大量的流量都打在最新的数据上了。
  • 或者是按照某个字段 hash 一下均匀分散,这个较为常用。

range 来分,好处在于说,扩容的时候很简单,因为你只要预备好,给每个月都准备一个库就可以了,到了一个新的月份的时候,自然而然,就会写新的库了;缺点,但是大部分的请求,都是访问最新的数据。实际生产用 range,要看场景。

hash 分发,好处在于说,可以平均分配每个库的数据量和请求压力;坏处在于说扩容起来比较麻烦,会有一个数据迁移的过程,之前的数据需要重新计算 hash 值重新分配到不同的库或表。

 

 

3、Sharding-jdbc

 是轻量级的java框架,是增强版的JDBC驱动。

主要作用:数据分片和读写分离。简化对数据库的操作

 

配置多个数据源

spring.shardingsphere.datasource.names=m1 #
#配置数据源具体内容,包含连接池,驱动,地址,用户名和密码 spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource

表数据分片策略:指定分片主键和分片规则

#指定course表分布情况,配置表在哪个数据库里面,表名称都是什么 m1.course_1 , m1.course_2

spring.shardingsphere.sharding.tables.course.actual-data-nodes=m1.course_$->{1..2}

# 指定course表里面主键cid 生成策略 SNOWFLAKE

spring.shardingsphere.sharding.tables.course.key-generator.column=cid spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE

# 指定分片策略 约定cid值偶数添加到course_1表,如果cid是奇数添加到course_2表

spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=cid

spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cid % 2 + 1}

复制代码
mport java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
 
import io.shardingjdbc.core.api.algorithm.sharding.PreciseShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
 
 
public class TableShardingAlgorithm implements PreciseShardingAlgorithm<String> {
    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<String> preciseShardingValue) {
        String tb_name=preciseShardingValue.getLogicTableName() + "_";
        try {
            Date date = (Date) new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(preciseShardingValue.getValue());
            
            String year = String.format("%tY", date);
            String mon  = String.format("%tm",date);
            String dat  = String.format("%td",date);
            tb_name=tb_name+year+mon+dat;
            System.out.println("tb_name:" + tb_name);
    } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
    }
        
        for (String each : collection) {
            System.out.println("tb:" + each);
            
            if (each.equals(tb_name)) {
                return each;
            }
        }
        
        throw new IllegalArgumentException();
    }
复制代码

 

 

4.跨表查询问题

可以将原来的连接分解成多个单表查询,然后在用户程序中进行连接。

 

5、公共表

(1)存储固定数据的表,表数据很少发生变化,查询时候经常进行关联
(2)在每个数据库中创建出相同结构公共表

解决跨距join的问题

所谓全局表,就是有可能系统中所有模块都可能会依赖到的一些表。比较类似我们理解的“数据字典”。为了避免跨库join查询,我们可以将这类表在其他每个数据库中均保存一份。同时,这类数据通常也很少发生修改(甚至几乎不会),所以也不用太担心“一致性”问题。

 

字段冗余

这是一种典型的反范式设计,在互联网行业中比较常见,通常是为了性能来避免join查询。

举个电商业务中很简单的场景:

“订单表”中保存“卖家Id”的同时,将卖家的“Name”字段也冗余,这样查询订单详情的时候就不需要再去查询“卖家用户表”。

字段冗余能带来便利,是一种“空间换时间”的体现。但其适用场景也比较有限,比较适合依赖字段较少的情况。最复杂的还是数据一致性问题,这点很难保证,可以借助数据库中的触发器或者在业务代码层面去保证。当然,也需要结合实际业务场景来看一致性的要求。就像上面例子,如果卖家修改了Name之后,是否需要在订单信息中同步更新呢?

posted on   潮流教父孙笑川  阅读(38)  评论(0编辑  收藏  举报

(评论功能已被禁用)
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示