简介有一天,阿雄去面试了!于是面试官:“阿雄,自我介绍一下!”阿雄:“我叫阿雄,来自一家国际电子商务公司a!”面试官:“我看到你们项目中使用了elasticsearch,你们是如何同步数据的?”阿雄:“代码中写入数据库的时候,同时写入elasticsearch!”面试官:“那怎么保证写数据库和elasticsearch的原子性呢?如果写数据库成功了,写elasticsearch失败了,怎么办?”雄:“我先回去等通知!”OK,以上情况纯属虚构,如有雷同,纯属巧合!其实本文所讨论的数据同步策略并不局限于两个固定的存储系统,而是想探索一种通用的数据同步策略。主要分为以下三个部分:(1)背景介绍(2)双写弊端(3)改进方案的文字背景介绍据说阿熊在加入一家国际电商的时候,业务系统非常简单,数据库可以处理一切!然而,一家国际电商公司,在产品韩的带领下,发展迅速。熊某发现数据库越来越慢,于是熊某加了一些缓存,比如redis,用来缓存一些数据,提高系统的响应速度。过了一段时间,产品韩发现搜索速度很慢,就让阿雄换了。阿雄在网上发现现在业界使用一些elasticsearch来做一些全文检索的操作,于是阿雄把一些需要全文检索的数据放到了elasticsearch中,提高了系统的检索能力!随着数据的膨胀,阿雄慢慢??发现,一些对数据库的数据分析操作性能跟不上。于是阿雄将数据库中的数据导入到hadoop中,然后对数据进行分析。(省略一万字。。。)终于,阿雄和产品韩幸福的在一起了。OK,好了,现在分析上面的场景!思考第一个问题1、database、redis、elasticsearch、hadoop中的数据是相关的还是相互独立的?很明显是有关系的,这些数据源里面的数据都是有关联的。只是形式不同!比如一条Product数据,在数据库中,在redis中,key为product:pId:1,value为{"pId":"1","productName":"macbook"}如上图,只是数据格式不同而已!好了,现在想想第二个问题2,既然这些数据源之间的数据是有关联的,那么如何保证这些数据源之间的数据一致性呢!一个比较简单易想的方案是hardcode在程序中有两个数据源DataSource1和DataSource2,我们往里面写入数据。代码如下ProductService{\\??omitpublicvoidsyncData(){x1.writeDataSource1();x2.writeDataSource2();}}这就是我们题目中提到的双写!那么双写的缺点是什么?好的,继续阅读!双写的缺点一致性问题比如我们现在有两个client,同时向两个DataSources写数据。一个client把X放在里面是1,一个client把X放在里面是5,那么就会出现如下图所示的情况,两个DataSources的数据不一致,一个是1,一个是5。这种现象只能改正,除非有新的请求,改变x数据!否则,你可能永远都不会知道。原子性问题因为我们需要同时向DataSource1和DataSource2写入数据,所以需要保证x1.writeDataSource1();x2.writeDataSource2();这两个操作一起成功,或者一起失败!如果采用双写的方式,这个问题就避免不了了!那么有没有通用的方法来解决这些问题呢?可以的,只要数据有变化就可以按顺序记录下来!那么具体是怎么做的呢,我们继续往下看吧!改进方案假设如果我们能把数据按顺序记录下来,写入消息队列,然后按照消息的顺序在其他系统中恢复数据,我们看看会发生什么?此时的架构图在这个架构下,所有的数据变化都写入到一个消息队列中,如下所示。所有其他数据源都可以从消息队列中恢复数据!那么,此时是否还存在一致性问题和原子性问题呢?一致性问题没问题。在这种情况下,各个数据源之间的数据必须保持一致。因为在消息队列中已经定义了写入顺序,所以各个数据源都可以按照消息在消息队列中的顺序来恢复数据,不存在竞争。因此,不会出现不一致!原子性问题是可以的。在这种情况下,如果写入DataSource失败会怎样?比如网络有问题,这条消息恢复失败。这个问题其实很容易解决。一般我们在按照消息的顺序恢复数据的时候,都会记录下坐标。如果写入失败,则停止恢复数据。下次可以从这个坐标恢复数据。但是在上图中,写入DataBase是异步写入的。这不符合很多业务场景下“先写后读”的需求。因此,在实际执行中,进行了一些改动!一般的做法是提取数据库中的变化!如下图所示,这个图中的中间件,比如oracle中的oraclegoldengate,可以提取数据变化。mysql中canal可以提取数据变化。至于消息队列,可以用kafka。直接抽取数据变化到Kafka,其他数据源从Kafka获取数据,避免直接重写造成一致性和原子性问题。小结本题讨论了项目中常见的数据同步问题,希望大家有所收获。
