分库分表太坑啦!

最近了解了一下分库分表,看完之后的感悟就是,能不用就不用!!一用就会有超多问题,果然每个技术不仅有优点而且背后都是有超级大的成本的,接下来我就来分享一下分库分表。

数据库分库分表后带来的优点和缺点

分库分表解决的现状问题

  • 解决数据库本身瓶颈
  • 连接数: 连接数过多时,就会出现‘too many connections’的错误,访问量太大或者数据库设置的最大连接数太小的原因
      • Mysql默认的最大连接数为100.可以修改,而mysql服务允 许的最大连接数为16384
      • 数据库分表可以解决单表海量数据的查询性能问题
      • 数据库分库可以解决单台数据库的并发访问压力问题
  • 解决系统本身IO、CPU瓶颈
    • 磁盘读写IO瓶颈,热点数据太多,尽管使用了数据库本身缓存,但是依旧有大量IO,导致sql执行速度慢
    • 网络IO瓶颈,请求的数据太多,数据传输大,网络带宽不够,链路响应时间变⻓
    • CPU瓶颈,尤其在基础数据量大单机复杂SQL计算,SQL语 句执行占用CPU使用率高,也有扫描行数大、锁冲突、锁等待等原因

分库分表带来新的问题

  • 问题一:跨节点数据库Join关联查询和多维度查询
    • 数据库切分前,多表关联查询,可以通过sql join进行实现
    • 分库分表后,数据可能分布在不同的节点上,sql join带来 的问题就比较麻烦
    • 不同维度查看数据,利用的partitionKey是不一样的
      • 例如
        • 订单表 的partionKey是user_id,用户查看自己的订单列表方便
        • 但商家查看自己店铺的订单列表就麻烦,分布在不同数据节
  • 问题二:分库操作带来的分布式事务问题
    • 操作内容同时分布在不同库中,不可避免会带来跨库事务
  • 问题三,即分布式事务 问题三:执行的SQL排序、翻⻚、函数计算问题
    • 分库后,数据分布再不同的节点上, 跨节点多库进行查询时,会出现limit分⻚、order by排序等问题
    • 而且当排序字段非分片字段时,更加复杂了,要在不同的分片节点中将数据进行排序并返回,然后将不同分片返回的结果集进行汇总和再次排序(也会带来更多的CPU/IO资 源损耗)
  • 问题四:数据库全局主键重复问题
    • 常规表的id是使用自增id进行实现,分库分表后,由于表中数据同时存在不同数据库中,如果用自增id,则会出现冲突问题
  • 问题五:容量规划,分库分表后二次扩容问题
    • 业务发展快,初次分库分表后,满足不了数据存储,导致需要多次扩容
  • 问题。。。

OK!相信大家看完这么多问题,头都快大了叭,咱们先轻松一下,看看啥是分库分表

【垂直分表-垂直分库】

  • 需求:商品表字段太多,每个字段访问频次不一样,浪费了IO资 源,需要进行优化
  • 垂直分表介绍
    • 也就是“大表拆小表”,基于列字段进行的
    • 拆分原则一般是表中的字段较多,将不常用的或者数据较大,⻓度较⻓的拆分到“扩展表 如text类型字段
    • 访问频次低、字段大的商品描述信息单独存放在一张表中;
    • 访问频次较高的商品基本信息单独放在一张表中
    • 垂直拆分原则
      • 把不常用的字段单独放在一张表;
      • 把text,blob等大字段拆分出来放在附表中;
      • 业务经常组合查询的列放在一张表中
  • 需求:C端项目里面,单个数据库的CPU、内存⻓期处于90%+的 利用率,数据库连接经常不够,需要进行优化
  • 垂直分库讲解
    • 垂直分库针对的是一个系统中的不同业务进行拆分, 数据库 的连接资源比较宝贵且单机处理能力也有限
    • 没拆分之前全部都是落到单一的库上的,单库处理能力成为瓶 颈,还有磁盘空间,内存等限制
    • 拆分之后,避免不同库竞争同一个物理机的CPU、内存、网络 IO、磁盘,所以在高并发场景下,垂直分库一定程度上能够 突破IO、连接数及单机硬件资源的瓶颈
    • 垂直分库可以更好解决业务层面的耦合,业务清晰,且方便管理和维护
    • 一般从单体项目升级改造为微服务项目,就是垂直分库

【水平分表-水平分库】

  • 需求:当一张表的数据达到几千万时,查询一次所花的时间⻓, 需要进行优化,缩短查询时间
  • 都是大表拆小表
    • 垂直分表:表结构拆分
    • 水平分表:数据拆分
  • 水平分表
    • 把一个表的数据分到一个数据库的多张表中,每个表只有这个 表的部分数据
    • 核心是把一个大表,分割N个小表,每个表的结构是一样的, 数据不一样,全部表的数据合起来就是全部数据
    • 针对数据巨大的单张表(比如订单表),按照某种规则 (RANGE,HASH取模等),切分到多张表里面去 但是这些表还是在同一个库中,所以单数据库操作还是有IO 瓶颈,主要是解决单表数据量过大的问题
    • 减少锁表时间,没分表前,如果是DDL(create/alter/add等) 语句,当需要添加一列的时候mysql会锁表,期间所有的读写 操作只能等待
  • 需求:高并发的项目中,水平分表后依旧在单个库上面,1个数 据库资源瓶颈 CPU/内存/带宽等限制导致响应慢,需要进行优化
  • 水平分库
    • 把同个表的数据按照一定规则分到不同的数据库中,数据库在不同的服务器上
    • 水平分库是把不同表拆到不同数据库中,它是对数据行的拆分,不影响表结构
    • 每个库的结构都一样,但每个库的数据都不一样,没有交集, 所有库的并集就是全量数据
    • 水平分库的粒度,比水平分表更大

好!看完了基础的啥是分库分表,咱要直面狂风暴雨了,首当其冲的就是,当使用了用户的uiserId当成PartitionKey分库分表后,用户想要查看订单列表非常简单,只需要用自己的用户id取模一下,就能找到所有的订单是哪个库,那个表,但是,可怜的商家呢,他完全没法知道所有买了他辛辛苦苦卖出去商品的用户ID,那么他用啥来取模,找到自己卖出去的商品订单呢!

解决方式一【NONOSQL方案】

  • 订单表 的partionKey是user_id,用户查看自己的订单列表方便
  • 订单数据在ES上冗余一份,让商家去ES查

解决方式二【冗余双写方案】

  • 既然!一个partionKey满足不了需求,那么非常简单,直接整两个partionKey
  • 拆分买家库和卖家库
    • 买家库,按照用户的id来分库分表
    • 卖家库,按照卖家的id来分库分表
  • 数据冗余
    • 下订单的时候写两份数据
    • 在买家库和卖家库各写一份

OK!这两种方案一出来,看起来冗余双写方案会更好一点,但是其实还是要看业务,哈哈哈哈哈,冗余双写的方案没有过多的中间件节点,越少!系统越稳定,而且ES太吃内存啦,要好多钱钱。不过选择具体的技术方案的时候一定要结合业务哦。

方案敲定了,那么随之而来的又是一个大问题,分布式的事务咋解决???

好~在说解决方案之前,老规矩,啥是分布式事务呢,为啥就会有分布式事务的问题嘞?

什么是分布式事务

  • 什么是分布式事务
    • 事务指的就是一个操作单元,在这个操作单元中的所有操作最终要保持一致的行为,要么所有操作都成功,要么所有的操作都被撤销
    • 一个是本地事务:
      • 本地事物其实可以认为是数据库提供的事务机
      • 一个是分布式事务
      • 分布式事务指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用分布式事务需要保证这些小操作要么全部成功,要么全部失败。
  • 本质上来说,分布式事务就是为了保证不同数据库的数据一致性
  • 产生的原因 业务发展,数据库的拆分-分库分表 SOA和微服务架构的使用
  • 多个微服务之间调用异常
    • 网络异常、请求超时、数据库异常、程序宕机等

分布式事务下数据最终一致性-CAP的权衡 结果 BASE理论

  • 什么是Base理论
    • CAP 中的一致性和可用性进行一个权衡的结果,核心思想就是: 我们无法做到强一致,但每个应用都可以根据自身的业务特点, 采用适当的方式来使系统达到最终一致性, 来自 ebay 的架构 师提出
  • Basically Available(基本可用)
    • 假设系统,出现了不可预知的故障,但还是能用, 可能 会有性能或者功能上的影响,比如RT是10ms,变成 50ms
  • Soft state(软状态)
    • 允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时
  • Eventually consistent(最终一致性)
  • 系统能够保证在没有其他新的更新操作的情况下,数据最终一定能够达到一致的状态,因此所有客户端对系统的数据访问最终都能够获取到最新的值
  • 关于数据一致性
    • 强一致:操作后的能立⻢一致且可以访问
    • 弱一致:容忍部分或者全部访问不到
    • 最终一致:弱一致性经过多一段时间后,都一致且正常

分布式事务的常⻅解决方案

  • 常⻅分布式事务解决方案
    • 2PC 和 3PC
      • 两阶段提交, 基于XA协议
    • TCC
      • Try、Confirm、Cancel
    • 事务消息
      • 最大努力通知型
  • 分布式事务分类
    • 刚性事务:遵循ACID
    • 柔性事务:遵循BASE理论

刚性事务模型

在分布式系统中,每一个机器节点能够明确知道自己在进行事务 操作过程中的 结果是成功还是失败,但无法直接获取到其他分 布式节点的操作结果

当一个事务操作跨越多个分布式节点的时候,为了保持事务处理 的 ACID 特性,

需要引入一个“协调者”(TM)来统一调度所有分布式节点的执行 逻辑,这些被调度的分布式节点被称为 AP。

TM 负责调度 AP 的行为,并最终决定这些 AP 是否要把事务 真正进行提交到(RM)

 

两阶段提交 2PC流程解析

  • 准备阶段:
    • 事务管理器给每个参与者都发送Prepared消息,每个数 据库参与者在本地执行事务,并写本地的Undo/Redo日 志,此时事务没有提交。
      • Undo日志是记录修改前的数据,用于数据库回滚
      • Redo日志是记录修改后的数据,用于提交事务后写入数据
  • 提交阶段:
    • 如果事务管理器收到了参与者的执行失败或者超时 消息时,直接给每个参与者发送回滚(Rollback)消 息,否则发送提交(Commit)消息;
    • 参与者根据事务管理器的指令执行【提交】或者 【回滚】操作,并释放事务处理过程中使用的锁资源
  • 注意:必须在最后阶段释放锁资源。

刚性事务总结

  • XA协议简单,数据库支持XA协议,开发使用成本比较低
  • 对业务侵入很小,最大的优势就是对使用方透明
  • 用户可以像使用本地事务一样使用基于 XA 协议的分布式事务,能够严格保障事务ACID 特性
  • 事务执行过程中需要将所需资源全部锁定,也就是俗称的刚性事务
    • 刚性事务:遵循ACID
    • 柔性事务:遵循BASE理论
  • 性能不理想,占用锁资源比较多,高并发常⻅下无法满足

柔性事务模型

  • 什么是TCC柔性事务
    • 刚性事务:遵循ACID
    • 柔性事务:遵循BASE理论
    • TCC:
  • 将事务提交分为
    • Try:完成所有业务检查( 一致性 ) ,预留必须业 务资源( 准隔离性 )
    • Confirm :对业务系统做确认提交,默认 Confirm阶段不会出错的 即只要Try成功, Confirm一定成功
    • Cancel : 业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放, 进行补偿性
    • TCC 事务和 2PC 的类似,Try为第一阶段,Confirm - Cancel为第二阶段,它对事务的提交/回滚是通过 执行一段 confirm/cancel 业务逻辑来实现,并且也 并没有全局事务来把控整个事务逻辑

柔性事务总结

  • 优点:
    • 它把事务运行过程分成 Try、Confirm/Cancel 两个阶段
    • 每个阶段由业务代码控制,这样事务的锁力度可以完全自由控制
    • 不存在资源阻塞的问题,每个方法都直接进行事务的提交
  • 缺点
    • 在业务层编写代码实现的两阶段提交,原本一个方法, 现在却需要三个方法来支持
    • 对业务的侵入性很强,不能很好的复用
  • 注意:使用TCC时要注意Try - Confirm - Cancel 3个操作的幂等控制,由于网络原因或者重试操作都有可能导致这 几个操作的重复执行

事务消息

  • 事务消息
    • 消息队列提供类似Open XA的分布式事务功能,通过消 息队列事务消息能达到分布式事务的最终一致
  • 半事务消息
    • 暂不能投递的消息,发送方已经成功地将消息发送到了 消息队列服务端,但是服务端未收到生产者对该消息的 二次确认,此时该消息被标记成“暂不能投递”状态,处 于该种状态下的消息即半事务消息。
  • 消息回查
    • 由于网络闪断、生产者应用重启等原因,导致某条事务 消息的二次确认丢失,消息队列服务端通过扫描发现某 条消息⻓期处于“半事务消息”时,需要主动向消息生产 者询问该消息的最终状态(Commit或是Rollback), 该询问过程即消息回查

事务消息总结

  • 好处
    • 事务消息不仅可以实现应用之间的解耦,又能保证数据的最终一致性
    • 同时将传统的大事务可以被拆分为小事务,能提升效率
    • 不会因为某一个关联应用的不可用导致整体回滚,从而最大限度保证核心系统的可用性
  • 缺点
    • 不能实时保证数据一致性
    • 极端情况下需要人工补偿,比如 假如生产者成功处理本 地业务,消费者始终消费不成功

总结

OK!了解完分布式事务,在看看双写的模型,多么妙啊,这里的消息队列不仅可以选择事务消息来处理分布式事务的问题,甚至自己想再让事务锁的粒度小一点的话,可以自己写柔性事务,比如提交订单的时候发一个消息,没有异常之后,状态机推进到最后一个状态,再提交事务。

OMG!我只是解决两个问题,就扯出来这么多,别说还有主键ID如何确保不重复,数据存到数据库里,会不会有些数据库读写特别频繁,有些数据库没啥读写量嘞,分库分表完发现还是不够用,需要再分库分表一次,那么这个时候,如何保障以前的数据不用迁移呢,这些问题还是等以后的我继续补充叭(挖坑.jpg)。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ShardingSphere是一个开源的分布式数据库中间件,用于实现分库分表分库分表是将一个数据库按照一定的规则分成多个库或者多个表,从而达到提高数据库性能和扩展性的目的。 在ShardingSphere中,可以通过配置公共表的方式来实现分库分表。通过设置配置文件中的参数,指定需要进行分库分表的表以及相应的规则和算法。例如,在配置文件中可以设置公共表和分库分表的策略,如分库数量、分表数量、分片键的生成策略等。引用 同时,在使用ShardingSphere进行分库分表时,需要进行综合评估确定分库分表的数量。一般建议初次分库分表时,将数据库分为4-8个库。引用 分库分表可以解决一些问题,例如垂直分表可以将热门数据和冷门数据分开存储,同时将大字段放在冷门数据表中。垂直分库可以按照业务进行拆分,将不同的业务放在不同的库中,解决单一服务器性能的瓶颈,提升整体架构的业务清晰度。水平分表可以解决单一表数据量过大的问题,而水平分库可以将一个表的数据分别分到不同的库中,解决单一服务器数据量过大的问题。引用 总结来说,ShardingSphere是一个用于实现分库分表的分布式数据库中间件,通过配置公共表和分库分表的策略,可以将数据库按照一定规则进行分割,从而提高数据库性能和扩展性。分库分表的选择需要综合评估,并根据实际业务需求来确定分库分表的数量和策略。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值