后端面试38讲_20_18_反应式编程框架设计如何使程序调用不阻塞等待立即响应
你好,我是李智慧。
我们在专栏第一篇就讨论了为什么在高并发的情况下程序会崩溃。
主要原因是在高并发的情况下,有大量用户请求需要程序计算处理。
而目前的处理方式是为每个用户请求分配一个线程。
当程序内部因为访问数据库等原因造成线程阻塞时,线程无法释放去处理其他请求,这样就会造成了请求堆积不断的消耗资源,最终导致程序崩溃。
这在传统的部应用程序运行器的线程特性,对于一个高并发的应用系统来说,总是同时有很多用户请求到达系统的weweb容器。
Web容器为每个请求分配一个线程进行处理线程。
在处理过程中呢,如果遇到访问数据库或者远程服务等操作,就会进入阻塞状态。
这个时候,如果数据库或者远程服务响应延迟,这会出现程序内的线程无法释放的情况,而外部的请求不断进来,导致计算机资源被很快消耗,最终程序崩溃。
那么有没有不阻塞线程的编程方法呢?答案就是反应式编程。
反应式编程呢本质上是一种异步编程方案。
这个线程异步方法调用异步l访访问等技术基础上,提供了一整套与异步调用相匹配的编程模型,从而实现程序调用非阻塞、及时响应等特性。
也就是开发一个反应式的系统,以应对编程领域越来越高的高并发处理需求。
人们还提出了一个反应式宣言,认为反应式系统呢应该具备四个特质。
第一个呢就是及时响应应用的调用者可以及时得到响应,无需等到整个程序执行能毕。
也就是说当应用调用是非阻塞的。
第二个呢是回弹性。
当应用程序部分功能失效的时候,应用程序本身应该能够进序自我修复,保证正常运行,保证响应不会出现系统崩溃和宕季的情况。
第三个是弹性系统能够对应用负载压力做出响应,能够自动伸缩,以适应应用负载压力,根据压力自动调整自身的处理能力,或者根据自身的处理能力调整进入系统中中的访问请求数。
第四个就是消息驱动,功能模块之间、服务之间通过消息进行驱动,完成服务的流程。
目前主流的反反应式编框框架RRX、 java、 reactor等们的主要特点呢就是基于观察者模式的异步编程方案。
编程模型采用函数式编程、观察者模式和函函式编程有自己的优势,势是反应式,编程程并不是必须须观观察者模式。
函数式编程fflower就是一个从消息驱动完全异步,支持命令式编程的反应式编程框架。
下面我们就看如何何现异步步组设的编用下及ffloflower这个框架设计使用了什么样的设计原则与设计模式。
你则文章中可以看到一个使用flower框架开发的典型的web应用的现程特性。
当并发用户请求到达应用服务器的时候啊,web容器线程不需要执行应用程序代码。
它只是将用户的HDP请求变为请求对象,将请求对象异步交给flower框架的service去处理。
不会立刻就返回了,因为容器线程不做太多的工作,所以呢只需要极少的容器线程,就可以满足高并发的用户请求。
用户的请求不会阻塞,不会因为容器线程不够而无法处理。
相比传统的阻塞式编程,web容器线程要完成全部的请求处理操作,直到返回响应结果才能够释放线程。
使用flower框架呢只需要极少的容器线程就可以处理较多的并发用户请求。
而且容器线程不会阻塞,用户请求交给基于flower框架开发的业务设备式对象。
以后设备室之间依然是使用异步消息通信的方式进行调用,不会直接进行阻塞时的调用。
一个设备是完成业务逻辑处理,计算以后会返回一个处理结果。
这个结果以消息的方式异步发送给他的下一个service.传统编程模型的service之间如果进行调用,如我们在专来第一篇讨论那样被调用的service是返返回之调调的的service是方法只能阻塞等待。
而flower的service之间,使用了阿卡的actor进行消息。
通信调用者的设备是发送调用消息以后,不需要等待被调用者返回,结果将可以处理自己的下一个消息了。
事实上,这些service可以复用同一个线程去处理自己的消息。
也就是说,只需要有限的几个线程就可以完成大量的service处理和消息传输,这些线程也不会阻塞等待。
我们刚才提到啊常用的web应用,主要的线程阻塞是因为数据库的访问导致的线程阻塞,flower支持异步数据库启动。
当用户请求数据库的时候,将请求提交给异步数据库启动,立刻就返回了,不会阻塞当前线程异步数据库访问,连接远程的消息库,进行真正的数据库操作。
得到结果以后,将结果以异步回调的方式发送给flower的service进行进一步的处理。
这个时候依然不会有线程被阻塞。
也就是说,使用flower开发的系统在一个典型的web应用中,几乎没有任何地方会被阻塞。
所有的线程都可以被不断的复用,有限的线程可以完成大量的并发用户请求,从而大大的提高了系统的通透能力和响应时间。
同时,由于线程不会被阻塞,应用,就不会因为并发量太大,从者数据库处理缓慢而宕机,从而提高了系统的可用性。
Flower框架,实现异步无阻塞。
一方面是利用了web容器的异步特性,主要是设用三点零以后提供的a sink context,快速释放容器线程。
另一方面是利用了异步的数据库驱动,以及异步的网络通信,主要是HTA、 sink、 cllent等异步通信组件。
而flower框架内,核心的应用代码之间的异步无阻塞调用,则是利用了阿卡的actor模型,实现一个actor向另一个actor进行通信的时候,当前actor就是一个消息的发送者standard.当他想要向另一个actor进行通信的时候,就需要获得另一个actor的actor. Ref也就是一个引用,通过引要进行消息通信,而目标actor收到消息以后,会将这个消息放到目标actor的milbox里面去,然后就立即返返回。
也就是是说,一acactor向另一acactor发送消息的时候,不需要另一个actor去真正处理这个消息,只需要将消息发送到目标actor的new box里面就可以了,自己不会被阻塞,可以继续执行自己的消息。
而目标actor检查自己的mailbox是否有消息,如果有消息actor,则会在milbox里面去获取消息,而消息进行异步的处理。
而所有的actor会共享线程,这些线程不会有任何的阻塞,但是直接使用actor进行编程有很多不便。
Flower框架对actor进行了分装,开发者只需要编写一些细粒度的service,这些service会被包装在actor里面进行异步通行。
文章中有一个flower service的例子,每个service都需要实现框架的service接口和process方法。
Process方法的输入参数就是前一个service process方法的返回值,这样只需要将service编配成一个流程,service的返回值就会变成一个actor的一个消息被发送给下一个service,从而实现service的异步通信。
Service的流程编排有两种方式,一种方式是编程实现service a的返回值将作为消息发送给service b成为service b的输入值。
这样两个service就可以合作完成一些更复杂的业务逻辑。
Flower还支持可视化的流程,编排编辑流程、定义文件,就可以开发一个异步业务处理流程。
那么这个flower框架是如何实现的呢? Flower框架的设计也是基于前面专栏讨论过的,依赖倒置原则,所有应用开发者实现的service类都需要包装在actor里面进行异步同行。
但是,actor不会依赖开发者实现的service类开发者,也不会依赖actor类,他们共同依赖一个service接口,这个接口是框架提供的。
如上面例子所示,你在文章中可以看到actor与service的依赖道置关系,每个actor都依赖一个service接口,而具体的service实现类。
比如my service则实现这个service接口,而用心期实例化actor的时候,这个接口被注入具体的service实现类。
比如my service flower中调用my asservice对象,其实就是给包装my yservice对象的actor发消息actor收到息息执行自己unreceive方法。
在这个方法里,actor调用my service的系统t tor这样flover收到的message对象当做process输入参数传入process,处理完后返回一个object对象。
Actor会根据编排好的流程,获取mi service流程中的下一个service对应的actor及next service actor,将process返回的object对象当做消息发送给这个next service actor.这样service之间就根据编排好的流程,一补无阻塞的调入参数起来。
Flower框架在部分项目中落地,应用效果较为显著。
一方面,flower可以显著提高系统的性能,这是某个s sap开发的系统。
使用。
Flower重构后的TPS性能比较使用flower开发的系统,TPS差不多是原来SH arp系统的两倍。
另一方面,flower的系统可用性也有较大的提升,用户请求通过网关服务器调用微服完成处理。
那么当有某个微服务连接的数据库查询执行较慢时,如图中服务一。
那么按照传统的线程阻塞模型,就会导致服务一的线程都被阻塞的。
这个慢查询的数据库操作上,同样网关线程也会被阻塞。
在这个调用延迟比较厉害的服务一上最终的效果就是使用所有的线程都被阻塞。
即使是不调用服务一的用户请求也无法处理。
最后,整个系统失去响应、应用宕机、使用阻塞式编程。
当服务一响应延迟出错率大幅提升的时候,通过网关调用正常的服务。
二的出错率也非常高,使用服lower开发的网关同样服务一、响应延迟出错率极高的情况下,通过flower网关调用服务。
二、完全不受影响。
事实上,flower不仅是一个反应式,y编程框架,还是一个反映式的微服务框架。
也就是说,flower的service可以远程部署在一个service容器里面。
就像我们现在常用的微服务架构一样,flower会提供一个独立的flower容器,用于启动一些service.这些service在启动以后,会向注册中心进行注册,而且应用程序可以将这些分布式service进行流程编排,得到一个分布式的非阻塞微服务系统。
整体架构和主流的微服务架构很像。
主要的区别呢就是flower的服务是异步的,通过流程编排的方式进行服务调用,而不是通过接口依赖的方式进行调用。
我在文章中给了一个链接,你可以点击进入flower框架的源代码地址,欢迎你参与flower的开发,也欢迎将flower应用到你的系统开发中。
你对flower有什么疑问,也欢迎与我交流。
反应式编程虽然能够带来性能和可用性方面的提升,但是也带来了一些问题。
你觉得反应式编程可能存在的问题有哪些?应该如何应对?你是否愿意在工作实践中尝试反应式编程,欢迎你在评论区写下你的思考,也欢迎把这篇文章分享给你的朋友,或者同事一起交流。