轻量级Web服务器的高并发技术研究与实现

2020-10-28 01:48:24李思莉杨井荣
计算机技术与发展 2020年10期
关键词:线程吞吐量学分

李思莉,杨井荣,苟 强

(成都理工大学 工程技术学院 电子信息与计算机工程系,四川 乐山 614000)

0 引 言

大量用户在同一个时间点同时访问某个相同的站点称为高并发。高并发现象在如今的互联网行业应用中非常普遍,如12306铁路购票网站,双11时阿里巴巴、京东、唯品会等电子商务网站要处理的并发数通常都高达每秒百万级。但如何处理高并发却是一个非常难的技术瓶颈。该文研究的是在单机无集群的情况[1],以NIO为基础的同步非阻塞IO,而非传统的IO方式,结合Vert.x[2]的事件驱动完成同步通信与异步事件处理的并行运算,是数据通信部分百万级别的并发。并在此研究基础上利用Java Spring线程池,完成了课外学分管理系统。通过大量的实验数据,与传统Web应用的IO方式进行对比,得出论文研究并实现的MVC层的扩展、数据安全优化、同步非阻塞模式与NIO在Web的应用中完全能胜任百万级甚至更高的并发量的结论。同时,由于这种异步事件处理方式是基于Spring管理的线程池,在系统扩展上,很容易实现分布式系统完成更多的并发与集群架设。

1 高并发学分管理系统架构

客户/服务器模式(C/S)不能应对多平台带来的开发时间、开发效率、开发投入等多方面要求,加之各PC之间操作系统不同,为了兼顾过时的Windows XP系统,在开发PC端系统时通常出现两种情况:(1)开发多个版本;(2)兼顾XP不使用高版本Windows系统的特性和高效率API。这两种情况都不好,因此在开发学分管理系统时,放弃C/S架构,使用B/S[3]架构。这套架构,在客户端上只需要前端网页和可运行在系统上的浏览器就可满足用户对于多平台,不同系统设备的需求,节约开发时间和开发成本。在具体的程序内部架构设计上,传统的三层架构已经无法满足系统高并发需求,数据传输中传统的I/O设计模式和传统的I/O传输必将面临性能瓶颈甚至会导致整个课外学分管理系统的崩溃。因此在实际的开发过程中,将系统设计成5层模式,由外向内展开依次是:

(1)负责与前端信息交互的restfulApi层;

(2)负责管理处理逻辑的中央组件管理层;

(3)负责管理并发线程的调度和管理的并发层;

(4)负责处理信息的逻辑层;

(5)负责持久化信息的ORM层。

通过实验证明,该架构在技术上是可行的,在并发请求每秒10万数量级上依然保持稳定。

2 高并发系统分析

2.1 处理高并发请求的MVC层

要完成十万级,百万级的并发请求,普通的IO会导致系统性能急速下降,这将导致系统无法正常运行。因此,在具体的开发实现中,使用了非阻塞式IO。非阻塞式IO分为异步非阻塞IO和同步非阻塞IO。通过对学分管理系统的需求分析,得出整个流程不需要消耗很多的等待时间,因此,采用同步非阻塞IO模式。加之非阻塞IO、零拷贝、事件驱动等特性,在开发生态圈里有很多经验可取,在框架的设计上也能利用现有的同步非阻塞IO框架,不必重头开发底层。

2.2 处理高并发请求的Server层

Server层的高并发,着重体现在线程安全上,在数据处理上,不能出现很多线程去同时操作运算数据的情况。对于线程安全,在整个Server层实现上完全使用了线程安全的数据结构,如:ConcurrentHashMap,SynchronizeList等,需要注意的是要避免使用过时的线程安全的数据结构,如:vector,HashTable等,这会降低整体的效率。

除了线程安全的数据结构,很多方法的逻辑也不允许多线程同时操作,一般的解决方案是使用Synchronize关键字对需要加锁的方法或者代码块进行修饰,但这是一种悲观锁,如果发生异常,会出现阻塞,这对系统是致命的,不仅会导致后续的操作挂起,还会导致程序崩溃。要避免发生这种情况,在Server层实现上采用了非阻塞的并发算法CountDownLatch[4],它是Java提供的原生非阻塞并发算法,可以有效实现学分管理系统的线程同步。

2.3 持久化、并行数据接收与Restful层

利用数据库的隔离机制完成数据安全是一种低效的做法。在学分管理系统持久化层的设计中,将数据安全因素放到调用持久化层的Server层里面去实现[5]。持久化层事务的传播机制统一采用Spring的传播机制,并利用缓存技术,减少系统响应时间。在初始化时,采用快速数据库连接池初始化一个足够大的数据库连接池交给持久化层使用[6]。

并行数据接收是并发的开始,这里采用了成熟的模式设计,即一个接收的总线Boss线,多个负责传输转发到相应处理的Server逻辑的Worker线程,将多个Worker线程初始化为一个线程池由Spring统一管理,它存在于整个Springboot程序中。这个模式实现了代码复用,减少了初始化、调用等冗余代码,也能更好地融合在主框架里。

Restful层的设计采用Vert.x Web框架而放弃了低性能的SpringMvc[7],Vert.x是事件驱动的,整个处理过程基于事件总线而非单独的控制器。

3 高并发关键技术实现

3.1 SpringBoot配置说明

整个系统采用YAML配置模板,Server配置了Http访问端口,访问根路径和内嵌的Tomcat编码[8]、响应时间等配置,其关键参数如表1所示。

表1 关键配置参数

3.2 Restful层的实现

Restful层的设计采用Vert.x Web框架,它采用异步模式,通过事件循环调用存储在异步任务队列中的任务,大大降低了传统阻塞模型中线程对于操作系统的开销[9]。

整个学分管理系统实现高并发通信高效率的核心步骤是创建多路复用的通信通道。为了减少冗余代码,主框架采用Springboot。将复用通道交由Spring统一管理,在此之前要创建由Spring管理的Worker线程池,部分代码如下:

@Component

public class SpringVertxFactory implements VerticleFactory, ApplicationContextAware {

private ApplicationContext applicationContext;

@Override

public String prefix() {

return "credit"; }

@Override

public boolean blockingCreate() {

return true;

}

@Override

public Verticle createVerticle(String s, ClassLoader classLoader) throws Exception {

String clazz=VerticleFactory.removePrefix(s);

return (Verticle) applicationContext.getBean(Class.forName(clazz));

}

@Override

public voidsetApplicationContext(ApplicationContext applicationContext) throws BeansException {

this.applicationContext=applicationContext; }}

上述代码完成了三个目标:

(1)实现了VerticleFactory和Application ContextAware接口,VerticleFactory接口能产生Vert.x工作线程,ApplicationContextAware接口是当SpringContext初始化完成后,用于获取SpringContext的接口,其目的是将产生的Vert.x工作线程Verticle加入到SpringContext中,达到由Spring容器统一管理Verticle线程池的目的[10]。

(2)初始化通道总线和事件总线,注册RestfulApi到Vert.x,并设置相关联的属性。使用了线程同步的方式保证初始化顺序执行。

(3)初始化Vert.x核心容器Vertx,并设置最大线程量和最大连接响应时间。注册Vert.x工作线程到Vert.x容器,检查初始化过程中是否超时,初始化过程中是否有错误,以及是否全部线程都已经初始化完成。

由于Vert.x的工作线程由Spring容器统一管理[11],只有当Spring容器初始化完毕后才能使用Spring容器里的Vert.x工作线程,故需要监听Springboot的启动消息事件。Vert.x中的RestfulApi没有一套现成的能直接完成映射注册的开发注解或模板类,因此Vert.x的RestfulApi需要自己去实现。

该文定义的RestfulApi必须继承AbstractVerticle这个抽象类,才能被Vert.x核心容器接收作为通信处理链上的一部分。并且会去执行该对象类里面的start方法,所以一定要重写这个方法。这个方法里面首先要创建处理逻辑的代理接口,而且这个接口也必须要能被Vert.x核心容器接受,然后注册访问地址[12]到Vert.x的核心路由上面,由于整个过程是事件驱动的,所以要设立监听端口。将事件处理的逻辑结果写入到Router的routingContext中,这样才可到前端解析[13]。

4 实验结果

4.1 程序编写

Java原生的NIO API在开发中显得过于繁琐,也未封装成一个高并发的架构。为了减少开发带来的时间消耗和框架封装的性能消耗,采用现有的Vert.x框架。现有主流的Web开发中Spring是必不可少的,将两者结合由Spring管理Vert.x的部分组件能用工程化的开发流程去简化异步Web程序的开发。

将部分ajax请求接口更改为Vert.x开发,应用更多Spring带来的方便且规范的服务,减少在后续服务带来的开发难度和性能消耗。

整合Web其余所有部分通过Spring与Vert.x协同工作,并借此管理Vert.x的异步线程池,动态地申请资源,减少性能浪费。

4.2 相同固定时间和压力内测量吞吐量和响应时间

为了保证实验的可行度和可信度,采用由Apache基金会开发的JMeter压力测试工具[14-15],对该项目进行测试,并且实验是基于课外学分管理系统设计的,这两个不同接口会运行在同一个Java虚拟机中,最大程度地保证了在运行环境、参数、性能等各方面的一致性,得出的实验结果对比也更有说服力。

设定为百万级并发请求:让程序能模拟一百万个用户对同一个接口模块请求。

设定图形结果计算包括吞吐量和响应时间。

固定时间为一分钟或者一分钟又几秒钟(结束上百个线程会消耗几秒时间)。

接口调用的逻辑和功能完全一致。

设定线程请求无延迟,即延迟0 ms。

4.3 学分管理系统实验结果及实验数据处理

在实验过程中,为了保证发送的数量是一样的,应当同时启动两个线程组,且设置完全一模一样,设置在同一个测试组中,启动整个测试组。

在此期间密切关注线程数量变化,记录线程非满载的情况下的测试数据,在后期处理数据时需要除去这一部分不合格的启动数据。观察后台是否已经崩溃,因为在百万级的并发下SpringMvc大概率会假死,如果已经崩溃或者假死则数据上没有对比的必要性。

在实验数据监听器中取得相应数据和统计图形,首先在SpringMvc组里面取得吞吐量和响应时间结果,如图1和图2所示。

图1 学分管理系统SpringMvc吞吐量

图2 学分管理系统SpringMvc响应时间

Vert.x的响应时间和吞吐量如图3和图4所示。

图3 学分管理系统Vert.x吞吐量

图4 学分管理系统Vert.x响应时间

由上面四幅图片可以获得的信息,仍然需要比对SpringMvc和Vert.x,需要排除不合格的测试量。首先排除前10秒钟的线程启动时测试的数据,再减去20秒后衰减的线程量这样的响应时间才是合格的比对样本,其结果如图5所示。

相同时间发出的数量能保证在误差范围内,故可以记录所有的量一次吞吐代表完成一次请求,结果如图6所示。

图6 吞吐量对比

5 结束语

在实验数据的对比下能发现,在响应时间是万倍的差距,在吞吐量上是数十倍的差距,在同一JVM,同一功能,执行同一逻辑,同一线程组中排除不合格数据得出的数据对比中可以得到如下结论:

(1)相较于传统且主流的SpringMvc的IO模式,NIO更能胜任高并发环境,而且这个性能是提升巨大的,能在主要的两方面中体现出指数倍的差距;

(2)能在相同逻辑下大幅度减少通信时间;

(3)相同条件下,NIO通信的程序能处理更多的请求。

猜你喜欢
线程吞吐量学分
如何用学分币激发小学生的学习兴趣
甘肃教育(2020年8期)2020-06-11 06:09:46
学分美食
2016年10月长三角地区主要港口吞吐量
集装箱化(2016年11期)2017-03-29 16:15:48
2016年11月长三角地区主要港口吞吐量
集装箱化(2016年12期)2017-03-20 08:32:27
浅谈linux多线程协作
环球市场(2017年36期)2017-03-09 15:48:21
斯皮尔伯格为什么要历时33年修完学分?
颈部淋巴结超声学分区
2014年1月长三角地区主要港口吞吐量
集装箱化(2014年2期)2014-03-15 19:00:33
上海港11月集装箱吞吐量同比增长4.25%
广东造船(2013年6期)2013-04-29 16:34:55
Linux线程实现技术研究