前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >微服务架构下如何做数据分区呢?

微服务架构下如何做数据分区呢?

作者头像
田维常
发布于 2020-06-28 09:59:33
发布于 2020-06-28 09:59:33
79800
代码可运行
举报
运行总次数:0
代码可运行

前言

对于大规模的分布式集群,或者对于数据密集型应用来说,为了提高吞吐量和性能以及可用性,一般会结合使用数据复制和数据分区。数据复制将对单库的请求压力分给更多的数据库实例,数据分区将每个实例中的庞大的数据文件以一定规则切分成更小的数据文件,并可以存储到不同的磁盘(或数据节点 Node)上,以提高请求的并发性能,同时,增加了扩展性。

本文将介绍分布式存储集群的高可用的另外一个解决方案——数据分区,以及以 MySQL 为示例看一些数据分区的具体实现。

理解数据分区

复制和分区的差别是什么?请看下面一张图:

分区和分表有什么差别

对于一些大规模数据集群的应用,经常能听到分库分表的解决方案。微服务的体系按照服务维度分库是必然(一个微服务对应一个库),但一个微服务刚刚起步,领域模型刚搭建的时候,切忌一开始凭着感觉来预估需要做分表。如果初期为了数据存储的扩展性,选择分区会更好实施,很多存储引擎都内置建立分区的策略。架构是演进的,随着业务数据增加到一定量之后,再进行分表也可以。

下面来具体看下数据库分表和分区的差别:

(1)存储结构和查询逻辑

分表:一张表会被分成多张表,分表后的每个表都是独立的结构,有自己的索引文件、数据文件、表结构文件。通过分表字段的查询语句会查到具体的一张分表,而不是查询所有的分表。

分区:一张表分区之后还是一张表,只是数据文件和索引文件被分成更小的数据文件和索引文件。查询的还是一张表,只是数据需要从多个分区进行查找、合并处理。

(2)实现方式

分表:分表的方法有很多,有一些是数据库存储引擎内置的方案,对应用开发透明。如果引擎不支持,需要找一些分表中间件来实现,比如 MySQL 可以使用开源的 Cobar,以及国内开源爱好者基于 Cobar 开发的,解决了一些 Cobar 问题的 mycat,类似的,阿里的 Tddl 也是支持分表的中间件。

分区:实现简单,多数存储服务都自带分区实现。对使用者来说跟平常写入、读取的方式没什么区别,对应用开发透明,只是建表时需要确定分区方案。

(3)适用场景

分表:适用于基于业务索引的分表,分表的列不一定是主键或者包含主键。需要手动创建多张表,读写的时候要应用根据分表规则路由到具体的子表中。

分区:适用于基于主键的分区。不需要任何手动处理创建表,应用程序也还是按照原来访问单表的规则进行请求,一般由存储引擎提供到分区的路由。分区规则创建时需要比较谨慎,尽量减少分区之间数据的依赖。

虽然两者有一些区别,但对于单表有大量数据的情况,很多时候是分区和分表一起用,两者都能提升读写的性能。如果想快速扩容的话,可以先分区再分表,分区对开发和运维来说更加透明。

数据分区的好处

了解了分区和分表的差别,聚焦回分区,对于有大规模数据集群的应用来说,进行数据分区的好处是:

  • 性能:通过将大数据切分到不同的数据节点,提升了访问性能。
  • 可用性:分区允许部分分区节点的崩溃,分散了风险,增强可用性。
  • 易用:跟复制一样,对应用程序完全透明,分区 + 复制可以说是大规模数据存储型应用的倚天屠龙。

数据分区的实现

当你决定要对一堆大数据做数据分区的时候,需要决定要以哪个维度进行分区,即当一个数据写入进来的时候,这条数据应该放到哪个分区里。如果没有明确的目的以及足够了解怎样设计分区策略,很容易出现分区之后性能反而下降。存储服务如 HBaseCassandra、MySQL 都会有内置的分区策略,不同的存储引擎的分区策略使用的加密算法、支持的类型会略有不同,但思想都是大同小异。下面以 MySQL 为例看一下分区的方案,以及不同分区方案适合的场景。

MySQL 的分区策略

MySQL 截止到 5.7 版本主要提供了以下几种分区类型,简单列举一些场景。

Hash 分区

Hash 分区有两种方式,常规 Hash线性 Hash常规 Hash 是使用 MySQL 内置的 Hash 算法,并且可以添加用户自定义的函数,计算指定列的值。但这个函数以及选择的列值也有约束:通过指定的函数计算之后的值必须是整数值类型(int,bigint)的数据,这种方式简单易理解并且可以分区很均匀。但问题是,在需要重新分区的时候,比如原来是 10 个分区,现在要分成 15 个分区了,那就需要数据迁移,Hash 分区不易于再分区和扩展。

线性 Hash 基于一个线性的 2 的幂运算法则,算法规则:分区值 = POWER(2, CEILING(LOG(2, 待计算的key)))。线性 Hash 扩充分区或者缩小分区时,更易扩展,适用于一开始不是很确定分区数的情况。

这两者都很适用于比如连续 key 的场景,比如想要均匀的按照某列进行分区的话,就可以选择 Hash,Hash 分区比线性分区更均匀。考虑到以后可能会扩展迁移的话,就用线性分区。

使用 Hash 分区,只要在建表语句之后加上分区策略即可。分区公式:HASH( your expression(column_name) ),示例使用 Year 函数的 Hash 分区:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
PARTITION BY HASH(YEAR (xx_id))
PARTITIONS 10;  
Range 分区

Range 分区可以理解成将分区的列值(xx_id),按照一定的范围分好,并且这个范围需要一开始定义好的,比如可以 1-10000,10001-20000。一般比较适合于时间分区,如按照月份规则来划分。MySQL 内置支持用 Less Than 语法来划分范围。

也是在 create table 之后,添加分区信息,写法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
PARTITION BY RANGE (xx_id) (
    PARTITION p0 VALUES LESS THAN (10000),
    PARTITION p1 VALUES LESS THAN (20000),
    PARTITION p2 VALUES LESS THAN (50000),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);

如果是按照时间戳可以使用内置函数UNIX_TIMESTAMP(按照 TIMESTAMP 时间戳类型字段),YEAR(按照 DATE 类型的时间字段的年份)等,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
PARTITION BY RANGE ( UNIX_TIMESTAMP(work_time) ) (
    PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2016-01-01 00:00:00') ),
    PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2017-01-01 00:00:00') ),
    PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2018-01-01 00:00:00') ),    
    PARTITION p9 VALUES LESS THAN (MAXVALUE)
);
Key 分区

Key 分区跟 Hash 分区很像。不过 Key 分区不提供用户自定义函数,使用 MySQL 提供的 Hash 函数,并且其设置分区的列,必须至少包含部分或者全部的主键或者唯一索引。如果表没有主键,则需要使用 INT 类型的、非空的(Not Null)、唯一索引(Unique Key),否则会报错。同时,Key 分区也支持类似线性 Hash 算法的 线性 Key,如下示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CREATE TABLE test (
    t_key INT NOT NULL PRIMARY KEY,    
    t_name CHAR(5),
    t_date DATE
)
PARTITION BY LINEAR KEY (t_key)
PARTITIONS 10;
List 分区

List 分区 跟 Range 分区比较类似,但是 Range 是连续的值在一个范围内的落在一个分区,而 List 提供了一种通过指定的离散的值的分区方式。写入的列值落在 List 集合中,就在这个分区内,如果写入的值不在定义好的 List 里面,则会报错:Table has no partition for value XX。如下示意:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 CREATE TABLE test_list (
     birth_month INT,
     name VARCHAR(10),
     )
     PARTITION BY LIST(birth_month) (
     PARTITION p0 VALUES IN (1, 2, 3),
     PARTITION p1 VALUES IN (4, 5, 6),
     PARTITION p2 VALUES IN (7, 8, 9),
     PARTITION p3 VALUES IN (10, 11, 12)
     );
Columns 分区

以上四种分区,都需要分区的 key 是 Int 类型的数据列,Columns 分区可以接受一些非 Int 类型的值。Columns 分区提供了两种分区策略:按照范围值的 Range Columns 以及离散值的 List Columns 分区。

如下使用 List Columns 示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 CREATE TABLE test_list_columns (
     birth_month VARCHAR(25),
     name VARCHAR(10),
     city VARCHAR(15),
     )
 PARTITION BY LIST COLUMNS(city) (
    PARTITION p_north VALUES IN('Haerbin', 'Beijing', 'Jiamusi'),
    PARTITION p_east VALUES IN('Shanghai', 'Hangzhou', 'Nanjing'),
    PARTITION p_west VALUES IN('Xian', 'Lasa', 'Chengdu'),
    PARTITION p_sourth VALUES IN('Guangzhou', 'Nanning')
    );  

分区路由的实现

在一张表的数据进行分区之后,分区的文件会分散到不同的数据节点(Node)里(如文章前面第一张图的示意)。对于一个请求来说,需要知道请求到哪个 Node 里的哪个分区,也即请求的路由。路由也是“服务发现”的一环,服务发现不仅仅用于存储 DB,也可以用于应用层的服务路由。

不同的存储引擎,有的有内置路由方案,有的需要通过一些中间件来做路由配置,但基本的策略也都比较相似,比较常见的路由方式有:

  • 客户端(应用程序)连接到任何一个 Node 实例,如果这个 Node 可以处理这个数据分区则处理,否则将请求转发到其他可以处理这个数据的分区所在的 Node。
  • 客户端将请求先发送到一个请求的转发中心(路由中心),然后由这个代理中心决定将数据请求转发到哪个 Node 上。这个代理不处理任何数据请求,只做一个分区的负载均衡
  • 客户端自己做服务发现,也即客户端在发送请求的时候就知道要发送到哪个分区处理,应该连接哪个 Node。

Cassandra 使用 Gossip 协议来管理集群的服务实例的状态(节点上线、下线),整体的思路就是第一种方案,请求发送给任意节点,然后由那个节点决定怎样处理或者转发请求,这种方式避免了对一些其他服务类似 ZK 的依赖,更加灵活。

很多的分布式数据系统会依赖一个独立的专门处理服务发现的协作型服务,比如 ZooKeeper。HBase、Kafka 就是通过 Zookeeper 来做服务发现,整体的路由模型类似第二种方式。MongoDB 也比较类似只不过是只用它自带的 Config Server 来实现路由服务。

Redis 的分区方案是基于第三种路由方案,客户端需要自己进行分区的路由。目前被广泛使用的开源路由代理有 Twitter 的 twemproxy。Twemproxy 相当于一个路由代理,客户端将请求发送给 Twemproxy,再由 Twemproxy 通过对 Redis 分区路由配置的解析,将其请求转发给含有数据的分区的 Redis 节点,并将结果返回给客户端。

小结

本文介绍了数据存储服务的分区,除了 MySQL,很多存储引擎都支持分区,分区可以对现有的大数据进行数据拆分、并且对开发人员透明。但分区也是有一些问题的,很多的存储引擎的分区数一般是有上限的,比如 MySQL 5.6.7 版本之前支持的最大分区数是 1024,该版本之后支持到 8192 个分区数,并且分区的策略制定后,想要重新分区一般都需要进行一定的数据迁移,所以最开始的分区策略的选择尤为重要。

在分布式的存储集群中,无论是否使用微服务,都需要进行存储层的优化,或者随着领域模型的数据的增大,很多时候是从上至下优化的,比如 DB 的读请求负载高,可以考虑用 Cache、搜索。如果是存在一些数据热区,可以针对部分大表进行垂直拆分,将一部分字段抽离出领域模型,建立关联表,因为不是所有请求都要返回所有列的数据的。如果还是无法分担,可以考虑用上一篇介绍的数据库复制,先水平扩容。如果表数据量很大,检索效率还是低,可以考虑用本文所述的数据分区,但要注意分区要让查询尽量路由到少数的分区,防止扫描过多分区文件。如果还是无法满足性能和扩展要求,可以考虑用一些中间件做水平拆分——分表,让请求尽量落在一个分表中。如果分表很难满足场景,对于写少读多的场景,那就可以再做冗余的其他查询维度的分表。

在实际选择哪个方案进行集群的扩展,都是因团队、业务而异的。了解了底层的分布式存储知识之后,就可以往应用服务去扩展了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java后端技术栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Mysql性能优化四:分库,分区,分表,你们如何做?
分库分区分表概念 分区 就是把一张表的数据分成N个区块,在逻辑上看最终只是一张表,但底层是由N个物理区块组成的 。 分表 就是把一张数据量很大的表按一定的规则分解成N个具有独立存储空间的实体表。系统读写时需要根据定义好的规则得到对应的字表明,然后操作它。表名可以按照某种业务hash进行映射。 分库 一旦分表,一个库中的表会越来越多。 下面来具体看看 分区 mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面(可以通过my.cnf中的datadir来查看),一张表主要对应着三
友儿
2022/09/09
9610
Mysql优化-表分区
已经基于行级锁的话,就没有办法从软件层面提升并发度了,否则会事务冲突。所以思路:行级锁、物理层面提升。
码客说
2019/10/21
4.4K0
下一代实时数据库:Apache Doris 【五】数据表的创建
一张表包括行(Row)和列(Column)。Row 即用户的一行数据。Column 用于描述一
Maynor
2023/09/25
7020
下一代实时数据库:Apache Doris 【五】数据表的创建
经验分享|MySQL分区实战(RANGE)
在 MySQL 中, InnoDB存储引擎长期以来一直支持表空间的概念。在 MySQL 8.0 中,同一个分区表的所有分区必须使用相同的存储引擎。但是,也可以为同一 MySQL 服务器甚至同一数据库中的不同分区表使用不同的存储引擎。
六月暴雪飞梨花
2023/11/30
6230
经验分享|MySQL分区实战(RANGE)
MySQL分区分库分表(2) --- 实操篇
上一篇主要讲到了分区分库分表的概念,其实在不影响性能的情况下,我们完全可以使用单分区单库单表。但是业务量大的情况下,受到性能限制我们不得不选择使用分区分库分表。本篇是上一篇的拓展,本篇主要讲讲十几种我们如何使用分区分库分表。如果还未看过上一篇文章建议先阅读概念篇:Mysql分库分表(1) --- 概念篇
创译科技
2019/10/24
1.7K0
MySQL分区分库分表(2) --- 实操篇
Mysql调优之分区表
表非常大以至于无法全部都放在内存中,或者只在表的最后部分有热点数据,其他均是历史数据,分区表是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。
iginkgo18
2022/01/13
1.7K0
mysql分区表_MySQL分区分表[通俗易懂]
数据库数据越来越大,随之而来的是单个表中数据太多。以至于查询速度变慢,而且由于表的锁机制导致应用操作也搜到严重影响,出现了数据库性能瓶颈。
全栈程序员站长
2022/08/11
13.8K0
mysql分区表_MySQL分区分表[通俗易懂]
一文带你搞懂 MySQL 中的分区!
首先要先介绍一下InnoDB逻辑存储结构和区的概念,它的所有数据都被逻辑地存放在表空间,表空间又由段,区,页组成。
良月柒
2020/04/23
1.3K0
一文带你搞懂 MySQL 中的分区!
Spider 引擎分布式数据库解决方案(最全的 spider 教程)
飞鸿无痕
2017/05/27
7.1K1
Spider 引擎分布式数据库解决方案(最全的 spider 教程)
MySQL表分区的选择与实践小结
在一些系统中有时某张表会出现百万或者千万的数据量,尽管其中使用了索引,查询速度也不一定会很快。这时候可能就需要通过分库,分表,分区来解决这些性能瓶颈。
北桥苏
2024/05/21
1730
MySQL · 最佳实践 · 分区表基本类型
随着MySQL越来越流行,Mysql里面的保存的数据也越来越大。在日常的工作中,我们经常遇到一张表里面保存了上亿甚至过十亿的记录。这些表里面保存了大量的历史记录。对于这些历史数据的清理是一个非常头疼事情,由于所有的数据都一个普通的表里。所以只能是启用一个或多个带where条件的delete语句去删除(一般where条件是时间)。这对数据库的造成了很大压力。即使我们把这些删除了,但底层的数据文件并没有变小。面对这类问题,最有效的方法就是在使用分区表。最常见的分区方法就是按照时间进行分区。分区一个最大的优点就是可以非常高效的进行历史数据的清理。
码农编程进阶笔记
2021/07/20
8690
蔚来汽车 x TiDB丨单表超 20 亿条数据,从 MySQL 到 TiDB 的迁移思考与实践
本文来自 TiDB 社区合肥站走进蔚来汽车——吴记老师的演讲《TiDB 在新能源车企的实践:MySQL 到 TiDB 的迁移思考》。
PingCAP
2024/08/05
2170
蔚来汽车 x TiDB丨单表超 20 亿条数据,从 MySQL 到 TiDB 的迁移思考与实践
深入解析实时数仓Doris:介绍、架构剖析、应用场景与数据划分细节
Apache Doris 是一个基于 MPP 架构的高性能、实时的分析型数据库,以极速易用的特点被人们所熟知,仅需亚秒级响应时间即可返回海量数据下的查询结果,不仅可以支持高并发的点查询场景,也能支持高吞吐的复杂分析场景。基于此,Apache Doris 能够较好的满足报表分析、即席查询、统一数仓构建、数据湖联邦查询加速等使用场景,用户可以在此之上构建用户行为分析、AB 实验平台、日志检索分析、用户画像分析、订单分析等应用。
公众号:码到三十五
2024/05/24
6.8K0
深入解析实时数仓Doris:介绍、架构剖析、应用场景与数据划分细节
最佳实践 · MySQL 分区表实战指南
在数据量急剧增长的今天,传统的数据库管理方式可能无法有效处理海量数据的存储和查询需求。MySQL 提供了分区表功能,这不仅能够帮助优化性能,还能简化数据管理过程。分区表允许将数据表拆分成多个逻辑上的分区,每个分区可以在物理上存储于不同的存储介质上,从而提升查询效率和数据处理速度。本文将深入探讨 MySQL 中四种主要的分区类型——范围分区(RANGE)、列表分区(LIST)、哈希分区(HASH)以及键分区(KEY),并通过实际的案例分析和示例数据,帮助你掌握如何使用这些分区技术来优化数据库性能,提升数据处理能力。
不惑
2024/09/09
7180
最佳实践 · MySQL 分区表实战指南
mysql如何进行分区_mysql如何进行分区_mysql分区有哪些方法「建议收藏」
大家好,又见面了,我是你们的朋友全栈君。 MySQL 可应用于多种语言,包括 PERL, C, C++, JAVA 和 PHP。 在这些语言中,MySQL 在 PHP 的 web 开发中是应用最广泛。
全栈程序员站长
2022/09/02
3.9K0
MySQL分库分表分区解析
- 概念:分区是在数据库内部层面将一张大表的数据分割成多个更小的部分,每个部分称为一个分区。尽管从逻辑上看仍然是一个完整的表,但在物理层面上,数据被分布在不同的物理区块上,这些区块可以位于同一台服务器的不同硬盘分区,或甚至是不同服务器上。MySQL支持多种分区类型,如范围分区、列表分区、哈希分区等。
用户7353950
2024/05/25
2090
MySQL分库分表分区解析
开发篇-MySQL分区(一)
MySQL从5.1版本开始支持分区的功能。分区是指根据一定的规则,数据库把一个表分解成多个更小的、更容易管理的部分。就访问数据库的应用而言,逻辑上只有一个表或一个索引,但是实际上这个表可能由数十个物理分区对象组成,每个分区都是一个独立的对象,可以独自处理,可以作为表的一部分进行处理。分区对应用来说是完全透明的,不影响应用的业务逻辑。 MySQL分区的优点主要包括以下4个方面: 和单个磁盘或者文件系统分区相比,可以存储更多数据。 优化查询:在Where子句中包含分区条件时,可以只扫描必要的一个或多个分区来
企鹅号小编
2018/01/24
1.3K0
开发篇-MySQL分区(一)
别看不起分区表:我要为你点个赞
接下来分别尝试有分片键查询,二级索引(idx_name)查询,无分片键查询这三种非常典型查询,并查看执行计划(并且为了防止查询结果被缓存,每条SQL都加上SQL_NO_CACHE):
程序猿DD
2019/03/08
4140
别看不起分区表:我要为你点个赞
MySQL分区表姿势
分区的功能不是在存储引擎层实现的。因此不只是InnoDB才支持分区。MyISAM、NDB都支持分区操作。
保持热爱奔赴山海
2019/09/17
5.8K0
数据库分区概念及简单运用
分类:分为水平分区(Horizontal Paritioning)和垂直分区(Vertical Partitioning)
全栈程序员站长
2022/09/06
1.3K0
推荐阅读
相关推荐
Mysql性能优化四:分库,分区,分表,你们如何做?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验