云原生Web服务框架ESA Restlight

ESA Restlight是OPPO云计算中心推出的一款面向云原生的高性能Web服务框架,旨在解决Spring MVC在微服务场景中的一些性能和设计问题。它基于Netty实现,提供了轻量级、高性能和高扩展性的特性,支持Spring MVC和JAX-RS注解,拥有灵活的线程调度,并对路由、拦截器和性能进行了优化。通过对比测试,Restlight在性能上比Spring MVC有显著提升,特别适合云原生微服务和FaaS场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

云原生Web服务框架ESA Restlight

在这里插入图片描述
ESA Stack(Elastic Service Architecture) 是OPPO云计算中心孵化的技术品牌,致力于微服务相关技术栈,帮助用户快速构建高性能,高可用的云原生微服务。产品包含高性能Web服务框架、RPC框架、服务治理框架、注册中心、配置中心、调用链追踪系统,Service Mesh、Serverless等各类产品及研究方向。

当前部分产品已经对外开源

开源主站:https://www.esastack.io/

Github: https://github.com/esastack

Restlight项目地址:https://github.com/esastack/esa-restlight

Restlight文档地址:https://www.esastack.io/esa-restlight/

欢迎各路技术爱好者们加入,一同探讨学习与进步。

本文将不可避免的多次提到Spring MVC,并没有要与其竞争的意思,Restlight是一个独立Web框架,有着自己的坚持。

Java业内传统Web服务框架现状

Spring MVC

说到Web服务框架,在Java领域Spring MVC可谓是无人不知,无人不晓。在Tomcat(也可能是Jetty,Undertow等别的实现)基础之上实现请求的路由匹配,过滤器,拦截器,序列化,反序列化,参数绑定,返回值解析等能力。由于其丰富的功能,以及与当今用户量巨大的Spring容器及Spring Boot的深度结合,让Spring MVC几乎是很多公司Web服务框架的不二选择。

本文中的Spring MVC泛指Tomcat + Spring MVC的广义Web服务框架

Resteasy

Resteasy也是Java体系中相对比较成熟的Rest框架,JBoss的一个开源项目,它完整的实现了JAX-RS标准,帮助用户快速构建Rest服务,同时还提供一个Resteasy JAX-RS客户端框架 ,方便用户进行Rest服务调用。Resteasy在许多三方框架中集成使用的场景较多,如Dubbo,SOFA RPC等知名框架中均有使用。

Spring MVC就是万能的么?

某种意义上来说,还真是万能的。Spring MVC几乎具备了传统的一个Web服务应有的绝大多数能力,不管是做一个简单的Rest服务,还是All In One的控制台服务,还是在Spring Cloud中的RPC服务,都可以使用Spring MVC。

可是随着微服务技术的演进和变迁,特别是当今云原生微服务理念的盛行,这个全能选手似乎也出现了一些水土不服。

性能

功能与性能的折中

Spring MVC设计更多是面向功能的设计,通过查看Spring的源码可以看到各种高水平的设计模式及接口设计,这让Spring MVC成为了一个“全能型选手”。但是复杂的设计和功能也是有代价的, 那便是在性能这个点上的折中, 有时候为了功能或者设计不得不放弃一些性能。

Tomcat线程模型

Spring MVC使用单个Worker线程池处理请求

在这里插入图片描述

我们可以使用server.tomcat.threads.max进行线程池大小配置(默认最大为200)。

线程模型中的Worker线程负责从socket读取请求数据,并解析为HttpServletRequest,随后路由到servlet(即经典的DispatcherServlet),最后路由到Controller进行业务调用。

IO读写与业务操作无法隔离

  • 当业务操作为耗时操作时,将会占用Worker线程资源从而影响到其他的请求的处理,也会影响到IO数据读写的效率

  • 当网络IO读写相关操作耗时也将影响业务的执行效率

线程模型没有好坏之分,只有适合与不适合

Restful性能损耗

Restful风格的接口设计是广大开发者比较推崇的接口设计,通常接口路径可能会长这样

  • /zoos/{id}

  • /zoos/{id}/animals

但是这样的接口在Spring MVC中的处理方式会带来性能上的损耗,因为其中{id}部分是基于正则表达式来实现的。

拦截器

使用拦截器时可以通过下面的方式去设置匹配逻辑

  • InterceptorRegistration#addPathPatterns("/foo/**", "/fo?/b*r/")
  • InterceptorRegistration#excludePathPatterns("/bar/**", "/foo/bar")

同样的,这个功能也会为每次的请求都带来大量的正则表达式匹配的性能消耗

这里只列出了一些场景,实际上整个Spring MVC的实现代码中还有很多从性能角度来看还有待提升的地方(当然这只是从性能角度…)

Rest场景的功能过剩

试想一下,当我们使用Spring Cloud开发微服务的时候,我们除了使用@RequestMapping, @RequestParam等常见的注解之外,还会使用诸如ModelAndView, JSP, Freemaker等相关功能么?

在微服务这个概念已经耳熟能详的今天,大多数的微服务已经不是一个All in One的Web服务,而是多个Rest风格的Web服务了。这使得支持完整Servlet, JSP等在All in One场景功能的Spring MVC在Rest场景显得有些大材小用了。即使如此,Spring Cloud体系中大家还是毫不犹豫的使用的Spring MVC,因为Spring Cloud就是这么给我们的。

体积过大

继上面的功能过剩的问题,同样也会引发代码以及依赖体积过大的问题。这在传统微服务场景或许并不是多大的问题,但是当我们将其打成镜像,则会导致镜像体机较大。同样在FaaS场景这个问题将会被放大,直接影响函数的冷启动。

后续将会讨论FaaS相关的问题

缺乏标准

这里的标准指的是Rest标准。实际上在Java已经有了一个通用的标准,即JAX-RS(Java API for RESTful Web Services),JAX-RS一开始就是面试Rest服务所设计的,其中包含开发Rest服务经常使用的一些注解,以及一整套Rest服务甚至客户端标准。

注解

JAX-RS中的注解

  • @Path
  • @GET, @POST, @PUT, @DELETE
  • @Produces
  • @Consumes
  • @PathParam
  • @QueryParam
  • @HeaderParam
  • @CookieParam
  • @MatrixParam
  • @FormParam
  • @DefaultValue

Spring MVC中的注解

  • @RequestMapping
  • @RequestParam
  • @RequestHeader
  • @PathVariable
  • @CookieValue
  • @MatrixVariable

实际上JAX-RS注解和Spring MVC中注解从功能上来说并没有太大的差别。

但是JAX-RS的注解相比Spring MVC的注解

  1. 更加简洁:JAX-RS注解风格更加简洁,形式也更加统一,而Spring MVC的注解所有稍显冗长。
  2. 更加灵活:JAX-RS的注解并非只能用在Controller上,@Produces, @Consumes更是可以用在序列化反序列化扩展实现等各种地方。@DefaultValue注解也可以和其他注解搭配使用。而@RequestMapping将各种功能都揉在一个注解中,代码显得冗长且复杂。
  3. 更加通用:JAX-RS注解是标准的Java注解,可以在各种环境中使用,而类似@GetMapping@PostMapping等注解都依赖Spring的@AliasFor注解,只能在Spring环境中使用。

对于习惯了Spring MVC的同学可能无感,但是笔者是亲身实现过Spring MVC注解以及JAX-RS兼容的,整个过程下来更加喜欢JAX-RS的设计。

三方框架亲和性

假如现在你要实现一个RPC框架,准备去支持HTTP协议的RPC调用,设想着类似Spring Cloud一样用户能够简单标记一些@RequestMapping注解就能完成RPC调用,因此现在你需要一个仅包含Spring MVC注解的依赖,然后去实现对应的逻辑。可是遗憾的是,Spring MVC的注解是直接耦合到spring-web依赖中的,如果要依赖,就会将spring-core, spring-beans等依赖一并引入,因此业内的RPC框架的HTTP支持几乎都是选择的JAX-RS(比如SOFA RPC,Dubbo等)。

不够轻量

不得不承认Spring的代码都很有设计感,在接口设计上非常的优雅。

但是Spring MVC这样一个Web服务框架却是一个整体,直接的依附在了Spring这个容器中(或许是战略上的原因?)。因此所有相关能力都需要引入Spring容器,甚至是Spring Boot。可能有人会说:“这不是很正常的嘛,我们项目都会引入Spring Boot啊”。但是

如果我是一名框架开发者,我想在我的框架中启动一个Web服务器去暴露相应的Http接口,但是我的框架十分的简洁,不想引入任何别的依赖(因为会传递给用户),这个时候便无法使用Spring MVC。

如果我是一名中间件开发者,同样想在我的程序中启动一个Web服务器去暴露相应的Metrics接口,但是不想因为这个功能就引入Spring Boot以及其他相关的一大块东西,这个时候我只能类似原生的嵌入式Tomcat或者Netty自己实现,但是这都有些太复杂了(每次都要自己实现一遍)。

ESA Restlight介绍

基于上述一些问题及痛点,ESA Restlight框架便诞生了。

ESA Restlight是基于Netty实现的一个面向云原生的高性能,轻量级的Web开发框架。

以下简称Restlight

Quick Start

创建Spring Boot项目并引入依赖

<dependency>
    <groupId>io.esastack</groupId>
    <artifactId>restlight-starter</artifactId>
    <version>0.1.1</version>
</dependency>

编写Controller

@RestController
@SpringBootApplication
public class RestlightDemoApplication {
   

    @GetMapping("/hello")
    public String hello() {
   
        return "Hello Restlight!";
    }

    public static void main(String[] args) {
   
        SpringApplication.run(RestlightDemoApplication.class, args);
    }
}

运行项目并访问http://localhost:8080/hello

可以看到,在Spring Boot中使用Restlight和使用Spring MVC几乎没有什么区别。用法非常的简单

性能表现

测试场景

分别使用Restlight以及spring-boot-starter-web(2.3.2.RELEASE) 编写两个web服务,实现一个简单的Echo接口(直接返回请求的body内容),分别在请求body为16B, 128B, 512B, 1KB, 4KB, 10KB场景进行测试

测试工具
  • wrk4.1.0

  • OS CPU Mem(G)
    server centos:6.9-1.2.5(docker) 4 8
    client centos:7.6-1.3.0(docker) 16 3
JVM参数
-server -Xms3072m -Xmx3072m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -XX:+PrintTenuringDistribution -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:logs/gc-${appName}-%t.log -XX:NumberOfGCLogFiles=20 -XX:GCLogFileSize=480M -XX:+UseGCLogFileRotation -XX:HeapDumpPath=.

参数配置
Framework Options
Restlight restlight.server.io-threads=8
restlight.server.biz-threads.core=16
restlight.server.biz-threads.max=16
restlight.server.biz-threads.blocking-queue-length=512
Spring Web server.tomcat.threads.max=32
server.tomcat.accept-count=128
测试结果(RPS)
16B 128B 512B 1KB 4KB 10KB
Restlight(IO) 129457.26 125344.89 125206.74 116963.24 85749.45 49034.57
Restlight(BIZ) 101385.44 98786.62 97622.33 96504.81 68235.2 46460.79
Spring Web 35648.27 38294.94 37940.3 37497.58 32098.65 22074.94

可以看到Restlight的性能相较于Spring MVC有2-4倍的提升。

Restlight(IO)以及Restlight(BIZ)为Restlight中特有的线程调度能力,使用不同的线程模型

功能特性

  • HTTP1.1/HTTP2/H2C/HTTPS支持
  • SpringMVC 及 JAX-RS注解支持
  • 线程调度:随意调度Controller在任意线程池中执行
  • 增强的SPI能力:按照分组,标签,顺序等多种条件加载及过滤
  • 自我保护:CPU过载保护,新建连接数限制
  • Spring Boot Actuator支持
  • 全异步过滤器,拦截器,异常处理器支持
  • Jackson/Fastjson/Gson/Protobuf序列化支持:支持序列化协商及注解随意指定序列化方式
  • 兼容不同运行环境:原生Java,Spring,Spring Boot环境均能支持
  • AccessLog
  • IP白名单
  • 快速失败
  • Mock测试

ESA Restlight架构设计

设计原则

  • 云原生:快速启动、省资源、轻量级
  • 高性能:持续不懈追求的目标 & 核心竞争力,基于高性能网络框架Netty实现
  • 高扩展性:开放扩展点,满足业务多样化的需求
  • 低接入成本:兼容SpringMVC 和 JAX-RS常用注解,降低用户使用成本
  • **全链路异步:**基于CompletableFuture提供完善的异步处理能力
  • **监控与统计:**完善的线程池等指标监控和请求链路追踪与统计

分层架构设计

通过分层架构设计让Restlight具有非常高的扩展性,同时针对原生Java, Spring, Spring Boot等场景提供不同实现,适合Spring Boot业务,三方框架,中间件,FaaS等多种场景。

在这里插入图片描述

架构图中ESA HttpServer, Restlight Server, Restlight Core, Restlight for Spring, Restlight Starter几个模块均可作为一个独立的模块使用, 满足不同场景下的需求

ESA HttpServer

基于Netty 实现的一个简易的HttpServer, 支持Http1.1/Http2以及Https等

该项目已经同步开源到Github:https://github.com/esastack/esa-httpserver

Restlight Server

ESA HttpServer基础之上封装了

  • 引入业务线程池
  • Filter
  • 请求路由(根据url, method, header等条件将请求路由到对应的Handler)
  • 基于CompletableFuture的响应式编程支持
  • 线程调度

eg.

引入依赖

<dependency>
	<groupId>io.esastack</groupId>
	<artifactId>restlight-server</artifactId>
	<version>0.1.1</version>
</dependency>

一行代码启动一个Http Server

Restlite.forServer()
        .daemon(false)
        .deployments()
        .addRoute(route(get("/hello"))
                .handle((request, response) ->
                        response.sendResult("Hello Restlight!".getBytes(StandardCharsets.UTF_8))))
        .server()
        .start();

适合各类框架,中间件等基础组建中启动或期望使用代码嵌入式启动HttpServer的场景

Restlight Core

Restlight Server之上, 扩展支持了Controller方式(在Controller类中通过诸如@RequestMappng等注解的方式构造请求处理逻辑)完成业务逻辑以及诸多常用功能

  • HandlerInterceptor: 拦截器
  • ExceptionHandler: 全局异常处理器
  • BeanValidation: 参数校验
  • ArgumentResolver: 参数解析扩展
  • ReturnValueResolver: 返回值解析扩展
  • RequestSerializer: 请求序列化器(通常负责反序列化Body内容)
  • ResposneSerializer: 响应序列化器(通常负责序列化响应对象到Body)
  • 内置Jackson, Fastjson, Gson, ProtoBuf序列化支持
Restlight for Spring MVC

基于Restlight Core的Spring MVC注解支持

eg

<dependency>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值