高效分布式操作解决方案
2017-12-18 09:29
232 查看
高效分布式操作解决方案
http://blog.csdn.net/wyzxg/article/details/6181574为什么要替代分布式事务?
当我们系统的数据量很大,大都需要对数据库进行分割,部署多台数据库实例,这样就避免不了某些操作需要同时修改几个数据库实例里的数据,为了保证数据准确性和一致性,我们大都使用分布式事务来实现(非常经典的两阶段提交协议)。
分布式事务最大的优点就是简化应用开发,对于时间紧迫并且性能要求不高的系统可以大大的提高开发效率,这也是大多开发者沉醉于其中的主要原因。但没有十全十美的,有利必有弊,虽然开发便捷了,但是也严重的损害了系统的可用性,高性能和可扩展性,尤其对于海量数据复杂的系统体现就更明显。
系统的可用性
系统的可用性就相当于参加分布式事务的各个数据库实例的可用性之积,数据库实例越多,可用性下降的越明显;因为参加分布式事务的所有数据库实例都可以正常工作下,这个分布式事务才算完成,如果有一个数据库实例有故障,那这个分布式事务都会失败。
高效能和可伸缩性
对于一个分布式事务总的持续时间是操作各个数据库实例的时间之和,因为在分布式事务中每个操作是顺序执行的,这样每个事务的响应时间就会很长;还有对于一个OLTP系统,事务都很小,一般几毫秒,当涉及到分布式事务时,节点间的网络通信时间占事务总响应时间的比例也是不容忽视的。还有由于事务时间相对于变长了,锁定的资源的时间也就变长了。从而严重影响系统的并发性,吞吐率和可伸缩性。
根据以上描述可以了解到分布式事务的弊端,那怎么避免呢?
假设有三个数据库实例,每个实例上有一个user(id,username,account,routedb)表,其中一个数据库实例是读写的,另外两个user是只读的(实现读写分离)。
Primay db:user1
Standby db:user2
Standby db: user3
假如我要更新user表时,对于分布式事务,伪代码如下:
Begin
Update user1 set account=account+$b;
Update user2 set account=account+$b;
Update user3 set account=account+$b;
Commit;
End;
这里为了消除分布式事务,引入消息队列和状态表
事务1:
Begin
Update user1 set account=account+$b;
Put_queue user2;
Put_queue user3;
Commit;
事务2:
For each message in queue
begin
If(routedb=’db2’) then
Begin
Select count(1) cnt from message_state where meg_id=$messageid;
If (cnt=0) then
Update user2 set account=account+$b;
End;
Insert into message_state values($messageid);
End;
Elseif(routedb=’db3’) then
Begin
Select count(1) cnt from message_state where meg_id=$messageid;
If (cnt=0) then
Update user3 set account=account+$b;
End;
Insert into message_state values($messageid);
End;
End;
Commit
If事务2成功;
Dequeue message;
Delete from message_state where meg_id=$messageid;
End;
可以用图表示如上过程:
描述过程:
1. 在第一步里,消息队列和表user1在同一个数据库实例里,不存在分布式操作;在这一步把对其他每个数据库实例的操作
都作为一条消息进行入队列操作。
2. 每个数据库实例都对应一个状态表message_state,用于实现消息的幂等性,也就是用于记录消息是否成功被应用(避
免多次更新),在这一步里也不存在分布式操作,所以也能保证数据一致性。
3. 在第二个事务成功,也就是第2,3步成功后,已经从消息队列中删除的消息从message_state表中删除,这样可以将
message_state表保证在很小的状态(不清除也是可以的,不影响系统正确性)。由于消息队列与message_state在不同实例(服务器)上,dequeue message(消息出队列)之后,将对应message_state记录删除之前也可能出故障。 一旦这时出现故障,message_state表中会留下一些垃圾内容,但不影响系统正确性;但是如果在第二个事务结束后和dequeue
message(出队列)之间出现故障,故障后系统会重新从消息队列中取出这一消息,但通过message_applied表可以检查出来这一消息已经被应用过,跳过这一消息实现正确的行为;
总结:使用如上方案不能保证数据时刻一致性,在发生故障时,系统将在短时间内不能保证数据一致性,但基于消息队列和状态表,最终是可以保证系统恢复重一致性的,使用这个方案,解除了数据库实例之间的紧密耦合,其性能和可伸缩性是分布式事务不可比拟的。
消息队列-状态表方案和分布式事务的对比
对于时间紧迫或者对性能要求不高的系统,应采用分布式事务加快开发效率;对于时间需求不是很紧,对性能要求很高的系统,应考虑使用消息队列方案。所以时间与便捷,性能与扩展是需要仔细衡量的,找好中间的平衡点;对于原来使用分布式事务,且系统已趋于稳定,性能要求高的系统,则可以使用消息队列-状态表方案进行重构来优化性能。
-----end------
版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢。
-END-
相关文章推荐
- 高效分布式操作解决方案
- 高效分布式操作解决方案
- C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志
- Android高效加载大图、多图解决方案,有效避免程序OOM
- 位操作来轻松高效的解决问题
- 分布式服务下的交易一致性解决方案
- 位操作来轻松高效的解决问题
- 分布式实时日志分析解决方案ELK部署架构
- 高效编辑器vim之快速操作
- 分布式事务处理解决方案
- 一些高效的Linux命令行操作
- Android高效加载大图、多图解决方案,有效避免程序OOM
- Spark:一个高效的分布式计算系统
- Linux中Curl命令couldn't connect to host解决方案 php操作Curl(http,https)无法获取远程数据解决方案
- 基于AgileEAS.NET企业应用开发平台的分布式解决方案
- MYSQL关于INSERT操作主键冲突的几个解决方案
- 分布式计算需求场景以及解决方案
- 分布式集群系统下的高可用session解决方案
- 【系统服务】分布式系统事务一致性解决方案
- 分布式事务解决方案课程概述(一)