后端技术面试 38 讲
李智慧
同程艺龙交通首席架构师,前 Intel& 阿里架构师,《大型网站技术架构》作者
37373 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 46 讲
不定期加餐 (1讲)
后端技术面试 38 讲
15
15
1.0x
00:00/00:00
登录|注册

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

可用性提升
性能提升
Service流程编排
封装Service在Actor中
异步数据库驱动
Service间异步消息通讯
Web容器线程异步处理
Flower
Reactor
RxJava
消息驱动
弹性
回弹性
即时响应
是否愿意尝试反应式编程
如何应对问题
反应式编程可能存在的问题
落地效果
设计方法
基本原理
主流框架
特质
思考题
反应式编程
问题:程序调用阻塞等待,高并发导致程序崩溃
反应式编程框架设计

该思维导图由 AI 生成,仅供参考

我们在专栏第 1 篇就讨论了为什么在高并发的情况下,程序会崩溃。主要原因是,在高并发的情况下,有大量用户请求需要程序计算处理,而目前的处理方式是,为每个用户请求分配一个线程,当程序内部因为访问数据库等原因造成线程阻塞时,线程无法释放去处理其他请求,这样就会造成请求堆积,不断消耗资源,最终导致程序崩溃。
这是传统的 Web 应用程序运行期的线程特性。对于一个高并发的应用系统来说,总是同时有很多个用户请求到达系统的 Web 容器。Web 容器为每个请求分配一个线程进行处理,线程在处理过程中,如果遇到访问数据库或者远程服务等操作,就会进入阻塞状态,这个时候,如果数据库或者远程服务响应延迟,就会出现程序内的线程无法释放的情况,而外部的请求不断进来,导致计算机资源被快速消耗,最终程序崩溃。
那么有没有不阻塞线程的编程方法呢?

反应式编程

答案就是反应式编程。反应式编程本质上是一种异步编程方案,在多线程(协程)、异步方法调用、异步 I/O 访问等技术基础之上,提供了一整套与异步调用相匹配的编程模型,从而实现程序调用非阻塞、即时响应等特性,即开发出一个反应式的系统,以应对编程领域越来越高的并发处理需求。
人们还提出了一个反应式宣言,认为反应式系统应该具备如下特质:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

反应式编程框架设计:如何使程序调用不阻塞等待,立即响应? 本文介绍了反应式编程作为解决高并发情况下程序崩溃问题的方案。通过异步编程、多线程和异步I/O访问等技术,实现程序调用非阻塞、即时响应的特性。主流的反应式编程框架有RxJava、Reactor和Flower,它们基于观察者设计模式和函数式编程,实现了异步无阻塞的调用。Flower框架利用了Web容器的异步特性和异步的数据库驱动,实现了几乎没有任何地方会被阻塞的特性。文章还介绍了Flower框架的设计方法,包括对Actor进行封装,编写细粒度的Service,并支持可视化的Service流程编排。Flower框架在部分项目中落地应用,显著提高系统性能和可用性。它不仅是一个反应式Web编程框架,还是反应式的微服务框架,提供了分布式非阻塞的微服务系统。反应式编程虽然带来性能和可用性提升,但也可能存在问题,需要谨慎应对。欢迎读者尝试并分享交流。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《后端技术面试 38 讲》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(26)

  • 最新
  • 精选
  • Paul Shan
    高并发系统,传统解决方案的弊端在于调度的单元是线程,当IO操作时,线程做无谓地等待,相应的CPU资源白白浪费,线程数目多到一定程度,系统就会被压垮。 反应式编程的第一个目标即时响应,就是异步非阻塞的,遇到IO操作就返回,通过回调函数来取结果。 反应式系统第二个目标回弹性,系统有一定的自我修复功能,个人以为这和反应式编程的本质没太大关系,系统自我修复和错误处理是任何系统都想要的功能,和反应式编程关系不大,这里可能和微服务的关系更大,不知道老师如何看这个问题。 反应式系统第三个目标是弹性,反应式编程在数据的请求和回调存在间隙,系统需要合理安排资源,让这个间隙全局而言最小。 反应式编程第四个目标是消息驱动,反应式编程在数据请求和消费解耦了,需要用另外的机制串起来,消息驱动就是其中一种串法。 反应式编程通过分离数据请求和数据消费以达到有效利用CPU和IO资源,提高并发的目的。我个人以为反应式编程是编程的未来,因为异步才是数据流转的本质。传统操作系统成型的时候CPU只有一颗,那时同步编程思想是主流。现在多核系统已经是主流,异步编程更为高效。 反应式编程本身的问题就是得学一种新的编程范式,像rxjava学习曲线还是挺陡峭的。反应式编程拆分了请求数据和消费数据,通过消息来驱动可能带来数据的多次拷贝,函数式编程尤其强调数据的不可更改,只好通过拷贝来解决,本质上是一种用空间换时间的策略,会消耗更多的内存。异步编程调错总归有些麻烦,这也是成本之一。

    作者回复: 👍

    2020-01-08
    2
    38
  • 草原上的奔跑
    异步的调用一般比较难调试,运行正常的时候性能好、可用性高,但出问题后debug比较困难,不知道李老师你们是如何处理的

    作者回复: 异步难调试主要是因为异步的代码执行在不同的线程上,导致没有统一的调用栈,异常的时候不知道哪里出错的。Flower通过流程编排的方式管理异步方法代码,出错的时候可以通过流程定位异常,对调试定位有帮助。

    2020-01-01
    2
    24
  • 蚂蚁内推+v
    请教一下老师,我理解的异步非阻塞调用其实就是将耗时操作放到了另外的线程池中,这个感觉对性能上没有多大提升啊,比如我了解到的reactor

    作者回复: 1 不是放入线程池中,是放入队列中,等待线程执行,这样就只需要较少的线程,执行大量的操作,减少线程启动和调度,性能更好 2 对于IO操作,非阻塞意味着不会不会阻塞线程,避免线程资源浪费,性能更好 3 性能不只是响应时间或者处理速度,异步操作也许不能降低响应时间,但是可以处理更多请求,也是提升性能,具体参考高性能一篇专栏

    2020-02-23
    2
    9
  • Jagger Chen
    老师您好,关于即时响应,如果程序还没计算出结果,响应什么给调用端呢?

    作者回复: 即时响应的目的是为了不阻塞调用端线程,提高处理能力。 调用端为什么需要得到计算结果,为了下一步计算?那被调用者把自己的计算结果传递给自己的下一个被调用者就可以了。 你可以看下Flower的web开发demo,http response不是Controller返回的,而是计算出客户端结果的那个service调用web.print返回的。这样在计算过程中,可以随时返回response,而不用等到全部处理完在返回。

    2020-06-28
    4
    6
  • 老男孩
    李老师和专栏的朋友们新年快乐!哈哈!又一年了。虽然我还在现实的苟且中徘徊,但依然算是不忘初心吧。用一句现在很流行的话就是,愿大家只争朝夕,不负韶华。之前研究了一下spring的webflux发现目前异步编程在数据库驱动这块对关系型数据库的支持不太好,比如myspl。还有诺诺的问一下,mailbox是不是一个内存队列?不知道flower能不能支持用第三方的消息队列来替换mailbox的工作?还有actor里边是不是用到模板设计模式了?

    作者回复: 新年快乐。异步数据库驱动还是有一些的,但是因为业界用的不多,所以都不怎么维护。反应式编程的大气候还是没起来。

    2020-01-01
    4
  • Jagger Chen
    老师您好,同步编程中使用 ThreadLocal 来跨类传递状态,在响应式编程模型中如何做呢?这个算不算是一个弊端?

    作者回复: 消息驱动的反应式框架,比如flower,可以通过消息传递状态。

    2020-06-28
    3
  • 蚂蚁内推+v
    老师,回调函数由谁来执行呢?比如线程1异步调用某方法,由线程2执行方法,那线程2执行完之后谁来执行回调函数呢

    作者回复: Flower中没有调用,也就没有回调。 服务经过编排后,由框架异步执行服务。 一个服务执行完,他的结果不是返回给他的上一个服务,而是发送给他的下一个服务。

    2020-02-26
    3
  • 麋鹿在泛舟
    “反应式实践其实更多落地就是在前端,发送请求后就不管了,然后等到异步响应到达后异步更新页面。” 所以对于后端系统来说,怎么应对阻塞呢?

    作者回复: 阻塞基本上都是IO阻塞,使用异步IO即可,如文中所述。

    2020-01-20
    2
  • 饭饭
    这样流程编排的为什么不用akka stream?有什么考虑嘛?

    作者回复: 编程模型不同,我们认为Flower编程模型更加友好,事实如何,我们将来再看。

    2020-01-10
    2
  • 托尼斯威特
    请问一个细节: "Actor 则会在从 Mailbox 里面去获取消息,对消息进行异步的处理". 消息的处理结果如何返回给Sender呢? Sender如果不靠回调函数, 又是如何知道怎么处理返回来的结果的呢?

    作者回复: 在actor里给sender发消息,把处理结果发送过去

    2020-12-24
    1
收起评论
显示
设置
留言
26
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部