分享

记录一次经历的数据库从单库到分库分表的过程

 cjiemen 2017-11-19

 

前言

   目前所在的的项目组,由于项目正在处于一个业务爆发期,每天数据的增长量已经给我们数据库乃至系统造成了很多不确定的因数,前期依靠优化业务和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

暂用存储空间比较大,非可排序的,体现不出增长的趋势

较高

twitter snowflake

Xx年以后可能存在重复问题,需要配置生产参数

高,分布式的没单点故障问题,时间上是递增的。推荐

基于DB步长的方式

不是所有数据库都支持

  我选择的是snowflake。

 

实现细节  

   因为分库分表所以查询和添加都需要带上分配策略主键。

添加流程


查询逻辑



分库分表后能解决我们的性能问题,但是也带来了很多其他的问题:我总结了一下分库分表后的坑

1.分完之后只能直接按分片键查询,为了避免扫所有分片,如果按非分片键查询,在OLTP环境中得走搜索引擎。数据库和搜索引擎同步数据靠binlog
2.按不同维度查询,比如买家维度和卖家维度查订单。除了走搜索引擎之外,还可以在不同的系统中各写一条订单数据。
3.ID得通过ID生成器。
4.有热点数据问题,比如一个超级买家,买了好多种商品,然而还有不怎么热的买家,没什么订单。解决方法两种,热点数据拿出来放到单独的系统。或者按数据块分片,比如十种商品算一个块,但这种方法具体细节我忘了,只是听人分享过。
5.跨库事务问题,NPC一般不用,补偿是一种方法,TCC是一种方法,TCC的变种,比如SAGA比如XTS,努力送达是一种方法
6.数据扩展问题,可以看看阿里的愚公。我个人觉得还半夜停机维护比较靠谱。
7.分页的坑,前期可以用中间件Limit,中期得走搜索引擎,后期OLAP
8.可用性问题,依赖数据库高可用方案。据说会出现 sharding 算法 会因为网络抖动 造成部分分区错误 导致片出问题
9.配置中心问题。尽量使用配置中心,不要用zookeeper
10.非代理模式,就是JDBC路由模式 每个client都会对 db开启pool ,数据库可能会死在数据库连接上,一种方法是定制
Mysql,设置高低水位,让超过数据库处理能力的数据库连接排队。第二种方法是在JDBC路由模式之上做Mysql的Proxy

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多