基于数据库的事务消息解决分布式事务方案

转载请注明出处:http://www.cnblogs.com/lizo/p/8516502.html

概述

当单库已不能支撑当前业务的时候,我们往往都考虑进行分库(横向拆分或者纵向拆分)。但分库有个无法回避的问题,就是事务问题。网上有很多分布式事务解决方案,例如XA,TCC等,但是最常用,也是改造成本最低就是使用最终一致性来保证分布式事务。
比较常用的就是使用消息中间件(RabbitMq,RocketMq),通过事务消息来解决最终一致性。参考https://zhuanlan.zhihu.com/p/25933039?utm_source=tuicool&utm_medium=referral。

本篇文章将使用数据库的来达到最终一致性的实现方案。

名词解释

  • 主库-拆分前,业务访问的数据库
  • 分库-拆分后,部分业务数据放入到分库中

注:以下有些内容是在使用事务消息(无论是基于数据库还是基于消息队列)应该考虑的地方。

基于数据库的事务消息

事务消息

所谓基于数据库的事务消息,其实很好理解,就是在数据库中创建一个类似消息队列的表,用于保存事务消息。在拆分前,一个事务中,有多个主库的数据操作。如下图,

 

但是在拆分数据库后,有业务被拆分到分库中去了,这样,原有的单库事务被打破,但是通过把拆分出去的业务使用一个事务消息来代替(事务消息表也是在主库中,所以这里还是单库事务),后续再通过其他方式去执行该事务消息所对应的业务逻辑即可,这样,就可以达到最终一致性,如下图

 

事务消息执行器

前面说到了,事务消息需要一个处理器来进行执行事务消息所对应的业务逻辑。事务处理器应该是顺序的去读取并执行的。

设想一个场景:当出现某一条消息处理失败,如果执行器要等当前消息执行成功才继续往后执行(甚至该消息永远不会处理成功),那么会影响后续消息的执行,导致整个系统出现问题。

因此,消息处理器即要保证消息处理尽可能处理快,又能保证消息最终能执行成功。 在消息执行器中必须设置2个任务:

  • 第一个任务,消息处理任务,已最快的速度执行消息,如果消息处理失败了,跳过该消息继续执行后面的消息。
  • 第二个任务,消息校验任务,这个任务就是顺序检查消息,保证所有消息都执行成功,如果失败,进行重试,多次重试失败以后发出告警以让人工介入处理。 如下图

 

注:上图左边那个是消息队列及其处理状态

消息执行的特性

  • 延迟处理性。消息不是实时处理的,而是用过消息执行器来异步执行的。因此,如果在原有逻辑中,需要特别注意后续流程对该消息处理结果是不是有实时依赖性(例如后续业务逻辑中会使用该消息处理结果来做一些计算等)。
  • 处理无序性。由于消息不一定是顺序执行的,所有保证即使后生成的消息先执行,也不能出现问题。
  • 最终成功性。对每条插入的消息,保证该条消息一定要能执行成功

如何确认消息已执行成功

设想,如果分库业务执行成功(更新分库),然后去更新消息状态(主库),这样,又是一个夸库事务,所以,得想其他办法来避免,最简单的方法,就是在分库里面也建一个消息表,保存处理的成功的消息。这样,通过对比主库和分库的消息表,就知道哪些事务消息没有执行成功

消息处理器基本框架

前面介绍了,消息处理器的核心功能就:

  • 获取消息,并把消息发送给业务放处理
  • 保证消息执行的成功 

为了完成上面功能,需要消息处理任务和消息校验任务,通过定时调度任务来触发这2个任务(例如,5s触发一次)

 

消息处理任务

消息处理任务就是通过扫描待处理的消息,然后通知业务系统执行。

 

再次强调,消息处理任务不会管消息是否执行成功。都是按照消息队列表顺序执行下去。

消息校验任务

校验任务就是比较主库和分库中的消息记录(主库中记录的所有消息,分库中记录的执行成功的消息),对执行未成功的消息发起重试,如果多次重试失败则发出告警,需要人工介入。 

 

和基于消息中间件的事务消息比较

相同点

  • 都是采用异步确保最终一致性:
  • 可以控制异步执行消息的速率,可以利用RPC调用的负载均衡
  • 消息处理都必须支持重试和幂等性
  • 事务消息异步执行失败,都没办法回滚产生事务消息的事务 

不同点

消息事务的提交

使用消息中间件,一般都需要在代码中显示的编写提交中间件事务消息的代码,类似下面

public boolean transaction(String text){try {发送事务消息执行本地事务提交事务消息return true;} catch (TmcException e) {return false;}
}

但在实际项目中,事务的传播性的问题(spring 的事务注解是支持事务的传播性),就需要修改业务代码。但使用基于数据库的消息队列就没有这个问题

@Transactional
public void publishAS(String text){   执行本地事务逻辑插入事务消息
}

所以在既有代码改造上(特别是复杂系统中),使用数据库的事务消息可以减少代码的改动

不需要回调check

我们知道,在使用消息中间件的时候,都需要实现一个回调接口,当事务消息长时间没有commit的时候,会调用该接口来确认是否需要commit(例如发送消息成功,但是在commit的时候网络不可用)。而基于数据局的事务消息队列就没有这个问题

更多的数据库访问资源

基于数据库的事务消息也有一个比较明显的缺点:

  • 占用更多的数据库空间和数据库访问资源
  • 需要额外编写DAO层代码

小结

基于数据库和基于消息队列的事务消息的基本思路都一样,使用最终一致性来避免分布式事务带来的额外系统复杂性和代码开销。基于数据库的事务消息在既有业务改造中,代码变动较小,也不需要额外的引入消息中间件,但是带来的问题就是对数据库更多的访问。而基于消息中间件的问题就是如何避免在与消息中间件交互的出现问题的时候如何应对。当然,以上只是我个人理解,如果系统有什么设计不合理或者有改进的地方,欢迎讨论。

转载于:https://www.cnblogs.com/lizo/p/8516502.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/267501.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中service层的作用_浅析Java中dto、dao、service、controller的四层结构

目前我所在的项目组采用的是SpringBoot框架,前端使用BootStrapjQuery。SpringBoot是BS开发框架之一,不用单独开启tomcat服务器,目前比较流行,一般开发大型项目时会将所有的功能细分为许多小模块,每个模块都有dto、dao、…

【iOS开发必收藏】详解iOS应用程序内使用IAP/StoreKit付费、沙盒(SandBox)测试、创建测试账号流程!...

Himi 原创, 欢迎转载,转载请在明显处注明! 谢谢。 原文地址:http://blog.csdn.net/xiaominghimi/article/details/6937097 终于在11月公司的游戏即将上线了,那么对于iOS游戏来说当今都是内置道具收费属于主流&#xf…

不越狱换壁纸_终于来了!iOS 14.3 正式版,可自动定时换壁纸

嘿嘿,我没有猜错吧!iOS 14.3 正式版会在12月15日凌晨时段发布,在前几天我就有提到,这一天会发布,主要是与新品 AirPods Max 发售时间与iOS 14.3正式版发布时间一致。其次这次发布iOS 14.3正式版更新内容与 iOS 14.3 RC…

Hibernate【inverse和cascade属性】知识要点

Inverse属性 Inverse属性:表示控制权是否转移.. true:控制权已转移【当前一方没有控制权】false:控制权没有转移【当前一方有控制权】Inverse属性,是在维护关联关系的时候起作用的。只能在“一”的一方中使用该属性!Inverse属性的…

中list如何清空_如何根据索引删除 list 中的元素

这个问题很简单, 首先想到的就是a list(range(10)) del a[2]这个就可以很方便的删除掉 a 中的第 3 个元素.如果我想删除多个元素怎么办, 比如我想删除第 3, 4, 5, 6 个元素? 这个也很好办:a list(range(10)) del a[2:6]那么我要删除的元素的索引不连续呢? 比如我要删除第 3…

查询时拼接两列数据_如何用VBA代码查询两列数据差异?

爱就一个字,我只说一次……北京市第三交通委提醒您:代码千万条,注释第一条,命名不规范,修订两行泪……咳,给大家拜晚年了,再提前祝大家元宵快乐……我们今天和大家分享的内容是如何用VBA代码查询…

setTimeout详解

https://www.cnblogs.com/wzndkj/p/7069331.html 一、setTimeout基础 setTimeout(func|code,delay);第一个参数表示将要推迟的函数名或者一段代码,第二个参数表示推迟执行的毫秒数eg: console.log(1); setTimeout(console.log(2),1000); console.log(3);answer: 1 3…

Kappa电商负责人顾皓澜:电商业务一直保持盈利

Kappa电商负责人顾皓澜(TechWeb配图) 【TechWeb报道】10月初,闹得沸沸扬扬的淘宝商城事件吸引了无数互联网用户的目光,处于漩涡中心的淘宝商城当仁不让地挤入话题排行榜,商城上大小卖家的命运也牵动了众多消费者的心。…

Citrix VDI-in-a-Box 第二篇:架构篇

前言:为什么Citrix会收购Kaviza,就是因为其VDI-in-a-Box产品架构比较简单。 本文重点描述其架构和安装要求。 如果你想了解一个东西,首先必须了解其架构。 vdiManager是管理整个架构的工具,所有的虚拟机都运行在Hypervisor上。整 …

看完此文再不懂区块链算我输,用Python从零开始创建区块链

如果你还没有听说过 3 点钟区块链群,说明你还不是链圈的人;如果你还没有加入 3 点钟区块链群,说明你还不是链圈的大佬;如果你还没有被 3 点钟区块链群刷屏,说明你还体会不到什么是“币圈一天,人间一年”。 …

重新加一个window_Activity、View、Window关系,进程间通信,责任链模式,Https,数据存储...

码仔,今天就给大家带来了《每日一道面试题》的第九期:01理解Activity View window的关系 Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图)LayoutInflater像剪刀,Xml配置像窗花图纸。 Activ…

排他网关(ExclusiveGateWay)

网关(ExclusiveGateWay) 作者:邓家海2018年3月11日 00:13:25 情景:某一家公司最近在给一个单位做一个财务审批的OA。具体需求是这样的:当部门申请的金额小于一万块的时候,财务部可以直接决策。当部分申请的金额大于一万…

离线安装宝塔lnmp_宝塔LNMP环境 Nginx安装EduSoho教程说明

[toc]宝塔下使用LNMP Nginx安装EduSoho创建站点 宝塔后台 > 网站 > 添加站点 > 输入信息 > 提交填写信息创建完成设置运行目录 宝塔后台 > 网站 > 管理运行目录选择web目录后保存 网站目录 > 运行目录 > 保存修改配置文件 配置文件 > 修改参数 >…

NHibernate初学者指南(10):一级和二级缓存

一级缓存 为了获得更好的性能,NHibernate智能地缓存数据。NHibernate有不同的缓存机制起作用,最重要的就是一级缓存。每个session对象维持一个一级缓存,session对象创建时缓存创建,session对象释放时缓存销毁。 缓存只不过是一个哈…

Freemarker模板引擎

模板引擎的实质就是将页面结构提前写好,然后将数据渲染到模板上生成一个静态页面,这样一来,下次就可以 直接访问静态文件,不用进行额外的获取数据的操作(例如:访问数据库),这样大大提…

postgresql主从备份_基于windows平台的postgresql主从数据库流备份配置

基于windows平台的postgresql主从数据库流备份配置因工作需要,需要搞pg数据库的主从备份,领导给了个方向使用流备份,于是开始朝着这个方向进发。鸣谢大佬A_ccelerator的博客一、配置主从库1.环境准备对于 pg 的主从库配置,建议是使…

msvcrt.lib和LIBCD.lib链接冲突

今天在移植一个开源代码到windows的VC6工程,编译时出现了这些奇怪的LINK错误。 msvcrt.lib(MSVCRT.dll) : error LNK2005: _toupper already defined in LIBCD.lib(toupper.obj)msvcrt.lib(MSVCRT.dll) : error LNK2005: _tolower already defined in LIBCD.lib(to…

jq获取最后一个子节点_如何选择jQuery中的最后一个子元素?

牧羊人nacy如果要选择最后一个子元素,并且需要具体说明元素类型,则可以使用选择器last-of-type这是一个例子:$("div p:last-of-type").css("border", "3px solid red");$("div span:last-of-type").…

面向对象 - 继承/组合 - 总结

面向对象 - 继承:1.继承: 类与类之间的关系 什么是什么的关系 eg:人是动物 狗是动物 功能: 解决代码重用问题, 创建新类的方式, 类: 可继承一个或多个父类: 父类 基类/超类 类 派生类/子类 类: 对象之间相似的特征 父类:…

巧妙的有css合并图片解决tab切换的背景图片

巧妙的有css合并图片解决tab切换的背景图片 有时候做tab切换的时候 会碰到下面的这种情况 我截个图过来看看 tab切换 打开页面时候 茶庄介绍 及鼠标移上去时候 是上面这样的效果 当鼠标移下来的时候 是下面这样的 茶庄介绍 就变成这样的背景 一刚开始做这样的 我就想到用j…