数据库【分库分表】

一、场景

       由于用户数量越来越大会出现以下问题:

  1. 订单量剧增,单表数据量已经达到了千万的级别了,这个时候的索引查询已经很慢了,所以现在我们的类似这些大数据表的查询性能很差。
  2. 数据量持续增加,现在我们的磁盘大部分空间都被使用,导致数据库的复制备份操作很缓慢,所以,目前数据库系统已不能满足现在的数据量级。
  3. 我们整个系统的所有业务,订单,用户,优惠券、政策等等都在一个数据库系统,耦合性太高,数据不隔离。
  4. 像每天大量的用户关注、行为数据以及订单数据的写入,导致系统的写入性能持续下降。

      以上问题均是由于打冰法的写入操作导致目前的系统读写性能下降,并且系统可用性也在降低,这些就需要将这些数据进行分片,均摊我们整个数据库的压力,同时解决单机数据容量以及性能的问题。业界比较流行的方法就是分库分表方案。

二、垂直拆分

       垂直切分,就是将表按列竖着拆分。不同的数据库对应不同的业务,比如我们可以将用户相关的表放到用户数据节点里,订单相关的表放到订单数据节点,关注相关的表放到关注数据库节点。好处就是,关注数据库庞大到了几亿的量级如果影响到了数据的操作,但是并不影响用户的登录和浏览、搜索和下单操作,起到了很好的数据隔离作用。

       【例子】

        以前,我们用户表、关注表、订单表都在同一个库里面,也就是在我们的主库中,后来经过拆分后,它们分别被拆到用户库、关注库、订单库等。

              

        小结:垂直拆分这种方案,其实在我们中等规模的互联网公司里都会首先使用到,但是,随着数据的增加,这种单库里面的表还是会面临瓶颈的,如关注表数据,虽然拆到了关注库里面,但是关注表数据都已经好几亿了,仍是会影响我们这块业务的。所以说,垂直拆分只能暂缓我们的问题,但是,像那种单表数据骤增的情况还是需要采取另一种方法的,那就是我们下面要说的水平拆分。

 三、水平拆分

        水平拆分,就是按列拆分,减少单表的数量值。

        3.1、有哪些拆分规则

                1、 按照表中某一字段取哈希值进行拆分,例如我们的用户表,如果将其拆分为16个库,每个库64张表,那么,我们就将UID哈希,为什么哈希大家知道吧,前面文章分析了hashmap,应该都懂吧。然后将哈希值对16取余,得到哪一个数据库,然后对64取余就知道哪个表。这种规则比较适用于这种实体类的表。

                                 

              2、按照某一个表字段的区间做拆分,这里最常使用就是日期字段了,比如我们关注表的创建时间,比如我们要查某个月的关注数据,就可以将月份数据放进对应月份表中,这样我们就可以根据创建时间来定位到我们数据存储在哪张表里面,然后在根据我们的查询条件进行相应的查询。 

                              

        3.2、小结

                 分库分表后,虽然解决了数据库瓶颈,并发写入和读取的问题,也解决了扩展和数据隔离的问题,但是引入了分库分表,也会带来一些问题。

四、解决分库分表带来的问题

       4.1、分区键

               分区键就是我们用来进行分库分表的字段,我们每次查询的时候都必须得带上这个字段,才能找到数据所在的库和表,我们将上面用户数据按照uid进行分库分表的,那如果现在我想按照昵称来查询怎么办呢。

  1. 建议另外建立一张UID和昵称的映射表。
  2. 通过昵称查询出UID。
  3. 通过UID就可以进行定位库和表。

      4.2、多表JOIN

               我们现在的单表数据都被分到多库多表中了,然后有些程序员之前写的那些连表join 操作怎么办,跨库了,就不能使用JOIN了。所以这块我们需要将他们放到我们业务代码中进行处理了,其实代码中处理我们会更清晰一些 。 

      4.3、统计类

               和上面JOIN类似,类似统计的count()就不能使用了,然后这块我们建议是,通过另外建一张表或者放到redis缓存里面,最后再合并就行了,也很简单。        

      4.4、最后建议

               在我们的业务中不要一开始就去分库分表,在没必要的情况下不要去分库分表;如果真的要分库分表,在公司资源充足下,建议一次性分到位,会给你很爽的感觉,比如分16个库64张表,资源紧缺的话,我们就根据业务来分。

五、数据迁移问题

       5.1、停机部署

               【步骤】:

  1.  公告停机。
  2. 写一个后台程序,该程序用以从我们的旧数据库中查询出所有数据,通过之前制定的分库分表策略,家长数据库中间件,用嵌入代码 shadding-jdbc或者代理层的Mycat也可以,将这些数据进行hash路由到我们的新分的库表中去。
  3. 等迁移到新的分库分表的表中  ,再将我们的线上代码数据资源配置进行修改成链接我们的数据库中间件上,最后再重新启动服务。         

                        

 

                【缺点】:

                               1、系统必须进行停机一段时间。

                               2、如果在规定的一段时间内并未完成数据的迁移,就需要回滚,重新切回原库。

                               3、开发人员比较疲惫。

          5.2、不停机部署

                  在线双写。

              【步骤】:

  1.  在写旧数据库同时,也写一份数据到新的库表;
  2. 同时写一个后台数据迁移程序,将我们的旧库数据,通过数据库中间件迁移到新的多库表中;
  3. 迁移过程中,每次插入数据,需要检测数据的更新情况。如果新表中没有当前数据,则直接新增;如果有,则更新为当前数据,只允许新数据覆盖旧数据。
  4. 经过一轮后,校验新旧两边数据是否一样。
  5. 如此反复跑几天后,新旧数据库就会相同,最后观察数据正常后,就可以停止旧库的写入操作了。                                                                  

                            

六、动态扩容缩容

      【核心思想】

        如果不用分库分表就坚决不用,如果实在要用分库分表,就要一次性分到位,目的就是防止出现扩容问题。比如32*32的规模。

      6.1、扩容的原因

               1、数据库并发瓶颈。当前数据库服务器伴随业务发展,相关请求并发已经超过现有的并发范围;

               2、现有的库表数据已经快满了,数据装不下,又到了上亿的数据量级,服务器磁盘容量也不够存储使用,需要扩容了。

      6.2、流程

               1、首次分库分表时,一次性分为32*32,即分成32个库,然后每个库32张表。

               2、现有4台数据库服务器,可只每台服务器上搭建8个MySql数据库实例,每个库32张表。

               3、伴随公司业务发展,4台服务器达到了并发或者磁盘瓶颈,这时候如果要对其进行拆分,直接动态扩容。就需要再扩容4台机器出来(公司业务这么好,还说没有资源,那就说不过去了),将之前的每台数据库服务器上数据库分出一半到新数据库服务器上,即现在一共有8台数据库服务器,然后每台服务器分4个数据库,每个数据32张表。

               4、如果业务继续上升,又需要扩容,就按上面的逻辑来动态扩容,在不用动业务代码的情况下,可以扩展到32台服务器,每台放一个数据库,可以支撑多年使用了。

                           

             动态扩容优点:

  1.  节省开发人员时间,扩容过程简单。
  2. 不用再哈希路由,直接整个数据库移动,原有数据库压根不用动。
  3. 提高并发性能。
  4. 提高磁盘利用率。

             建议:

             hash路由表的时候,如果只是hash表32的话,会有可能不太均匀,建议大家hash的时候,先对32取整,然后在对32取余即可。

           1、路由库:ID % 32

           2、路由表:ID /  32,然后得到的整数 % 32

              

 七、优化

        每次扩容就全量迁移,公司几千万上亿的数据量,一次扩容浪费太多的资源,每次按需扩容数据又运行的太慢,同事轮流值班,一个报错全部回滚,直接扯淡,真心不想全量迁移。如何搞?

        7.1、Hash一致性算法

                 采用hash环或者hash槽等方式,具体参考:算法--hash取模 - 木乃伊人 - 博客园 (cnblogs.com)

        7.2、工具

                1、sharding-sphere:jar,前身是 sharding-jdbc

                2、TDDL:jar,Taobao Distribute Data Layer

                3、Mycat:中间件

               注意:工具执行调研,官网和社区优先。

八、分库分表步骤

       1、根据容量(当前容量和增长量)评估分库或分表个数;

       2、选key(均匀);

       3、分表规则(hash或range等);

       4、执行(一般双写);

       5、扩容问题(尽量减少数据的移动)。

 

 

 

               

 

posted on 2023-10-30 17:20  木乃伊人  阅读(28)  评论(0编辑  收藏  举报

导航