本文主要记录本周的学习内容,搭建mysql的高性能数据库服务
源于
现最多被使用的数据库还是Msql,而MySQL本身不是一种分布式型数据库,在高性能要求下,简单的主从、复制已无法满足高性能要求。
而本文主要在提供读者一种高性能方案。
主要进入角度在于分库,将数据按指定的维度进行分库处理。
为什么
试想你有一台数据库你为了希望它高可用你部署了主从,在意外情况下可以切换到从库。为了提高性能你又使用了读写分离,但你发现性能还是不够因为主要的写库还是只有一台,然后你想做到集群化部署,不搞什么读写了,将数据分批放到不同的数据库中,其数据库之间不关联,性能也是独立的。两台性能+2、三台性能+3,就此性能问题解决了。
但实际上想要实现这样子分库并没有那么简单,需要借助一些中间件实现
选择
现有适用与MySQL的分库分表实现方案,主要有以下两种类型,其区别主要在于是否置入应用、独立应用的数据库上层代理
-
JDBC直连层
-
Proxy 代理层
主要代表方案 :
方案 | 类型 | 描述 |
---|---|---|
Sharding-JDBC | JDBC直连层 | 现比较常用的方案,其织入应用维护成本较底,但统一管理变的麻烦-后续已经支持集群proxy方案 |
mycat | Proxy 代理层 | 需要独立部署,无疑加大了维护成本适用于大规模的开发 |
Sharding-JDBC
笔者这里不介绍Sharding-JDBC的实现,希望读者自行去点标题进入官网了解它能做些什么, 笔者已经把能直接运行的项目放到了👉gitee👈,方便读者学习
在我们对数据的数据进行分片后,订单数据已经成功的根据不同的订单号进入了不同的数据库了,但出现了一些问题,我希望查询用户Id是2的订单数据,但出现在了两个数据库中,我的sql应该怎么写;
select * from table_name where user_id=2;
现在这样子写还可以吗
不出意外的出现了异常,因为我们的数据划分是通过订单号,也就是说我们提供Sharding-JDBC一个订单号然后它去更具规则算出它在那个数据库中,但是如果我们没有提供订单号的查询,它无法进行判断,那此类sql就会变成整个集群的查询,此类查询不出意外的被拦截了,当然我们也可以关闭拦截,但关闭了拦截我们的分库就毫无意义(还是变成了全库扫描查询)。
分库后会出现以下问题
- 分库分表的算法 : 以什么条件作为分法,是否兼容后续数据库扩容
- 分库分表ID问题 : 多库如果用自增编号,会出现重复编号
- 分库分表后的事务 : 多库之间的分布式事务问题
- 多表联合查询/多维度 : 数据分布在不同的数据库中怎么做order by、group by等等
问题一 : 分库分表的算法
- 通过对order_id取模 : 取模的方案固然最简单,但在后续的扩容取模数+1会导致旧数据已经分配出去的,无法查询;
- 一致性哈希:当然还有其他方案,这里就直接告诉读者比较优解,该方案也是redis采用的,算法比较复杂,但如其名无论追加集群也不会导致order_id计算结果;
问题二:分库分表ID问题
通常我们单机应用的时候,我们完全可以采用主键自增,但在分布式集群的情况下,如果还使用自增那会出现不同库中自增的编号一样,也就是两个库的表里都会出现编号为1的数据,这种重复编号的出现十分破坏原子性,当然解决方案也是非常多,常见的雪花、美团的leaf、uuid等等都可以作为分布式id生成方案
问题三: 分库分表后的事务
在单机下我们的数据都在一个数据库中,MySQL会帮助我们管理事务,多表的修改可以统一的回滚,但分布式下不同数据库的事务并不互通,此时我们可以引入分布式XA事务解决方案
问题四:多表联合查询/多维度
也是本文的关键,如果我想在订单表下用用户维度查询,也就是上图的情况,应该怎么办,本文采用的解决方案也就是异构索引
异构索引
即采用异步机制将原表的每一次创建或更新,都换另一个维度保存一份完整的数据表或索引表。这是另一种解决思路:拿空间换时间。
笔者再次描述该问题:
为了提高数据库性能我们将数据库根据订单维度,并使用一些算法均匀的分存到了不同的数据库集群中,但订单本身最关键的就是用户需要查自己的订单列表,此时数据根据的维度是订单,也就照成一个用户的订单数据被划分到了不同的集群中,此时如果我们想对存储在不同数据库中的数据进行聚合计算,就变得复杂/
可能读者会文,那为什么不直接用用户维度去划分数据,因为考虑到订单也有很多附属表这些附属表以订单维度存在,所以使用用户维度就不太好,也不够独立。
此时我们想到的是以用户编号的维度去构建一张表,即:
该表只存储关联列,以用户的编号和订单的编号做关联,用户作为划分维度,数据根据用户编号维度划分到不同的数据库,那么我们只要查询一个数据库就能查询到用户的订单列表,后续我们只需要再用订单编号去不懂的库查指定的详情即可,此表即一张索引表
但此时我们考虑到了一个问题,这张索引表谁来维度
这种情况下我们如果在业务代码下去操作且不说容易容易出错,还与业务代码织入在一起,这种架构设计是是否差劲的也不利于统一维护。
就此我们引入下小节的Canal作为解耦工具;
Canal
Canal一个通过伪装为Mysql的从节点,从而获取MySQL的同步数据,现被用户监听数据表记录变更,从而实现在一些业务需求下解耦
功能不仅限于以下:
- 不同数据源的数据实时同步
- 业务解耦
- 数据缓存建立
在搭建后就能收到数据
此时我们就可以根据不同的消息标识去做一些一些操作,从而达到解耦功能
笔者已经在自己的项目中做了一些功能如果感兴趣可以进入源码查看
学习流程
结束
本文描述的不够详细,因为有些东西还是需要读者自己去官网一点点的学习,如果想深入了解希望读者可以自己搭建一次和做一
些业务操作;