引言

某日,阿雄跑去面试!于是有如下情形

面试官:"阿雄是吧,做做自我介绍!"
阿  雄:"我叫阿雄,来自某a国际电商公司!"
面试官:"我看你项目里用了elasticsearch,你是怎么同步数据的呢?"
阿  雄:"在代码里写入数据库的时候,同时再写入elasticsearch!"
面试官:"那你如何保证写入数据库,和写入elasticsearch原子性问题呢?
万一写入数据库成功了,写入elasticsearch失败了怎么处理?"

阿  雄:"我还是回去等通知吧!"

OK,以上情形纯属虚构,如有雷同,绝对巧合!

其实这篇文章所探讨的数据同步策略并不限于某两种固定的存储系统之间,而想去探讨一种通用的数据同步策略。主要分为以下三个部分

  • (1)背景介绍

  • (2)双写缺点

  • (3)改良方案

正文

背景介绍

话说阿雄在加入某a国际电商公司的时候,业务系统十分简单,一个database就能搞定一切!

可是某a国际电商公司在产品韩的领导下,业务增长迅速,阿雄发现了数据库越来越慢,于是乎阿雄加入了一些缓存,如redis来缓存一些数据,提高系统的响应能力。

又过了一段时间,产品韩发现搜索的速度灰常慢,让阿雄去改。阿雄在网上发现,现在业内都用一些elasticsearch做一些全文检索的操作,于是乎阿雄将一些需要全文检索的数据放入elasticsearch,提高了系统的搜索能力!

随着数据的膨胀,阿雄慢慢的发现了,对数据库做一些数据分析操作,性能明显的跟不上了。于是乎阿雄将数据库里的数据,导入hadoop,然后进行数据分析。

(省略一万字….)

最后,阿雄和产品韩幸福的在一起了

OK,好,现在分析上面的场景!思考第一个问题
1、在database,redis,elasticsearch,hadoop中的数据是有关系的,还是彼此独立的?
显然是有关系的,在这几个数据源中的数据都是相关的。只是格式不一样而已!例如,对于一条Product数据,在数据库里是

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

{       "pId": "1","productName": "macbook"
}

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

那好,现在思考第二个问题
2、既然这些数据源之间数据是相关的,如何保证这几个数据源之间数据一致性!
一种比较简单且容易想到的方案是,hardcode在程序中
例如现在有两个数据源DataSouce1和DataSource2,我们往里头写数据,代码如下

ProductService{\\省略public void syncData(){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中获取数据,避免了直接双写从而导致一致性和原子性问题。

总结

本问讨论了在项目中常见的数据同步问题,希望大家有所收获。

面试官:为什么在系统中不推荐双写?相关推荐

  1. 面试官:Zookeeper怎么解决读写、双写并发不一致问题,以及共享锁的实现原理?

    哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新,可以微信搜索[小奇JAVA面试]第一时间阅 ...

  2. 如何应对面试官:什么场景中会用到java多线程?

    如何应对面试官:什么场景中会用到java多线程? 作者:云栖社区 原文:https://yq.aliyun.com/ziliao/1765 (点击文末阅读原文即可前往) 问:能不能简单描述一下你在ja ...

  3. 面试官比较看重简历中的哪些维度,有什么写简历的技巧、建议和总结?

    [每日一问]面试官比较看重简历中的哪些维度,有什么写简历的技巧.建议和总结? Datawhale优秀回答者:千夜同学,陶志杰 第一 ,简历一定要工整 字体格式对奇 字体大小不一 格式错乱 文字乱码的 ...

  4. 后处理程序文件大小的变量_【每日一题】(17题)面试官问:JS中事件流,事件处理程序,事件对象的理解?...

    关注「松宝写代码」,精选好文,每日一题 作者:saucxs | songEagle 2020,实「鼠」不易 2021,「牛」转乾坤 风劲潮涌当扬帆,任重道远须奋蹄! 一.前言 2020.12.23 立 ...

  5. 面试官告诉你,为什么一定要过手写算法这一关

    IT互联网公司的技术面试,一般都会有手写算法的这一关,有的简单,有的复杂,根据岗位的不同有所差异.面向业务的研发岗,算法要求不高,考察的算法不会太难.面向算法一类的研发岗,算法就比较难了.我主要关注的 ...

  6. 教你从0到1搭建秒杀系统-缓存与数据库双写一致

    本文是秒杀系统的第四篇,我们来讨论秒杀系统中缓存热点数据的问题,进一步延伸到数据库和缓存的双写一致性问题. 在秒杀实际的业务中,一定有很多需要做缓存的场景,比如售卖的商品,包括名称,详情等.访问量很大 ...

  7. 面试官绝杀:系统是如何支撑高并发的?

    作者 | 中华石杉 责编 | 伍杏玲 很多人面试的时候被问到一个让人特别手足无措的问题:你的系统如何支撑高并发? 大多数同学被问到这个问题压根儿没什么思路去回答,不知道从什么地方说起,其实本质就是没经 ...

  8. 面试官:大型系统架构设计细节你知道多少??

    随着互联网经济的深度发展,传统的服务模式已难以满足商业需求.企业为了适应新的业务规模,不断在部署.管理.功能交付方面更新迭代技术,一时间大量技术各显神通--Zookeeper.Netty.Dubbo. ...

  9. 500并发 一台服务器的性能_面试官绝杀:系统是如何支撑高并发的?

    作者 | 中华石杉 责编 | 伍杏玲 本文经授权转载石杉的架构笔记(ID:shishan100) 很多人面试的时候被问到一个让人特别手足无措的问题:你的系统如何支撑高并发? 大多数同学被问到这个问题压 ...

最新文章

  1. Python 实现 PD 文字识别、提取并写入 CSV 文件脚本分享
  2. 素数和_只愿与一人十指紧扣_新浪博客
  3. 采用HttpModules来重写URLs(实践篇)
  4. SQLServer2008 视图创建实例
  5. 再见,RabbitMQ,你好,Kafka!
  6. 8个超震撼的HTML5和纯CSS3动画源码
  7. 粮草先行——Android折叠屏开发技术点番外篇之运行时变更处理原则
  8. 最详细MySQL的安装与介绍Windows
  9. 面试(2)——StringBuffer StringBuilder String /==与equals
  10. 千牛机器人回复词库_智能聊天机器人 ai机器人电销-
  11. oracle海量数据中提升创建索引的速度
  12. 流量和延迟减半!挑战 TiDB 跨数据中心难题
  13. 高并发消息队列常用通知机制
  14. python查看微信撤回消息_python实现文件助手中查看微信撤回消息
  15. 【bzoj 3433】{Usaco2014 Jan} Recording the Moolympics(算法效率--贪心)
  16. 数据驱动的综合能源系统
  17. 【复】基于 WebRTC 的音视频在线监考模块的设计与实现(下)
  18. html英雄联盟网页,Html+Css+JQuery实现简易英雄联盟官网
  19. 判断闰年java_java中判断是否闰年
  20. 谷歌 火狐 主页被篡改,修改文件名解决

热门文章

  1. 如何清空DNS缓存Windowslinux
  2. js之浅拷贝和深拷贝
  3. 单片机找工作好找吗?不懂英语怎么学会单片机?
  4. poj3264(ST表模版)
  5. P1502 窗口的星星 离散化+扫描线
  6. 表达式 控件 html,获取HTML表单控件的UrlEncode字符串表达式
  7. php程序里的configini_php中配置文件操作 如config.php文件的读取修改等操作
  8. powerbi输入数据_Power BI 的多种共享方式
  9. (每日一题)2016 北京ICPC网络赛G hihocoder 1388 (中国剩余定理 + NTT)
  10. #6280. 数列分块入门 4(区间修改,区间查询)