在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1....
Transcript of 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1....
![Page 1: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/1.jpg)
在 ongoDB 中实现强事务
![Page 2: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/2.jpg)
{ name: “TJ Tang/唐建法”,
title: “MongoDB 大中华区首席技术顾问”, des: “mongoing.com 中文社区发起人”,
email: “[email protected]”, wechat:“tjtang826”
}
关于讲师
![Page 3: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/3.jpg)
MongoDB 介绍
ACID事务
事务补偿设计模式
mongosaga – 事务补偿框架
关于今天的分享
![Page 4: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/4.jpg)
MongoDB 介绍
![Page 5: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/5.jpg)
600+ employees MongoDB Inc. 原10gen公司 MongoDB开源代码贡献者
2,000+ customers
13 offices worldwide
15,000,000+ Downloads
![Page 6: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/6.jpg)
RANK DBMS MODEL SCORE GROWTH (20 MO)
1. Oracle Rela+onal DBMS 1,442 -‐5%
2. MySQL Rela+onal DBMS 1,294 2%
3. Microso? SQL Server Rela+onal DBMS 1,131 -‐10%
4. MongoDB Document Store 277 172%
5. PostgreSQL Rela+onal DBMS 273 40%
6. DB2 Rela+onal DBMS 201 11%
7. Microso? Access Rela+onal DBMS 146 -‐26%
8. Cassandra Wide Column 107 87%
9. SQLite Rela+onal DBMS 105 19%
Source: DB-engines database popularity rankings; May 2015
最流行、发展最快的分布式数据库
![Page 7: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/7.jpg)
高性能,水平扩展
Always On 全球部署
灵活的模式 丰富的查询语句
⼆二级索引
事务支持,Join
企业工具集成
MongoDB:新一代架构NewSQL数据库
关系型 非关系型
NewSQL
![Page 8: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/8.jpg)
高可用 Replica Set
水平扩展 Sharding
灵活动态 文档模型
MongoDB的特点
![Page 9: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/9.jpg)
{ ! first_name: ‘Paul’,! surname: ‘Miller’,! city: ‘London’,! location: [45.123,47.232],! cars: [ ! { model: ‘Bentley’,! year: 1973,! value: 100000, … },! { model: ‘Rolls Royce’,! year: 1965,! value: 330000, … }! ]!}!
文档模型的优点
丰富的结构 JSON文档结构可以直接表达复杂对象结构 非常接近In Memory数据模型 动态的模式 可以随时增加、修改结构,无需数据迁移
快速开发 无需建模 程序接口自然无需ORM
![Page 10: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/10.jpg)
10
高可用,自动故障切换
多数据中心支持,自动容灾
滚动维护无下线
读写分离
多变易用复制集
![Page 11: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/11.jpg)
自动均衡
自动路由分发请求
运维透明化, 底层部署不影响应用
横向扩展支持海量的数据及并发
![Page 12: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/12.jpg)
社区版 MongoDB Community 企业版 MongoDB Enterprise Advanced
MongoDB Core Server ✔ ✔
Replication and Sharding ✔ ✔
Aggregation Framework ✔ ✔
Security: Role-Based Access Control, PKI Certificates, SSL, Field-Level Redaction ✔ ✔
Advanced Security: LDAP Authentication, Kerberos Authentication, x.509 Certificates, Auditing
✔
Automated Deploy, Configuration, Maintenance, Zero Downtime Upgrades ✔
Backup and Point-In-Time Recovery ✔
Monitoring and Alerting ✔
Encrypted & In-Memory Storage Engines ✔
MongoDB Compass ✔
MongoDB Connector for BI ✔
On-Demand Training ✔
Support SLA 1 hr
License Type AGPL Commercial
![Page 13: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/13.jpg)
• 用户管理 • 电商、产品目录 • 游戏 • 实时分析 • 仓储管理 • 购物车 • IM应用 • 广告 • 社交应用
MongoDB适用场景
• 账单查询 • 客户管理 • 风险分析 • ECM • 参考数据 • 360度视图
• 内容管理系统CMS • 物联网 • 车联网 • 数据即服务 • 通用数据平台 • 地理位置系统 • 高速缓存
RDBMS能做的,MongoDB基本都能做!
RDBMS不能做的,MongoDB还是能做!
![Page 14: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/14.jpg)
可是,听说MongoDB不支持强事务?
![Page 15: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/15.jpg)
!
常见数据库的事务支持
数据库 事务支持程度
Oracle DB2 SQL Server MySQL PostgreSQL
支持ACID
MongoDB Cassandra Couchbase
支持单文档ACID
![Page 16: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/16.jpg)
关于ACID事务
ACID
Consistency 一致性
Atomicity 原子性
Durability 持久性
Isolation 隔离性 数据持久存在, 哪怕宕机后
All or Nothing 要么全部提交, 要么回滚
在事务范围内看到的数据前后一致,并且符合既定数据库规则如外键
你对数据的操作对其他用户不可见,直到提交为止
![Page 17: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/17.jpg)
!
ACID简化编程
@Transactional!public void transfer(from, to, amount) {! try{!
!begin()!!debit(from, amount);!!credit(to, amount);!!commit();!
}! catch(Exception e){!
!rollback();! }!}!
public boolean transfer(from, to, amount) { double origBalance = readBalance(from);! double origBalance2 = readBalance(to);! boolean creditOk = false, debitOk=false,! try{!
!synchronized(from) {!! synchronized(to) {!! debit(from, amount); ! credit(to, amount);!! double newBalance = readBalance(from);
if(newBalance != origBalance – amount)!! ! throw new Exception(“wrong”);!! }!!}!
}! catch(Exception e){!
! // if debit has been done! undoDebit(from, amount);!
! return false;! }! return true; !!}!
经典案例:小明转账100元给小红
数据库实现事务
应用实现事务
![Page 18: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/18.jpg)
!
MongoDB的单文档事务性
场景 事务性
db.employee.update({ _id: 100}, {! $inc: { salary: 10000 },! $set: { level: 10 }! } !)!
支持单文档内原子性和隔离性: $inc 和 $set
db.employee.update({ level:9}, {! $inc: { salary: 10000 },! } !)!
更新多个文档时候不能保证全部更新或全部不更新,无回滚行为
db.employee.update(…) db.salary.update(…) !
不能保证全部更新或全部不更新,无回滚行为
![Page 19: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/19.jpg)
为什么不支持Full ACID?
ACID 是为 单机设计的
POIN POINT 分布式事务通常 需要二阶段提交
二阶段提交 性能差 问题多
如果不能提供 高性能ACID, 还不如先实现 更有意义的功能
目前还没有生产 级别的高性能
分布式事务数据库
![Page 20: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/20.jpg)
!
二阶段提交
1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障
Transac+on Manager
Can commit?
Yes
commit
phase 1: prepare
Phase 2: commit
DB Queue
http://www.oracle.com/technetwork/products/clustering/overview/distributed-transactions-and-xa-163941.pdf
3. 无法保证节点之间强一致! T1: 01.000 DB和Queue同时commit T2: 01.050 Queue commit 完成 T3: 01.200 这时候去读DB&Queue? T4: 01.500 DB commit 完成(或者commit失败)
T2 T4 T1 T1
![Page 21: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/21.jpg)
!
CAP 定理 – 2000年
Eric Brewer Professor, UC Berkeley VP Infrastructure, Google
2000年版本
![Page 22: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/22.jpg)
CAP 定理 – 2012年
数据允许暂时的不一致,只要最终一
致
操作对其他线程可见
![Page 23: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/23.jpg)
强一致 vs 最终一致
Full ACID 强一致 非分布式 无大规模并发
Partial ACID 最终一致 分布式 大规模并发
![Page 24: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/24.jpg)
强事务:你到底想要什么?
public void transfer(from, to, amount){!!debit(from, amount);!!credit(to, amount);!
}!
All or Nothing 原子性 全部提交或回滚
![Page 25: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/25.jpg)
Saga事务:补偿机制
ATM 订单 跨行转账 电信扣费 . . .
• 多个相对独立的操作,各自提交
• 某个步骤出错时启用补偿机制,消除之前操作的效果
• 无全局事务锁,可实现分布式高并发
• 提供原子性的事务支持
Transaction Compensation
![Page 26: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/26.jpg)
一个订单的例子
hRps://msdn.microso?.com/en-‐us/library/dn589800.aspx
订单处理步骤: 1. 减库存 2. 保存订单 3. 扣款
补偿操作
最终状态 操作
库存减掉 订单保存 扣款成功
系统已经一致
库存已减 订单未保存
1. 恢复库存
2. 系统达成一致
库存已减 订单保存 但是扣款未成功
1. 恢复库存
2. 修改订单状态为取消
3. 系统达成一致
![Page 27: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/27.jpg)
!
事务补偿伪代码
public boolean placeOrder(order) {!!!!boolean inventoryUpdated,orderSaved, paymentReceived;!
!!inventoryUpdated = subtractInventory(order.sku, order.quantity);!
!!if(inventoryUpdated){!! !orderSaved = saveOrder(order);!! !if(orderSaved)!! ! !paymentReceived = processPayment(order);!!}!
!!if(!paymentReceived){!! !if(orderSaved)!! ! !updateOrderStatus(order, "canceled");!! !if(inventoryUpdated)!! ! !addInventory(order.sku, order.quantity);!!}!!else if(!orderSaved){!! !if(inventoryUpdated)!! ! !addInventory(order.sku, order.quantity);!!}!
}!
订单处理三部曲:减库存,保存订单,订单支付
![Page 28: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/28.jpg)
!
我明白了,可是这个代码有点不好看⋯
![Page 29: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/29.jpg)
mongosaga
基于Spring Framework的补偿式事务组件
帮助你在MongoDB里面实现分布式事务
https://github.com/tjworks/mongosaga
![Page 30: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/30.jpg)
工作原理– 正常模式
• 基于Spring AOP
• Java Annotation
• 自动注入Proxy
• 记录事务范围内所有可补偿操作(enlist)
![Page 31: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/31.jpg)
工作模式 – 补偿模式
• Credit 步骤失败
• 确定需要补偿的操作 getCompensations()
• 自动调用补偿器 undoCredit()
![Page 32: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/32.jpg)
如何使用 1-2-3
1. 下载mongosaga jar 文件或者直接在POM.xml里面用 maven dependency
<dependency> <groupId>com.mongoing.mongosaga</groupId> <artifactId>mongosaga</artifactId> <version>0.5 </version> </dependency>
2. 对需要事务的方法加一个 @Compensatable 标注 3. 对该事务内的每一个操作实现一个补偿器(方法)
![Page 33: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/33.jpg)
演示步骤 1
Clone或者下载 mongosaga 项目(包含测试代码)
# git clone https://github.com/tjworks/mongosaga!
AccountManager.java
transfer()
Account.java debit() debit_compensator() credit() credit_compensator()
LoadTest.java
testTransfer()
![Page 34: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/34.jpg)
演示步骤 2
在test目录下定义AccountManager类,把需要在一个事务内完成的操作封装在一个方法里,使用@Compensatable 来标注该方法启用补偿事务 package com.mongoing.mongosaga;!!public class AccountManager {!! @autowired! Account account;!! @Compensatable !!
public void transfer(from, to, amount) {!!account.debit(from, amount);!!account.credit(to, amount);!
}!!}!
![Page 35: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/35.jpg)
演示步骤 3
public class Account {! . . .! private DBCollection accounts;! ! @Compensate! public void debit(String from, double amount){! log.info("debit " + amount+" from account "+from);! accounts.update(new BasicDBObject("name", from), ! new BasicDBObject("$inc", new BasicDBObject("balance", -1* amount)));! }! public void debit_compensator(String from, double amount){! log.info(“compensating debit operation, adding " + amount+" back to "+from); ! accounts.update(new BasicDBObject("name", from), ! new BasicDBObject("$inc", new BasicDBObject("balance", amount)));! }! ! @Compensate! public void credit(String to, double amount){! log.info("credit "+ amount+" to "+to);! accounts.update(new BasicDBObject("name", to), ! new BasicDBObject("$inc", new BasicDBObject("balance", amount)));! }! public void credit_compensator(String to, double amount){! log.info(”compensating credit operation, subtract " + amount+" from "+to); ! accounts.update(new BasicDBObject("name", to), ! new BasicDBObject("$inc", new BasicDBObject("balance", -1* amount)));! } !!
增加一个Account类, 为每一个需要补偿的操作(方法)在同一个类内创建一个补偿器方法, 补偿器方法命名规则: 原方法名+ “_compensator”
补偿器
![Page 36: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/36.jpg)
演示步骤 4
. . .! final class Worker implements Runnable {! int id;! public Worker(int id){ this.id=id; }! public void run(){! int amount = (int)(Math.random()*100)+1;! for(int k=0;k<1000;k++){! try{! counter[0]++;! accountManager.transfer("mona"+ id, "tj"+ id, amount); ! }! catch(Exception e){ counter[1]++; } ! } ! }! } ! int poolSize = 100;! ExecutorService executor = Executors.newFixedThreadPool(poolSize); ! for (int i = 0; i < poolSize; i++) { ! executor.execute(new Worker(i));! } !
写一个Junit测试来验证: • 创建100对用户,初始balance均为0,允许负值 • 100个线程,每个线程执行1000次左右转账操作 • 5-10% 随机错误(引起补偿动作) • 检查最终结果(所有balance加起来应该为0)
![Page 37: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/37.jpg)
演示步骤 5
MacBook-‐Pro-‐13:compensatable tjworks$ mvn clean test -‐Dtest=LoadTest -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ T E S T S -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ Running com.mongoing.mongosaga.LoadTest 224 [main] INFO org.springframework.beans.factory.xml.XmlBeanDefini+onReader -‐ Loading XML bean defini+ons from class path resource [applica+onContext.xml] … … #### Time used: 25s #### Total compensa+ons: 6994 out of total op: 99788 Results : Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 !
运行测试
![Page 38: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/38.jpg)
演示步骤 6
> db.accounts.aggregate({$group:{_id:"", sum: {$sum: "$balance"}}}) { "_id" : "", "sum" : 0 } > > db.accounts.find().limit(10) { "_id" : ObjectId("57319bacc026280ce28867a3"), "name" : "tj0", "balance" : 89000 } { "_id" : ObjectId("57319bacc026280ce28867a4"), "name" : "mona0", "balance" : -‐89000 } { "_id" : ObjectId("57319bacc026280ce28867a5"), "name" : "tj1", "balance" : 58000 } { "_id" : ObjectId("57319bacc026280ce28867a6"), "name" : "mona1", "balance" : -‐58000 } { "_id" : ObjectId("57319bacc026280ce28867a7"), "name" : "tj2", "balance" : 5000 } { "_id" : ObjectId("57319bacc026280ce28867a8"), "name" : "mona2", "balance" : -‐5000 } { "_id" : ObjectId("57319bacc026280ce28867a9"), "name" : "tj3", "balance" : 57000 } { "_id" : ObjectId("57319bacc026280ce28867aa"), "name" : "mona3", "balance" : -‐57000 } { "_id" : ObjectId("57319bacc026280ce28867ab"), "name" : "tj4", "balance" : 16000 } { "_id" : ObjectId("57319bacc026280ce28867ac"), "name" : "mona4", "balance" : -‐16000 } >
验证结果
![Page 39: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/39.jpg)
简易测试结果 - MongoDB
SUB POINT
ATM 订单 跨行转账 电信扣费 . . .
测试场景
• 一台 Macbook Pro • 8G RAM • 4 Core • 100线程并发执行,每个线程执行1000次左右转账 • MongoDB 3.2.0 运行于本机,无任何优化 • Spring + MongoDB Java Driver
测试结果
• 每秒 3990 次转账操作,7%的模拟出错/补偿操作
• 结果100% 准确
• 相当于每天3.5亿次 – 银联支付每天7亿业务
![Page 40: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/40.jpg)
简易测试结果 - MySQL
SUB POINT
ATM 订单 跨行转账 电信扣费 . . .
测试场景
• 一台 Macbook Pro • 8G RAM • 4 Core • 100线程并发执行,每个线程执行1000次左右转账 • MySQL 5.6 InnoDB • Spring Transaction Management
测试结果
• 每秒 ~200 次转账操作
0 500 1000 1500 2000 2500 3000 3500 4000 4500
Transfers/s
MongoDB
MySQL
![Page 41: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/41.jpg)
事务补偿设计
SUB POINT
ATM 订单 跨行转账 电信扣费 . . .
SUB POINT
注意事项 • 补偿!=回滚
• 回滚: 动作从未被提交过 • 补偿: 通过提交另一个操作来中和
前一个动作的效果
• 不是所有场景都适合事务补偿,如多进程同时更新一条记录,并且不是增加或减少的情况
• 尽量实现幂等性:失败时可以自动重试(功能正在实现中)
ATM 订单 跨行转账 电信扣费 . . .
场景举例:
订单处理
转账类业务
电信扣费
ERP进销存
. . .
![Page 42: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/42.jpg)
补充说明
SUB POINT
ATM 订单 跨行转账 电信扣费 . . .
SUB POINT
注意事项 • 补偿!=回滚
• 回滚: 动作从未被提交过 • 补偿: 通过提交另一个操作来中和
前一个动作的效果
• 不是所有场景都适合事务补偿,如多进程同时更新一条记录,并且不是增加或减少的情况
• 尽量实现幂等性:失败时可以自动重试(功能正在实现中)
ATM 订单 跨行转账 电信扣费 . . .
关于mongosaga的使用,此PPT内所含信息不是最新的。 具体使用请参见github页面。 订单处理
电信扣费 https://github.com/tjworks/mongosaga
ERP进销存
. . .
![Page 43: 在 ongoDB 中实现强事务 - · PDF file分布式事务数据库 ! 二阶段提交 1. 基于锁机制,提交阶段用到资源都处于阻塞状态 2. TransactionManager 单点故障](https://reader030.fdocument.pub/reader030/viewer/2022012309/5a74c10d7f8b9a0d558be4f0/html5/thumbnails/43.jpg)
MongoDB 官网 http://www.mognodb.com MongoDB 中文社区 http://www.mongoing.com