nodeEE双写与分布式事务要点一二
数据库与缓存双写问题
计算机领域任何一个问题都可以通过增加一个抽象“层”来解决。
业务中为了减少热点数据不必要的db查询,往往会增加一层缓存来解决I/O性能。可是I/O多了一层也就多了一层的更新维护与容错保障,当修改db中某些数据时,往往会面临缓存更新的问题,在这里简单介绍 数据库与缓存双写问题以及在业务场景如何使用双写策略。
缓存更新时机
缓存在以下情况下需要更新:
- 不存在缓存,回源至db后添加缓存
- 缓存超时,重复上个步骤
- 修改db,更新缓存
缓存更新策略
- 若不存在缓存或者缓存超时:
- 查询db
- 设置缓存
- 若缓存存在,且需要更新db,则有多种缓存更新策略:
- 先更新db,然后更新缓存
- 先删除缓存,然后更新db
- 先更新db,在删除缓存
本节主要讨论更新db时如何更新缓存的问题,且暂时不考虑缓存操作失败的情况(如网络原因、redis服务不可用等)。
如果业务场景中不会出现修改相同数据字段竞争的问题,那么这三种更新策略毫无疑问都可以使用。如果出现缓存竞争态的情况,那么第一种策略是最先排除的:
上图所示,如果A、B先后修改db,会出现最终缓存与db不一致的现象,导致随后至缓存超时或下次更新的时间段内使用脏数据的现象。
而且业务方需要考虑的是,是否每次更新db,都需要立即刷新缓存。如果在“写频繁,而读频率远小于写的情况下,频繁的刷新缓存是否有必要?”
第二种策略,先删除缓存再更新数据库旨在牺牲性能下尽可能降低使用脏缓存的情况,可是此种情况下仍有可能出现脏缓存的情况:
如上图,A先删除缓存,同时开始更新db;与此同时B查询缓存为空,进而查询db,由于db的读性能高于写且数据库隔离级别默认为提交读,因此B查询db的数据往往为旧数据,此后B查询完毕更新缓存,导致缓存在超时时间或者下次修改db的范围内为脏数据。
如果db底层做了读写分离的情况下,这种现象更容易出现,B查询db是读库,而A修改主库后需要一定时间的同步才能保障从库的数据最新,因此在此种情况下,缓存肯定仍是脏数据。
为了避免这种情况,A可以在更新db后延时一定间隔(往往是查询db时间+设置缓存的时间)删除缓存,尽量缩短脏缓存的时段,新的请求回源db并设置新的缓存数据。如下图所示。
第三种策略先更新数据库再删除缓存,此种策略较为安全,几乎不会出现脏缓存的情况,就算出现也是会在极不合理的情况下导致脏缓存:
如上图,缓存出现脏数据的前提是第2步骤耗时大于第3、4步骤,即读耗时大于写耗时,这几乎不可能发生。就算发生,也可以通过A再次延迟删除缓存(两次删除)解决。
缓存操作问题
在上一节中提到的所有缓存更新策略都是在暂时不考虑缓存操作失败的情况(如网络原因、redis服务不可用等)前提下讨论的,如果缓存操作失败,则必须通过业务代码重试、消息队列或者设置缓存超时解决。
业务代码重试,设置合理的重试次数与间隔,如果超时后缓存仍然无法操作则需要等待缓存超时或者人为介入;
消息队列则在缓存操作失败后投递对应消息,在非业务代码中进行重试;
缓存超时则是兜底方案,这是允许最长的缓存不一致的时间。
分布式事务
比较遗憾的是,在node领域还没有类似JAVA的JTA规范及其实现,JTA规范中的核心“事务管理器TM”大都由容器来实现,如常见的jboss和websphere;TM接收业务层的事务请求,同时协同参与事务的各个资源管理器RM如dbms、mq等,实现分布式事务的提交与回滚;同时也提供分布式事务在不同自治系统的传递。
分布式事务的集中解决方案有如下几种:
1. 两阶段提交
2. 三阶段提交
3. 异步确保
4. TCC
在JAVA和其他生态已经证明了,两阶段提交的低效以及无法抗住高并发且存在单点的问题;三阶段提交虽然解决了两阶段的单点和减少协调者阻塞等待参与者的问题,但仍存在数据不一致的情况,因此这两种理论上的模型其实并不符合实际业务中的场景,在工程领域需要追求的是最优化,可见理论与现实仍然有不少差距。
那么在node场景中,处理分布式事务的方式也就只剩下两种工程上的解决方案。
node中使用异步确保模型可以使用相比较简单的基于消息队列的异步确保模型(也可基于本地数据库表)。将分布式长事务切分为多个本地事务,通过保障本地事务的可靠性实现分布式长事务的最终提交。如果参与分布式事务的某个本地事务执行出错进行回滚,则通过消息队列实现业务主动方的补偿,实现最终的数据一致性。
如下图:
TCC模型相比较异步确保而言则比较重,需要开发一个TCC的TM协调各个服务参与方,同时对参与事务的各个从服务侵入性比较大,必须提供try、confirm和cancel三个接口。其中try接口预留相关资源,并确保数据一致性,confirm接口和cancel接口保证幂等性,执行或回滚try阶段预留的资源。其中,在业务中主动调用所有参与分布式事务的从服务的try接口,并汇报给TM执行情况,由TM根据try阶段的结果完成后续的执行或回滚操作,同时记录分布式事务状态传递以及各个从服务的执行阶段等信息,便于追踪。
因此用node实现分布式事务时,在没有自研TCC中间件的前提下,可根据业务特性自行扩展异步确保型方案。
nodeEE双写与分布式事务要点一二的更多相关文章
- 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制
[原创]分布式之数据库和缓存双写一致性方案解析(三) 正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...
- EF架构~关系表插入应该写在事务里,但不应该是分布式事务
回到目录 这个标题很有意思,关系表插入,就是说主表和外表键在插入时,可能会有同步插的情况,如在建立主表时,扩展表需要同步完成数据的初始化工作,而对于多表插入时,我们为了保证数据的一致性会针它写在事务中 ...
- 借读:分布式锁和双写Redis
本帖最后由 howtodown 于 2016-10-3 16:01 编辑问题导读1.为什么会产生分布式锁?2.使用分布式锁的方法有哪些?3.本文创造的分布式锁的双写Redis框架都包含哪些内容? ...
- 如何实现XA式、非XA式Spring分布式事务
Spring应用的几种事务处理机制 Java Transaction API和XA协议是Spring常用的分布式事务机制,不过你可以选择选择其他的实现方式.理想的实现取决于你的应用程序使用何种资源,你 ...
- 非XA式Spring分布式事务
Spring应用的几种事务处理机制 Java Transaction API和XA协议是Spring常用的分布式事务机制,不过你可以选择选择其他的实现方式.理想的实现取决于你的应用程序使用何种资源,你 ...
- 面试前必知Redis面试题—缓存雪崩+穿透+缓存与数据库双写一致问题
今天来分享一下Redis几道常见的面试题: 如何解决缓存雪崩? 如何解决缓存穿透? 如何保证缓存与数据库双写时一致的问题? 一.缓存雪崩 1.1什么是缓存雪崩? 回顾一下我们为什么要用缓存(Redis ...
- 【分布式事务】基于RocketMQ搭建生产级消息集群?
导读 目前很多互联网公司的系统都在朝着微服务化.分布式化系统的方向在演进,这带来了很多好处,也带来了一些棘手的问题,其中最棘手的莫过于数据一致性问题了.早期我们的软件功能都在一个进程中,数据的一致性可 ...
- 3分钟搞定SpringBoot+Mybatis+druid多数据源和分布式事务
文章来自: https://blog.csdn.net/qq_29242877/article/details/79033287 在一些复杂的应用开发中,一个应用可能会涉及到连接多个数据源,所谓多数据 ...
- 基于两阶段提交的分布式事务实现(UP-2PC)
引言:分布式事务是分布式数据库的基础性功能,在2017年上海MySQL嘉年华(IMG)和中国数据库大会(DTCC2018)中作者都对银联UPSQL Proxy的分布式事务做了简要介绍,受限于交流形式难 ...
随机推荐
- centos6.8 编译安装lnmp php7.2 mysql5.6 nginx1.1.4
编译操作参考版,没有每一步详细操作,慎入 关闭selinux和防火墙 service iptables stop chkconfig iptables off vi /etc/selinux/conf ...
- Python3.6 提示 ModuleNotFoundError: No module named '_ssl' 模块问题
国内 163 yum 源挺好用 (中科大的也不错) http://mirrors.163.com/.help/CentOS6-Base-163.repo yum install openssl-dev ...
- 杂_小技巧_将网页上的内容通过亚马逊邮箱传到kindle中
所需条件 1.kindle要联网 2.要有亚马逊邮箱 3.要有微信,电脑上或者手机上 操作步骤: 1.找到你想要传送到kindle上的文章网页 2.在微信中关注“亚马逊kindle服务号”并且按照里边 ...
- LeetCode 240 - 搜索二维矩阵 II
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target.该矩阵具有以下特性: 每行的元素从左到右升序排列.每列的元素从上到下升序排列.示例: 现有矩阵 matrix 如 ...
- Head First Python-python面向对象
与大多数其他的编程语言一样,Python容许创建并定义面向对象的类,类可以将代码与代码处理的数据相关联. 对于更加复杂的数据,一般的列表已经不能满足需求了. 我们可以使用字典dict将数据值与键相关联 ...
- linux获取网络信息函数
获取IP地址 int sys_getIP(char *ip_addr) { ] = {"ifconfig eth0 | grep inet | cut -d: -f2 | cut -d' ' ...
- MessengerJS
跨文档通信解决方案 Since modern browsers have native cross-document communication method(the PostMeessage API ...
- JAVA项目中文件重命名方式
可以直接改类名,之后eclipse会报错: 点击×号会给出解决方案: 注意:不能通过右击servlet文件直接重命名.否则运行之后程序会报错(文件路径不对之类的)
- centOS 7 设置DNS方法 同之前版本不同
在CentOS 7下,手工设置 /etc/resolv.conf 里的DNS,过了一会,发现被系统重新覆盖或者清除了.和CentOS 6下的设置DNS方法不同,有几种方式: 1.使用全新的命令行工具 ...
- mac pro换屏指南
https://www.ifixit.com/ 该网站提供了 换屏的详细操作步骤.