首页 资讯频道 互联频道 智能频道 网络 数据频道 安全频道 服务器频道 存储频道

数据库同步数据 为什么在系统中不推荐双写?

2020-08-25 10:40:35 来源 : 数据库开发公众号

1、在database,redis,elasticsearch,hadoop中的数据是有关系的,还是彼此独立的?

显然是有关系的,在这几个数据源中的数据都是相关的。只是格式不一样而已!例如,对于一条Product数据,在数据库里是

在redis里就是key为 product:pId:1,value是

{

"pId":"1",

"productName":"macbook"

}

如上所示,只是数据格式不一样而已!

那好,现在思考第二个问题

2、既然这些数据源之间数据是相关的,如何保证这几个数据源之间数据一致性!

一种比较简单且容易想到的方案是,hardcode在程序中

例如现在有两个数据源DataSouce1和DataSource2,我们往里头写数据,代码如下

ProductService{

\\省略

publicvoidsyncData(){

x1.writeDataSource1();

x2.writeDataSource2();

}

}

这就是我们标题中所提到的双写!那么,双写会带来什么坏处呢?OK,继续往下看!

双写缺点

一致性问题

打个比方我们现在有两个client,同时往两个DataSouce写数据。

一个client往里头入X为1

一个client往里头入X为5

那么会有如下情形出现

如图所示,两个DataSouce的数据就不一致了,一个为1,一个为5。除非接下来有一个新的请求,对x数据发生了变更,才能修正这种现象!否则,你可能永远都发现不了。

原子性问题

因为我们需要同时往DataSource1和DataSource2一起写数据,你需要保证

x1.writeDataSource1();

x2.writeDataSource2();

这两个操作一起成功,或者一起失败!如果采用双写的方法,是避不开这个问题的!

那么有没有通用的办法来解决这些问题呢?

有的,只要能按顺序记录数据的变更即可!那具体怎么做呢,我们继续往下看!

改良方案

假设,如果我们能将数据按顺序记录,写入某个消息队列,然后其他系统按消息顺序恢复数据,看看what happen?

此时架构图如下

在该架构下,所有的数据变更写入一个消息队列里去。其他各数据源从消息队列里恢复数据即可!

那么,此时还有一致性问题,和原子性问题么?

一致性问题

OK,这种情况下,各个数据源之间数据肯定是一致的。因为写入顺序已经在消息队列中定义好,各数据源按照消息队列中的消息顺序,恢复数据即可,并不存在竞争现象。因此,不会出现不一致的问题!

原子性问题

OK,这种情况下,如果写入DataSource失败会怎么样?例如出现了网络问题,这条消息恢复失败了。这个问题其实好解决,一般我们在顺序根据消息恢复数据的时候,会记录下坐标。如果写入失败,停止恢复数据。下次从该坐标处恢复数据即可。

但是在上面那张图中,写入DataBase是异步写入的。这样就不符合很多业务场景的"写后即读"的要求,因此,在实际落地中,做了一些变更!通用做法是去提取数据库的变化!

如下图所示

在该图中的中间件,例如oracle中的oracle golden gate可以提取数据变化。mysql中的canal能提取数据的变化。至于消息队列,可以选用kafka。直接提取数据变化到kafka中,其他数据源从kafka中获取数据,避免了直接双写从而导致一致性和原子性问题。

最近更新