背景介绍

在介绍异步编程之前,让我们回顾现在普遍的开发模式是怎样的,以一个外网调用请求为例,当在一个Server服务开发中调用HttpUrlConnection进行http外网请求后,再进行业务逻辑处理,正常情况下Server服务的的请求如下:

此时如果某一服务出现异常,例如调用微信获取用户头像的请求超时60秒,那将拖垮整个服务链路,消耗整个线程队列和工作线程,造成服务不可用,资源耗尽

于是上面Server所有线程均阻塞在外网请求的等待中,直到请求超时为止其他用户的请求都无法进行处理,导致用户页面加载慢,客户端超时重试及用户不断刷新进一步加重请求压力,严重时直接造成业务雪崩。

基于以上场景的解决方案之一便是业务逻辑采用异步处理,业务逻辑的处理不再阻塞整个线程的执行,在逻辑处理结束之后再回调通知进行数据发送,提升服务整体性能。也因此,底层对于外网的请求改造成支持同步和异步两种网络请求,当然除了网络请求支持异步外,耗时的业务逻辑处理也可以用异步(用自定义的线程池来做异步)。

目前市面上主流的异步实现目前有回调、Promise、协程、响应式等思想,著名的node.js采用的便是回调的方式,es6标准采用的是Promise设计。为了避免各种回调地狱,且便于提供更大的灵活空间,底层的异步设计思想参照RxJava采用响应式流式调用,有一定的学习成本,但提供最大的灵活性。

但请注意,随着技术的发展,无论哪种异步编程,虽然为了解决某些特定领域问题而提出的解决方案,但由此带来的问题是大部分采用异步会导致编程难度将会比同步开发高一个台阶,这中间有调试上的困难,也有异步开发思维的转变。

异步请求的处理

当前Netkit框架的设计思路均采用异步的编程模式,即基于RxJava的响应式编程思维,这样可以最大化利用机器自身性能,用最小的时间耗时和资源占用来响应百万级的并发连接

异步与同步编程对比

模式 优势 劣势
异步 提升整个服务的吞哇量,不会因为网络阻塞或者逻辑阻塞过长导致服务性能下降,严重的会导致整个服务系统雪崩 开发模式不如同步开发直观,对编程人员有一定的开发成本,但后期习惯养成之后影响不会太大
同步 和异步编程相反,对开发人员来说快速上手开发 整个服务在网络阻塞或者逻辑阻塞过长导致服务性能下降,严重的会导致整个服务系统雪崩

代码示例

@Action
public class UserAction {
    // 异步响应输出
    @Request("/")
    public RxIo<String> async() {
        return RxIo.just("Hello").map(new IoFunction<String, String>() {
            @Override
            public String call(String s) throws Exception {
                return s + " in " + Thread.currentThread();
            }
        });
    }
}

如上所示,异步是采用RxIo的统一封装,基于响应式编程的开发模式,结合jdk8支持的lambda表达式,相对于层层递归嵌套的回调来说,链式调用的展现更具有清晰的结构化体现,避免大量的回调地狱。

当然人类的思维模式天然是同步的,异步开发的思维需要将该同步调用的服务逐个拆分成异步模式,转变起来对开发的要求比较高。但从今后的技术趋势发展,大数据大流量的时代背景下异步将是一个趋势,当然两者也将共存,但如同nginx高性能在于其底层所有的逻辑都需要是异步一样,一旦nginx底层有任何同步调用,例如有socket阻塞等待网络数据的话,那nginx的性能将直线下降。