反应式编程框架设计:如何使程序调用不阻塞等待,立即响应?( 二 )


也就是说,使用 Flower 开发的系统,在一个典型的 Web 应用中,几乎没有任何地方会被阻塞,所有的线程都可以被不断地复用,有限的线程就可以完成大量的并发用户请求,从而大大地提高了系统的吞吐能力和响应时间,同时,由于线程不会被阻塞,应用就不会因为并发量太大或者数据库处理缓慢而宕机,从而提高了系统的可用性 。
Flower 框架实现异步无阻塞,一方面是利用了 Web 容器的异步特性,主要是 Servlet3.0以后提供的 AsyncContext,快速释放容器线程;另一方面是利用了异步的数据库驱动以及异步的网络通信,主要是 HttpAsyncClient 等异步通信组件 。而 Flower 框架内,核心的应用代码之间的异步无阻塞调用,则是利用了 Akka 的 Actor 模型实现 。
Akka Actor 的异步消息驱动实现如下:

反应式编程框架设计:如何使程序调用不阻塞等待,立即响应?

文章插图
 
一个 Actor 向另一个 Actor 进行通讯的时候,当前 Actor 就是一个消息的发送者sender,当它想要向另一个 Actor 进行通讯的时候,就需要获得另一个 Actor 的ActorRef,也就是一个引用,通过引用进行消息通信 。而 ActorRef 收到消息以后,会将这个消息放入到目标 Actor 的 Mailbox 里面去,然后就立即返回了 。
也就是说一个 Actor 向另一个 Actor 发送消息的时候,不需要另一个 Actor 去真正地处理这个消息,只需要将消息发送到目标 Actor 的 Mailbox 里面就可以了 。自己不会被阻塞,可以继续执行自己的操作,而目标 Actor 检查自己的 Mailbox 中是否有消息,如果有消息,Actor 则会在从 Mailbox 里面去获取消息,对消息进行异步的处理,而所有的 Actor会共享线程,这些线程不会有任何的阻塞 。
三、反应式编程框架Flower的设计方法但是直接使用 Actor 进行编程有很多不便,Flower 框架对 Actor 进行了封装,开发者只需要编写一些细粒度的 Service,这些 Service 会被包装在 Actor 里面,进行异步通信 。Flower Service 例子如下:
publicclassServiceAimplementsService<Message2>{@OverridepublicObjectprocess(Message2message){returnmessage.getAge()+1;}}每个 Service 都需要实现框架的 Service 接口的 process 方法,process 方法的输入参数就是前一个 Service process 方法的返回值,这样只需要将 Service 编排成一个流程,Service 的返回值就会变成 Actor 的一个消息,被发送给下一个 Service,从而实现Service 的异步通信 。
Service 的流程编排有两种方式,一种方式是编程实现,如下:
getServiceFlow().buildFlow("ServiceA","ServiceB");表示 ServiceA 的返回值将作为消息发送给 ServiceB,成为 ServiceB 的输入值,这样两个Service 就可以合作完成一些更复杂的业务逻辑 。
Flower 还支持可视化的 Service 流程编排,像下面这张图一样编辑流程定义文件,就可以开发一个异步业务处理流程 。
反应式编程框架设计:如何使程序调用不阻塞等待,立即响应?

文章插图
 
那么这个 Flower 框架是如何实现的呢?
Flower 框架的设计也是基于依赖倒置原则 。所有应用开发者实现的Service 类都需要包装在 Actor 里面进行异步调用,但是 Actor 不会依赖开发者实现的Service 类,开发者也不会依赖 Actor 类,他们共同依赖一个 Service 接口,这个接口是框架提供的,如上面例子所示 。
Actor 与 Service 的依赖倒置关系如下图所示:
反应式编程框架设计:如何使程序调用不阻塞等待,立即响应?

文章插图
 
每个 Actor 都依赖一个 Service 接口,而具体的 Service 实现类,比如 MyService,则实现这个 Service 接口 。在运行期实例化 Actor 的时候,这个接口被注入具体的 Service 实现类,比如 MyService 。在 Flower 中,调用 MyService 对象,其实就是给包装MyService 对象的 Actor 发消息,Actor 收到消息,执行自己的 onReceive 方法,在这个方法里,Actor 调用 MyService 的 process 方法,并将 onReceive 收到的 Message 对象当做 process 的输入参数传入 。
process 处理完成后,返回一个 Object 对象 。Actor 会根据编排好的流程,获取MyService 在流程中的下一个 Service 对应的 Actor,即 nextServiceActor,将 process返回的 Object 对象当做消息发送给这个 nextServiceActor 。这样,Service 之间就根据编排好的流程,异步、无阻塞地调用执行起来了 。
四、反应式编程框架Flower的落地效果【反应式编程框架设计:如何使程序调用不阻塞等待,立即响应?】Flower 框架在部分项目中落地应用,应用效果较为显著,一方面,Flower 可以显著提高系统的性能 。这是某个 C# 开发的系统使用 Flower 重构后的 TPS 性能比较,使用 Flower 开发的系统 TPS 差不多是原来 C# 系统的两倍 。


推荐阅读