《消息队列高手课》课程笔记(七)

news/2024/11/28 22:01:28/

如何使用异步设计提升系统性能?

异步设计如何提升系统性能?

  • 假设我们要实现一个转账的微服务 Transfer(accountFrom, accountTo, amount),这个服务有三个参数:分别是转出账户、转入账户和转账金额。
    • 这个例子的实现过程中,我们调用了另外一个微服务 Add(account, amount),它的功能是给账户 account 增加金额 amount,当 amount 为负值的时候,就是扣减响应的金额。
    • 在这段代码中,为了使问题简化以便我们能专注于异步和性能优化,省略了错误处理和事务相关的代码,在实际的开发中不要这样做。

同步实现的性能瓶颈

  • 首先我们来看一下同步实现,对应的伪代码如下:
    Transfer(accountFrom, accountTo, amount) {// 先从accountFrom的账户中减去相应的钱数Add(accountFrom, -1 * amount)// 再把减去的钱数加到accountTo的账户中Add(accountTo, amount)return OK
    }
    
    • 假设微服务 Add 的平均响应时延是 50ms,那么很容易计算出我们实现的微服务 Transfer 的平均响应时延大约等于执行 2 次 Add 的时延,也就是 100ms。
    • 在这种实现中,每处理一个请求需要耗时 100ms,并在这 100ms 过程中是需要独占一个线程的,那么可以得出这样一个结论:每个线程每秒钟最多可以处理 10 个请求。
    • 我们知道,每台计算机上的线程资源并不是无限的,假设我们使用的服务器同时打开的线程数量上限是 10,000,可以计算出这台服务器每秒钟可以处理的请求上限是 10,000(个线程)* 10(次请求每秒)= 100,000 次每秒。
    • 如果请求速度超过这个值,那么请求就不能被马上处理,只能阻塞或者排队,这时候 Transfer 服务的响应时延由 100ms 延长到了:排队的等待时延 + 处理时延 (100ms)。
    • 也就是说,在大量请求的情况下,我们的微服务的平均响应时延变长了。
    • 采用同步实现的方式,整个服务器的所有线程大部分时间都没有在工作,而是都在等待。

采用异步实现解决等待问题

  • 接下来我们看一下,如何用异步的思想来解决这个问题,实现同样的业务逻辑。

    TransferAsync(accountFrom, accountTo, amount, OnComplete()) {// 异步从 accountFrom 的账户中减去相应的钱数,然后调⽤OnDebit⽅法。AddAsync(accountFrom, -1 * amount, OnDebit(accountTo, amount, OnAllDone(OnComplete()))
    }
    // 扣减账户 accountFrom 完成后调⽤
    OnDebit(accountTo, amount, OnAllDone(OnComplete())) {// 再异步把减去的钱数加到 accountTo 的账户中,然后执⾏ OnAllDone ⽅法AddAsync(accountTo, amount, OnAllDone(OnComplete()))
    }
    // 转⼊账户 accountTo 完成后调⽤
    OnAllDone(OnComplete()) {OnComplete()
    }
    
  • 异步的实现过程相对于同步来说,稍微有些复杂。

    • 我们先定义 2 个回调方法:
      • OnDebit():扣减账户 accountFrom 完成后调用的回调方法;
        • 异步从 accountFrom 的账户中减去相应的钱数,然后调用 OnDebit 方法;
        • 在 OnDebit 方法中,异步把减去的钱数加到 accountTo 的账户中,然后执行 OnAllDone 方法;
      • OnAllDone():转入账户 accountTo 完成后调用的回调方法。
        • 在 OnAllDone 方法中,调用 OnComplete 方法。
    • 异步化实现后,整个流程的时序和同步实现是完全一样的,区别只是在线程模型上由同步顺序调用改为了异步调用和回调的机制。
      在这里插入图片描述
    • 由于流程的时序和同步实现是一样的,在低请求数量的场景下,平均响应时延一样是 100ms。
    • 在超高请求数量场景下,异步的实现不再需要线程等待执行结果,只需要个位数量的线程,即可实现同步场景大量线程一样的吞吐量。
    • 由于没有了线程的数量的限制,总体吞吐量上限会大大超过同步实现,并且在服务器 CPU、网络带宽资源达到极限之前,响应时延不会随着请求数量增加而显著升高,几乎可以一直保持约 100ms 的平均响应时延。

简单实用的异步框架: CompletableFuture

  • Java 中比较常用的异步框架有 Java 内置的 CompletableFuture 和 ReactiveX 的 RxJava。
  • 接下来,我们来看下,如何用 CompletableFuture 实现的转账服务。
    • 首先,我们用 CompletableFuture 定义 2 个微服务的接口:
      /*** 账户服务*/
      public interface AccountService {/*** 变更账户⾦额* @param account 账户 ID* @param amount 增加的⾦额,负值为减少*/CompletableFuture<Void> add(int account, int amount);
      }
      
      /*** 转账服务*/
      public interface TransferService {/*** 异步转账服务* @param fromAccount 转出账户* @param toAccount 转⼊账户* @param amount 转账⾦额,单位分*/CompletableFuture<Void> transfer(int fromAccount, int toAccount, int amount);
      }
      
    • 然后我们来实现转账服务:
      /*** 转账服务的实现*/public class TransferServiceImpl implements TransferService {@Injectprivate AccountService accountService; // 使⽤依赖注⼊获取账户服务的实例@Overridepublic CompletableFuture<Void> transfer(int fromAccount, int toAccount, int amount) {// 异步调⽤ add ⽅法从 fromAccount 扣减相应⾦额// 然后调⽤ add ⽅法给 toAccount 增加相应⾦额return accountService.add(fromAccount, -1 * amount).thenCompose(v -> accountService.add(toAccount, amount));}
      }
      

http://www.ppmy.cn/news/105062.html

相关文章

Vue登录界面精美模板分享

文章目录 &#x1f412;个人主页&#x1f3c5;Vue项目常用组件模板仓库&#x1f4d6;前言&#xff1a;&#x1f380;源码如下&#xff1a; &#x1f412;个人主页 &#x1f3c5;Vue项目常用组件模板仓库 &#x1f4d6;前言&#xff1a; 本篇博客主要提供vue组件之登陆组件源码…

S7-1200 和 CP342-5 PROFIBUS DP主从通信例程

S7-1200 与 CP342-5 之间 PROFIBUS DP主从通信的几种可能情况分别提供了例程&#xff1a; 1. 同一项目中S7-1200 与 S7-300 CP342-5 之间 DP 主从通信&#xff0c;S7-1200 通过CM1243-5作为 DP 主站&#xff0c;CP342-5作为 DP 从站&#xff1b; 2. 不同项目中S7-1200 与 S7-3…

2022年软件测试人员调查统计

1、软件测试从业人员的年龄分布 测试行业的主力军年龄分布主要是集中在 26-30 岁这个区间&#xff0c;这部分的群体承担着行 业发展的主导力量&#xff0c;占 43.2%。根据数据显示&#xff0c;被调查者中占比最多的是 26-30 岁区间的软件测试从业人员&#xff0c;26-30 岁的测试…

spring入门-bean

Spring 是一个开源的、轻量级的企业级 Java 应用程序框架&#xff0c;它提供了一种全新的、基于 IoC &#xff08;控制反转&#xff09;和 AOP&#xff08;面向切面编程&#xff09;的软件开发方式&#xff0c;以及众多的企业级应用程序开发组件和 API。使用 Spring 框架可以大…

辅助驾驶功能开发-功能规范篇(26)-1-紧急转向辅助ESA

1.前言 1.1.目的 本文档定义了高级驾驶辅助领域中紧急转向辅助的基本控制功能及性能需求,适用于紧急转向辅助功能的功能性能开发和测试验证。 1.2.缩写及术语 ELK Emergency Lane Keeping 紧急车道保持 ESA

数据传输选Ajax还是Axios

前言 随着Web应用程序的发展&#xff0c;越来越多的开发人员需要通过JavaScript与服务器进行交互。在前端开发过程中&#xff0c;Ajax和Axios是两种最为常见的数据请求方式。虽然它们可以实现同样的目的&#xff0c;但却有一些重要的不同点和优劣势。 Ajax和Axios的介绍 Aja…

2023-05-30 Unity 2进制6——Excel写入器ExcelWriter

文章目录 一、Epplus 使用二、ExcelWriter&#xff08;一&#xff09;文件结构&#xff08;二&#xff09;操作说明&#xff08;三&#xff09;操作示例&#xff08;四&#xff09;完整代码 一、Epplus 使用 &#xff08;一&#xff09;获取 Excel 文件 string filePath App…

如何在 Python 中进行条件语句控制?

在 Python 中&#xff0c;条件语句控制是编程中最基本的结构之一。它允许程序员根据特定的条件来选择执行不同的代码块。在本篇博客中&#xff0c;我们将介绍 Python 中的条件语句控制以及如何使用它来编写更加灵活的程序。 Python中的条件语句 在 Python 中&#xff0c;条件…