通信技术选择

Socket、RPC、MQ、HTTP等通信技术的差异与选择

同步、异步、阻塞、非阻塞

同步和异步的概念描述的是用户线程与内核的交互方式:同步是指用户线程发起IO请求后需要等待或者轮询内核IO操作完成后才能继续执行;而异步是指用户线程发起IO请求后仍继续执行(直接返回),当内核IO操作完成后会通知用户线程,或者调用用户线程注册的回调函数。
阻塞和非阻塞的概念描述的是用户线程调用内核IO操作的方式:阻塞是指IO操作需要彻底完成后才返回到用户空间;而非阻塞是指IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成。

一个IO操作可以分为两个步骤:发起IO请求和实际的IO操作

阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。

同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程(IO操作完成后才能返回),那么就是同步IO,因此阻塞IO、非阻塞IO、IO复用、信号驱动IO都是同步IO,如果不阻塞,而是操作系统做完IO两个阶段的操作再将结果返回给用户线程,那么就是异步IO。

可以简单理解,调用需等待返回结果就是同步;调用后程序可以继续执行,完成后会调用回调函数。

五种IO模型

  1. 阻塞I/O(blocking I/O)。进程从调用开始到它返回的整段时间内是被阻塞的
  2. 非阻塞I/O (nonblocking I/O) 应用进程持续轮询内核,以查看某个操作是否就绪
  3. I/O复用(select 和poll) (I/O multiplexing) 一个进程可以监视多个描述符,一旦某个描述符就绪,能够通知程序进行相应的读写操作
  4. 信号驱动I/O (signal driven I/O (SIGIO))
  5. 异步I/O (asynchronous I/O (the POSIX aio_functions)) [真正异步]

根据上述5种IO模型,前4种模型-阻塞IO、非阻塞IO、IO复用、信号驱动IO都是同步I/O模型,因为其中真正的I/O操作将阻塞进程,在内核数据拷贝到用户空间时都是阻塞的

Socket

Socket先对于其他技术来说比较底层,Netty、Mina等框架都是对Socket进行封装。协议需要自行定义开发,重连,心跳等各种处理。游戏开发,程序间交互等会用到Socket

RPC

一般都是同步的调用端需要等待结果后才能执行后续操作,也有异步RPC(Future,CompletableFuture)。一般还需要一个注册中心来管理服务和支持集群。比如一个验证订单是否合法需要调用RPC获取商品单价,RPC获取当前用户余额等操作后进行校验,异步就是这两个操作可以同时进行。RPC电商平台用的比较多。超时处理是个大问题,超时并不代表失败。
RPC的方式一般可以保证调用返回即处理完成
RPC一般用在需要立即返回结果并且调用关系明确的场景。比如登录系统

MQ

异步。用在消费者与发送者需要解耦的场景。比如生产非常多的数据提供给多个下游服务使用,并不关心他们怎么用。电商中的应用比如:订单系统下单成功后,写入消息队列,库存系统从订阅中获取订单信息进行后续操作,调整完库存后才能付款等。秒杀由于用户太多可以用MQ对用户进行排队

优点:
平台统一调用方式
缺点:

  1. 需要增加MQ组件
  2. 消息调用路径变长,增加延时
  3. 消息不丢不重难保证

异步,解耦,消峰,MQ的三大主要应用场景。
上游关注和依赖下游的响应,宜用RPC;上游不关注不依赖下游的响应,宜用MQ。
还可以使用MQ来实现RPC,比如RabbitMQ中有Direct reply-to

MQ使用场景举例

数据驱动的任务依赖:比如统计任务,task2需要task1的结果,可以用MQ来编排
上游不关心执行结果:比如用户发布帖子,之后的加积分,统计分析等都可以通过MQ来解耦
上游关注执行结果,但执行时间很长:比如微信支付,一般用“回调网关+MQ”解耦
当调用方需要关心消息执行结果时,通常使用MQ,而使用RPC调用。比如登录,登录要根据登录接口结果给出成功失败,跳转,错误等各种状态提升

HTTP

无状态。一般都是同步的一发一收断开链接。异步实现方案:比如银行交易系统,提交交易操作后,提供一个异步返回链接。操作完成后银行调用异步返回接口返回操作结果。现在也有不少系统使用Rest API,比如Spring Cloud的默认方案