为什么基于事件驱动的服务器能实现高并发?

为什么基于事件驱动的服务器能实现高并发?

这种并发实际说的是并发的不活跃的长连接,并不是并发请求

典型的后端服务,在逻辑上可以划分为两层,

  • 跟业务无关的通信层,负责socket连接的创建和管理,负责bind/listen/accept/send/recv…

  • 通信层上面是业务逻辑层,负责被动响应请求,或主动推送业务消息

通信层特点:

  • 都是IO行为,几乎不大消耗CPU
  • 连接数很多,可能同时有10K甚至100K个TCP连接
  • 通信协议就那么几种,decode/encode简单
  • 外部网络是慢速IO,收发一点数据可能要1秒甚至更久

业务逻辑层特点:

  • 少量CPU消耗,大部分时间在等待数据库或者其它网络服务返回
  • 业务逻辑五花八门,逻辑中往往需要调用别的网络服务,如db
  • 并发请求数,往往小于连接数,10K个连接,可能每秒只有100个请求
  • 单个业务请求通常很快,毫秒级别,几十毫秒算慢的了

如果完全采用传统的多线程模型,1个tcp连接对应1个线程,10K个连接需要10K个线程,典型的内存消耗是10G。但是业务逻辑层并发请求往往要小1到2个数量级,每个请求往往只需要100ms以内,所以业务逻辑层需要的线程数,比通信层小2-3个数量级,不需要10K个线程,只要100个甚至10个就够了。

​ 这种2-3个数量级差距的不匹配,促使了第一代事件驱动的流行,常见的模型,纷纷把通信层剥离出来,用事件驱动的形式取代多线程,但是在业务逻辑层仍然采用多线程模型。几个著名的例子:

  • nginx负责通信层,PHP-FPM负责业务逻辑层
  • nginx负责通信层,uwsgi负责Python的业务逻辑层
  • tomcat nio负责通信层,业务逻辑层扔到线程池里处理

​ 这些模型都很成功,用几百个甚至区区几十个线程/进程,满足了几万甚至几十万的并发连接。在整个199X年到2010年,这个模型都相当的适用,之后移动互联网兴起,随之也出现越来越多的网络API服务,我们的业务逻辑层,不但要跟内网的网络服务通信,还要跟外网的服务通信,在业务逻辑层也产生了大量的外网网络IO,导致一个请求不能在100ms内完成,可能增加到了500ms甚至几秒钟,其中大部分时间是在等待网络,白白的占用了一个线程等IO。

如果业务逻辑层也要消耗很多时间等待网络IO,那么它跟通信层的2-3个数量级的线程数量需求这个特性就被打破了,在极端的业务下,他们甚至重新回来1:1这个比例,举个例子,APP的广告服务,一个请求里可能包含3个广告位,每个广告位从20家广告供应商那里获取广告,再选价格最高的返回给APP展示。这里每一个http请求,需要对外发起60个http请求,按照一个100ms算,需要耗时6秒,如果每秒有1000个广告请求,就需要6000个线程才能不积压至服务崩溃。

所以第二代事件驱动模型应运而生,把业务逻辑也变成事件驱动,彻底消除浪费线程等待IO这个现象。事件驱动有两件常见的外衣,一件是异步回调,另一件是coroutine,近几年有了很多应用:

  • Go的goroutine
  • Python 3的coroutine
  • Kotlin的coroutine
  • nodejs的异步回调
  • swoole 1的异步回调和swoole 2的coroutine
  • erlang/elixir的process也算是coroutine
  • VertX的异步回调…

第二代普遍出现的比较晚,而且只有大厂有这个流量需要用到,所以远没有第一代那么普及,coroutine和csp等概念都是几十年前提出的,流行和普及的晚,因此只能算是老年新生事物。

该文出自于知乎。https://www.zhihu.com/question/64727674

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值