在分布式环境中使用状态机支持数据的一致性

简介

在本文中,我们将介绍如何在分布式系统中使用transaction以及分布式系统中transaction的局限性。然后我们通过一个具体的例子,介绍了一种通过设计状态机来避免使用transaction的方法。

什么是数据库transaction

Transaction是关系型数据普遍支持的一种操作。Transaction可以包含若干对数据库的操作。如果任何操作失败,所有的操作都被取消,数据保持transaction执行前的状态。这种情况叫回滚(rollback)。假如所有操作成功,transaction被认为成功。这种情况叫做提交(commit)。Transaction需要支持所谓的ACID。因为我们这种主要介绍NO-SQL数据库的transaction,ACID就不详细说了,如果不熟悉大家可以自行阅读。Transaction对于维护数据的完整性非常重要。比如说对于在两个银行账户之间的转账操作,从一个账户扣除金额和向一个账户增加金额就应该放在一个transaction里。否则只完成了扣除操作或者只完成增加操作,都会破坏数据的完整性,恢复起来非常麻烦。

No-SQL数据库的transaction

不少No-SQL数据库也支持transaction,但是普遍来说No-SQL数据库对transaction的支持相对较弱。主要原因是No-SQL数据库一般都是基于分布式的架构设计和实现的,而transaction的某些特性是和分布式系统有冲突的。比如说,在分布式系统中,我们往往放弃数据的强制一致性而追求整体系统的可用性。但是数据可能存在不一致的状态对于维护transaction的原子性和一致性是非常大的挑战。

我们在这里以AWS的DynamoDB为例。DDB支持两种transaction:写transaction和读transaction。写transaction可以支持最多100个写操作,包括put(创建),update(更新),delete(删除),和conditionCheck(条件检查)。而读transaction可以支持最多100个读操作,也就是通过primary key获取一个item,即Get。关于DDB的transaction的介绍可以参考这篇文档。

问题

现在我们在DDB中有四张表。表1保存了某种记录,该记录拥有自己的primary key,同时该记录还拥有3种其它的属性可以作为index。另外3张表即用来保存某种index到该记录的primary key的对应关系。关系如下所示:

需要说明的是每一种index都可能有多个值,也就是说在item里每种index都是一个list。比如说对于一个item,我们可能有3个index1,5个index2,10个index3。这样我们就要在index1表中创建3条记录,在index2表中创建5条记录,在index3中创建10条记录。很明显,我们需要保持item和它相关的index的完整性。也就是说我们不希望出现如下的情况:

  1. Index存在,但是其索引的item已经被删除了;
  2. Index存在,但是它已经不该索引到当前的item了;
  3. Item存在,但是它的某个index丢失了;
  4. 。。。

如果我们考虑使用DDB transaction来解决这个问题,我们会发现我们可能面临下面两个问题:

  • 一个item和它的索引数目大于100,所以DDB transaction无法支持该操作;
  • 因为有太多的数据要被一起更新,有很大的概率更新之间经常互相冲突,造成transaction的commit的成功率很低。

那么我们该如何解决这个问题呢?

解决方案

通过分析,我们发现这个问题其实可以通过设计一个简单的状态机来解决。我们将该方法的细节描述如下。

首先,我们规定在更新item和index时,我们遵循以下的顺序:

  1. 更新index1
  2. 更新index2
  3. 更新index3
  4. 更新item

如果我们其中任何一个步骤失败的话,我们就终止掉本次更新,并且抛出一个异常,然后根据设定在某段时间后重新尝试更新。根据我们执行的过程,我们可能会有如下的状态和状态转换:

最开始假设我们处于一个合法的状态下,也就是说item的RVN和index的RVN是相等的,都是n。然后我们更新index成功,此时我们处于一个临时状态下,也就是index的RVN变成了n+1,但是item的RVN仍然是n。再然后我们更新item成功,我们就转换成下一个合法的状态,也就是item的RVN和index的RVN再次相等,都变成了n+1。有一个例外的不合法状态,就是item的RVN已经变成了n+1,但是index的RVN仍然是n。出现这种状态的原因是这个index被从RVN为n+1的数据中移除出去了,那么此时这个index就不能再被认为是该item的合法索引了。

现在我们在更新数据时逻辑非常简单,我们不需要做很多的比较和检查,仅仅是依照顺序依次更新index和item即可。那么在使用该index查询item时,我们就需要做一些检查工作,确保我们是通过合法的index找到了合法的item。首先,我们需要一个index的值,来获取该index的RVN。然后我们通过该index获取item和item的RVN。然后我们检查的具体逻辑如下:

  1. 假如index的RVN和item的RVN相等,那么我们得到的index和item都是合法的;
  2. 假如index的RVN大于item的RVN,那么我们得到的是一个临时状态数据。我们可以抛出一个异常,然后重新尝试读取数据;
  3. 假如index的RVN小于item的RVN,我们是否可以直接认为数据不合法而放弃呢?是不可以的。原因在于有可能在我们得到index的RVN和得到item的RVN之间有过一次更新,从而使得我们已经有的index的RVN变旧了。所以我们要再次查询一次index的RVN,然后分成下面三种情况进行处理:
    1. 如果新的index的RVN仍然等于之前得到的index的RVN,说明是index被移除的情况,此时我们应该认为通过该index查询不到item;
    2. 如果新的index的RVN和item的RVN相等了,说明我们得到了合法的数据;
    3. 如果新的index的RVN和item的RVN仍然不相等,并且新的index的RVN和之前的index的RNV也不相等,说明我们得到的是一个中间状态的数据。我们可以抛出异常然后重新尝试查询。

通过这个处理逻辑,我们是可以完成保证没有任何合法的数据被遗漏,通过也不会有任何非法的数据被使用的。

结论和扩展

本文中,我们介绍了一种通过设计状态机以达到最终数据一致性的方法来避免使用transaction的方法。在这里我们看到两个问题:第一,在分布式环境中的transaction通过有一定的局限性,并且transaction本身运行的代价也很大,所以我们在决定使用transaction的时候还要经过和其它方法的比较,以及分析可能出现的局限性和问题;第二,基于数据的最终一致性,我们可能会发现其它更简单的方法以避免使用transaction。但是需要说明的是,这里并不是简单的建议不使用transaction。事实上,transaction在很多情况下是最佳解决方案。只是提供一个在使用transaction之外的其它代替方案。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Ubuntu】gonme桌面的 gdm 和 lightdm 区别

总结:都可以 gdm: 【Gnome Display Manager】 完整,体积大 lightdm: 【Light Display Manager】 轻量

学习Java的第十天

本章来讲一下什么是字符串 一、什么是字符串 在Java中,最常见的基本类型就是字符串了,哪哪都能见到,如输入语句,输出语句等!那么,什么是字符串呢,字符串就是String类,String类是Ja…

【Python】新手入门学习:详细介绍里氏替换原则(LSP)及其作用、代码示例

【Python】新手入门学习:详细介绍里氏替换原则(LSP)及其作用、代码示例 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyT…

颠覆传统!D 咖无人咖啡机再添新动作

D 咖无人咖啡机,作为国内领先的无人自助咖啡机品牌,一直以来都在不断创新和升级,以满足消费者日益增长的咖啡需求。近日,D 咖智能饮品机再添新动作,推出了一系列令人期待的新功能和服务,再次引领便捷咖啡新…

[MYSQL数据库]- 索引

前言 作者:小蜗牛向前冲 名言:我可以接受失败,但我不能接受放弃 如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、认识索…

C#快速入门基础

本篇文章从最基础的C#编程开始学习,经过非常优秀的面向对象编程思想和方法的学习,为C#编程打下基础。 第 01 章 C#开发环境之VS使用和.NET平台基础 1.1 Visual Studio 开发环境 1.1.1 硬件环境 i5CPUi5CPU(建议 4核 4线程或以上 &#xff0…

android 怎么自定义view

首先了解view的绘制流程: 所以onmeasure ---测量view onlayout---确定view大小----》所以继承ViewGroup必须要重写onlayout,确定子view 而onDraw----是继承view时候需要操作的。 所以:自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件。 自定义Vi…

计算机网络——计算机网络体系结构

计算机网络——计算机网络体系结构 计算机网络体系结构的由来正确认识分层协议与层次划分著名的几个体系结构OSI体系结构TCP/IP体系结构5层体系结构 我们今天来了解一下计算机网络体系结构: 计算机网络体系结构的由来 俗话说,“没有规矩,不…

Ele admin pro和iView Admin pro的用户管理页面对比

Ele admin pro和iView Admin pro都是非常优秀的B端框架,功能大同小异,本文就着重比对一下二者的用户案例页面,让老铁们感知一些细节。 一、用户列表 用户列表 用户列表 二、用户编辑 三、用户添加 四、角色管理 五、权限分配 六、角色添加

使用Python构建强大的网络爬虫

介绍 网络爬虫是从网站收集数据的强大技术,而Python是这项任务中最流行的语言之一。然而,构建一个强大的网络爬虫不仅仅涉及到获取网页并解析其HTML。在本文中,我们将为您介绍创建一个网络爬虫的过程,这个爬虫不仅可以获取和保存…

vivado 启动实施运行

启动实施运行 您可以启动活动的实现运行,也可以选择同时启动多个运行。 启动单个实施运行 执行以下任意操作以在“设计运行”窗口中启动活动的实现运行。启动单个实现运行将为实现启动一个单独的过程。 提示:在“设计运行”窗口中选择一个运行&#…

智慧公厕的特点和特色

智慧公厕是指利用信息化、数字化、智慧化技术,对公共厕所的使用、运营、管理、养护等全方位业务流程进行智能化改造的创新型厕所。这些智慧公厕不仅提供了便捷的厕所服务,还能提升城市形象,为智慧环卫等管理平台提供基础数据信息。本文以智慧…

串口协议、I2C协议、SPI协议总结

目录 一、串口协议 1.串口基本认知 2.RS-232 3.RS-422 4.RS-485 (1)RS232电平: (2)TTL电平: 6.串口51开发板实现 (1)软件自动配置: (2)…

Docker容器化技术(使用Dockerfile制作Nginx镜像)

编写Dockerfile制作Web应用系统nginx镜像,生成镜像名为nginx:v1.1,并推送其到私有仓库。 1、基于centos7基础镜像; 2、指定作者为Chinaskill; 3、安装nginx服务,将提供的dest目录传到镜像内,并将de…

从政府工作报告探计算机行业发展(在医疗健康领域)

从政府工作报告探计算机行业发展 政府工作报告作为政府工作的全面总结和未来规划,不仅反映了国家整体的发展态势,也为各行各业提供了发展的指引和参考。随着信息技术的快速发展,计算机行业已经成为推动经济社会发展的重要引擎之一。因此&…

使用 Jenkins 管道在 Docker Hub 中构建 Docker 镜像

Jenkins Pipeline 是一个强大的工具,可以自动执行部署。在各个阶段之间拆分的灵活和自定义操作是尝试此功能的一个很好的理由。 构建您自己的 Docker 镜像并将其上传到 Docker Hub 以保持存储库更新是了解 Jenkins Pipeline 如何改进您的工作方式的一个很好的示例。…

Oracle Primavera P6 Analytics 是什么,与P6的关系?

前言 Oracle Primavera P6 Analytics 是与P6有关的一个相对较新的模块,Primavera 用户社区在很大程度上尚未对其进行探索。 那么它到底有什么作用呢? 通过了解得知它旨在通过深入了解组织的项目组合绩效,帮助高级管理层对其项目组合做出更好…

DM数据库安装(Windows)

先解压安装包 点击setup安装 下一步 勾选接受然后下一步 下一步 选择典型安装下一步 下一步 搜索DM数据库配置助手然后一直下一步 然后搜索DM管理工具 登录 登录成功 widows版本安装成功

热门骨传导耳机深度评测:南卡、韶音、墨觉全面对比分析!

蓝牙耳机现在已经融入了我们的日常生活,尤其对于运动爱好者而言,一款好的蓝牙耳机不仅能够丰富锻炼时的听觉体验,还能激发运动热情。而骨传导耳机凭借着创新的设计理念和听音方式广受欢迎。骨传导耳机的优势可以让用户在听音乐的同时保持对周…

C++训练营:引用传递

大家好: 衷心希望各位点赞。 您的问题请留在评论区,我会及时回答。 一、引用传递 简单来说,“引用”就是给已有的变量起一个别名。引用并没有自己单独的内存空间,作为引用,它和原变量共用一段内存空间。引用的定义格…