学术论文投稿/征稿

欢迎您!请

登录 注册

手机学刊吧

学刊吧移动端二维码

微信关注

学刊吧微信公众号二维码
关于我们
首页 > 学术论文库 > 理工论文 异步编程和反应式编程在网络软件开发中的应用论文

异步编程和反应式编程在网络软件开发中的应用论文

0

2024-04-17 15:28:14    来源:SCI论文网    作者:xuling

摘要:随着智能油气田的建设,数据服务将发挥越来越重要的作用,对提供数据服务应用系统的容量、健壮性、响应时间等性能也提出了更高的要求,其反应式系统所要解决的问题与此相同。

  摘要随着智能油气田的建设,数据服务将发挥越来越重要的作用,对提供数据服务应用系统的容量、健壮性、响应时间等性能也提出了更高的要求,其反应式系统所要解决的问题与此相同。本文将从经典的服务器模型出发,并逐步引出异步编程和反应式编程,同时介绍异步编程与反应式编程的生态,最后以常见的Spring框架为例,比较了Spring框架反应式技术栈和传统技术栈的性能差异,得出了反应式技术栈相比于传统技术栈在处理高并发请求时有更好性能的结论。通过对反应式相关概念的研究,可为后续的信息系统建设提供一种新的思路。

  关键词:异步编程,反应式编程,网络软件开发,架构设计

  Application of Asynchronous Programming and Reactive Programming in Network Software Development

  JU Yuanmao

  (Petro China Southwest Oil&Gas Field Digital Intelligent Technology Branch Company,Chengdu Sichuan 610041)

  【Abstract】:With the construction of intelligent oil and gas fields,data services will play an increasingly important role,and higher requirements have been put forward for the capacity,robustness,response time,and other performance of data service application systems.The problems that their reactive systems need to solve are the same.This article will start from the classic server models,and gradually lead to asynchronous programming and reactive programming.At the same time,it will introduce the ecology of asynchronous programming and reactive programming.Finally,taking the common Spring framework as an example,it compares the performance of Spring framework reactive technology stack and the performance of traditional technology stack,and it is found by tests that the reactive technology stack has better performance than the traditional technology stack in handling high concurrent requests.Through the research on the related concepts of reactive,it can provide a new way of thinking for the subsequent construction of information system.

  【Key words】:asynchronous programming;reactive programming;network ssoftware development;architecture design

  0引言

  随着智能油气田的建设,数据服务的地位越来越重要,对数据服务的需求也会越来越多。现在可以满足需求的系统框架,可能在将来不能满足需求。相比于后期增加硬件,在系统设计之初采用更高性能的架构,花销更少,所能提高的性能更多[1,2]。而异步编程和反应式编程正是众多提高性能方案中较为流行的一种。

  1经典服务器模型

  在讨论异步和反应式之前,我们需要了解经典的网络服务器是如何工作的。下面将介绍几种经典的服务器模型。

  1.1阻塞式I/O的迭代服务器

  阻塞式I/O是最常见的I/O方式,阻塞式I/O模型也是最简单的I/O模型。迭代服务器则是在一个无限循环中不断接收和处理数据。如图1所示为UDP的阻塞式I/O模型[3],对于应用进程,在没有数据可读时,进程将阻塞在recvfrom处,直到有数据可读或发生错误。对于UDP服务器,只需要从一个套接字读取数据,阻塞式I/O的迭代服务器即可为多个客户提供服务。但是对于TCP服务器,如图2所示,阻塞式I/O的迭代服务器在完成对当前客户端的服务前,无法处理已经等待服务的新客户端。对于这个问题一般有两种解决思路:I/O复用和并发服务器。

060cbf235a229be163beafc0cde6587.png

3860f6ff079a1d7288901e254856c05.png

      1.2 I/O复用的迭代服务器

  I/O复用可以使用Select、Poll、Epoll(Linux内核)或Kqueue(UNIX内核),这里以Select举例。如图3所示是基于UDP协议对I/O复用模型的一个展示[3],与TCP原理相同。Select函数会筛选出有数据可读、有缓存可写以及有异常的套接字,根据筛选后的结果,仅对有数据可读的套接字调用Read等函数进行读操作。因为被调用Read等函数的套接字始终有数据可读,所以在进程调用Read等函数时始终不会阻塞,以保证进程在一段时间内可以为多个客户端提供服务。

37dacca4f10bb6665de59877a27b3f7.png

  事件循环模型是一种与Select模型相近的设计,与Select不同的是,Select是主动轮询到达的事件(如可读的套接字等I/O事件),而事件循环模型是将事件推送到一个事件循环中。事件循环模型不仅仅用在网络编程中,在GUI开发中也有着大量使用。最经典的例子就是在Web浏览器中JavaScript运行时内置有事件循环。

  1.3并发服务器

  传统的UNIX模型中,一个进程只做一件事。在这个模型下的网络服务器会为每一个接入的用户Fork一个子进程,但是为每一个接入的用户Fork进程存在着开销过大、进程间通信复杂等问题,相比之下线程所消耗的资源更小,线程间的通信更简单,将进程替换为线程就是另一种并发服务器。此外,并发服务器还有两种变体:预先派生进程(PreForking)和预先派生线程(PreThreading),即在服务器启动时预先建立进程池(线程池),每个用户由当前的某个子进程(子线程)处理。预先建立进程池(线程池)的好处是可以避免在服务器运行过程中创建和销毁进程(线程)的开销。

  1.4小结

  在实际应用中,使用多线程还是多进程需要考虑多种因素。一般来说多线程的服务器比多进程的服务器消耗更小,开发更简单,但是进程相比于线程,隔离性更好。一个进程下的线程之间共享一个内存空间,当一个线程出现错误时可能导致在一个进程下的所有线程全部异常退出。在一些需要高可靠性和高可用性的系统中会使用多进程,如Nginx。在Python语言构建的程序中,由于全局解释器锁(Global Interpreter Lock)的限制,其多线程无法发挥CPU的多核性能。在一些需要使用CPU多核性能的Python程序中需要使用多进程,如Python开发的Web服务器,Gunicorn、Python开发的分布式异步消息任务队列Celery,采用的都是PreForking的模型。

  现在的服务器程序大多是多种模型相结合的,并发服务器相比于迭代服务器可以更有效地利用电脑的CPU多核性能,但是过多的线程或进程反而会使服务器的性能下降。一般设置的线程数量或进程数量会参考CPU的核心数量,Nginx设置的自动进程数量等于CPU核心数量,Gunicorn建议的进程数量为CPU核心数量的两倍。而在每个进程或线程下可以使用I/O多路复用或者下文所述的协程等模型。

  2异步编程模型

  多路复用、事件循环等机制是实现异步编程的基础,将其中事件处理部分的代码从其他部分剥离出来,将多路复用、事件循环等机制的实现代码封装隐藏起来,就形成了异步编程的模型。

  JavaScript是一个常用的编程语言,并且在运行环境中集成了异步支持。下面会以JavaScript代码为例,通过一个简单的案例,3s后弹出一个警告框,介绍回调函数、Promise模型、Async/Await模型。

  2.1回调函数

  对于这个案例,回调函数是最简单的实现方式,代码如下:

58b5f78842c72cde8c862136beaba3f.png

  setTimeout函数是JavaScript中提供设置定时器的函数,其拥有两个参数:第一个参数为回调函数,即到达设定时间后执行的函数;第二个是设定的时间。虽然在这个例子中通过回调函数实现比较简单,但是在逻辑复杂之后,容易形成回调函数深层嵌套的“回调地狱”,代码的维护性会降低。

  2.2 Promise模型

  在回调函数模式的基础上,可以进一步将延时的功能提取成独立的函数。在JavaScript中提供了Promise对象—一种对于异步操作的抽象。基于Promise修改后的代码如下:

7f77a274c4dfd0dec3cd834d5ba6674.png

c7784279fbf320a85c84430c6a4e3d9.png

  Promise的构造方法参数比较复杂,参数本身是一个回调函数,用于执行求值过程。回调函数有两个参数,Resolve和Reject,此参数也是函数分别用于传递操作成功时的值和传递失败时的异常。在示例中,传入Promise构造函数中的参数(即回调函数),执行setTimeout设置定时器,在到达设定时间后,定时器会执行Resolve函数,表示操作成功,Resolve函数同样可以传递参数,例如通过xhr请求收到的响应可以通过类似Resolve(Response)的代码传递出去。Promise对象的实例有两个重要的方法:then方法和catch方法,分别用于操作成功时下一步操作和在发生异常时处理异常。then方法和catch方法的返回值依然是Promise对象,所以可以实现链式调用。在示例里,delay函数返回了一个Promise示例,在其中的then方法中执行了弹出警告窗的代码。

  Promise模型虽然起到了简化代码的作用,解决了部分由回调函数所带来的问题,但是同一般的同步编程相比依然存在可读性低、调试繁琐等问题。

  2.3 Async/Await模型

  Async/Await模型在Promise模型的基础上进一步简化,代码如下:

a77325d29d06940fc50412985f53493.png

  在JavaScript中Async是Promise的语法糖,标记为Async的函数,其返回值会被自动封装为一个Promise对象,在Async函数中可以对于Promise对象前添加Await,等待Promise完成并取得Promise中的值,对于错误处理,则可以使用Ary-catch语法。

  Async/Await模型在Promise上进一步简化,其编码风格已经与同步编程的相同,在可读性和调试的便捷性上也有所提升。

  2.4小结

  在这里虽然使用的是JavaScript介绍回调函数、Promise模型、Async/Await模型这3种模型,但是在其他的编程语言中也是支持的。

  除了上述的3种模型外,还有一种类似线程并发的模型,比如Go语言中的协程和Java Loom项目所引入的协程,它们虽然在编码风格上类似于线程,但是底层的调度并不是由系统负责,而是由自己运行时负责。这样的好处在于提升了性能的同时,不需要已经熟悉多线程开发的人员学习过多的新知识即可掌握。

  3异步生态和反应式生态

  3.1 Python

  Python于3.4版本在标准库中添加了异步支持库Asyncio,于3.5版本加入对Async/Await的支持。在Python标准库中加入异步支持后,在WSGI的基础上,发展处理异步网关接口(Asynchronous Server Gateway Interface,简称ASGI),弥补了网络异步接口的空白。Python常用的数据库工具库SQLAlchemy也于1.4版本添加了对异步的支持。

  3.2 Go

  Go语言作为一个比较新的语言,在设计之初是为了解决Google公司内部后台程序开发的一些问题。其中内置了对协程的支持。如上文所说Go语言的协程与其他语言的线程模型相似,在Go语言中可以使用Go关键字来启动一个Go协程(在Go语言中也成称Goroutines)。Go协程的调度并不是由操作系统完成,而是由程序中的Go协程调度器完成的。在现在的云原生开发中,有很多优秀的Go语言项目,其中包括Docker和Kubernetes。

  3.3 JVM

  Java的Loom项目允许用户像建立线程一样建立虚拟线程,虚拟线程的设计与Go语言类似,虚拟线程的调度不是由系统来完成的,而是通过JDK或JRE来完成的。

  Vert.x是一个JVM下用于编写异步应用程序的工具包,其设计参考了Node.js[4]。Vert.x的核心项目为Vertx-Core提供了异步编程、非阻塞式I/O、流传输API和多种网络协议(TCP、UDP、HTTP等)的支持,同时还提供了一个类似消息队列的事件总线(Event Bus),其事件总线与消息队列相比并没有崩溃后恢复等功能。Vert.x的其他包提供了如异步数据库操作等功能。在Techempower性能测试中Vert.x常常位于排行榜的前列[5]。

  Quarkus是一个比较新的Java网络开发框架,意在优化k8s等云原生应用的性能与开发,它可以将命令式编程和反应式编程统一在一个框架之中。

  Kotlin是JetBrains公司发明的一个基于JVM的语言,在语言层面上支持协程异步编程,Spring等框架同时支持使用Kotlin开发。在开发过程中适当使用Kotlin开发可以起到简化代码的作用。

  4性能测试

  4.1测试方法及原理

  测试中将会使用Spring的Servlet技术栈以及Reactive技术栈中的Spring Data JPA和Spring Data R2DBC从数据库中读取数据,并分别使用Spring MVC和Spring Webflux相同的API接口。实现的API接口如表1所示,每次获取数据的规模包括1条、5条、10条和20条,共计4种情况。测试会使用压力测试工具Locust以相同权重访问这4种API,测试时间为2min,接入链接为1000个,通过请求速率和响应时间等指标,对比两种技术栈的性能[6]。

1430f28ffff56194b726f2190fbb86c.png

  4.2测试环境及过程

  测试环境使用3台云服务器,通过VPC网络连接,各云服务器的功能及配置如表2所示。客户端采用Docker运行Locust压力测试工具,其中Locust以1个Master、2个Worker的方式运行。Web服务器在使用Ubuntu 22.04默认的OpenJRE 17运行两个协议栈打包后的jar文件。数据库服务器上运行最新版本的Postgresql 15。
       4.3测试结果及分析

  两种协议栈每秒的请求数量如图4所示,可以明显观察到Reactive技术栈相较于Servlet协议栈在处理请求上有明显优势。

a24ebaa326bd56ec08d6dfbed846750.png

  两种协议栈50%响应时间曲线和95%响应时间曲线如图5所示,Reactive技术栈的响应时间相比于Servlet协议栈的响应时间更短,并且Reactive技术栈响应时间的波动比Servlet协议栈的响应时间波动更小。

0df4aec1e6f8c863a91ddd459f3470a.png

612e484a9c9bccd35c54f89541c6a16.png

  测试结果统计如表3所示,在时间为2min,接入链接为1000个时,Reactive技术栈相比于Servlet技术栈在处理请求速率和响应时间2个性能指标上均有优势。在处理请求速率方面,Reactive技术栈相比于Servlet技术栈有27%的性能提升;在响应时间上,Reactive技术栈的是响应时间中位数Servlet技术栈的83.3%,Reactive技术栈的响应时间平均值是Servlet技术栈的83.5%,Reactive技术栈最差情况下的响应时间是Servlet技术栈的44.0%,Servlet技术栈有0.1%的响应时间明显高于其他请求的响应时间,而在Reactive技术栈没有出现该情况。由此可得出结论,Reactive技术栈相比于Servlet技术栈在处理高并发请求时有更好的性能。

d0ca774036eb8a8871af62d0ffad9d0.png

  5结语

  异步编程和反应式编程是一种编程的发展趋势,也是一种提高系统整体性能的有效途径,同时从软件工程角度出发,现在对于异步编程和响应式编程有大量的工具和框架作为封装,开发人员并不需要过分担忧异步编程和响应式编程所带来的问题。总的来看,异步编程和响应式编程可以作为后续应用系统开发的一个方向。


 参考文献

  [1]梁鹏.智能化油气田建设关键技术与应用[J].中国管理信息化,2021,24(6):99-100.

  [2]LEISERSON C E,THOMPSON N C,EMER J S,et al.There's Plenty of Room at the Top:What will Drive Computer Performance After Moore's law?[J].Science,2020,368(6495):1079.

  [3]STEVENS W R,FENNER B,RUDOFF A M.UNIX网路编程—卷1:套接字联网API(第3版)[M]北京:人民邮电出版社,2015.

  [4]Julien Ponge.Vert.x实战(第1版)[M].黄灰红,译.北京:清华大学出版社,2022.

  [5]TechEmpowe.Web Framework Benchmarks[DB/OL].(2022-7-19)[2023-6-30].https://www.techempower.com/be nchmarks/#hw=ph&test=composite&section=data-r21.

  [6]崔晓雪,陈文捷,陈敏刚.分布式列存储数据库性能测试方法研究[J].信息技术与标准化,2022(11):34-39.