搭建高性能数据库服务⭐《Sharding-JDBC+Canal》⭐

20 篇文章 0 订阅
4 篇文章 0 订阅

本文主要记录本周的学习内容,搭建mysql的高性能数据库服务

源于

现最多被使用的数据库还是Msql,而MySQL本身不是一种分布式型数据库,在高性能要求下,简单的主从、复制已无法满足高性能要求。
而本文主要在提供读者一种高性能方案。
主要进入角度在于分库,将数据按指定的维度进行分库处理。

为什么

试想你有一台数据库你为了希望它高可用你部署了主从,在意外情况下可以切换到从库。为了提高性能你又使用了读写分离,但你发现性能还是不够因为主要的写库还是只有一台,然后你想做到集群化部署,不搞什么读写了,将数据分批放到不同的数据库中,其数据库之间不关联,性能也是独立的。两台性能+2、三台性能+3,就此性能问题解决了。
但实际上想要实现这样子分库并没有那么简单,需要借助一些中间件实现

在这里插入图片描述

选择

现有适用与MySQL的分库分表实现方案,主要有以下两种类型,其区别主要在于是否置入应用、独立应用的数据库上层代理

  1. JDBC直连层
    在这里插入图片描述

  2. Proxy 代理层
    在这里插入图片描述

主要代表方案 :

方案类型描述
Sharding-JDBCJDBC直连层现比较常用的方案,其织入应用维护成本较底,但统一管理变的麻烦-后续已经支持集群proxy方案
mycatProxy 代理层需要独立部署,无疑加大了维护成本适用于大规模的开发

Sharding-JDBC

笔者这里不介绍Sharding-JDBC的实现,希望读者自行去点标题进入官网了解它能做些什么, 笔者已经把能直接运行的项目放到了👉gitee👈,方便读者学习

在我们对数据的数据进行分片后,订单数据已经成功的根据不同的订单号进入了不同的数据库了,但出现了一些问题,我希望查询用户Id是2的订单数据,但出现在了两个数据库中,我的sql应该怎么写;

select * from table_name where user_id=2;

现在这样子写还可以吗
在这里插入图片描述
不出意外的出现了异常,因为我们的数据划分是通过订单号,也就是说我们提供Sharding-JDBC一个订单号然后它去更具规则算出它在那个数据库中,但是如果我们没有提供订单号的查询,它无法进行判断,那此类sql就会变成整个集群的查询,此类查询不出意外的被拦截了,当然我们也可以关闭拦截,但关闭了拦截我们的分库就毫无意义(还是变成了全库扫描查询)。
在这里插入图片描述
分库后会出现以下问题

  1. 分库分表的算法 : 以什么条件作为分法,是否兼容后续数据库扩容
  2. 分库分表ID问题 : 多库如果用自增编号,会出现重复编号
  3. 分库分表后的事务 : 多库之间的分布式事务问题
  4. 多表联合查询/多维度 : 数据分布在不同的数据库中怎么做order by、group by等等

问题一 : 分库分表的算法

  1. 通过对order_id取模 : 取模的方案固然最简单,但在后续的扩容取模数+1会导致旧数据已经分配出去的,无法查询;
    在这里插入图片描述
  2. 一致性哈希:当然还有其他方案,这里就直接告诉读者比较优解,该方案也是redis采用的,算法比较复杂,但如其名无论追加集群也不会导致order_id计算结果;

问题二:分库分表ID问题
通常我们单机应用的时候,我们完全可以采用主键自增,但在分布式集群的情况下,如果还使用自增那会出现不同库中自增的编号一样,也就是两个库的表里都会出现编号为1的数据,这种重复编号的出现十分破坏原子性,当然解决方案也是非常多,常见的雪花、美团的leaf、uuid等等都可以作为分布式id生成方案

问题三: 分库分表后的事务
在单机下我们的数据都在一个数据库中,MySQL会帮助我们管理事务,多表的修改可以统一的回滚,但分布式下不同数据库的事务并不互通,此时我们可以引入分布式XA事务解决方案

问题四:多表联合查询/多维度
也是本文的关键,如果我想在订单表下用用户维度查询,也就是上图的情况,应该怎么办,本文采用的解决方案也就是异构索引

异构索引

即采用异步机制将原表的每一次创建或更新,都换另一个维度保存一份完整的数据表或索引表。这是另一种解决思路:拿空间换时间。

笔者再次描述该问题:

为了提高数据库性能我们将数据库根据订单维度,并使用一些算法均匀的分存到了不同的数据库集群中,但订单本身最关键的就是用户需要查自己的订单列表,此时数据根据的维度是订单,也就照成一个用户的订单数据被划分到了不同的集群中,此时如果我们想对存储在不同数据库中的数据进行聚合计算,就变得复杂/
可能读者会文,那为什么不直接用用户维度去划分数据,因为考虑到订单也有很多附属表这些附属表以订单维度存在,所以使用用户维度就不太好,也不够独立。

在这里插入图片描述

此时我们想到的是以用户编号的维度去构建一张表,即:
该表只存储关联列,以用户的编号和订单的编号做关联,用户作为划分维度,数据根据用户编号维度划分到不同的数据库,那么我们只要查询一个数据库就能查询到用户的订单列表,后续我们只需要再用订单编号去不懂的库查指定的详情即可,此表即一张索引表
在这里插入图片描述
但此时我们考虑到了一个问题,这张索引表谁来维度
这种情况下我们如果在业务代码下去操作且不说容易容易出错,还与业务代码织入在一起,这种架构设计是是否差劲的也不利于统一维护。
就此我们引入下小节的Canal作为解耦工具;

Canal

安装地址
管理界面安装地址
接管MQ

笔者安装流程

Canal一个通过伪装为Mysql的从节点,从而获取MySQL的同步数据,现被用户监听数据表记录变更,从而实现在一些业务需求下解耦
在这里插入图片描述
功能不仅限于以下:

  1. 不同数据源的数据实时同步
  2. 业务解耦
  3. 数据缓存建立

在搭建后就能收到数据

笔者安装流程

在这里插入图片描述
此时我们就可以根据不同的消息标识去做一些一些操作,从而达到解耦功能

笔者已经在自己的项目中做了一些功能如果感兴趣可以进入源码查看

学习流程

  1. Canal官网安装步骤
  2. Canal管理界面安装步骤
  3. Canal投递MQ
  4. 笔者安装流程
  5. 笔者实际项目-更新中…

结束

本文描述的不够详细,因为有些东西还是需要读者自己去官网一点点的学习,如果想深入了解希望读者可以自己搭建一次和做一
些业务操作;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
v1.8优化了超过maxUsingTime的链接的处理,(直接关闭超长链接,新建新链接放回池中),防止出现超长链接直接放回池中后原超长链接使用者仍存在此链接产生的preparedstatement并执行preparedstatement,造成此语句被超长链接的后一使用者提交。 v1.7对池中返回的所有链接做了默认setAutoCommint(true)设置。 v1.6增加了一个配置项(类似于proxool的最大连接使用时间),当一个连接的使用时间超过这个配置后将被自动回收,改连接内的内容将被自动回滚。 v1.5将整个工具包优化减少了一个Wrap包装类,减少少量内存消耗。 v1.3改进了清理线程可能出现的减少连接池中链接而不计数的问题。 v1.2处理了oracle环境下由于服务器关闭休眠链接造成的连接池循环检测进程异常退出的情况,改为当循环周期大于服务器关闭休眠链接间隔时,后台打印异常并重新连接数据库。 R2 jdbc连接池,用于java程序中jdbc连接池的配置管理,可应用于非web项目(纯java项目),全参数化配置。 应用时,先用rar打开jar包,拷贝r2.properties文件到class目录,并修改参数。 本包需要用到log4j,请在调用时确保存在log4j的jar包。 单池调用方式为Connection conn = R2PoolUtil.getStaticPool().getConnection(); conn用完后必须关闭,不然池中连接会被用完(原理:关闭conn时放回池中)。 多池调用方式为R2Pool pool1=R2PoolUtil.getPool(new File("第一个连接池的配置文件.properties")); Connnection conn1 = pool1.getConnection(); R2Pool pool2=R2PoolUtil.getPool(new File("第二个连接池的配置文件.properties")); Connnection conn2 = pool2.getConnection(); 修改源代码,请保留作者信息 张人杰 北京师范大学 计算机系 alex.zhangrj@hotmail.com 2012.01.05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值