前言
目前所在的的项目组,由于项目正在处于一个业务爆发期,每天数据的增长量已经给我们数据库乃至系统造成了很多不确定的因数,前期依靠优化业务和SQL等方式暂时还能够支撑住。但是最近发现某些表数据达到500W+以后查询统计性能严重下降,高峰时段出现了很多SQL阻塞的情况例如:
这种阻塞带来的灾难是滚雪球的,由于越堆越多基本上把数据库已经拖死,所以我们就面临数据库切分的问题。
技术选型
既然要分库分表那数据库集群是少不了的,那我们的项目怎样和这些集群打交道呢?我调研了大概分为以下几种来完成这个功能(仅仅针对java项目)
中间件 |
例如淘宝开源的cobar,以及后来开源社区根据cobar做二次开发的Mycat(个人建议如果使用中间件的话可以考虑Mycat) |
Jar形式的开源工具 |
例如淘宝的TDDL,以及当当开源出来的,Sharding-JDBC等 |
动态数据源 |
根据自己的业务来指定数据源来完成不同库和表的操作 |
给予上面三个我最后选择了估计看起来最LOW的第三种方式:我说一下我自己选择的依据:
上述开元产品中淘宝系的cobar没有维护,TDDL开源出来的和内部版本也不一样有不少BUG我们这边人力紧缺,估计没时间来爬坑。Sharding-JDBC呢,刚推出来没有项目实战经验。Mycat其实是我发现目前比较好的一个解决方案,但是mycat是给予代理模式的需要人维护,如果维护不得力,性能也不会太高,基于我们组人员的能力和我还是最终放弃了。
之所以选择动态数据源:主要是因为技术相对简单,对于业务代码修改也比较少,可控性较高,减少了加入中间件或者第三方工具所带来的风险。(申明一下我们项目完全没有使用JPA事物的,对于事物是采用的补偿机制这里就不赘述)
主键生成策略
既然要分库分表那么全局唯一主键也是我们需要考虑的问题,我所知道的和有使用经验的有如下几种技术:
问题 |
可行性 |
|
基于redis |
单点问题,redis重启问题等 |
较高,公司有项目使用 |
给予DB(每次生成多个使用时去取出来) |
单点问题,并发量问题 |
低并发,数据量较小的可以使用 |
UUID |
暂用存储空间比较大,非可排序的,体现不出增长的趋势 |
较高 |
Xx年以后可能存在重复问题,需要配置生产参数 |
高,分布式的没单点故障问题,时间上是递增的。推荐 |
|
基于DB步长的方式 |
不是所有数据库都支持 |
低 |
我选择的是snowflake。
实现细节
因为分库分表所以查询和添加都需要带上分配策略主键。
添加流程
查询逻辑
分库分表后能解决我们的性能问题,但是也带来了很多其他的问题:我总结了一下分库分表后的坑
Mysql海量数据分表分库如何列表分页?
1,可以使用ElasticSearch或者solr了。基于Lucene的解决方案
可以将mysql里的数据写入到类似hbase这样的分布式数据库,查询快。但分页、查询的话,可以在hbase前加一层solr,用于建立数据索引
2,我还想了一种思路,就是分表分库的时候根据查询条件,比如areaid,productid,userid都进行分库分表,也就是说入库的时候一共入了3份insert到3个不同的库不同的表(当然
可以优先入一个条件的库,其他2个库通过队列延时入库)。这样查询的时候可以根据条件进行查询不同的表和库。但是组合条件查询的时候也有问题。
我把我现在的项目抽出来了一个简单的模型放出来:源码我将放在git上面
https://github.com/bingzhilanmo-bowen/spring-multi-datasource