您现在的位置是:首页 > 正文

数据库之分库分表

2024-02-29 10:57:46阅读 2

中大型项目中,一旦遇到数据量比较大,我们就需要对数据进行拆分,我们知道的就是垂直和水平分两种

垂直拆分

比较简单,也就是本来一个数据库,数据量大以后,从业务角度进行拆分多个库,如下图:独立的拆分出订单库和用户库

水平拆分

是同一个业务数据量大之后,进行水平拆分

 上图中订单数据达到了4000万,我们也知道mysql单标存储推荐是百万级,如果不进行处理,mysql单表数据太大,会导致性能变慢,使用方案可以参考数据进行水平拆分,把4000万数据拆分4张表,或者更多,当然也可以进行分库,再分表,把压力从数据库层级分开

传统分库分表设计方案

分库分表方案中有常用的方案,hash取模和range范围方案,分库分表方案最主要就是路由算法,把路由的key按照指定的算法进行路由存放,下面介绍一下两个方案的特点:

1.hash取模方案

在我们设计系统之前,可以先预估一下大概这几年的订单量,如:4000万,我们每张表可以容纳1000万,我们可以设计4张表进行存储

具体如何路由存储的呢?

hash的方案就是对指定的路由key(如:id)对分表总数进行取模,上图中,id=12是订单号,对4进行取模,也是会得到0,那订单就会放到0表中,id=13的订单,取模得到为1,就会放到1表中,为什么对4取模,因为我们分表的总数是4

其实在实际中,我们的订单编号都是自动生产的,可能很难按照定增的排序,我们可以建立一个额外的字段递增进行分表

优点: 

订单数据可以均匀的放到那4张表中,这样此订单进行操作时,就不会有热点问题

热点的含义:

热点的意思就是对订单进行操作集中到1个表中,其他表的操作很少

订单有个特点就是时间属性,一般用户操作订单数据,都会集中到这段时间产生的订单,如果这段时间产生的订单,都在同一张订单表中,那就会形成热点,那张表的压力就会比较大

缺点: 

将来数据迁移和扩容,会很难

如:业务发展很好,订单量很大,超出了4000万的量,那我们就需要增加分表数,如果我们增加4个表

一旦我们增加了分表的总数,取模的基数就会变成8,以前id=12的订单按照此方案就会到4表中查询,但之前的此订单是在0表的,这样就导致了数据查不到,就是因为取模的基数产生了变化 

遇到这个情况,我们想到的方案就是做数据迁移,把之前的4000万数据,重新做一个hash方案,放到新的规划表中,也就是我们要做数据迁移,这个是很痛苦的事情,有些小公司可以接受晚上停机,但是大公司是不允许停机做数据迁移的

当前做数据迁移可以结合自己的公司业务,做一个工具进行,不过也带来了很多工作量,每次扩容都要做数据迁移 

2.range范围方案

range方案也就是以范围进行拆分数据

range方案比较简单,就是把一定范围内的订单,存放到一个表中,如上图id=12放到0表中,id=1300万的放到1表中,设计这个方案时就是前期把表的范围设计好,通过id进行路由存放

优点: 

我们想一下,这个方案是不是有利于将来的扩容,不需要做数据迁移,即使再增加4张表,之前4张表的范围不需要改变,id=12的还是在0表,id=1300万的还是在1表,新增的4张表他们的范围肯定是大于4000万之后的范围划分

缺点:

又热点问题,因为id的值会一直递增变大,那这段时间的订单是不是一直在某张表中,如id=1000万-2000万,这段时间产生的订单是不是都会集中到此表中,这个就会导致表1过热,压力过大,而其他表反而没什么压力

总结:

hash取模方案:没有热点问题,但是扩容迁移数据痛苦

range方案:不需要迁移数据,但有热点问题

那有什么方案可以做到两者的优点结合呢,即不需要迁移数据,又能解决数据热点的问题?

其实还有一个现实需求,能否根据服务器的性能以及存储高低,适当均匀调整存储呢

终极方案之思路

hash是可以解决数据均匀的问题,range可以解决数据迁移问题,那我们可以不可以两者相结合?利用这两者的特性呢?

我们考虑一下数据的扩容代表着,路由key(如:id)的值变大了,这个是一定的,那我们先保证数据变大的时候,首先用range方案让数据落地到一个范围里面,这样以后id再变大,那以前的数据是不需要迁移的

但又要考虑到数据均匀,那是不是可以在一定的范围内数据均匀的呢?因为我们每次扩容肯定会事先设计好这次扩容范围大小,我们只要保证这次的范围内数据均匀是不是就ok啦

终极方案之设计

我们先定义一个group组概念,这组里面包含了一些分库以及分表,如下图

上图有几个关键点:

1)id=0~4000万肯定落到group01组中

2)group01组有3个DB,那一个id如何路由到哪个DB?

3)根据hash取模定位DB,那模数为多少?模数要为所有此group组DB中的表数,上图总表数为10。为什么要去表的总数?而不是DB总数3呢?

4)如id=12,id%10=2;那值为2,落到哪个DB库呢?这是设计是前期设定好的,那怎么设定的呢?

5)一旦设计定位哪个DB后,就需要确定落到DB中的哪张表呢

终极方案之核心主流程 

按照上面的流程,我们就可以根据此规则,定位一个id,我们看看有没有避免热点问题。

我们看一下,id在【0,1000万】范围内的,根据上面的流程设计,1000万以内的id都均匀的分配到DB_0,DB_1,DB_2三个数据库中的Table_0表中,为什么可以均匀,因为我们用了hash的方案,对10进行取模

在我们安排服务器时,有些服务器的性能高,存储高,就可以安排多存放些数据,有些性能低的就少放点数据。如果我们取模是按照DB总数3,进行取模,那就代表着【0,4000万】的数据是平均分配到3个DB中的,那就不能够实现按照服务器能力适当分配了。

按照Table总数10就能够达到,看如何达到

 上图中我们对10进行取模,如果值为【0,1,2,3】就路由到DB_0,【4,5,6】路由到DB_1,【7,8,9】路由到DB_2。现在小伙伴们有没有理解,这样的设计就可以把多一点的数据放到DB_0中,其他2个DB数据量就可以少一点。DB_0承担了4/10的数据量,DB_1承担了3/10的数据量,DB_2也承担了3/10的数据量。整个Group01承担了【0,4000万】的数据量

 

注意:千万不要被DB_1或DB_2中table的范围也是0~4000万疑惑了,这个是范围区间,也就是id在哪些范围内,落地到哪个表而已。

 上面一大段的介绍,就解决了热点的问题,以及可以按照服务器指标,设计数据量的分配。

终极方案之如何扩容

其实上面设计思路理解了,扩容就已经出来了;那就是扩容的时候再设计一个group02组,定义好此group的数据范围就ok了。

 

因为是新增的一个group01组,所以就没有什么数据迁移概念,完全是新增的group组,而且这个group组照样就防止了热点,也就是【4000万,5500万】的数据,都均匀分配到三个DB的table_0表中,【5500万~7000万】数据均匀分配到table_1表中。

终极方案之系统设计

 思路确定了,设计是比较简单的,就3张表,把group,DB,table之间建立好关联关系就行了。

group和DB的关系

table和db的关系

 

上面的表关联其实是比较简单的,只要原理思路理顺了,就ok了。在开发的时候不要每次都去查询三张关联表,可以保存到缓存中,这样不会影响性能

这里面隐含了一个关键点:那就是路由key(如:id)的值是非常关键的,要求一定是有序的,自增的 

网站文章

  • 5、操作元素

    5、操作元素

    5、操作元素 JavaScript的 DOM 操作可以改变网页内容、结构和样式,我们可以利用 DOM 操作元素来改变元素里面的内容、属性等。(注意:这些操作都是通过元素对象的属性实现的) 1. 改变元素内容(获取或设置) innerText改变元素内容 显示当前系统时间 某个时间 123

    2024-02-29 10:57:15
  • JDK与CGLIB动态代理复习笔记

    JDK与CGLIB动态代理复习笔记

    目录 JDK动态代理(基于Proxy和InvocationHandler) 代理接口代码 代理类的代码 究其原理 Cglib动态代理(基于Enhancer和MethodInterceptor) 代理接...

    2024-02-29 10:57:07
  • Linux升级GCC清晰简明教程

    前言: 这次我在Ubuntu 12.04 LTS 64位版上更新gcc,发现了原来的一些问题,这次没有什么时间上的压力,我比较认真地去查阅了官方文档,也参考了一些网上的帖子,对整个升级过程在依赖包的安装、不同Linux流派、32和64位下的区别和共同点有了更深的认识。 现总结如下: PS:不标注出处的转载是可耻的。 (如果你很忙的话,可以只把里面的shell代码复

    2024-02-29 10:56:59
  • V4L2编程框架(*)

    V4L2编程框架(*)

    <br />V4L2编程框架(*)2009年2月17日zooyoo发表评论阅读评论<br />V4L2较V4L有较大的改动,并已成为2.6的标准接口,函盖video/dvb/FM…,多数驱动都在向V4...

    2024-02-29 10:56:30
  • RHCE(2)

    RHCE(2)

    2.查看文件,将 id_rsa.pub 文件追加到授权的authorized_keys,重启服务。

    2024-02-29 10:56:25
  • Centos7 使用ssm调整lvm下目录空间

    Centos7 使用ssm调整lvm下目录空间

    起因今天在安装centos7的时候分区选的自动lvm分区,然后在装完系统后发现,大部分空间放到了/home ,而/ 分区的空间少的可怜!!!不能忍!!PS:使用本方法时需要注意:centos7刚安装完...

    2024-02-29 10:56:18
  • html实现照片添加功能,HTML5 Canvas调用手机拍照功能实现图片上传功能(图文详解上篇)...

    这篇文章主要为大家详细介绍了HTML5 Canvas,和jquery技术,调用手机拍照功能实现图片上传,具有一定的参考价值,感兴趣的小伙伴们可以参考一下因为最近一段时间,一直在弄微信项目,其中涉及到了...

    2024-02-29 10:55:44
  • 嵌入式常见的段错误死机原因之一strlen函数

    在做嵌入式产品常见死机原因有很多种,其中之一就是strlen函数引起的。这个函数大家不会陌生,学c语言最基本的函数了,但在实际使用中偶尔不小心还是可能会引起段错误造成死机的。为什么呢? 函数原型:un...

    2024-02-29 10:55:33
  • Django使用apscheduler写定时任务遇到 django.db.utils.OperationalError: (2006, ‘Server has gone away‘)

    Django使用apscheduler写定时任务遇到 django.db.utils.OperationalError: (2006, ‘Server has gone away‘)

    ORM语句打开数据库连接太多未能及时关闭造成

    2024-02-29 10:55:03
  • linux下执行shell脚本,提示Command not found解决办法

    在Linux下运行shell脚本时,经常会遇见Command not found的问题,对于这类问题,基本上可以归类为以下原因: 1、忘记在脚本第一行加上#!/bin/bash或者#!/bin/s shell一种解释性语言,和编译语言不同的是它需要解释器来解释运行,脚本的第一行指定了解释器的位置和类型,没有这一句的话,脚本无法解释也就无法运行。有的脚...

    2024-02-29 10:54:55