前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数据库分割扩展

数据库分割扩展

作者头像
码农戏码
发布2021-03-23 11:22:19
1.1K0
发布2021-03-23 11:22:19
举报
文章被收录于专栏:DDDDDD

此篇作为《架构即未来》读书笔记吧,再额外补充一下主从模式、分库分表实施的知识点

书中提到AKF扩展立体结构

对三轴总结如下:

  • X轴:X轴表示把相同的数据或镜像分散在多个实体。通常依赖于复制并对有多少节点设限
  • Y轴:Y轴表示基于服务、资源或数据关系的意义分离和分散数据
  • Z轴:Z轴表示基于所查阅或在请求处理时确定的属性分割和分布数据

因此,X轴是数据镜像,Y轴按主题分割数据,Z轴通过查找或取模分割数据。通常Z轴分割基于客户,但也可以基于产品ID或其他一些数值

X轴

X轴代表毫无差别的数据克隆。这意味着数据层沿着X轴扩展,N个数据库中的每一个将有与其他N-1个系统完全相同的数据

X轴分割方法比较简单,也就是我们常使用的主从模式,常用的一主多从,少用的多主多

而且数据库内置自备复制能力,实施也比较简单

负责管理平台基础设施团队不需要担心大量独特配置的数据模式或存储系统

但X轴扩展也不是毫无节制,X轴扩展从数据一致角度看,是数据库“最终一致性”,意味着经过短暂间隔后,复制技术可以确保数据库的状态完全被复制到所有其他的数据库

而且X轴扩展技术无法解决固有的数据规模增加所带来的扩展限制问题

比如当数据量增加时,数据库响应时间增加;虽然索引有助于显著减少响应时间增加,但表规模如果增加10倍,仍然会导致响应时间增加

X轴复制也有数据复制所带来的成本。X轴实施是完全克隆主数据库,这意味着可能要移动大量的相对很少读的数据。解决这个问题的一个方案只选择性地复制那些与大量读相关联的数据,很多数据库的复制技术允许以表为基础的选择,但很少允许以列为基础的选择

团队必须在实施、监控和维护复制解决方案方面具备

实践

上面的理论性指导其实已经把问题都已经描述清楚了,但如果没有在项目中实践应用过,可能还有些抽象

1、读写分离是必备架构吗?

在互联网,大多数公司都是这种架构,习以为常;

前一段时间老板讲公司技术进化史,说之前数据库不稳定,从mysql换成了polardb;当时就感觉特别奇怪,以往项目经验,单表几亿的数据量,每天读写量也不低,但从没有说数据库挂掉的情况,是不是mysql使用不当呢?

后来发现公司没有使用读写分离,认为这一块不合理,为什么不使用读写分离呢?后来反省这算不算经验主义了,进而反问读写分离是万金油吗?

此时,不得不去追问一下,为什么需要读写分享架构

读写分离基本原理是让主数据库处理事务性增、改、删操作,而从数据库专门负责处理查询,在数据库的后台会把事务性操作导致的主数据库中的数据变更同步到集群中的从数据库。

根据原理,常使用的一主多从模式,明显是解决了读性能瓶颈,这符合常规互联网业务场景:读多写少

由此看,貌似读写分离对于读多写少的系统的确是必备良方

但兼听则明,也有些公司的确也没有使用此架构,因为此方案也带了一些问题

2、数据一致性

这是第一个问题,复制延迟。这在《流程服务》中也提及到。对于这个缺点,可以分业务场景去规避,业务本身对这种延迟的容忍度

  1. 所读数据是否会用在计算中并在未来写入数据库?
  2. 是否对看到的数据影响决策?比如股票价格

当然从技术角度讲,也有一些手段来实现强一致性

第一种方案:读主表

比如之前的流程服务,如果有用户交互时,延迟不会影响,因为用户交互时长远远超过复制延迟时长。而有时没有交互,需要马上读取写入的数据,此时可以直接读主表,不用额外的开销,但这种场景很少很少,不然就失去了分离带来的好处

第二种方案:使用缓存

比如正常读写延迟是10ms,那么在更新数据时,会同步放入到过期时间为10ms的缓存中,当然为了正确性,可以把缓存过期时间设置为11ms

这样,在读取数据时,先读取缓存,如果没有缓存,就读取从库;缓存存在,就直接取缓存

3、技术实施成本

像上面所讲,改造一下dao算不上什么工作量

还有连接信息的切换,这也没多大问题,使用threadlocal切换

从库出现单点出现问题时的故障自动转移,这个曾经遇到,就是从库挂掉之后,连接池需要自动切换,不然可能需要重启应用,来获取新的连接

当然,这些可以说有成熟的中间件,但DBA需要相应的监控与维护,曾经遇到一条慢SQL拖住了单个从库节点,造成从库负载不均衡现象

这些投入,是不是使用缓存来得更直接容易些呢?

还有额外的,比如云上架构,有些云,主库提供高可用服务,但从库不提供高可用服务;而云上缓存一般都保障高可用

Y轴

在X轴扩展中,有几个问题是无法解决的,数据规模带来的查询效率、复制成本,需要通过其它维度来扩展

Y轴基于意义、功能或者使用情况分割数据,解决数据集的复杂性和规模显著增长而且很可能持续增长的问题

例如:可以把客户数据放在一个地方,产品数据在另一个地方,用户生成的内容放在第三个地方等。但这样要么把应用改变为基于资源的分割,要么接受因为产品没有泳道和故障隔离所带来的后果。

Y轴的数据分割往往比X轴更加复杂,在以工程实施时间计算的成本上,它们比X轴要绝对更昂贵。

比如现在流行的微服务架构,各个系统对应个独立的数据库,这就是相应的Y轴扩展

Z轴

Z轴代表基于在交易时查找的或者确定的属性分割工作。通常这些方法都是基于请求者、客户或者当事人分割的

Z轴分割往往是最昂贵的实施,需要修改软件以确定在哪里找到、操作和存储信息。通常需要为这些类型的分割编写查找服务或者确定算法

Z轴分割将有助于交易增长的扩展、缩短处理时间(通过限制执行任何交易必需的数据)和容量规划(需求更均匀地在系统间分配)。对客户、当事人、请求者或其他均匀分布的数据元素的增长进行均匀的扩展,Z轴分割是最有效的方法。

Z轴最常见的场景,冷热数据分离,这是根据数据使用频率进行分割

融合

结合Y轴分割,Z轴分割可以帮助我们实现故障隔离,但这两个维度并不独立使用,至少都有X轴的参与。

比如孤立使用Z轴分割,如一个客户群体做N次分割,每个实例是一个虚拟或物理数据库服务器。由于硬件或软件原因造成系统失败,为客户或客户集提供的应用服务就变得完全不可用

这其实就是单点问题,解决单点问题就得再X轴分割,也就是准备一个额外的数据库,当某个库失败时,就使用此库

如果迭代式地在Z轴分割,每分割一次,就得带上X轴分割;而且每执行一次,都需要更新代码来识别分割信息,还需要写程序或者脚本来把数据移到新分割的数据库或存储基础设施中的预定位置,完成每个连续分割的成本远大于购买新服务器的成本

怎么办?

一种在Z轴泳道里使用X轴的扩展性实现交易增长的可扩展性

还可以在一旦有了足够的对额外Z轴分割强烈的需求或显著增加了对系统可用性的愿望,我们可以一次性地完成多个Z轴分割,这样可以通过批处理同步完成多个分割,以降低软件成本

Y轴孤立使用也一样,遇到的问题与Z轴一样,处理方式也一样

Y轴分割无法对客户、产品或Z轴分割的其他一些数据元素增长起扩展作用

虽然Y轴分割可以帮助分解数据,但只能是数量有限的分割,其具体的数据取决于数据之间的关系和应用架构

当Y轴出现问题时,比如用户的数据库开始变得拥挤不堪,出现了CPU利用率上升、内存争用负载问题。解决方案是沿Z轴方向,通过分割用户和创建多个不同的用户数据库扩展

应该在什么时候采用X轴分割,什么时候考虑Y轴和Z轴分割?

在理论上这些分割没有时间表,在理想情况下,一个技术或架构团队将选择合适的扩展方法,其数据和交易增长需要以符合成本效益的方式去实现扩展,也就是以性价比最高的方式实现

对高成交量、低数据需求和高读写比率的系统而言,最具成本效益的解决方案可能是X轴分割。这样的系统或组件在数据层和系统层中可能只需要简单的复制。然而在客户数据增长、功能复杂度增加和交易量增长同时发生的情况下,该公司可能需要完成所有三个轴的分割。

分库分表

数据库分割不得不详谈的分库分表,由上面的三轴分割可知,分库分表其实算是Z轴分割

类似上面所讲,Y轴分割并不能完全解决数据增长带来的问题,只能配合Z轴来解决,而分库分表则是常见解决方案

单单对数据进行拆分的操作本身不复杂,但在很多实际的业务场景中,不可避免会出现跨库的表join,事务操作,以及数据的统计、排序等情况,而且数据进行了拆分后,对于数据库的运维管控也提出了更高的要求

分库分表的核心思路是将原本保存在单表中太大的数据进行拆分,将这些数据分散保存到多个数据库的多个表中,避免因为单表数据太大给数据的访问带来读写性能问题

数据尽可能平均拆分

分库分表场景下,最重要的一个原则就是被拆分的数据尽可能的平均拆分到后端的数据库中,如果拆分得不均匀,还会产生数据访问热点,同样存在热点数据因为增长过快而双面临数据单表数据过大的问题

最常见拆分维度,以业务数据的ID(大部分场景此ID是以自增的方式)进行哈希取模的方式将数据进行平均拆分,这个简单的方法在很多场景都是非常合适的拆分方法,但并不是适合所有场景

比如常见的订单表,从理论上可以有两种分法:一是以订单ID(自增)取模;二是以用户ID取模

以订单ID取模方式,订单数据可以平均落入到后端的各个数据库中,原则上很好地满足了数据尽可能平均拆分原则

以用户ID取模方式,会出现一个业务场景问题,如果有些用户交易量非常大,那么就会出现数据不平均现象,最终导致这些订单数据所在的数据库会相对其它数据库提早进入到数据归档

以此场景看,似乎要使用订单ID来拆分

尽量减少事务边界

如果第一次SQL都带上了分库分表键,整个数据库的查询过程跟之前的单机数据库操作没有任何差别

如:以自增ID,基数是8取模,将订单平均分布到8个数据库的订单表中

但并不是所有场景都会带上分库分表键。比如在买家中心,要显示买家test1过去三个月的订单列表,因为该买家test1的订单按订单ID取模,此时SQL中就没有分库分表键值

那只能把获取test1订单的sql推送到所有数据库中执行,再进行聚合,返回给前端。这样就出现了全表扫描。

“事务边界”就是指单个SQL语句在后端数据库上同时执行的数量,上面示例中就是事务边界大的典型示例,即一条SQL语句同时被推送到所有数据库执行。事务边界大,带来很多弊端

  • 系统的锁冲突概率越高
  • 系统越难以扩展:如果每一次SQL都需要全表扫描,那么整个平台的数据库连接数量是取决于后端单个数据库的连接能力
  • 整体性越低:整个SQL执行过程包含5个步骤,仔细看,其实一次带分库分表键执行的SQL过程也会经历这5个步骤,区别只是在2,3步骤是并行的方式同时跟多个后端数据库进行交互,但在时间上带来的影响几乎是毫秒级的;而在第4步可能造成一点差异,如果数据量小,没差异;如果遇到大数据量的聚合、排序、分组等计算时,则会占用较大的内存和CPU计算资源,如果这些的SQL请求比较频繁,就会给数据层带来较大资源占用,从而导致整体服务处理性能

还有一些查询,也很复杂,比如进行复杂的条件搜索,一定需要采用全表扫描

但这样的调用不会频繁,而且计算量不会太大,所以整体不会给数据库整体性能带来太大影响

如果这类SQL请求有并发或频繁访问的要求,则考虑采用其他平台来满足这一类场景要求,比如hadoop类大数据离线分析技术

但这样的请求出现高并发呢?怎么办?

异构索引表

如果按订单ID分库分表,满足订单数据均匀地保存在后端数据库中,但在买家查看自己订单的业务场景中,就出现全表扫描情况,而且买家查看自己订单的请求是非常频繁的,必然给数据库带来扩展或者性能的问题,有违“尽量减少事务边界”这一原则

其实这类场景还有很多,比如卖家要查看与自己店铺相关的订单信息

针对这类场景问题,最常用的是采用“异构索引表”的方式解决,即采用异步机制将表内的每一次创建或更新,都换另一个维度保存一份完整的数据表或索引表。本质上这就是拿空间换时间

也就是应用在创建或更新一条按照订单ID为分库分表键的订单数据时,也会再保存一份按用户ID为分库分表键的订单索引数据,这样同一个买家的所有的订单索引表都保存在同一数据库中,这就是给订单创建了异构索引表

这样查看买家订单信息时,对应数据库访问流程有发生了变化:

图中示意并没有将订单的完整数据保存

数据全复制,可以减少一次数据库访问,但也会带来大量数据冗余,从而增加不少数据库存储成本

搜索引擎

采用数据异构索引的方式在实战中基本能解决和避免90%以上的跨join或全表扫描的情况,是分布式数据场景下,提升数据库服务性能和处理吞吐能力的最有效技术手段。

但在某些场景下,比如像商品搜索,访问用户可能都会使用,调用频繁,如果采用SQL语句的方式在商品数据库进行全表扫描的操作,则必然对数据库的整体性能和数据库连接资源带来巨大压力

所以对此类场景,不建议采用数据库的方式提供这样的搜索,而是采用专业的搜索引擎

选择

这些方案怎么选择呢?如果在“尽量减少事务边界”与“数据尽可能平均拆分”两个原则间发生了冲突,那么请选择“数据尽可能平均拆分”作为优先考虑原则,因为事务边界的问题相对来说更好解决,无论是做全表扫描或做异构索引复制都是可以解决的,而写入或单机容量如果出现不均衡,那处理难度比较大

而异构索引表也不能烂用,一是系统运维带来复杂性,二是出现大量数据冗余,数据一致性的保障也会带来挑战,同时数据库间的业务逻辑关系也变得复杂

在实际中,仅针对那些在80%情况下访问的那20%的场景进行如数据异构索引这样的处理,达到这类场景的性能最优化,而对其他80%偶尔出现的跨库join,全表扫描的场景,采用最为简单直接的方式往往是就最有效的方式

CQRS

数据库做读写分离是用实现解决问题,CQRS是用设计解决问题

CQRS命令查询职责隔离(Command Query Responsibility Segregation)的简称,顾名思义,它涉及隔离或问题的分隔。

如上图,它将持久化数据模型和使用数据的模块分为两部分:命令端和查询端

命令端模块和数据模型实现创建、更新和删除操作

查询端模块和数据模型实现查询

查询端通过命令端发布的事件,使其数据模型与命令端数据模型保持同步

为什么需要CQRS
  1. 使用API组合模式检索分散在多个服务中的数据会导致昂贵、低效的内存中连接
  2. 拥有数据的服务将数据存储在不能有效支持所需查询的表单或数据库中
  3. 隔离问题的考虑意味着,拥有数据的服务不一定是会实现实现查询操作的服务
CQRS的好处
  • 在微服务架构中高效地实现查询: API组合时需要调用多个服务所拥有的数据查询
  • 高效地实现多种不同的查询类型:这算是异构索引表实现方式
  • 在基于事件溯源技术的应用程序中实现查询:这什么鬼,没明白
  • 更进一步地实现问题隔离:不必同时处理命令与查询
CQRS弊端
  • 更加复杂的架构
  • 处理数据复制导致的延迟

总结

此篇算是对数据库架构的一次总结。

今年在面试时,这方面的内容几乎是每家都被问,奇怪

比如:

分库分表时,怎么去查询无分库分表键的情景;冷热数据怎么分离?归档?

还有像邮箱黑名单场景怎么过滤

经过此篇总结,这些问题都有了常规的架构设计,至于实现中的细节问题,下次再开篇了

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

本文分享自 码农戏码 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • X轴
    • 实践
    • Y轴
    • Z轴
      • 融合
        • 分库分表
          • 数据尽可能平均拆分
          • 尽量减少事务边界
        • 异构索引表
          • 搜索引擎
            • 选择
              • CQRS
                • 为什么需要CQRS
                • CQRS的好处
                • CQRS弊端
            • 总结
            相关产品与服务
            云数据库 SQL Server
            腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档