剑客
关注科技互联网

白话 Reactor 模型

假设给你一家餐馆,叫你经营,一个最基本的目标是保证客户体验,客户来就餐时尽可能地缩短等待时间,你会如何做?

我相信,要解决上面这个问题,不同的人会有不同的方法,但是一个最基本的也是最容易想到的思路是:

多招几个服务员,每当有客户来就餐时就安排一个服务员,全程服务,这样的体验无疑是至尊级的。

但是,问题来了,这种方法在餐馆很小,客户量很小的时候可能行得通,当客户量很多时,再为每一个客户安排一个服务员的做法无疑是扯犊子,巨额的成本支出会让你蓝瘦、香菇,除非你经营餐馆不是为了赚钱,而是为了消遣!

既然不能无限制地增加服务员,那就控制一下服务员的数量呗,第二种方案如下:

招聘一定数量的服务员,随时待命,每次有客户来就餐时如果有服务员空闲就安排一个服务员去全程服务,如果所有的服务员没空时就只能将客户拒之门外,等到有服务员空闲下来再去招呼。

这个方案看起来好像挺完美的,能够很好地控制成本,并且在大部分情况下都很有效,但是当高峰期时,客户人数比较多,服务员很快就会全部被用完,这个时候门外的不能就餐也没人理睬的客户可能就不开心了,没有体验到顾客是上帝的感觉,毫无疑问,下次不会再光顾。

还有没有更好的解决方案呢? 答案是肯定的。在上面的第二种方案中,还有很大的优化余地:每一个服务员全程服务一个客户时,其实服务员有很大一部分时间都是在等客户点菜,如果能利用这部分等待时间去服务其他客户,那将能大大提高服务资源的利用率。下面是第三种方案:

招聘一定数量的服务员,其中过一个服务员负责站台,她的任务是迎接前来就餐的客户,每当有客户到来时,都会问候一下,并且带到空桌坐下,然后从服务员资源池中安排一个服务员来服务,然后继续去迎接下一位客户。其他服务员的任务是服务客户(好像是废话),但是不像第二种方案一样全程服务,可以在客户点菜的时候去服务其他客人,客户点菜完成之后再叫服务员来下单。

可以注意到,当今的大型的饭店基本都是采用第三种方案。

好了,言归正传,咱们聊聊计算机网络IO模型吧。

网站这个东西大家都知道,是一个典型的C/S架构,就拿小米网举例子吧,每次用户想在小米网上买手机(比如小米MIX),都会先登录小米网,然后抢购,下单,付款。抢得到抢不到另说吧,但是如果用户在登录小米网或者浏览商品的时候服务器响应很慢,那用户的心情一定是奔溃的,会骂小米网**。

那怎么样提高网站服务响应速度呢?设计来源于生活,受到餐馆服务模式的启发,计算机网络IO模型也有几种对应的方案:

  1. 每有一个client连接到来时都创建一个新的线程,由它负责处理本client的相关逻辑,处理完成之后销毁线程;

  2. 事先创建一批线程,用于构建一个线程池,每有一个client连接到来时,如果线程池中当前有空闲的线程,则选择一个空闲的线程去处理该client的逻辑,处理完成之后线程回归线程池,等待下一个client的到来;

  3. 事先创建两批线程,用于构建两个线程池,一个称为acceptor线程池,另一个称为worker线程池,acceptor用于接收client的连接,做一些基本的轻量级的验证,完成之后将该client的相关信息交给worker线程池,由worker线程池负责具体的逻辑处理,每一个线程完成自己的本职工作之后到回归线程池待命。最重要的是,worker线程池中的线程不应该被client的一些IO操作阻塞。

重点到了,上面的第三种方案就是 Reactor模型
的原型,很出名的Netty框架就是对Reactor模型的具体实现!

分别分析一下上面三种方案的优劣:

  1. 优势:实现非常简单,在小规模环境中能完美工作; 劣势
    :在高并发大规模环境下基本无法工作,因为线程的创建和销毁都需要额外的时间开销,另外每创建一个线程都需要一定的系统资源,系统资源有限,不可能无限创建线程,再者,线程数多了之后系统用于上下文切换的时间就会增大;

  2. 优势 :实现比较简单,在一般规模的环境中能够很好地工作;
    劣势
    :在高并发大规模的环境下很可能会因为处理某些任务时需要等待一些外部资源而导致处理时间很长,最终导致整个线程池的所有线程全部繁忙,无法对外提供服务,给用户的感觉就是网站挂了;


  3. 优势
    :在高并发大规模环境下也能工作得很好,性能很棒;
    劣势
    :实现很复杂,在Java中需要使用NIO来实现,网上相关的实现已经随处可见,在此就不写代码了。

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址