春招面试复习:消息队列(六)- 异步编程妙用

0 异步的优势

太多的线程会造成频繁的cpu上下文切换,你可以想象一下,假设你的小公司只有8台电脑,你雇8个程序员一直不停的工作显然是效率最高的。考虑到程序员要休息不可能连轴转,雇佣24个人,每天三班倒,效率也还行。

但是,你要雇佣10000个人,他们还是只能用这8台电脑,大部分时间不都浪费在换人、交接工作上啦。

异步编程是通过分工的方式,是为了减少了cpu因线程等待的可能,让CPU一直处于工作状态。换句话说,如果我们能想办法减少CPU空闲时间,我们的计算机就可以支持更多的线程。
其实线程是一个抽象概念,我们从物理层面理解,就是单位时间内把每毫核分配处理不同的任务,从而提高单位时间内CPU的利用率。

线程就是为了能自动分配CPU时间片而生的。

异步实现里面还是要用线程池限制一下线程数吧,否则没有达到减少线程的效果。

异步模式设计的程序可以显著减少线程等待,从而在高吞吐量的场景中,极大提升系统的整体性能,显著降低时延。

因此,像MQ这种需要超高吞吐量和超低时延的中间件系统,在其核心流程中,会大量采用异步设计。

1 案例引入

一个转账的微服务Transfer( accountFrom, accountTo, amount),该服务有三参数

  • 转出账户
  • 转入账户
  • 转账金额

要从账户A中转账100到账户B:

  1. 先从A的账户中减去100元
  2. 再给B的账户加上100元,转账完成。
  • 对应时序图:

调用另外一个微服务Add(account, amount),给账户account增加金额amount,当amount为负值时,就是扣减相应金额。

为简化,省略了错误处理和事务相关代码

2 同步的性能瓶颈

同步实现,对应的伪代码:

Transfer(accountFrom, accountTo, amount) {
   
  // 先从accountFrom的账户中减去相应的钱数
  Add(accountFrom, -1 * amount)
  // 再把减去的钱数加到accountTo的账户中
  Add(accountTo, amount)
  return OK
}

先从accountFrom的账户中减去相应的钱数,再把减去的钱数加到accountTo的账户中,同步实现简单直接。
性能如何?
假设微服务Add的平均响应时延是50ms,微服务Transfer的平均响应时延大约等于执行2次Add的时延,即100ms。随调用Transfer服务的请求越来越多,会出现什么情况呢?

该实现,每处理一个请求耗时100ms,这100ms过程要独占个线程。
可得:每个线程每秒最多可处理10个请求。假设服务器同时打开的线程数量上限10,000,可以计算出这台服务器每秒钟可以处理的请求上限是: 10,000 (个线程)* 10(次请求每秒) = 100,000 次每秒。

若请求速度超过这个值,那么请求就不能被马上处理,只能阻塞或者排队,这时候Transfer服务的响应时延由100ms延长到了:排队的等待时延 + 处理时延(100ms)。即大量请求时,我们的微服务的平均响应时延变长了。

这是不是已达服务器极限?远没有!
若监测服务器指标,会发现无论是CPU、内存,还是网卡流量或者是磁盘的IO都空闲的很,那我们Transfer服务中的那10,000个线程在作甚?
没错!绝大部分线程都在等待Add服务返回结果。

即采用同步,整个服务器的所有线程大部分时间都没在工作,而在等待!

若能减少或避免这种无意义等待,即可大幅提升服务吞吐能力,提升性能。

异步实现方案

异步实现同样的业务。

TransferAsync(accountFrom, accountTo, amount
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值