Mysql高可用高性能存储应用系列4 - 分库分表、中间件

2023-10-27

概述

为什么要分库的原因:1)很多时候接口性能慢都是数据库造成的,2)并发量比较大时,大量的数据库请求,会带来磁盘I/O的性能瓶颈,3)来越多,导致sql查询数据,即使走了索引也比较慢。

分库分表的场景

分库和分表是不同的两个概念,解决的问题也不同。

  • 并发量很大,但数据量比较小,可以只分库,不分表。
  • 并发量不大,但数据量比较大,可以只分表,不分库。
  • 并发量很大,数据量也比较多时,既要分库,也要分表。

垂直分库分表

分库垂直分库,针对一个系统的不同业务进行拆分,比如:用户拆到User库,文章拆到Novel库,拆分后放到不同的服务器上,在高并发一定程度能够给解决I/O链接数,硬件资源瓶颈等。

垂直分表

垂直分表,整体策略就是大表拆小表,基于表中字段拆分,将不常用的,数据较大的拆分到扩展表,一般针对几百列的大表进行拆分。

特点:

  • 每个库/表的结构都不一样
  • 每个库/表的数据至少一列一样
  • 每个库/表的并集是全量数据

垂直拆分:

优点:拆分后业务清晰,数据维护简单,按照业务放到不同的服务器中。

缺点:

  • 单表数据量大时,写读压力大
  • 受业务影响,热门业务压力大,冷门业务造成资源浪费。

比如我们常用的user表,由2部分主要的功能组成,用户和密码主要是用来鉴权用户,一部分是展示用户信息,这个表就可以拆分成2个表。

mysql> desc user;
+----------------------+---------------------+------+-----+------------+----------------+
| Field                | Type                | Null | Key | Default    | Extra          |
+----------------------+---------------------+------+-----+------------+----------------+
| user_id              | int(4)              | NO   | PRI | NULL       | auto_increment |
| user_name            | varchar(16)         | NO   | MUL | NULL       |                |
| user_psw             | varchar(50)         | NO   |     | NULL       |                |
| user_status          | tinyint(1)          | NO   |     | 1          |                |
| user_display         | tinyint(4)          | NO   |     | 1          |                |
| user_nickname        | varchar(50)         | YES  | MUL | NULL       |                |
| user_email           | varchar(50)         | NO   | MUL | NULL       |                |
| user_qq              | varchar(15)         | YES  |     | NULL       |                |
| user_tel             | varchar(18)         | YES  | MUL | NULL       |                |
| user_sex             | int(1)              | NO   |     | 1          |                |
| user_birthday        | date                | NO   |     | 1991-10-24 |                |
| user_head            | varchar(200)        | NO   |     | NULL       |                |
| user_sign            | varchar(225)        | NO   |     | NULL       |                |
| user_ticket_act      | int(11)             | NO   |     | 0          |                |
| user_gold2           | decimal(12,3)       | NO   |     | 0.000      |                |
| user_gold2_frozen    | int(11)             | NO   |     | 0          |                |
| user_ticket_rec      | int(11)             | NO   |     | 0          |                |
| user_ischarge        | tinyint(1)          | NO   |     | 0          |                |
| user_exp             | int(4)              | NO   |     | 0          |                |
| user_browse          | int(4)              | NO   |     | 0          |                |
| user_logintime       | int(4)              | NO   |     | 0          |                |
| user_regtime         | int(4)              | NO   | MUL | 0          |                |
| user_regip           | varchar(15)         | NO   |     | 0.0.0.0    |                |
| user_displaytime     | int(4)              | NO   |     | 0          |                |
| user_nickname_before | text                | YES  |     | NULL       |                |
| user_auth            | tinyint(1)          | NO   |     | 0          |                |
| delete_time          | int(11)             | NO   |     | 0          |                |
| refresh_token        | varchar(50)         | NO   |     |            |                |
| nation_code          | int(10) unsigned    | NO   |     | 86         |                |
| credit               | int(11)             | NO   |     | 0          |                |
| close_time           | int(10) unsigned    | NO   |     | 0          |                |
| finance_id           | int(11)             | NO   |     | 0          |                |
| user_underage_status | tinyint(1)          | NO   |     | 0          |                |
| attr_limit           | varchar(20)         | NO   |     | NULL       |                |
| identity             | tinyint(3) unsigned | NO   |     | 1          |                |
+----------------------+---------------------+------+-----+------------+----------------+
35 行于数据集 (0.08 秒)

水平拆分分库分表

  • 水平分表,针对数据量巨大的单表,按照某种规则,拆分到多个表中,但是这些表还是在一个库中。
  • 水平库分表,按照某种规则,把拆分的表再拆到不同的库中去。

水平分库的分表规则

  • RANGE, 按照范围拆分,比如0-10000一个表,10001到20000一个表
  • HASH取模,比如通过用户ID取模,然后分配到不同的库表中。
  • 地理区域,比如按照华北,东北等区域区分。
  • 时间拆分,比如将6个月前的数据拆出去放到一张表,随着时间的流逝,这些表的数据查询的几率很小,这也是冷热数据分离。

水平拆分

优点:

  • 单库/表的数据减少,有利性能
  • 库/表结构相同,程序改动小

缺点:

  • 数据库扩容难度大,比如取模值变了

水平拆分的好处在于使用一个业务场景的划分值,比如user_id进行取模进行分表,但是在后台管理数据的时候会遇到一个问题,数据聚合和保持一致性的问题,比如我们现在业务中的评论数据就很多,user_id 对 128进行取模,再后台管理的时候,把数据再存储在MongoDB中一份做数据管理使用,所有的方法都会有优缺点的,看你怎么设计更符合业务场景。

一致性Hash算法

普通取模方法

根据10取模,数据1保存到节点上,数据2保存在节点2上,当节点数发生变化,分子发生了变化,需要同步旧数据的值。

一致性Hash算法

  • hash值是非负的整数,值的范围构成一个圆环,值为2^32
  • 集群节点按照一定的规则求hash值,然后放在环中
  • 对数据K求hash值,然后放入环中,在按照顺时针方向找到最近的节点,保存到上面

一致性Hash算法是怎么解决节点上的存储不均的情况呢?

在节点上创建虚拟节点,让虚拟节点对应真实节点,让数据的存储尽量均衡,这样就解决了数据不均的情况。

当添加新节点时,在普通取模算法中会影响到其他数据,而在一致性Hash算法中,首先会停止服务,防止数据乱掉,先把属于新增节点D的数据迁移到D节点中,然后添加节点,放入环中,启动服务。

当移除节点时,首先停止服务,把D节点移除之后,根据顺时针原则,把属于D节点的数据迁移在节点A上,把D节点服务移除,启动服务,整个节点受到影响的只有D节点的数据,不会影响其他的服务节点。

中间件

中间件的范围比较笼统,我理解的中间件就是在数据处理流程里,加入了一层逻辑处理,用规定好的规则下发在下一个流程中,主要介绍Mysql的2种中间件,ShardingSphere(直连模式) 和 MyCat(代理模式)。

  • ShardingSphere:Jdbc直连,相当于增强JDBC包,对所有的数据库操作语句按照特定的要求分发到不同的库中,这部分操作在jdbc中直接完成了。
  • MyCat:proxy代理,把sql发送给代理服务,代理服务去数据库完成相应的操作后再返回给web应用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mysql高可用高性能存储应用系列4 - 分库分表、中间件 的相关文章

  • 在 PHP 字符串中格式化 MySQL 代码

    是否有任何程序 IDE 可以在 PHP 字符串中格式化 MySQL 代码 例如 我使用 PHPStorm IDE 但它无法做到这一点 它对 PHP 和 MYSQL 执行此操作 但不适用于 php 字符串内的 MYSQL 我已准备好使用新的
  • 一次从多个表中删除行

    我正在尝试将 2 个查询合并为一个这样的查询 result db gt query DELETE FROM menu WHERE name new or die db gt error result db gt query DELETE F
  • 在 MySQL 中存储表情符号的编码问题:如何使用 Prisma ORM 在 NodeJS 中定义字符排序规则?

    亲爱的 Nodejs 专家和数据库专家 我们在 MySQL 数据库中存储表情符号和其他特殊字符时遇到问题 我们使用 Prisma 得到一个错误 这是我们使用的 ORM 参数无法从排序规则 utf8 general ci 转换为 utf8mb
  • 在mysql中的单个查询中更新多个表

    我有三个查询 我想要一个 这是我的查询 UPDATE tab1 SET a WHERE id 3 UPDATE tab2 SET b WHERE id 9 UPDATE tab3 SET c WHERE id 5 您可以尝试下面的代码 UP
  • Galera 集群问题

    我想在我们的生产环境中使用Galera集群 但我有一些顾虑 每个表必须至少定义一个显式主键 每个表必须运行在InnoDB或XtraDB存储引擎下 分批处理您的大额交易 例如 不要让一个事务插入 100 000 行 而是将其分成更小的块 例如
  • 在 C# 中,当有人插入、删除或修改记录时,如何从 MySQL 获取事件?

    我正在 WPF Net 中开发一个程序 我需要知道何时有人对数据库的任何表进行更改 这个想法是在数据库发生更改时从数据库接收一个事件 我读了很多文章 但找不到解决我的问题的方法 亲切的问候 最好的解决方案是使用消息队列 在您的应用程序向数据
  • covertJSONtoSQL 在 NiFi 中返回空值

    我正在设计一项工作 使用以下命令将数据从 MySQL 中的数据库转移到另一个数据库 MySQL 执行SQL处理器随后将Avro转换为Json then 将Json转换为SQL then PutSQL如下流程图所示 将JSON转换为SQL返回
  • 在 MySQL 中对整数字段运行带引号的数字(字符串)查询时会发生哪些复杂情况

    在 SQL 中 不应引用整数 因为如果引用 它将是一个字符串 但我很好奇如果我这样做会出现什么问题 并发症 例如 SELECT FROM table WHERE id 1 正确的 vs SELECT FROM table WHERE id
  • MySQL“LIKE”搜索不起作用

    我通过 LOAD DATA INFILE 在 MySQL 中导入了一个 txt 数据库 一切似乎都正常 唯一的问题是 如果我使用以下查询在数据库上搜索记录 SELECT FROM hobby WHERE name LIKE Beading
  • mysql 中的二进制、十六进制和八进制值

    我对在 mysql 数据库中使用二进制 十六进制和八进制系统非常感兴趣 首先 请给我一个建议 为什么我们在存储信息时需要它们 因为信息太多 或者为什么 另外 哪种类型的值必须存储在标记系统中 另外这里还有像 这是例子 gt SELECT 5
  • 非常大的字段会对 MySQL 数据库产生负面影响吗?

    我目前正在使用 Django 构建一个网站 并希望托管用户生物样式页面 该页面可能长达几 KB 这些字段不一定需要搜索 但在查找用户名时确实需要提供 将这些数据存储在数据库中会产生负面影响吗 如果我使用带有数据库链接的静态文本文件 我的服务
  • Mysql用in语句限制

    我正在写一个查询 SELECT user bookmarks id as user bookmark id bookmark id user bookmarks user id bookmark url bookmark website b
  • MYSQL - 使用逗号分隔字符串作为变量输入的存储过程

    我希望有人能够提供帮助 我已经创建了我的第一个存储过程 没什么花哨的 但是我遇到了问题 我想给它一个字符串输入 例如 1 2 3 4 5 然后它执行一个简单的操作SELECT FROM TABLE WHERE EAN IN VAR 所以存储
  • 学说迁移后备

    我们正在使用原则迁移 当迁移包含多个操作并且其中一个操作失败时 通常会出现问题 例如 如果迁移添加了 5 个外键 其中第 5 个失败 而字段长度不同 则修复字段错误并重新生成迁移不会not修复整个问题 而现在出现一个与 4 个密钥已存在有关
  • 随机组合 MySQL 数据库中的两个单词

    我有一个包含名词和形容词的数据库 例如 id type word 1 noun apple 2 noun ball 3 adj clammy 4 noun keyboard 5 adj bloody ect 我想创建一个查询 它将抓取 10
  • PHP 与 MySQL 查询性能( if 、 函数 )

    我只看到这个artice http www onextrapixel com 2010 06 23 mysql has functions part 5 php vs mysql performance 我需要知道在这种情况下什么是最好的表
  • 通过触发器应用表的列权限

    现在 我有一个名为 Members 的表 其中包含内容 分为联系人数据 银行数据 现在 管理员应该能够创建 更新 删除用户 这些用户保存在另一个表中 该表只能访问管理员 用户应该获得自己的 mysql 用户帐户 管理员还应该能够设置权限 例
  • mysql排序和排名语句

    我需要一些 mysql 语句的帮助 我的表 1 有 7 列 表 2 有 8 列 额外的列名为排名 我的语句应该是这样的 从表 1 中选择全部 然后按 用户数 排序 将其插入表 2 中并排名开始 1 2 3 等 table 1 usernam
  • 快速将列的副本添加到 MySQL 表

    我需要一种快速的方法来复制表中的 DATETIME 列并为其指定一个新名称 我的表中有一个名为 myDate 的列 名为 myResults 我需要一个查询来在名为 newDate 的表中创建一个新列 该列的数据与 myDate 列完全相同
  • post php mysql 的拆分关键字

    我有一个表存储帖子 ID 它的标签如下 Post id Tags 1 keyword1 keyword2 keyword3 我想循环遍历该表中的每一行并执行以下操作 将关键字1 关键字2 关键字3放入新表中 word id word val

随机推荐