关于数据同步:系统间数据同步场景及方法

10次阅读

共计 5391 个字符,预计需要花费 14 分钟才能阅读完成。

一、场景示例

本文的题目不是很顾名思义,然而你肯定在日常的开发工作中遇到过相似场景。

1. 场景一

假如公司从事电商业务,除了电商零碎外,公司外部个别也会有一个客户关系零碎(CRM)。如果 CRM 零碎心愿获取到电商零碎注册的客户信息,以实现本人的后续业务。该如何实现?

2. 场景二

仍然假如公司从事电商业务,电商零碎中通常有订单模块,模块中会有订单表。为了进步查问性能防止连表 Join,订单表除了存储用户 id 数据外也存储用户名作为冗余字段。用户侧业务用户名能够被更改,用户一旦更改了本人的用户名,订单表的数据也须要被更新。如何实现?

场景一是新增数据同步场景,场景二是更新数据同步场景。

3. 概念导入

在持续注释之前,咱们再细化两个概念。

3.1 如何定义“零碎”

题目中的“零碎”是被打上了引号,表明它其实一个很宽泛的定义,大到能够是一个业务功残缺的利用零碎平台(电商零碎、客户关系零碎),小到能够是一个单体利用中的业务模块(用户模块、订单模块)。这里的“零碎”不是按复杂程度、代码规模和实现形式划分的。 咱们将存储状态(数据)的业务组件定义为“零碎”

依据这个定义,一个微服务体系中微服务组件(用户核心、订单核心、库存核心、评估核心),分布式系统中主节点、从节点(各类中间件的架构)都是咱们文中的“零碎”。 因为两个零碎存储着状态(数据),所以“零碎”间有可能遇到须要状态(数据)同步的场景。

3.2 数据同步办法

“零碎”间同步数据的形式次要有三种:

  • 接口调用形式
  • 音讯队列形式
  • 数据库或文件形式(场景比拟小众,本文不开展形容)

三、接口调用形式实现

咱们应用接口调用的形式实现场景一、二中需要。

1. 场景一的实现形式

首先,如果电商零碎和 CRM 不是同期间上线的话,咱们要思考电商零碎历史存量数据问题,通常状况历史数据在首次数据同步的时候离线一次性导入。存量数据解决之后咱们就须要思考电商零碎的增量数据即新注册用户。依据接口调用方向有两种形式,数据推送模式和数据拉取模式。

1.1 数据推送模式


数据推送是一种绝对合乎直觉的形式,这是形式的语言形容就是“当你有新数据的时候通知我一声”, 这里的“通知”指的就是接口调用,就是电商零碎在有新用户注册的时候调用 CRM 提供的接口,将新增用户信息以接口入参的模式传递。

1.2 数据拉取模式


就像推和拉是一对反义词一样,数据拉取与数据推送在接口调用方向上是相同,由 CRM 调用电商零碎提供的接口,获取新增用户信息。

1.2.1 接口调用机会

因为 CRM 不晓得电商零碎何时会有新用户注册,所以它只能采纳轮询的形式定期调用接口。

1.2.2 获取数据形式

如何判断新增数据?就是在某个基线节点之后减少的数据,这个基线节点能够是工夫这个人造枯燥递增的数值也能够是其余枯燥递增的数值(数据库自增 ID)。所以电商零碎须要提供这样一个接口,以工夫(或自增 ID)为入参,批量查问出入参工夫(自增 ID)之后的所有数据。这也就要求电商零碎和 CRM 都要存储用户的创立工夫(或自增 ID)参数用于接口调用。

注:如果咱们用工夫作为接口参数,极其状况下可能呈现数据缺失问题,读者能够本人想一想起因

2. 场景二的实现形式

和场景一一样,如果后期没有思考过数据同步,也存在历史存量数据问题,也须要一次性批量同步。咱们重点关注增量数据,即前期产生的用户名更改数据同步问题。仍然有两种形式:

2.1 数据推送模式


和场景一的实现相似,只不过这次的语言形容变成了“当你有数据变动的时候通知我一声”,由用户模块调用订单模块接口,将用户名变动后的信息以接口入参的模式传递。

2.2 数据拉取模式


由订单模块调用用户模块提供的接口,获取更新用户的信息。

2.2.1 接口调用机会

和场景一雷同,订单模块也不晓得用户模块的数据何时被更新,所以它也只能采纳轮询的形式定期调用接口。

2.2.2 获取数据形式

这里和场景一有些不同,场景一咱们获取的是新增数据,这里咱们要获取的是数据变动状况,所以有两种实现形式

逐条查问

依照用户惟一标识(用户 ID)查问用户详情,判断订单模块中冗余的用户名和查问进去的值比拟,不同就表明用户名已扭转,进行更新操作。此时只须要用户模块提供一个依据用户惟一标识(用户 ID)查问用户详情的接口(更简略专用的接口就是依据 ID 查问用户名)。显然在须要大量数据同步的场景下这不是一个好的实现形式。

批量查问

和场景一相似,用户模块须要提供一个以工夫为入参,批量查问进去入参工夫之后产生变动的所有数据的接口。这时就须要用户模块和订单模块都存储更新工夫。(在这里在略微深刻一下,通常用户表都会存储更新工夫,然而这个更新工夫在用户任意属性变更的时候都会被更新,这样咱们会获取到所有的用户属性有变更数据而不只是用户名更改的数据。要保障获取数据精准,除非咱们在用户表独自存储用户名更新工夫,显然这样得失相当)

注:和场景一一样,应用工夫作为接口参数,极其状况下也可能呈现数据缺失问题。

通过对场景一、二的实现办法的形容咱们可见。推送和拉取行为是绝对数据方提供方和数据需求方而言,从数据提供方调用数据需求方接口就是数据推送,反之就是数据拉取,尽管两种形式接口的调用方向不同,然而数据的流向是雷同的,都是通过数据提供方想数据需求方转移。

3. 推送模式和拉取模式的区别

接下来咱们从两个方面,形容推送和拉取的区别:

3.1 零碎间依赖关系

推送的形式下,数据提供方依赖数据需求方,场景一中电商零碎调用 CRM 零碎的接口,所以电商系统对 CRM 零碎产生了依赖,同理场景二中用户模块也依赖了订单模块。在这种依赖关系咱们嗅到了“坏滋味”。

首先,直觉通知咱们数据提供方不应该依赖数据需求方。是你须要我的数据,我反而要调用你的接口并解决异样(异样如何解决也是有需求方业务决定的,例如是否能够重试,是否容许数据失落),一旦你的业务发生变化导致接口或者异样解决逻辑变动,我不得不批改代码以应答。

其次,随着业务演进,将来可能有更多的数据需求方退出,每减少一个数据需求方都会造成数据提供方的代码层面批改,这也是咱们不能承受的。

反观拉取的形式,因为是数据需求方调用数据提供方的接口,依赖方向转变了,无论数据需求方业务如何变动或者减少了更多的数据需求方,数据提供方均不受影响。

通常不好的耦合关系不会影响以后零碎实现和运行,而是影响系统对将来业务变动的扩展性。 如果咱们能确定将来业务不会变动,也就不须要关怀这类耦合关系,显然这种相对稳固的零碎少之又少。

3.2 数据同步的时效性和精确性

时效性方面

推送模式下,数据提供方能够在数据变动时同时调用数据需求方接口传递变动。而在拉取模式下,需求方无奈感知数据何时变动,只能定期轮询接口。时效性和接口轮序频率成正比,为了减少时效性,只能进步接口轮询频率。然而过高的频率通常不可取:一来在数据变动不频繁的场景下,频繁的接口调用是一种节约,二来过于频繁的接口调用也会个被调用方带来比拟大的性能压力。所以咱们须要在时效性和性能衡量,找到一个平衡点。

精确性方面

推送模式下,数据提供方能够准确的感知本身哪些数据发生变化并通过调用接口传递给数据需求方。而在拉取模式下,数据需求方无奈感知哪些数据变动,只能通过单方保留数据变动状态(新增工夫、更新工夫)、减少查问条件的形式进行范畴查问或者采纳全量查问后一一比对的形式(不实用新增数据场景)。相较于数据推送模式,数据拉取模式很难及时的获取到精准的同步数据信息。

4. 两种模式如何抉择

两种模式各有利弊,从零碎间依赖关系角度思考,采纳拉取模式的零碎有更好的业务扩展性、能更好的应答将来需要变动。然而拉取模式在数据同步时效性、精确性和零碎性能上有人造的劣势,实现起来也更加简单。所以在具体计划抉择上咱们须要依据具体场景判断。 数据同步时效性和零碎性能要求不高的场景能够采纳推送形式以进步系统对将来业务的扩大能力,反之须要采纳推送的形式以零碎扩展性换取数据同步时效性和零碎性能。

5. 推送模式优化

让咱们在回看一下推送模式的问题,既然推送模式场景下数据需求方的业务变动可能对数据提供方造成影响。咱们可不可以对推送模式进行优化以解决一个零碎变动影响到另一个零碎的问题。 咱们能够借鉴设计模式中“策略模式”的思维,将零碎分为固定局部和变动局部,对变动的局部进行肯定维度的形象而后在将这种形象拆散进来独立实现 。这种将固定逻辑和变动逻辑拆散的做法,肯定水平上能够解决咱们遇到的问题。

5.1 如何革新

将变动进行形象

首先,咱们将数据提供方中变动的逻辑,如调用哪些数据需求方的接口、调用接口签名(名称、地址、入参出参)是什么、如何解决调用过程中的异样等这些有可能变动并且须要代码实现的逻辑形象为通过自定义配置的形式实现,造成一个“接口配置核心”的概念。

对形象进行实现

接下来,咱们就须要编码实现“接口配置核心”的逻辑。配置中的主要职责就是对数据提供方提供对立的数据同步接口,一旦数据提供方调用数据同步接口,“配置核心”依据提前定义的配置调用后端数据需求方的接口实现数据同步工作,同时会依据配置解决接口调用过程中产生的各种异常情况。


注:图中箭头示意接口调用方向和依赖关系方向。

革新后,数据提供方调用接口核心的接口传递须要同步的数据,有接口配置核心负责调用个数据需求方的接口进行二次传递。数据提供方只依赖配置核心,不再依赖各个数据需求方,接口配置核心尽管依赖后端的各个数据需求方,然而数据需求方的种种变动曾经通过配置来实现,所以无论数据需求方业务如何变动,咱们只须要调整配置核心配置即可,这种变动并不能传导到数据需求方。通过引入配置核心,咱们无效隔离了数据需求方对数据提供方的影响。

5.2 革新后的长处和有余

长处

解决了拉取模式下数据需求方影响数据提供方的问题。

毛病

减少了零碎实现复杂度,显然“接口配置核心”实现起来并容易。

  • 如何接口调用的相干行为形象为能够配置的形式并加以实现
  • 如何解决接口调用过程中遇到的种种异常情况
  • 如何解决接口调用的性能问题

升高了零碎稳定性,进步了运维难度。 更多的模块意味着更多的问题点,咱们须要更多运维监控伎俩在第一工夫发现并解决问题,以确保零碎整体稳固运行。

5.3 应用倡议

是否要应用这种形式,还须要综合思考。 在一个业务逻辑绝对简略的小型零碎,咱们没有必要引入如此简单的实现形式,依据场景须要从下面介绍的拉取模式和推送模式抉择即可,而对于业务逻辑较简单的大型零碎,能够引入这种形式以升高零碎间简单的依赖关系。

四、音讯队列模式实现


注:图中箭头示意接口调用方向和依赖关系方向。

数据提供方以音讯的形式向数据需求方传递须要同步数据信息,数据提供发向音讯队列发送一条音讯,音讯队列负责将音讯发送给数据需求方。数据提供方和数据需求方都只依赖音讯队列,他们两者之间没有依赖也就不会相互影响。

置信大家对音讯队列并不生疏,在此我也不再赘述。你有没有发现音讯队列很像同咱们前文所述“接口配置核心”模式,只是实现略有不同。

  • “接口配置核心”中接口签名转换成了音讯队列中的主题、音讯概念
  • “接口配置核心”中接口调用行为就像音讯队列中的公布订阅模式
  • “接口配置核心”中异样解决机制就是音讯队列中的保障投递机制
  • “接口配置核心”中的性能要求也能够通过音讯队列中的削峰作用来满足

所以音讯队列能够齐全代替咱们上文所说的“接口配置核心”性能。免去咱们反复造轮子之苦。

可能有相熟和应用过音讯队列的同学看到文中场景之后第一反馈就是应用音讯队列来实现。为什么我要放在最初才介绍这种形式呢。其实就是想让大家体验一下解决问题的根本形式——由渐入深、层层递进。 首先,遇到一个问题,先从简略的计划动手,如果简略计划能解决你的问题就没有必要采纳简单的形式。 咱们尽管有大炮,但不能要来打苍蝇,有时候苍蝇拍更好使。 其次,以一个简略计划作为突破口能够将一个大问题合成为一个个小问题,随着咱们计划的优化调整一一解决。

长处和有余

音讯队列模式除了实现简略、开箱即用外,还能升高零碎耦合度、进步传输数据的时效性和精准度,进步零碎性能和吞吐量。然而因为援用了更多的中间件,也减少了零碎运维复杂度。

五、总结

最初让咱们来总结一下。本文介绍了“零碎”间数据同步的场景和各种实现形式。次要介绍了接口方式和音讯队列形式,接口方式分为推送模式、拉取模式、“接口配置核心”模式。理论我的项目中 ongoing 如何抉择实现形式,须要联合场景综合思考。以下是我的倡议:

业务规模不简单的单体利用零碎或小型零碎或者大型零碎中的简略业务模块、能够抉择绝对简略的接口同步形式。具体应用推送模式还是拉取模式,须要依据将来业务扩展性、数据同步时效性和性能权衡利弊。 推送模式在同步数据时效性和性能有劣势,而在将来业务扩展性略显有余。拉取模式相同。

业务规模较简单的分布式系统或微服务零碎,能够抉择音讯队列模式。 零碎越简单将来需要变动的可能性越大,应答将来需要变动是咱们的第一要务,不要存在侥幸心理而抉择简略的形式,切记。

除非现有市面上的音讯队列中间件不满足本身需要,能够思考定制开发,然而开发前肯定要审慎,反复造轮子的工作须要充沛的理由。

你也能够不遵循下面的倡议,只有的你抉择合乎你的场景即可。然而, 一个架构师的的职责就是利用最小的老本构建出一套可运行并易于扩大的零碎,并随着业务变动继续保证系统扩展性。 所以我还是心愿你能关注将来的零碎扩展性,因为这是你的长期职责,即便它总和老板的短期指标相违反。

正文完
 0