OLTP场景中的数据分布设计原则是什么?

分类:编程技术 时间:2024-02-20 16:10 浏览:0 评论:0
0
本文与大家分享OLTP场景下数据分布设计的原则。小编觉得还是比较实用的,所以分享给大家学习一下。希望您读完本文后有所收获。详细说一下,关注小编看看吧。

前言

这几年我一直在做分布式项目,很多工作都是关于OLTP(在线交易系统)中的数据分布式架构)场景。疫情期间,就整理一下这方面的一些设计和实践。为了避免太长,文章分为设计和技术部分。设计部分主要阐述了数据拆分的理论和方法,以及一些原理和经验。技术章节将主要介绍分库分表中间件的设计和使用实践,以及如何构建一个完整的分布式数据服务平台。

一般来说,在构建发行版时ted架构中,应用层最好是分布式的,因为往往是无状态的(或者无状态是通过将数据传输到DB、缓存、MQ等来实现的),只需添加一个负载均衡器(如Nginx、HAProxy、F5)在交通入口处,即在应用程序前面,这在大型整体架构中已经可用。所以一般当我们谈论分布式架构时,一个重要的部分就是分布式数据。

传统的单体中心化架构

数据分发并不像应用程序那么简单,因为每个节点的数据可能不同,需要进行路由、求解诸如多副本一致性甚至多写冲突等问题。尽管实现很复杂,但数据分布本质上由两个简单的思想组成:复制和分片。复制技术在传统关系型数据库中也很常见,主要用于主备、双活应用比如MySQL Replication、Oracle DataGuard等,Sharding在数据库中也有相应的产品。比如MySQL Fabric、Oracle Sharding,但与复制相比,这些数据库厂商的分片解决方案还没有被大众广泛接受。

NewSQL数据库往往内置分片机制,基于paxos和raft算法来保证复制一致性。分库分表和NewSQL方案的对比选型可以参考我之前的文章。 《分库分表 vs NewSQL 数据库》。

在OLTP场景中,复制和分片的思想被应用到传统的关系数据库中。它们有两个更为人熟知的名字:分库分表和读写分离。

分库分表就是将原来的单个数据库表进行拆分。是实现基于传统关系型分布式架构转型的主要方式数据库,所以第一个问题是:

为什么要拆分?什么时候需要拆分?

容量、性能、水平扩展、微服务

存储、CPU、内存存在上限瓶颈以及单机数据库的其他资源。当数据量和访问量达到一定量时,Scale Up后性能会急剧下降,这意味着通过Scale Up的垂直扩展方式存在上限,且成本较高。

如果要实现Scale Out水平扩展,需要将原表的数据拆分为多个物理数据库表进行存储(水平拆分)。

另外,如果是微服务架构,拆分后的服务属于不同的系统,对应不同的数据库。事实上,已经进行了垂直分割。

拆分方式有哪些?

1.垂直分割

垂直拆分是通用的、更贴近业务的一种拆分方式。这是做微服务时最常用的方法。具体来说,会根据DDD(领域驱动设计)技术或者业务能力进行拆分。一般来说,有界上下文确定了,分割规则就比较明确了。

这种方法对应用程序的侵入较小。它往往只需要配置独立的数据库(可能是物理机,或者只是不同的真实列)。最多可以用来从多个数据源中选择数据。接入层。

还有一种由于冷热数据导致的垂直分裂的场景。同一行数据中不同列的访问频率差别很大,或者一些大字段如Text、Blob影响读写效率。在这种情况下,这些列也将被拆分到不同的表中。这种方法一般不常见,在做perfor的时候经常会考虑曼斯优化。

垂直拆分

垂直拆分的优点

拆分后业务清晰。分裂的规则是明确的。往往基于系统或事务

易于系统间集成或扩展

数据维护简单,架构复杂度低

垂直拆分的缺点:

部分业务表无法Join,只能通过应用层接口解决

由于各业务限制不同,存在单一数据库性能瓶颈

这种情况经常出现分布式事务场景

由于垂直切分是根据业务分类将表分散到不同的库中,因此部分业务表会过大,出现单库读、写和存储瓶颈。对于这种情况,可以通过水平分离来解决。

2.水平分割

水平al 分裂更具技术性。它将一张表的数据分布到多个数据库和表中。具体方法是可以分为:只分库、只分表、分库分表。例如order表只分库(ds1.order,ds2.order…dsk.order),只分表(ds.order_0,ds.order_1…ds.order_n),分库和表(ds1 .order_0、ds2.order_1…dsk.order_n)。

水平拆分

水平拆分的优点:

如果操作数据分布在同一个数据库中,可以支持join ,子查询等复杂SQL

解决单个数据库的性能瓶颈,支持水平扩展

由于应用程序没有拆分,如果有分布式数据访问层,应用程序转换会少

p>

水平拆分的缺点:

拆分规则和子库、表的数量需要确定o 精心设计

如果涉及到多个库,会出现分布式事务的场景

当数据扩展时,数据迁移的工作量很大

跨数据库join往往需要应用程序实现,性能较差

数据合并、聚合、分页等无法由数据库直接支持

有分区表的数据库是否需要进行划分分为库和表?

传统关系数据库中的分区表本质上是共享CPU和内存的,因此仍然面临着扩展的问题。 ,而且分区表支持的分区键往往不够灵活。然而,一些新的NewSQL分布式数据库,例如OceanBase,将分区表分散在不同的存储节点上,以避免单机性能瓶颈。

拆分的具体步骤

1.确定拆分方式

选择合适的方式根据业务特点,拆分方法一般组合使用。

1)垂直拆分

场景:字段长度和访问频率差异较大的字段表、微服务

注意:尝试一下不要对同一事务中需要操作的表进行拆分

2)水平拆分

场景:数据量较大,超过单个表、单库性能

注意:是否有跨库事务、是否有非shard key操作表场景都会涉及到数据库表扫描事务

2.确认拆分字段

1)垂直拆分表格和字段

按照功能模块拆分,按表格即可。如果是要拆分某些列,则需要添加相关列甚至冗余列。

2)水平拆分字段

确保拆分表有sharding key,大多是主键或唯一索引。这些列需要包含分片信息。如果请求中不包含分片信息,则需要全局路由表。

3.确定拆分规则

1)范围

适合某些规则顺序递增的业务字段,如日期、序列号等.,这样例如0-9999->库1, 10000~19999->库2...20150101-20161231->库1, 20170101-20171231->库2....

这种方式天然支持水平扩展,方便冷热分离、归档、按需扩展。但负载容易出现不平衡现象。如果单个数据库压力较大,还需要进行数据迁移。

2)Hash

数据分布比较均衡。一般情况下,路由是通过mod库/表的数量来计算的。它本质上是一种预分配,所以它是可以扩展的。当需要数据迁移时,通常有一致性哈希和指数扩展的方法。

3)应用定制

应用定制路由规则,配置分片ID对应的库表序号,可以通过路由表和文件或其他自定义算法进行配置。这种方法灵活性最高,易于实现动态变化。

我们的项目中,都使用了方法1、2、3。

4.确定拆分数量

1)假设目标数据量为T(根据业务发展需求估算)

2)单表数据量建议为P(例如MySQL为500w),子表数量=T/P

3 ) 当前配置典型业务场景下,数据容量上限L

单数据基础性能可以根据CPU(80%以上)、磁盘IO(磁盘使用率100%iowait)在单库性能稳定的前提下逐步提升)、事务tps稳定性(tps波动较大)等系统指标来决定其瓶颈状态以获得容量上限的评估。

4)子数据库数量=T/L

数据库表数量与未来扩展和运维需求有关。它不应该太多或太大。较少的。上述计算主要是从容量的角度进行的。实际场景中,需要综合考虑硬件成本预算、数据清洗归档策略等因素。

拆分后如何扩容?

1.垂直扩展

垂直拆分后,如果某个应用的数据库压力过大,可以增加其资源配置(CPU、memory、PCIE)用于垂直扩展。

2.水平扩展

水平拆分下,可以通过添加数据库服务器来扩展容量。该方法需要进行数据迁移。如果哈希一致,则迁移最近节点的数据。如果容量增加一倍,则需要迁移所有节点一半的数据。

一致性哈希模式虽然迁移的数据量较小,但很容易造成数据冷热不均。因此,我们项目中采用的指数扩展方法就是提前将表分开。比如分为128张表。在项目初期,这些表均匀分布在4台数据库服务器上。随着业务的增加和数据量的增加,容量扩展到8个数据库。只需将原来 4 个数据库各一半的表移至新数据库即可。 4台服务器,然后修改SQL路由。

双倍扩容:为了应对整体数据量的增加,扩容后物理机将是原来的两倍

如果单个数据库有热数据压力,也可以只迁移部分数据数据库到新扩展的数据库。

单库扩容:为了应对某切片数据的快速增长,扩容到独立的物理机

问题拆分后面临

引入分布式事务的问题

跨库Join的问题

多库归并排序和分页

SQL路由、重写问题

多数据源管理问题

多维拆分导致的数据汇总查询等操作问题

< p>解决方案:

尽可能避免分布式事务、跨节点连接、排序场景

避免使用数据库分布式事务并提供灵活的事务支持(幂等性、纠错性、可靠性)消息、TCC)

应用层解决联接问题

提供分布式数据访问层

< p>摘要库、二级索引库、小表广播

分布式数据访问层将在技术章节详细介绍。

读写分离

实际业务场景中,对数据库的读写频率是不同的。有的写多读少,比如交易流表;有些是读写平衡的,比如订单表;有的读多写少,比如客户、信息、配置等信息表。

数据分片解决了单点性能瓶颈和水平扩展能力,适合写入压力较高的场景。在这种多读少写的场景下,如果单个数据库的容量能够满足的话,可以将读写分离,解决读压力大的问题。具体来说,写操作可以路由到主库,读操作根据权重、机房等分布在主库和各个从库之间。

读-写分离

读写分离模式有几点需要注意:

1)主从延迟。从库读取数据相对于主库有一定的延迟(一般是毫秒级,写压力大的时候可能是秒级),所以在选择这种方式时,业务必须允许有一定的数据延迟,比如一般的外部查询。所有交易均使用此方法。

2)同一个事务中,不能从从库读取数据,因为数据延迟可能会读取到脏数据,违反了事务的一致性,所以必须从主库读取。实际开发时,数据访问层可以根据自动事务提交是否关闭,自动判断是否必须从主库读取。

3)对于数据延迟容忍度较低的查询事务,可以在开发时单独封装一个向主库查询的接口,或者在输入参数中添加“是否需要强一致性”标志,事务执行时根据该标志选择是从主库还是从库读取。

实际项目中,存在使用分库、分表、读写分离方式的场景,但请注意,一般情况下,避免使用分库、分表等复杂的解决方案。 -表+读写分离,因为分库分表后面的读写压力不会太大。

原理与经验

数据分发是一个系统工程,需要从领域建模、场景划分、数据接入、数据迁移扩展等多方面综合考虑。考虑到在实施之前,我们必须从整体上进行设计看法。以下是我们的一些设计原则和经验:

1)用简单的方案解决问题。可以的话尽量不要拆分,千万不要为了分配而拆分。读写分离可以解决数据库不分表的问题。

2)对于分片,必须选择合适的分片规则(保证90%的交易不会跨分片),梳理好所有场景,提前做好规划实施它们。

3)数据访问层设计要强大,但使用场景要明确,避免盲目滥用。例如,虽然数据访问我我们项目中的ddleware支持分布式事务XA,一般不推荐使用;支持DDL,但在线交易时禁止使用;支持多库链事务提交,但默认只支持严格的单库事务。

4)制定应用程序开发规范,明确SQL使用限制和要求。 SQL 应该尽可能简单。 比如我们的项目使用MySQL,部署在PC Server上。单机性能比小型机上的DB2、Oracle差很多。因此,禁止使用触发器、外键、连接,SQL操作必须携带索引和分割列(数据访问层也会验证),主键必须自增等。

5)尝试使用灵活的事务来解决跨数据库、跨系统的事务问题。 如果可以使用 MQ,就不要使用 Saga 或 TCC最终一致性。

以上就是OLTP场景下的数据分布设计原则。小编相信有些知识点在我们日常工作中可能会看到或者用到。希望您能从本文中了解更多信息。更多详情请关注行业资讯频道。

1. 本站所有资源来源于用户上传或网络,仅作为参考研究使用,如有侵权请邮件联系站长!
2. 本站积分货币获取途径以及用途的解读,想在本站混的好,请务必认真阅读!
3. 本站强烈打击盗版/破解等有损他人权益和违法作为,请各位会员支持正版!
4. 编程技术 > OLTP场景中的数据分布设计原则是什么?

用户评论