什么是响应式编程

我们知道,当系统面对大流量、高并发的访问请求时,就可能会出现一系列性能问题,导致服务丧失了即时的响应性。如何时刻确保系统具有应对请求压力的能力,是架构设计的核心问题之一。

经典的服务隔离、限流、降级以及熔断等机制能够在一定程度上确保系统的响应性。但今天我们要介绍的是构建系统响应性的一种崭新的解决方案,这就是响应式编程(Reactive Programming)。响应式编程打破了传统的同步阻塞式(Blocking)请求响应过程,采用了异步非阻塞式(Non-Blocking)的编程模型,从而提高服务的响应能力。

这里提到了同步阻塞和异步非阻塞这两个核心概念,而正确理解这两个概念是掌握响应式编程的前提条件。接下来,我们首先对这两个概念做必要的展开,来引出响应式编程技术的诞生背景和解决的问题。

为什么需要响应式编程?

如果你使用Spring框架开发过Web应用程序,那么你一定对下面这种开发方式非常熟悉。

public Order getRemoteOrder(String orderNumber) {

RestTemplate restTemplate = new RestTemplate();

ResponseEntity<Order> result= restTemplate.exchange(

"http://orderservice/orders/{orderNumber}", HttpMethod.GET, null, Order.class, orderNumber);

Order order= result.getBody();

processOrder(order);

return order;

}

这是一个查询订单(Order)信息的应用场景,我们使用了Spring中的RestTemplate模板工具类,通过该类所提供的exchange()方法对远程Web服务所暴露的HTTP端点发起了请求。上述实现方式在日常开发过程中非常具有代表性,基于Spring Cloud开发的微服务系统本质上也是通过这种方式完成服务与服务之间的远程调用。但是,上述实现方法实际上存在明显的缺陷,即处理过程是阻塞式的。正是因为同步阻塞的存在才导致了响应式编程技术的诞生和发展。那么,究竟什么是阻塞式呢?让我们首先来对上述代码中的线程模型做进一步分析,看看问题出在哪里。

为了更好的分析整个调用过程,我们假设服务的提供者为服务A,而服务的消费者为服务B,那么这两个服务的交互过程应该这样的。


可以看到,当服务B向服务A发送HTTP请求时,线程B只有在发起请求和响应结果的一小部分时间内在有效使用CPU,而更多的时间则只是在阻塞式地等待来自服务A中线程的处理结果。显然,整个过程的CPU利用效率是很低的,很多时间被浪费在了I/O阻塞上,无法执行其他的处理过程。

更进一步,我们继续分析服务A中的处理过程。如果我们采用典型的三层架构,那么沿着Web服务层->业务逻辑层->数据访问层整个调用链路中,每一步的操作过程都存在着前面描述的线程等待问题。也就是说,整个技术栈中的每一个环节都可能是同步阻塞的。


为了解决同步阻塞问题,可以引入异步非阻塞的相关技术。在Java世界中,一般会采用回调(Callback)和Future这两种机制,但这两种机制都存在一定局限性。回调的核心问题在于处理过程会形成一种嵌套结构,给代码的开发和调试带来很大的挑战。而Future机制本质上是一种多线程技术,大量线程之间的相互协作需要频繁进行上下文切换,同样会导致资源利用效率低下。

通过引入响应式编程技术,我们就可以很好的解决这种类型的问题。响应式编程采用全新的响应式数据流(Stream)来实现异步非阻塞式的网络通信和数据访问机制,能够减低不必要的资源等待时间。那么,所谓的响应式编程到底是什么样子的呢?接下来让我们一起来看一下。

什么是响应式编程?

响应式编程技术的核心是数据流,而数据流又是构建在传统的事件驱动架构与发布订阅模式之上。所以,在引入响应式编程技术之前,我们先来回顾一下发布订阅模式和事件处理相关的技术体系。

发布订阅模式和事件

相信大家对设计模式中经典的观察者模式应该都不陌生。观察者模式拥有一个主题(Subject),以及针对这个主题的一个依赖者列表,这些依赖者被称为观察者(Observer)。而发布订阅(Publish-Subscribe)模式可以认为是对观察者模式的一种改进。在这种模式中,发布者和订阅者相互之间可以没有直接的依赖关系,而是通过发送事件到事件处理平台的方式来完成整合。针对今天开篇中提到的订单查询操作,我们可以基于发布订阅模式进行流程重构。


同样,让我们来到单个服务的内部。在三层架构中,从Web服务层到数据访问层再到数据库的整个调用链路同样可以采用发布订阅模式进行重构。这时候,数据库中的数据一有变化就会通知到上游组件,而不是上游组件通过主动拉取数据的方式来获取数据。


数据流和响应式

显然,上图中异步事件传播的思想可以扩展到整个系统。我们可以想象系统中会存在着很多类似OderEvent这样的事件。每一种事件会基于用户的操作或者系统自身的行为而被触发,并形成了一个事件的集合。我们可以把这个事件的集合看成是一串串连起来的数据流,而系统的响应能力就体现在对这些数据流的即时响应过程上。


对于技术实现过程而言,数据流是一个全流程的概念。也就是说,无论是从底层数据库,到服务层,最后到Web服务层,抑或是在这个流程中所包含的任意中间层组件,整个数据传递链路都应该是采用事件驱动的方式来进行运作。这样,我们就可以不采用传统的同步调用方式来处理数据,而是由处于全流程中的各层组件自行来执行事件。这就是响应式编程的核心特点。

相较传统开发所普遍采用的“拉”模式,在响应式编程下,基于事件的触发和订阅机制,这就形成了一种类似“推”的工作方式。


这种工作方式的优势就在于,生成事件和消费事件的过程是异步执行的,所以线程的生命周期都很短,也就意味着资源之间的竞争关系较少,服务器的响应能力也就越高。这就是响应式编程的精髓,也是解决系统性能问题的关键所在。

讲到这里,你可以会问,我们如何来使用响应式编程技术来开发业务系统呢?不用担心,到目前为止,业界已经诞生了诸如RxJava、Project Reactor、Akka等一大批优秀的响应式编程框架。而在Spring 5中,也引入了WebFlux、Reactive Spring Data等新一代的编程组件来实现响应式Web服务和响应式数据访问。通过这种框架和工具,可以很好的解决传统同步阻塞式处理方式所存在的性能问题。

今天的内容系统分析了传统服务调用存在的问题,从而引出响应式编程概念和实现方法。从技术演进的过程和趋势而言,响应式编程的出现有其必然性。另一方面,响应式编程也不是一种完全颠覆式的技术体系,而是在现有的异步调用、观察者模式、发布订阅模式等的基础上发展起来的一种全新的编程模式,能够会系统带来即时响应性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/359414.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024全国各地高考录取分数线一览表(含一本、二本、专科)

2024年高考录取分数线陆续公布&#xff0c;上大学网(www.sdaxue.com)为大家整理全国31个省市高考录取分数线汇总&#xff0c;包括本科批、专科批和特殊类招生控制分数线汇总&#xff0c;来看看你的省份多少分能上大学吧。 一、2024年全国高考录取线一览表 1、宁夏 一本线&…

一文搞懂Linux命令行下载OneDrive分享文件

一文搞懂Linux命令行下载OneDrive分享文件 什么问题&#xff1f; 因为OneDrive有些坑&#xff0c;无法从分享界面获取真实下载链接&#xff0c;比如下面这个链接&#xff1a; https://connecthkuhk-my.sharepoint.com/:f:/g/personal/jhyang13_connect_hku_hk/EsEgHtGOWbJIm…

Golang逃逸分析

在Go语言中&#xff0c;逃逸分析(Escape Analysis)是一种编译器优化技术&#xff0c;用于确定变量是应该分配在堆上还是在栈上。这对程序的性能有显著的影响&#xff0c;因为栈上资源的分配速度和释放速度要比堆上快得多&#xff0c;同时堆上的内存管理也更加简单。 基本概念 …

C++并发之协程实例(四)(通过迭代器访问生成器序列)

目录 1 协程2 实例3 运行 1 协程 协程(Coroutines)是一个可以挂起执行以便稍后恢复的函数。协程是无堆栈的&#xff1a;它们通过返回到调用方来暂停执行&#xff0c;并且恢复执行所需的数据与堆栈分开存储。这允许异步执行的顺序代码&#xff08;例如&#xff0c;在没有显式回调…

零代码搭建AI应用-文心智能体的设计与实现

本教程旨在帮助你开发一个结合语音识别和信息查询技术的智能应用&#xff0c;为用户提供登山小技巧和心得体会&#xff0c;满足用户在户外运动中的需求。通过设计不同角色和场景&#xff0c;可以满足用户在不同生活领域的需求&#xff0c;例如在家庭、社交、职场等场景下提供不…

什么洗地机值得推荐?洗地机选购攻略,热门洗地机推荐

在家庭清洁领域&#xff0c;洗地机已成为越来越多家庭的首选设备。它不仅能轻松应对各种材质的地面&#xff0c;还能有效去除顽固污渍&#xff0c;使家居环境更加整洁。然而&#xff0c;面对市场上众多洗地机品牌&#xff0c;许多消费者都会产生“什么洗地机值得推荐”的疑问。…

算法常见手写代码

1.NMS def py_cpu_nms(dets, thresh):"""Pure Python NMS baseline."""#x1、y1、x2、y2、以及score赋值x1 dets[:, 0]y1 dets[:, 1]x2 dets[:, 2]y2 dets[:, 3]scores dets[:, 4]#每一个检测框的面积areas (x2 - x1 1) * (y2 - y1 1)#按…

2024年数据、自动化与智能计算国际学术会议(ICDAIC 2024)

全称&#xff1a;2024年数据、自动化与智能计算国际学术会议&#xff08;ICDAIC 2024&#xff09; 会议网址:http://www.icdaic.com 会议地点: 厦门 投稿邮箱&#xff1a;icdaicsub-conf.com投稿标题&#xff1a;ArticleTEL。投稿时请在邮件正文备注&#xff1a;学生投稿&#…

Linux安装minio及mc客户端(包含ARM处理器架构)

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

Ubuntu 18.04 安装低延时内核

下面记录在在Ubuntu 18.04系统下安装低延时内核的流程&#xff1a; Ubuntu 内核信息 ll /boot其中initrd.img为根文件系统&#xff0c;System.map为内核符号表&#xff08;将内核代码段中的地址映射到对应的函数名或者全局变量名&#xff09;&#xff0c;vmlinuz为内核镜像。…

论文翻译 | Active Retrieval Augmented Generation 主动检索增强生成

Zhengbao Jiang1∗ Frank F. Xu1∗ Luyu Gao1∗ Zhiqing Sun1∗ Qian Liu2 Jane Dwivedi-Yu3 Yiming Yang1 Jamie Callan1 Graham Neubig1 卡内基梅隆大学语言技术研究所&#xff1b;海洋人工智能研究室&#xff1b;FAIR, Meta EMNLP 2023 main &#xff08;Proceedings of t…

低成本创业新篇章:上门回收小程序的崛起与挑战

在当今这个快速变化的时代&#xff0c;低成本创业项目成为了许多创业者的首选。其中&#xff0c;上门回收小程序以其独特的商业模式和市场需求&#xff0c;成为了创业市场中的一股新势力。本文将深入探讨上门回收小程序作为低成本创业项目的崛起之路以及面临的挑战。 一、上门回…

【R语言】地理探测器模拟及分析(Geographical detector)

地理探测器模拟及分析 1. 写在前面2. R语言实现2.1 数据导入2.2 确定数据离散化的最优方法与最优分类2.3 分异及因子探测器&#xff08;factor detector&#xff09;2.4 生态探测器&#xff08;ecological detector&#xff09;2.5 交互因子探测器&#xff08;interaction dete…

HTML(14)——结构伪类选择器和伪元素选择器

结构伪类选择器 作用&#xff1a; 根据元素的结构关系查找元素 选择器说明E:first-child查找第一个E元素E:last-child查找最后一个E元素E:nth-child(N)查找第N个E元素(第一个元素N值为1) 例如&#xff1a;查找第一个li标签&#xff0c;将背景改为绿色 <style> li:fir…

超越招聘技术人才目标的最佳技术招聘统计数据

研究发现&#xff0c;难以找到的人才比以往任何时候都更难找到&#xff1a;根据新人才委员会招聘调查报告&#xff1a;2024年难以找到的人才的战略和战略&#xff0c;60%的受访者表示&#xff0c;熟练人才的招聘时间比一年前长。调查进一步揭示了以下关于招聘技术的关键事实&am…

Git 常用命令,一文全搞懂

注意&#xff1a;每一次切换分支的时候&#xff0c;本地代码都会自动跟随改变&#xff0c;不需要重新pull,除非有人更新了代码 git remote add origin 地址 连接远程仓库 git clone 地址 克隆项目到本地 git init 更新本地隐藏文件初始化仓库 git add . 代…

Java--Data类

1.Data类 java.util.Date.表示指定的时间信息&#xff0c;不支持国际化 构造方法 new Date()&#xff1a;当前系统日期和时间 new Date(long)&#xff1a;给定日期和时间 主要方法&#xff1a; after(Date):判断当前日期对象是否在给定日期对象之后 before(Date):判断当前日期…

基础购物车(Javascript)

使用Javascript写一个基础购物车&#xff0c;其中包含商品数量加加减减&#xff0c;下面的总价和总数量跟着商品数量变动&#xff0c;还可以自己添加需要的商品。 基础购物车的结构样式如下&#xff1a; HTML代码&#xff1a; <body><table border"1px" c…

LeetCode26. 删除有序数组中的重复项题解

LeetCode26. 删除有序数组中的重复项题解 题目链接&#xff1a; https://leetcode.cn/problems/remove-duplicates-from-sorted-array 题目描述&#xff1a; 给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一…

JavaWeb——Mysql的启动/登录/卸载

目录 1.Mysql服务器 2.Mysql的简单使用 2.1 启动Mysql&#xff1a; 2.2 登录Mysql 2.3 退出 3. 连接别人的数据库 4.卸载mqsql 1.Mysql服务器 安装了Mysql的计算机都成为Mysql服务器 2.Mysql的简单使用 2.1 启动Mysql&#xff1a; 第一种方法&#xff1a;搜索服务&am…