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

news2024/9/29 1:28:06

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

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

  • 假设我们要实现一个转账的微服务 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 {
      	@Inject
      	private AccountService accountService; // 使⽤依赖注⼊获取账户服务的实例
      	@Override
      	public 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.coloradmin.cn/o/586673.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python中如何反转字符串:三种简单方法

Python中如何反转字符串&#xff1a;三种简单方法 当我们在处理字符串时&#xff0c;有时需要将其反向排列。在Python中&#xff0c;这可以通过以下三种简单方法实现&#xff1a; 1. 使用内置的切片方法 在Python中&#xff0c;可以使用字符串的切片方法将其反转。这种方法非…

(浙大陈越版)数据结构 第三章 树(上) 3.4 小白专场:树的同构(PTA编程题讲解)

题意理解和二叉树表示 给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换变成T2&#xff0c;则称两棵树是“同构”的。 eg1&#xff1a;现请你判断如下两棵树&#xff08;左侧为T1&#xff0c;右侧为T2&#xff09;是否为同构树&#xff1f; 显然T1可以通过有限次左右孩子…

REST风格 -- SpringMVC入门保姆级教程(四)

文章目录 前言四、REST风格1.了解REST风格2.REST风格写法一般步骤3.REST风格快速开发4.REST风格中的注解5. 案例&#xff1a;基于REST风格页面数据交互 总结 前言 为了巩固所学的知识&#xff0c;作者尝试着开始发布一些学习笔记类的博客&#xff0c;方便日后回顾。当然&#…

Redis高级篇 - 分布式缓存

分布式缓存 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题&#xff1a; 1.Redis持久化 Redis有两种持久化方案&#xff1a; RDB持久化AOF持久化 1.1.RDB持久化 RDB全称Redis Database Backup file&#xff08;Redis数据备份文件&#xff09;&#xff0c…

iPad触屏笔哪个牌子好用?Apple Pencil的平替笔

从无纸化的广泛使用&#xff0c;电容笔成为无纸化中不可替代的一部分。但由于原装电容笔的昂贵&#xff0c;市面上的电容笔品牌众多&#xff0c;不知如何下手&#xff0c;今天给大家推荐几款好用又平价的Apple Pencil平替笔。顺便给不知道如何挑选电容笔的小伙伴科普一下电容笔…

车载网络测试 - CANCANFD - 基础篇_02

目录 七、与CAN总线相关的标准 1、ISO 11898,ISO16845 2、SAE J1939,ISO 11783,NMEA 2000,CANopen 3、ISO15765/ISO14229 4、ISO 17356/OSEK 5、CCP(CAN Calibration Protocol) 6、GMLAN,VWTP,FNOS,DCNet,MCNet 八、CAN总线的特点 九、CAN总线基本概念 七、与CAN总线相…

机器学习-4 决策树算法

决策树算法 算法概述分类算法与分类器决策树算法树模型决策树的原理决策树算法的关键决策树构造的基本思路 算法基本思想决策树的训练与测试三种经典的决策树生成算法基于信息增益的ID3算法基于信息增益率的C4.5算法C4.5算法C5.0算法 基于基尼系数的CART算法 算法流程算法关键问…

chatgpt赋能python:Python中的包

Python中的包 对于使用Python进行编程的开发者来说&#xff0c;包是一个非常重要的概念。包可以看作是一个包含了多个模块的文件夹&#xff0c;这些模块可以在代码中使用。通过使用Python中的包&#xff0c;开发者可以使代码更加模块化&#xff0c;提高代码的可维护性和可读性…

Emacs之git操作(一百零五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

Apache Impala(1):Impala简介

1 Impala 基本介绍 impala 是 cloudera 提供的一款高效率的 sql 查询工具&#xff0c;提供实时的查询效果&#xff0c;官方测试性能比 hive 快 10 到 100 倍&#xff0c;其 sql 查询比 sparkSQL 还要更加快速&#xff0c;号称是当前大数据领域最快的查询 sql 工具&#xff0c…

小主机折腾记13

这个月折腾的事比较多&#xff0c;记个流水账 1.600g2mt加装wifi模块&#xff1b; 买了ngff转pcie的转接卡&#xff0c;发现竟然不能原生支持蓝牙&#xff0c;需要额外接一个4pin转9针usb的线&#xff0c;600g2mt是没有那种通用的usb9针口的…… 而内建蓝牙的转接卡网上也有卖&…

【项目】ROS下使用N100模块

本文主要记录如何使用WHEELTEC N100 模块。 之前的版本是CP2102串口芯片&#xff0c;而2022年5月之后的N100采用的是CH9102串口芯片。 一、修改串口号&#xff1a; 工具&#xff1a;链接&#xff1a;https://pan.baidu.com/s/13Pdq45_Z0ZRwuaNN0I84Cg 提取码&#xff1a;i6j…

《深入理解计算机系统(CSAPP)》第6章 存储器层次结构 - 学习笔记

写在前面的话&#xff1a;此系列文章为笔者学习CSAPP时的个人笔记&#xff0c;分享出来与大家学习交流&#xff0c;目录大体与《深入理解计算机系统》书本一致。因是初次预习时写的笔记&#xff0c;在复习回看时发现部分内容存在一些小问题&#xff0c;因时间紧张来不及再次整理…

【计算机网络详解】——应用层(学习笔记)

&#x1f4d6; 前言&#xff1a;应用层是计算机网络体系结构的最顶层&#xff0c;是设计和建立计算机网络的最终目的&#xff0c;也是计算机网络中发展最快的部分。在本文中&#xff0c;我们以一些经典的网络应用为例来学习有关网络应用的原理、协议和实现方面的知识。 目录 &a…

华为OD机试真题B卷 Java 实现【快速寻找某字符】,附详细解题思路

一、题目描述 给定一个一个目标值 target和一个 元素升序的无重复数字字符串 &#xff0c;写一个函数搜索 字符串 中的 target&#xff0c;如果目标值存在返回下标&#xff08;下标从 0 开始&#xff09;&#xff0c;否则返回 -1。 二、输入描述 第一行输入一个目标值target…

在Centos Stream 9上Docker的实操教程(三) - Docker容器数据卷

在Centos Stream 9上Docker的实操教程 - Docker容器数据卷 问题场景Docker容器数据卷简单介绍数据卷使用操作实例安装redis验证配置文件生效验证数据是否丢失 结语 问题场景 Docker容器我们可以理解就是微型的linux系统&#xff0c;在使用容器的时候自然会产生一系列数据文件&…

基于SpringBoot+Vue的儿童书法机构管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 儿童书法机构的管理是…

代码随想录算法训练营第四十二天 | 二维dp数组01背包, 力扣 416. 分割等和子集

背包 解析 1.确定dp数组以及下标的含义 对于背包问题&#xff0c;有一种写法&#xff0c; 是使用二维数组&#xff0c;即dp[i][j] 表示从下标为[0-i]的物品里任意取&#xff0c;放进容量为j的背包&#xff0c;价值总和最大是多少。 2.确定递推公式 有两个方向推出来dp[i][…

跨境电商app开发搭建多语言商城后的运营技巧,一件了解电子商城及运营

跨境电商APP包含&#xff1a;买家端手机H5版本, 电脑Pc网页版本, 安卓苹果App。 一、模式介绍 如需要探讨&#xff0c;请kan 名片。 无货源模式&#xff1a;电商平台上的卖家不需要自己拥有实体的库存&#xff0c;而是通过与供应链服务提供商合作&#xff0c;将订单和支付…

ai写作软件怎么写文章?这篇文章介绍三个好方法

在人工智能技术的迅速发展下&#xff0c;ai写作成为创作领域的一项炙手可热的新技术。随着越来越多的创作者开始借助ai写作工具&#xff0c;ai写作逐渐引起了广泛的关注。ai写作是指利用人工智能技术和自然语言处理算法&#xff0c;为创作者提供文章的初版。不过有很多小伙伴对…