一个包子铺看懂 JAVA中I/O 模型演变
小眼睛打算开个包子铺,拜访了 N 个餐饮界大佬后,决定直接搞 O2O 模式。依据大佬们透露的数据,省掉了房租、水电、工资,结合平台的优势只要按照每年 10% 的增速,用不了多久就能迎娶白富美走上人生巅峰了。在美好的幻想中,包子托拉斯开业了……
BIO
开张第一个月,下单量短暂增长,一周之后开始迅速滑落。持续收到大量投诉:客户投诉送餐太慢,骑手投诉取餐等待太久。眼看着刚开张,就有倒闭的预兆。包子托拉斯请来了著名咨询公司鹰邦邦给大家支招。鹰邦邦的基尔,梳理出来了整个运转的流程:
收到外卖订单后(socket 建立,生成 FD),为了不影响包子口感是不能提前打包的。外卖骑手到达后,报出自己的订单号(可读事件到来)。后厨根据订单号找到对应订单,根据订单数据,配餐、打包、交给骑手(写事件),确认订单已配送(socket 关闭),再继续处理下一个骑手拿到的订单。
后厨同一时刻只能处理一笔订单,某笔订单配餐的过程较长时,其余骑手的订单都需要等待(阻塞)前面的订单处理完毕。
问题:
一个时间只能处理一个订单,即便是后面的订单是个准备工作很简单的订单,也必须等待。
BIO + 多线程
鹰邦邦的人果然是高手,短短 1 天时间给出了提升方案。根据每份外卖的平均准备时长、高峰期的订单数等数据,建议把后厨分成 4 组(线程池)。
骑手到达后(可读事件到达),随机从空闲的 4 组里面选择一组处理订单。4 组都没有空闲下来时,骑手等待。
改进:
同一时刻,处理订单的能力比之前增加
问题:
每一个订单使用一个线程,线程数量有限(包子托拉斯只有 4 个),没订单时,后厨资源都在等待
NIO + 多线程
又过了两个月,后厨的老于约小眼睛聊这段时间的工作情况。言谈中,老于流露出的意思是,分了组整个配餐的速度确实提升了很多,但是后厨的兄弟们除了配餐还有其他工作。高峰期间总是盯着订单,耽误其他工作。
有问题就改,经过内部讨论,决定招聘一个导购MM。招聘通知发出去没几天,身材高挑的丽丽就上岗了。丽丽的职责是负责分配所有的骑手订单给到后厨。
当外卖骑手到达后,丽丽从所有订单中找出当前骑手负责的订单(selector 从所有 FD 中找到发生事件的 FD),把订单给到后厨,后厨的 4 个小组中空闲的小组,根据订单信息配餐。
丽丽去个卫生间,所有骑手的单子就不能处理(selector 阻塞)
改进:
丽丽专职处理订单的委派,后厨专职配餐,各司其职互不影响
问题:
丽丽要一直守着门口(selector 阻塞),不工作或者工作怠慢,后面就没有订单处理
NIO 加强(epoll)
丽丽和后厨吵架了,后厨老于觉得丽丽可以帮忙干点小事儿,打扫个卫生、帮忙拿拿材料啥的。丽丽很委屈,离开了门口外卖骑手来了她不知道,会被大家各种催促。
鹰邦邦的基尔又出手了。当骑手进入包子托拉斯的等待区,骑手点击「到店取货」,丽丽手中的终端设备会发出信号。(事件到达会发出通知)终端上展示等待取货的订单,丽丽只需要盯着终端设备的消息就可以了。丽丽平时可以做一些其他的事情,根据设备上的通知随时的分配订单给后厨。
改进:
丽丽专职处理订单的委派,基于事件的通知而不是盲目等待
问题:
丽丽的问题解决了,后厨是不是最高效地在运转呢
Reactor 模型
又过了一段时间,包子托拉斯又进行重量级改革。鹰邦邦给出终极解决方案:后厨按照流水线作业,有人负责配餐、有人负责包装、有人负责核验订单。负责配餐又细分为负责包子、负责饮料、负责小菜的。(处理线程职责单一)
外卖骑手到达后,丽丽根据系统中显示的订单信息(事件到达后通知),把订单交给后厨。后厨按照约定的流程顺序(责任链),完成自己的工作,转交下一个人。最后外卖被打包,交给骑手。(socket 写事件完成)
本次分享先到这里,欢迎关注我一起交流,随时指出各种错误和不足。
来源:InfoQ