返回介绍

10.4 数据库拆分(分布式)

发布于 2024-09-26 01:08:01 字数 4119 浏览 0 评论 0 收藏 0

垂直/水平拆分(分库分表)

首先进行垂直切分,按照表的内容将不同的表划分到不同的数据库中。(业务内容切分)

然后是水平切分,根据用户的 ID 将不同用户的内容再划分的不同的数据库中。

通过某种特定的条件,将存放在同一个数据库中的数据分散存放到多个数据库上,实现分布存储,通过路由规则路由访问特定的数据库,这样一来每次访问面对的就不是单台服务器了,而是 N 台服务器,这样就可以降低单台机器的负载压力。

  • 垂直( 纵向) 拆分 :是指按功能模块拆分,比如分为订单库、商品库、用户库…这种方式多个数据库之间的表结构不同。

  • 水平(横向) 拆分:将同一个表的数据进行分块保存到不同的数据库中,这些数据库中的表结构完全相同。

    image-20191201160925848

图 表结构不同的 垂直(纵向) 拆分

image-20191201161009520

图 表结构相同的水平(横向) 拆分图

垂直(纵向) 拆分

1, 实现原理 :使用垂直拆分,主要要看应用类型是否合适这种拆分方式,如系统可以分为,订单系统,商品管理系统,用户管理系统业务系统比较明的,垂直拆分能很好的起到分散数据库压力的作用。

业务模块不明晰,耦合(表关联)度比较高的系统不适合使用这种拆分方式。但是垂直拆分方式并不能彻底解决所有压力问题,例如有一个 5000w 的订单 表,操作起来订单库的压力仍然很大,如我们需要在这个表中增加(insert)一条新的数据,insert 完毕后,数据库会针对这 张表重新建立索引,5000w 行数据建立索引的系统开销还是不容忽视的,反过来,假如我们将这个表分成 100 个 table 呢,从 table_001 一直到 table_100,5000w 行数据平均下来,每个子表里边就只有 50 万行数据,这时候我们向一张只有 50w 行数据的 table 中 insert 数据后建 立索引的时间就会呈数量级的下降,极大了提高了 DB 的运行时效率,提高了 DB 的并发量,这种拆分就是横向拆分

2, 实现方法 :垂直拆分方式实现起来比较简单,根据表名访问不同的数据库就可以了。

水平(横向) 拆分

(1) 顺序拆分 :如可以按订单的日前按年份才分,2003 年的放在 db1 中,2004 年的 db2,以此类推。当然也可以按主键标准拆分。

优点:可部分迁移

缺点:数据分布不均,可能 2003 年的订单有 100W,2008 年的有 500W。

(2) hash 取模分 : 对 user_id 进行 hash(或者如果 user_id 是数值型的话直接使用 user_id 的值也可),然后用一个特定的数字,比如应用中需要将一个数据库切分成 4 个数据库的话,我们就用 4 这个数字对 user_id 的 hash 值进行取模运算,也就是 user_id%4 ,这样的话每次运算就有四种可能:结果 为 1 的时候对应 DB1;结果为 2 的时候对应 DB2;结果为 3 的时候对应 DB3;结果为 0 的时候对应 DB4,这样一来就非常均匀的将数据分配到 4 个 DB 中。

优点:数据分布均匀

缺点:数据迁移的时候麻烦;不能按照机器性能分摊数据 。

(3) 在认证库中保存数据库配置

就是建立一个 DB,这个 DB 单独保存 user_id 到 DB 的映射关系,每次访问数据库的时候都要先查询一次这个数据库,以得到具体的 DB 信息,然后才能进行我们需要的查询操作。

优点:灵活性强,一对一关系

缺点:每次查询之前都要多一次查询,会造成一定的性能损失。

分库分表的主要问题

  • ACID 原则:保证数据一致性,如 Binlog(二进制日志)、
  • 多表之间的关联查询
  • 无法使用外键约束
  • 无法使用全局 ID,如 Oracle 的 Sequence、MySQL 的 AUTO_INCREMENT 自增 ID。

Sharding 中间件

MySQL Cluster 和 MySQL Sharding

  • MySQL Cluster 是数据库集群,主要用于提升数据库的并行处理能力。
  • MySQL Sharding 是分片,不仅可以提升数据库的并行处理能力,还解决单表数据量大的问题。

表格 48 Sharding 中间件比较

功能CobarMyCatTDDLShark
是否开源部分
架构模型ProxyProxy应用集成应用集成
数据库支持MySQL任意MySQL、OracleMySQL
外围依赖Diamond
读写分离
分库分表

分库分表示例

1)根据用户 ID(简称 uid)进行分库分表

根据 uid 计算数据库、表编号: (表数 TBL_NUM 固定为 10,数据库数 DB_NUM 可取任意值,为 2 的整数指数倍~4/8/16/32/64)

  • 数据库编号(分库号) = (uid / TBL_NUM) % DB_NUM + 1
  • 表编号(分表号) = uid % TBL_NUM (0~9)

当 uid=9527 时,根据上面的算法,其实是把 uid 分成了两部分 952 和 7,其中 952 模 8 加 1 等于 1 为数据库编号,而 7 则为表编号。所以 uid=9527 的订单信息需要去 DB1 库中的 order_7 表查找。

分库分表信息存储字节数

  • 分库 DB_NUM <=10:1(分库)+1(分表)= 2byte
  • 分库 DB_NUM >10:2(分库)+1(分表)= 3byte

使用 DB_NUM= 64 来做冗余分库信息。 实际库编号=(数据库编号- 1) % 8 + 1

如上例: uid=9957 ,分库号 57,分表号 7,分库分表存储为 577 ,实际分库号需二次计算得 (57-1)%8+1=1

2)订单 ID 结构

订单为全局唯一。

版本号分库分表信息timestamp机器号自增序列号
     

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文