微服务架构下的数据一致性

微服务架构中的数据一致性:如何保证最终一致性与强一致性 微服务架构中,数据一致性问题是一个无法回避的挑战。强一致性适用于关键业务场景,但可能牺牲性能。最终一致性适用于性能要求高、可容忍短暂不一致的场景。合理设计事务管理、利用消息队列和分布式锁等工具,可以帮助我们在一致性与性能之间找到最佳平衡点。在你的项目中,可以尝试不同的模式,找到最适合的解决方案! 阅读详情

一、分布式事务保证一致性

1.1 两阶段提交

在分布式系统中,每个节点虽然可以知晓自己的操作时成功或者失败,却无法知道其他节点的操作的成功或失败。当一个事务跨越多个节点时,为了保持事务的ACID特性,需要引入一个作为协调者的组件来统一掌控所有节点(称作参与者)的操作结果并最终指示这些节点是否要把操作结果进行真正的提交(比如将更新后的数据写入磁盘等等)。因此,二阶段提交的算法思路可以概括为:参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。

所谓的二阶段提交(Two Phase Commit)是指:

第一阶段:准备阶段(投票阶段)

第二阶段:提交阶段(执行阶段)

这里写图片描述

缺点:

1、同步阻塞问题。执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。

2、单点故障。由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)。

3、数据不一致。在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据不一致性的现象。

4、二阶段无法解决的问题:协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。


1.2 传统分布式事务不是微服务中一致性的最佳选择

依据CAP理论,必须在可用性(availability)和一致性(consistency)之间做出选择。如果选择提供一致性需要付出在满足一致性之前阻塞其他并发访问的代价。这可能持续一个不确定的时间,尤其是在系统已经表现出高延迟时或者网络故障导致失去连接时。

依据目前的成功经验,可用性一般是更好的选择,但是在服务和数据库之间维护数据一致性是非常根本的需求,微服务架构中选择满足最终一致性。

当然选择了最终一致性,就要保证到最终的这段时间要在用户可接受的范围之内。


二、微服务架构实现最终一致性的三种模式

2.1 可靠事件模式

可靠事件模式属于事件驱动架构,当某件重要事情发生时,例如更新一个业务实体,微服务会向消息代理发布一个事件。消息代理会向订阅事件的微服务推送事件,当订阅这些事件的微服务接收此事件时,就可以完成自己的业务,也可能会引发更多的事件发布。

2.1.1 例子

(1)如订单服务创建一个待支付的订单,发布一个“创建订单”的事件。

这里写图片描述

(2)支付服务消费“创建订单”事件,支付完成后发布一个“支付完成”事件。

这里写图片描述

(3)订单服务消费“支付完成”事件,订单状态更新为待出库。


2.1.2 难点

这个过程可能导致出现不一致的地方在于:

  • 某个微服务在更新了业务实体后发布事件却失败;
  • 虽然微服务发布事件成功,但是消息代理未能正确推送事件到订阅的微服务;
  • 接受事件的微服务重复消费了事件。

可靠事件模式在于保证可靠事件投递和避免重复消费。

避免重复消费要求服务实现幂等性,如支付服务不能因为重复收到事件而多次支付。


2.1.3 异常捕获和回滚

举个例子,Bob向Smith转账100块,那我们到底是先发送消息,还是先执行扣款操作?

为了实现可靠事件投递,我们可以采用异常捕获和回滚。即先执行业务操作,再发送消息,如果消息发送失败,则回滚业务操作。

缺点:

(1)在网络不稳定的情况下,Producer发送的消息可能已经被消息中间件成功接收,但是返回超时了,这时Producer回滚了本地事务,这就会造成Bob并没有减少100块,但Smith增加了100块。

(2)在投递完成后到数据库commit操作之间如果微服务宕机也将造成数据库操作因为连接异常关闭而被回滚。最终结果还是事件被投递,数据库却被回滚。

2.1.4 本地事件表

在基于异常捕获和回滚的可靠事件方案中,本地事件表这样改进:

  • 在发布事件之前要先在本地事件表中添加一条记录,
  • 如果事件发布成功立即删除记录,
  • 事件恢复服务定时从事件表中恢复未发布成功的事件,重新发布,重新发布成功才删除记录的事件。

缺点:

额外的事件数据库操作也会给数据库带来额外的压力,可能成为瓶颈。


2.1.5 事务消息

下面以阿里巴巴的RocketMQ中间件为例,分析下其设计和实现思路。

第一阶段Producer发送Prepared消息时,RocketMQ也不会对外发送消息;

第二阶段:执行本地事务;在业务回滚时,通过实时事件向事件系统取消事件;

第三阶段,Producer向RocketMQ发送确认消息,这时RocketMQ才会对订阅者发送消息。如果确认消息发送失败,RocketMQ会定期扫描消息集群中的事物消息,这时候发现了Prepared消息,它会向消息发送者确认,Bob的钱到底是减了还是没减呢?如果减了是回滚还是继续发送确认消息呢?如下图:

这里写图片描述

我们继续分析分析异常情况。如果Prepared消息发送失败,则本地事务就不会执行;即使Prepared消息超时但是RocketMQ收到了Prepared消息,MQ也不会对外发送消息,而是调用Producer的反查接口确认这个消息的当前状态。

总结:据笔者的了解,各大知名的电商平台和互联网公司,几乎都是采用类似的设计思路来实现“最终一致性”的。这种方式适合的业务场景广泛,而且比较可靠。不过这种方式技术实现的难度比较大。目前主流的开源MQ(ActiveMQ、RabbitMQ、Kafka)均未实现对事务消息的支持,所以需二次开发或者新造轮子。比较遗憾的是,RocketMQ事务消息部分的代码也并未开源,需要自己去实现。

做过支付宝交易接口的同学都知道,我们一般会在支付宝的回调页面和接口里,解密参数,然后调用系统中更新交易状态相关的服务,将订单更新为付款成功。同时,只有当我们回调页面中输出了success字样或者标识业务处理成功相应状态码时,支付宝才会停止回调请求。否则,支付宝会每间隔一段时间后,再向客户方发起回调请求,直到输出成功标识为止。


2.1.6 幂等性

为保证幂等性一个简单的做法是在事件中添加时间戳,微服务记录每类型的事件最后处理的时间戳,如果收到的事件的时间戳早于我们记录的,丢弃该事件。

如果事件不是在同一个服务器上发出的,那么服务器之间的时间同步是个难题,更稳妥的做法是使用一个全局递增序列号替换时间戳。

对于本身不具有幂等性的操作,主要思想是为每条事件存储执行结果,当收到一条事件时我们需要根据事件的id查询该事件是否已经执行过,如果执行过直接返回上一次的执行结果,否则调度执行事件。


2.2 补偿模式

为了描述方便,这里先定义两个概念:

  • 业务异常:业务逻辑产生错误的情况,比如账户余额不足、商品库存不足等。
  • 技术异常:非业务逻辑产生的异常,如网络连接异常、网络超时等。

补偿模式使用一个额外的协调服务来协调各个需要保证一致性的微服务,协调服务按顺序调用各个微服务,如果某个微服务调用异常(包括业务异常和技术异常)就取消之前所有已经调用成功的微服务。

补偿模式建议仅用于不能避免出现业务异常的情况,如果有可能应该优化业务模式,以避免要求补偿事务。如账户余额不足的业务异常可通过预先冻结金额的方式避免,商品库存不足可要求商家准备额外的库存等。我们通过一个实例来说明补偿模式,一家旅行公司提供预订行程的业务,可以通过公司的网站提前预订飞机票、火车票、酒店等。


2.2.1 例子

假设一位客户规划的行程是,(1)上海-北京6月19日9点的某某航班,(2)某某酒店住宿3晚,(3)北京-上海6月22日17点火车。在客户提交行程后,旅行公司的预订行程业务按顺序串行的调用航班预订服务、酒店预订服务、火车预订服务。最后的火车预订服务成功后整个预订业务才算完成。

这里写图片描述

如果火车票预订服务没有调用成功,那么之前预订的航班、酒店都得取消。取消之前预订的酒店、航班即为补偿过程。

这里写图片描述

2.2.2 实现原理

开发者还可以将整个行为链加密,这样只有该行为链的接收者才能够操控这个行为链。当一个行为完成后,会将完成的信息记录到一个集合(比如说,是一个队列)中,之后可以通过这个集合访问到对应的行为。当一个行为失败的实收,行为将本地清理完毕,然后将消息发送给该集合,从而路由到之前执行成功的行为,然后回滚所有的事务。

程序会生成一个典型的集合用来访问对应的行为链中的行为,会创建3个独立的进程,每一个进程都会负责一个指定的任务。分别是租车,预订酒店以及预订机票三个独立的任务。

static ActivityHost[] processes;

static void Main(string[] args)
{
    var routingSlip = new RoutingSlip(new WorkItem[]
    {
        new WorkItem<ReserveCarActivity>(new WorkItemArguments),
        new WorkItem<ReserveHotelActivity>(new WorkItemArguments),
        new WorkItem<ReserveFlightActivity>(new WorkItemArguments)
    });

    // imagine these being completely separate processes with queues between them
    processes = new ActivityHost[]
    {
        new ActivityHost<ReserveCarActivity>(Send),
        new ActivityHost<ReserveHotelActivity>(Send),
        new ActivityHost<ReserveFlightActivity>(Send)
    };

    // hand off to the first address
    Send(routingSlip.ProgressUri, routingSlip);
}

static void Send(Uri uri, RoutingSlip routingSlip)
{
    // this is effectively the network dispatch
    foreach (var process in processes)
    {
        if (process.AcceptMessage(uri, routingSlip))
        {
            break;
        }
    }
}

其中的AcitivityHost就是对外部服务的一个抽象,RoutingSlip是对前面说的集合的抽象。
下面是具体的一个服务的简化实现,ReserveHotelActivity以及ReserveFlightActivity的实现就不在此处列出了,下面是ReserveCarActivity的实现。其中主要包括的几个方法:

DoWork以及Compensate方法是Activity抽象出来的用来执行实际操作以及回滚的补偿方法。
WorkItemQueueAddress以及CompensationQueueAddress都是用来索引到对应服务的。参考如下代码:

class ReserveCarActivity : Activity
{
    static Random rnd = new Random(2);

    public override WorkLog DoWork(WorkItem workItem)
    {
        Console.WriteLine("Reserving car");
        var car = workItem.Arguments["vehicleType"];
        var reservationId = rnd.Next(100000);
        Console.WriteLine("Reserved car {0}", reservationId);
        return new WorkLog(this, new WorkResult
        {
            { "reservationId", reservationId }
        });
    }

    public override bool Compensate(WorkLog item, RoutingSlip routingSlip)
    {
        var reservationId = item.Result["reservationId"];
        Console.WriteLine("Cancelled car {0}", reservationId);
        return true;
    }

    public override Uri WorkItemQueueAddress
    {
        get { return new Uri("sb://./carReservations"); }
    }

    public override Uri CompensationQueueAddress
    {
        get { return new Uri("sb://./carCancellactions"); }
    }
}

RoutingSlip是对成功行为集合的抽象,用来索引到对应的服务,包含了两个队列,一个是完成的任务,一个是等待执行的任务。RoutingSlip主要用来控制连接多个行为。如果成功就会将任务向前执行,如果失败就会向后执行 。RoutingSlip使用队列来向前执行,使用栈来向后执行。

class RoutingSlip
{
    readonly Stack<WorkLog> completedWorkLogs = new Stack<WorkLog>();
    readonly Queue<WorkItem> nextWorkItem = new Queue<WorkItem>();

    public RoutingSlip()
    {
    }

    public RoutingSlip(IEnumerable<WorkItem> workItems)
    {
        foreach (var workItem in workItems)
        {
            this.nextWorkItem.Enqueue(workItem);
        }
    }

    public bool IsCompleted
    {
        get { return this.nextWorkItem.Count == 0; }
    }

    public bool IsInProgress
    {
        get { return this.completedWorkLogs.Count > 0; }
    }

    public bool ProcessNext()
    {
        if (this.IsCompleted)
        {
            throw new InvalidOperationException();
        }

        var currentItem = this.nextWorkItem.Dequeue();
        var activity = (Activity) Activator.CreateInstance(
            currentItem.ActivityType);

        try
        {
            var result = activity.DoWork(currentItem);
            if (result != null)
            {
                this.completedWorkLogs.Push(result);
                return true;
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception {0}", e.Message);
        }
        return false;
    }

    public Uri ProgressUri
    {
        get
        {
            if (IsCompleted)
            {
                return null;
            }
            else
            {
                return
                    ((Activity)Activator.CreateInstance(this.nextWorkItem.Peek().ActivityType)).
                        WorkItemQueueAddress;
            }
        }
    }

    public Uri CompensationUri
    {
        get
        {
            if (!IsInProgress)
            {
                return null;
            }
            else
            {
                return ((Activity) Activator.CreateInstance(
                    this.completedWorkLogs.Peek().ActivityType)).
                        CompensationQueueAddress;
            }
        }
    }

    public bool UndoLast()
    {
        if (!this.IsInProgress)
        {
            throw new InvalidOperationException();
        }

        var currentItem = this.completedWorkLogs.Pop();
        var activity = (Activity) Activator.CreateInstance(
            currentItem.ActivityType);

        try
        {
            return activity.Compensate(currentItem, this);
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception {0}", e.Message);
            throw;
        }
    }
}

ActivityHost会调用RoutingSlip上面的ProcessNext方法来解析下一个行为并正向调用DoWork()或者反向调用Compensate()方法。

abstract class ActivityHost
{
    Action<Uri, RoutingSlip> send;

    public ActivityHost(Action<Uri, RoutingSlip> send)
    {
        this.send = send;
    }

    public void ProcessForwardMessage(RoutingSlip routingSlip)
    {
        if (!routingSlip.IsCompleted)
        {
            // if the current step is successful, proceed
            // otherwise go to the Unwind path
            if (routingSlip.ProcessNext())
            {
                // recursion stands for passing context via message
                // the routing slip can be fully serialized and passed
                // between systems.
                this.send(routingSlip.ProgressUri, routingSlip);
            }
            else
            {
                // pass message to unwind message route
                this.send(routingSlip.CompensationUri, routingSlip);
            }
        }
    }

    public void ProcessBackwardMessage(RoutingSlip routingSlip)
    {
        if (routingSlip.IsInProgress)
        {
            // UndoLast can put new work on the routing slip
            // and return false to go back on the forward
            // path
            if (routingSlip.UndoLast())
            {
                // recursion stands for passing context via message
                // the routing slip can be fully serialized and passed
                // between systems
                this.send(routingSlip.CompensationUri, routingSlip);
            }
            else
            {
                this.send(routingSlip.ProgressUri, routingSlip);
            }
        }
    }

    public abstract bool AcceptMessage(Uri uri, RoutingSlip routingSlip);
}

2.3 TCC模式(Try-Confirm-Cancel)

一个完整的TCC业务由一个主业务服务和若干个从业务服务组成,主业务服务发起并完成整个业务活动,TCC模式要求从服务提供三个接口:Try、Confirm、Cancel。

(1) Try:完成所有业务检查

预留必须业务资源

(2) Confirm:真正执行业务

不作任何业务检查

只使用Try阶段预留的业务资源

Confirm操作满足幂等性

(3)Cancel:

释放Try阶段预留的业务资源

Cancel操作满足幂等性

整个TCC业务分成两个阶段完成。

这里写图片描述

第一阶段:主业务服务分别调用所有从业务的try操作,并在活动管理器中登记所有从业务服务。当所有从业务服务的try操作都调用成功或者某个从业务服务的try操作失败,进入第二阶段。

第二阶段:活动管理器根据第一阶段的执行结果来执行confirm或cancel操作。如果第一阶段所有try操作都成功,则活动管理器调用所有从业务活动的confirm操作。否则调用所有从业务服务的cancel操作。

需要注意的是第二阶段confirm或cancel操作本身也是满足最终一致性的过程,在调用confirm或cancel的时候也可能因为某种原因(比如网络)导致调用失败,所以需要活动管理支持重试的能力,同时这也就要求confirm和cancel操作具有幂等性。

2.3.1 TCC和2PC的区别

  • TCC是更上层的抽象,Try阶段冻结资源(业务层面,不一定涉及本地事务),Comfirm/Cancel阶段执行事务或者取消;
  • 2PC是在Prepare阶段就已经开启了各个服务的本地事务,所以性能很低。

总的来说,TCC实际上把数据库层的二阶段提交上提到了应用层来实现,对于数据库来说是一阶段提交,规避了数据库层的2PC性能低下问题。

TCC事务的缺点,主要就一个:TCC的Try、Confirm和Cancel操作功能需要业务提供,开发成本高。


三、对账是最后的终极防线

如果有些业务由于瞬时的网络故障或调用超时等问题,通过上文所讲的3种模式一般都能得到很好的解决。但是在当今云计算环境下,很多服务是依赖于外部系统的可用性情况,在一些重要的业务场景下还需要周期性的对账来保证真实的一致性。比如支付系统和银行之间每天日终是都会有对账过程。

微服务架构下的数据一致性保证 从2014年开始,微服务逐渐进入大家的实现,被认为是下一代实现信息化的有效手段。设计到系统,其中绕不开的就是数据一致性,从本地事务,到后来的分布式事务,都能够有效的保证数据一致性。但是在微服务架构中,这两种方式都不是最好的选择。 1. 使用本地事务和分布式事务保证一致性 在传统的单击应用中,最简单、最直接、最普遍的会使用一个关系型数据库,通过关系型数据库的事务保证数据的一致性。这种事务有四个基... 阅读详情

相关推荐

一笔订单的一致性远征:两阶段提交的困局、CAP与BASE的取舍与六种柔性事务模式的工程选型

微服务拆分后,单体里一个本地事务就能保证的原子性被服务边界切断,跨服务丢失、幽灵、重复与悬挂随之出现。本文跟随一笔订单,先剖析XA与两阶段、三阶段提交,用离散事件仿真对比二者在协调者宕机与网络分区下的锁持有和数据分叉;再借CAP、PACELC、一致性模型光谱与BASE思想划定理论边界;随后逐一拆解可靠事件、补偿、Saga、TCC、最大努力通知与人工干预六种柔性事务模式的思路、关键点、实现策略与实测数据;最后给出横向对比、选型决策路径与下单链路组合方案,说明最终一致需要幂等、可观测与对账兜底。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 170万+

如何在微服务下保证事务的一致性 | 京东云技术团队

随着业务的快速发展、业务复杂度越来越高,传统单体应用逐渐暴露出了一些问题,例如开发效率低、可维护性差、架构扩展性差、部署不灵活、健壮性差等等。而微服务架构是将单个服务拆分成一系列小服务,且这些小服务都拥有独立的进程,彼此独立,很好地解决了传统单体应用的上述问题,但是在微服务架构下如何保证事务的一致性呢?

JDDTechTalk的博客 980

聊一聊微服务架构中的数据一致性

在微服务中,一个逻辑上原子操作可以经常跨越多个微服务。即使是单片系统也可能使用多个数据库或消息传递解决方案。使用多个独立的数据存储解决方案,如果其中一个分布式流程参与者出现故障,我们就会面临数据不一致的风险 - 例如在未下订单的情况下向客户收费或未通知客户订单成功。在微服务中,一个逻辑上原子操作可以经常跨越多个微服务。即使是单片系统也可能使用多个数据库或消息传递解决方案。

leyang0910的博客 1285

关于微服务系统中数据一致性的总结

笔者看山,本文是在阅读周志明老师的《凤凰架构》之后,对微服务的数据一致性做的总结。从单体架构到分布式架构,从巨石架构到微服务架构。系统之间的交互越来越复杂,系统间的数据交互量级也是指数级增...

华章IT官方博客 883

微服务架构设计原理与实战:如何进行微服务的数据一致性

作者:禅与计算机程序设计艺术 1.背景介绍 随着互联网技术的发展,网站应用服务越来越多样化,形成了庞大的微服务体系。对于这样的分布式系统来说,服务之间的数据一致性是一个关键问题。对于某些微服务架构来说,无状态的组件之间可以直接通信,而有状态的组件往往需要通过数据存储来实现数据的一致性。本文将会从微服

AI天才研究院 376

手把手教你用树莓派蓝牙抓取小米温湿度计2代数据,接入HomeAssistant(附密钥获取避坑指南)

本文详细介绍了如何通过树莓派蓝牙抓取小米温湿度计2代数据并接入HomeAssistant的完整流程。重点解析了获取32位加密密钥的三种方法,包括使用Telink Flasher工具、米家APP抓包和开源工具ATC_MiThermometer,并提供了HomeAssistant集成配置和常见问题排查指南,帮助用户实现稳定可靠的温湿度监测。

一名菜鸟攻城师 779

在微服务架构中的数据一致性

当从传统的单体应用架构转移到微服务架构时,特别是涉及数据一致性时,数据一致性是微服务架构中最困难的部分。传统的单体应用中,一个共享的关系型数据库负责处理数据一致性。在微服务架构中,如果使用“每个服务一个数据库”的模式,那么每个微服务都有自己的数据存储。因此,数据库在应用程序之间是分布式的。如果每个应用程序使用不同的技术来管理它们的数据,比如非关系型数据库,这种分布式架构虽然在数据管理方面有许多好处...

小技术君 1477

五段式S型算法笔记

又因为有 v-v0= 0.5jt通式: 所以有 vm-v0= 0.5jtm 所以有4vm-4v0= 2jtm。算法1: v=2vm-v0-0.5*jt+2jt*tm-2jtm*tm。加加速度j 自己设置 已知,vmax自己设置已知;所以有4vm-4v0= 2jtm带入算法1。

qq_36658033的博客 681

如何保证微服务架构数据一致性的问题

1、微服务架构数据一致性问题  电商为例,支付,订单,积分功能抽成三个服务,每个服务都有独立的数据库做数据存储。无论是修改订单状态失败,还是增加积分失败,都会导致数据的不一致 支付--------&gt;订单---------&gt;积分 为了解决这种问题,最好的方法避免微服务,实现本地事务保证数据的强一致性。但微服务架构中,每个服务都有自己的数据库,导致微服务系统不能简单的满足本地事务的特...

言午戌的博客 2458

超实用!用 Ollama + DeepSeek + Dify 搭建本地知识库,提升企业效率

本文介绍了如何使用 Ollama + DeepSeek + Dify 搭建本地知识库,帮助企业高效管理信息。通过简单配置,可实现智能问答、文档检索等功能,提升效率并保障数据安全。

Happiness is everywhere 4294

VC Spyglass CDC验证避坑指南:如何正确配置同步复位信号(实验二重点解析)

本文深入解析VC Spyglass CDC验证中同步复位信号的正确配置方法,通过实验二案例详细展示错误配置的典型表现及修正过程。文章提供同步复位的最佳实践方案,包括约束文件修改指南、验证流程优化建议和高级调试技巧,帮助工程师有效避免CDC验证中的常见陷阱。

rock5的博客 678

微服务架构中的数据一致性设计及技术实现

胡弦,视频号2023年度优秀创作者,互联网大厂P8技术专家,Spring Cloud Alibaba微服务架构实战派(上下册)和RocketMQ消息中间件实战派(上下册)的作者,资深架构师,技术负责人,极客时间训练营讲师,四维口袋KVP最具价值技术专家,技术领域专家团成员,2021电子工业出版社年度优秀作者,获得2023电子工业出版技术成长领路人称号。

huxian1234的专栏 1671

CHB-MIT波士顿儿童医院癫痫EEG脑电数据处理(一)

CHB-MIT癫痫EEG脑电数据处理CHB-MIT头皮脑电图数据介绍CHB-MIT头皮脑电图数据下载CHB-MIT头皮脑电图数据处理提取原始数据滤波(0.1~50hz)数据分块(时间窗口) CHB-MIT头皮脑电图数据介绍 该数据库收集自波士顿儿童医院,其中包括患有难治性癫痫发作的儿科患者的脑电图记录。停用抗癫痫药物后最多持续几天对受试者进行监测,以表征其癫痫发作并评估其对手术干预的候选资格。 从22位受试者中收集了23个病例的记录(5例男性,3至22岁; 17例女性,1.5至19岁)。 (案例chb21是

AI_DOG的博客 1万+

Java 微服务架构下的数据一致性问题

Java 微服务架构下的数据一致性问题 大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿! 随着微服务架构的流行,服务的独立性和可扩展性得到了极大的提升。然而,微服务架构也带来了数据一致性问题。在分布式系统中,确保数据的一致性是一个复杂且具有挑战性的任务。本文将探讨在Java微服务架构下处理...

weixin_29504817的博客 157

邮件伪造和SPF

之前看了下邮件伪造觉得挺有意思的,所以看了下邮件伪造的东西,下面简单的总结了一下,如果有不妥的地方还望大佬们提出来。 1. 什么是SPF SPF是 Sender Policy Framework 的缩写,一种以IP地址认证电子邮件发件人身份的技术,是为了防范垃圾邮件而提出来的一种DNS记录类型,它是一种TXT类型的记录。 接收邮件方会首先检查域名的SPF记录,来确定发件人的IP地址是否被包含在SP...

SunJ3t的菠萝屋 2448

使用 MATLAB/Simulink + Simscape Electrical,构建一个含储能的微电网系统,实现储能系统与并网逆变器的协同控制

摘要:本文基于Simulink平台,详细介绍了微电网中储能系统与并网逆变器的协同控制建模与仿真方法。主要内容包括:1)构建包含光伏、风电、锂电池和双向DC-DC变换器的微电网系统;2)设计并网逆变器的PQ/Vf双模式控制策略;3)实现储能系统与逆变器的协同控制逻辑,包括SOC保护和功率分配;4)通过多种工况仿真验证系统性能。结果表明,该系统能有效维持微电网稳定运行,支持并网/离网无缝切换。文章还探讨了优化方向和应用扩展,为新能源微电网控制提供了实用参考。

xiaoheshang_123的博客 100

微服务架构下,解决数据一致性问题的实践

牛旦教育IT课堂2019-03-19 12:22:00 ✏️ Pic by Alibaba Tech on Facebook 随着业务的快速发展,应用单体架构暴露出代码可维护性差、容错率低、测试难度大和敏捷交付能力差等诸多问题,微服务应运而生。微服务的诞生一方面解决了上述问题,但是另一方面却引入新的问题,其中主要问题之一就是:如何保证微服务间的业务数据一致性。 ...

u011277123的博客 2514

【零基础入门unity游戏开发——2D篇】SpriteEditor图片编辑器

【零基础入门unity游戏开发——2D篇】SpriteEditor图片编辑器

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 2328

如何保障微服务架构下的数据一致性

1、微服务架构的数据一致性问题 以电商平台为例,当用户下单并支付后,系统需要修改订单的状态并且增加用户积分。由于系统采用的是微服务架构,分离出了支付服务、订单服务和积分服务,每个服务都有独立数据库做数据存储。当用户支付成功后,无论是修改订单状态失败还是增加积分失败,都会造成数据的不一致。 为了解决例子中的数据一致性问题,一个最直接的办法就是考虑数据的强一致性。那么如何保证数据的强一致性呢?...

qq_36358942的博客 213

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

微服务架构设计原理与实战:微服务的数据一致性问题

1.背景介绍 微服务架构是近年来逐渐成为主流的软件架构设计方法。它将单个应用程序拆分成多个小的服务,这些服务可以独立部署和扩展。这种设计方法的主要优势在于它可以提高应用程序的可扩展性、可维护性和可靠性。然而,这种设计方法也带来了一些挑战,其中最重要的是如何实现数据一致性。 数据一致性是微服务架构中的一个关键问题,因为在分布式系统中,数据可能会在多个服务之间复制和更新。如果不能保证数据的一致性,...

AI天才研究院 1184

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

如何保障微服务架构下的数据一致性?

写在前面 随着微服务架构的推广,越来越多的公司采用微服务架构来构建自己的业务平台。就像前边的文章说的,微服务架构为业务开发带来了诸多好处的同时,例如单一职责、独立开发部署、功能复用和系统容错等等,也带来一些问题。 例如上手难度变大,运维变得更复杂,模块之间的依赖关系更复杂,数据一致性难以保证,等等。但是办法总是比问题多,本篇文章就来介绍一下我们是如何保障微服务架构的数据一致性的。 微服务架构...

caodongfang126的博客 373
上一篇: 会话保持原理
下一篇: Redis键过期-内存淘汰-持久化原理
奋起直追CDS
博客等级 码龄11年 57粉丝 94原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值