全部产品
云市场

性能压测

更新时间:2020-03-16 12:53:45

本文中模拟了转账的业务场景,分别用分布式事务的 TCC 模式与 FMT 模式实现了转账功能,并对 TCC 模式与 FMT 模式进行了压测。

通过本文,您可对 TCC 与 FMT 模式的性能有一个大致了解。

压测模型介绍

如下图所示,“应用 A”对外发布“转账服务”,服务完成“账号 A”向“账号 B”转账的功能。

model

  1. “转账服务”内部开启分布式事务;
  2. “参与者 A”负责从“账号 A”扣款,“参与者 A”由“应用 A”提供(与发起方为同一应用);
  3. “参与者 B”负责向“账号 B”加钱,“参与者 B”服务由“应用 B”提供。

说明:A 的账号数据存储在“数据库 A”中,此数据库仅由“应用 A”访问;B 的账号数据存储“数据库 B”中,此数据库由“应用 B”访问。

实现转账

表结构设计

数据库表 A 结构为:

  1. ## 账户余额表,存储账户余额信息
  2. create table account(
  3. account_no varchar(256) not null comment '账户',
  4. amount DOUBLE comment ‘账户余额’,
  5. freezed_amount DOUBLE comment ‘账户冻结金额,TCC才会用到的字段’,
  6. primary key (account_no)
  7. );
  8. ## 账号操作流水表,记录每一笔分布式事务操作的账号、操作金额、操作类型(扣钱/加钱),TCC模式下才会使用到此表
  9. create table account_transaction(
  10. tx_id varchar(256) not null,
  11. account_no varchar(256) not null,
  12. amount DOUBLE,
  13. type varchar(256) not null,
  14. primary key (tx_id)
  15. );

数据库表 B 结构与数据库表 B 结构相同。

实现 TCC 模式

发起方实现:

  1. @DtxTransaction(bizType="single-transfer-by-tcc")
  2. public boolean transferByTcc(String from, String to, double amount) {
  3. try{
  4. //第一个参与者
  5. boolean ret = firstTccActionRef.prepare_minus(null, from, amount);
  6. if(!ret){
  7. //事务回滚
  8. RuntimeContext.setRollBack();
  9. return false;
  10. }
  11. //第二个参与者
  12. ret = secondTccActionRef.prepare_add(null, to, amount);
  13. if(!ret){
  14. //事务回滚
  15. RuntimeContext.setRollBack();
  16. return false;
  17. }
  18. return ret;
  19. }catch(Throwable t){
  20. throw new RuntimeException(t);
  21. }
  22. }

参与者 A(扣钱)实现:

  1. public interface FirstTccAction {
  2. @TwoPhaseBusinessAction(name = "firstTccAction", commitMethod = "commit", rollbackMethod = "rollback")
  3. public boolean prepare_minus(BusinessActionContext businessActionContext,String accountNo,
  4. double amount);
  5. public boolean commit(BusinessActionContext businessActionContext);
  6. public boolean rollback(BusinessActionContext businessActionContext);
  7. }

参与者 B(加钱)实现:

  1. public interface SecondTccAction {
  2. @TwoPhaseBusinessAction(name = "secondTccAction", commitMethod = "commit", rollbackMethod = "rollback")
  3. public boolean prepare_add(BusinessActionContext businessActionContext,String accountNo, double amount);
  4. public boolean commit(BusinessActionContext businessActionContext);
  5. public boolean rollback(BusinessActionContext businessActionContext);
  6. }

实现 FMT 模式

发起方实现:

  1. @DtxTransaction(bizType="transfer-by-auto")
  2. public boolean transferByAuto(String from, String to, double amount) {
  3. boolean ret = false;
  4. try{
  5. //第一个参与者
  6. ret = firstAutoAction.amount_minus(from, amount);
  7. if(!ret){
  8. //事务回滚
  9. RuntimeContext.setRollBack();
  10. return false;
  11. }
  12. //第二个参与者
  13. ret = secondAutoAction.amount_add(to, amount);
  14. if(!ret){
  15. //事务回滚
  16. RuntimeContext.setRollBack();
  17. return false;
  18. }
  19. return ret;
  20. }catch(Throwable t){
  21. throw new RuntimeException(t);
  22. }
  23. }

参与者 A(扣钱)实现:

  1. public class FirstAutoActionImpl implements FirstAutoAction {
  2. ... ...
  3. @Override
  4. public boolean amount_minus(final String accountNo, final double amount) {
  5. try{
  6. return tccFirstActionTransactionTemplateAuto.execute(new TransactionCallback<Boolean>() {
  7. @Override
  8. public Boolean doInTransaction(TransactionStatus status) {
  9. try {
  10. Account account = firstAccountDAOAuto.getAccountForUpdate(accountNo);
  11. if(account == null){
  12. throw new RuntimeException("账号不存在");
  13. }
  14. //扣钱
  15. double newAmount = account.getAmount() - amount;
  16. if (amount < 0) {
  17. throw new RuntimeException("余额不足");
  18. }
  19. account.setAmount(newAmount);
  20. int n = firstAccountDAOAuto.updateAmount(account);
  21. if(n == 1){
  22. return true;
  23. }else{
  24. status.setRollbackOnly();
  25. return false;
  26. }
  27. } catch (Exception e) {
  28. logger.error("amount_minus error", e);
  29. status.setRollbackOnly();
  30. return false;
  31. }
  32. }
  33. });
  34. }catch(Exception e){
  35. logger.error("amount_minus failed", e);
  36. return false;
  37. }
  38. }
  39. }

参与者 B(加钱)实现:

  1. public class SecodeAutoActionImpl implements SecondAutoAction {
  2. ... ...
  3. @Override
  4. public boolean amount_add(final String accountNo, final double amount) {
  5. try{
  6. return tccSecondActionTransactionTemplateAuto.execute(new TransactionCallback<Boolean>() {
  7. @Override
  8. public Boolean doInTransaction(TransactionStatus status) {
  9. try {
  10. Account account = secondAccountDAOAuto.getAccountForUpdate(accountNo);
  11. if(account == null){
  12. throw new RuntimeException("账号不存在");
  13. }
  14. //加钱
  15. double newAmount = account.getAmount() + amount;
  16. account.setAmount(newAmount);
  17. secondAccountDAOAuto.updateAmount(account);
  18. } catch (Exception e) {
  19. logger.error("amount_add error", e);
  20. status.setRollbackOnly();
  21. return false;
  22. }
  23. return true;
  24. }
  25. });
  26. } catch (Exception e) {
  27. logger.error("amount_add failed", e);
  28. return false;
  29. }
  30. }
  31. }

硬件环境

本场景使用的硬件配置如下:

说明:RDS 为 MySql 5.6 数据库。

hardware

压测样本数据策略

用户数据规模(账号数量):5000->5000,以验证在不同业务数据规模的场景下,分布式事务的 TCC 模式和 FMT 模式的性能表现。

压测模式 A组账号数 B组账号数
TCC,FMT 5000 5000

压测结果

如下图所示,用户数据规模(A->B)在 5000->5000 的场景下,TCC、FMT 模式的 TPS 与 Response Time 数据如下:

说明: TCC(总)为 TCC 模式下 TPS 总数,TCC(成)为 TCC 模式下成功 TPS 总数;FMT(总)为 FMT 模式下 TPS 总数,FMT(成)为 FMT 模式下成功 TPS 总数。

  • A 组转账至 B 组(5000->5000)TPS

    用户量(A 组转账至 B 组) TPS
    A 组:5000
    B 组:5000
    并发数 TCC(总) TCC(成) FMT(总) FMT(成)
    1 50 50 40 40
    5 250 250 200 200
    10 460 460 380 380
    20 800 800 695 690
    50 1450 1450 1220 1200
    100 1500 1500 1550 1500
    200 1500 1500 1600 1450
    500 1600 1600 1500 1400
    700 1500 1500 1500 1300

    5000-tps

  • A 组转账至 B 组(5000->5000)Response Time

    Response Time(成功)
    并发数 TCC FMT
    1 19 26
    5 21 25
    10 23 27
    20 27 30
    50 35 45
    100 70 75
    200 135 160
    500 225 380
    700 490 520

    5000-rt