秒杀springboot——未来轻量级高性能的Java云原生微服务框架来啦

 

秒杀springboot——未来轻量级高性能的Java云原生微服务框架来啦

 

引子

2003RodJuergen Yann开发并发布Spring项目后,J2EE 迎来了新的开始。在 2013 年初Spring Boot 项目横空出世,Spring Web 应用体系结构得以大大简化。在好未来的Java研发伙伴的实践中,越来越多的团队开始使用SpringbootSpringCloud

那么除了Spring家族,还有没有更好的web开发框架呢?特别是在云时代和Docker化时代的当下,有没有更贴合技术发展方向的web框架呢?当然有!本文笔者就带大家走出低头走路的状态,抬头看天看未来。这就是秒杀Springboot,具有表征未来趋势的轻量级高性能Java云原生微服务框架light-4j

 

light-4j简介

light-4j(官网地址:https://doc.networknt.com/)于2016年在GitHubGitHub地址:https://github.com/networknt/light-4j)首发的框架。light-4j是一个快速、轻量级的云原生微服务框架,其主要设计目标是高吞吐量、低延迟和小内存占用。快速而小的内存占用,可以为企业降低成本,这也是其未来发展空间广阔的原因之一。

 

 

大家有木有想过这个框架为什么会叫light-4j呢?light有光的意思,也有闪电的意思,在这里意译为闪电,闪电就意味着很轻量级、有闪电般的速度,4j其实就是for java的简写,换言之框架基于Java SE Java 8) 实现。

 

那么light-4j有多快呢?light-4j比最流行的微服务平台Spring Boot(嵌入式Tomcat的形式)快44倍,并且只使用其1 / 5的内存!惊不惊喜,意不意外?!我们可以从benchmark 的性能测试报告,来一探light-4j Spring Boot 及其他微服务平台的比较结果:

Framework

Language

Max Throughput

Avg Latency

Transfer

Go FastHttp

Go

1,396,685.83

99.98ms

167.83MB

Light-4j

Java

1,344,512.65

2.36ms

169.25MB

ActFramework

Java

945,429.13

2.22ms

136.15MB

Go Iris

Go

828,035.66

5.77ms

112.92MB

Vertx

Java

803,311.31

2.37ms

98.06MB

Node-uws

Node/C++

589,924.44

7.22ms

28.69MB

Dotnet

.Net

486,216.93

2.93ms

57.03MB

Jooby/Undertow

Java

362,018.07

3.95ms

47.99MB

SeedStack-Filter

Java

343,416.33

4.41ms

51.42MB

Spring Boot Reactor

Java

243,240.17

7.44ms

17.86MB

Pippo-Undertow

Java

216,254.56

9.80ms

31.35MB

Spark

Java

194,553.83

13.85ms

32.47MB

Pippo-Jetty

Java

178,055.45

15.66ms

26.83MB

Play-Java

Java

177,202.75

12.15ms

21.80MB

Go HttpRouter

Go

171,852.31

14.12ms

21.14MB

Go Http

Go

170,313.02

15.01ms

20.95MB

JFinal

Java

139,467.87

11.89ms

29.79MB

Akka-Http

Java

132,157.96

12.21ms

19.54MB

RatPack

Java

124,700.70

13.45ms

10.82MB

Pippo-Tomcat

Java

103,948.18

23.50ms

15.29MB

Bootique + Jetty/Jersey

Java

65,072.20

39.08ms

11.17MB

SeedStack-Jersey2

Java

52,310.11

26.88ms

11.87MB

Baseio

Java

50,361.98

22.20ms

6.39MB

NinjaFramework

Java

47,956.43

55.76ms

13.67MB

Play 1

Java

44,491.87

10.73ms

18.75MB

Spring Boot Undertow

Java

44,260.61

38.94ms

6.42MB

Nodejs Express

Node

42,443.34

22.30ms

9.31MB

Dropwizard

Java

33,819.90

98.78ms

3.23MB

Spring Boot Tomcat

Java

33,086.22

82.93ms

3.98MB

Node-Loopback

Node

32,091.95

34.42ms

11.51MB

Payra Micro

Java

24,768.69

118.86ms

3.50MB

WildFly Swarm

Java

21,541.07

59.77ms

2.83MB

 

除了Springboot,我们还可以将light-4j和其他 web 框架的对比,从结果看light-4j足以吊打 Spring 等各种框架!

 

light-4j的特性

light-4j提供了丰富的特性,包含启动/关闭钩子和各种中间件的插件架构。具体细节汇总如下:

1)集成了分布式OAuth2 JWT安全验证

2)基于OpenAPI规范进行请求和响应验证

3)收集测量指标并支持服务和客户端在控制台显示

4)全局运行时异常处理,如API异常及其他受检查异常

5)在日志输出前加密敏感数据,如:信用卡、SIN号等

6)为请求参数、请求头、BODY清除跨站攻击脚本

7)重要信息或整个请求/响应的审计

8)请求体支持各种类型的content-type

9)配置标准化响应码及响应消息

10)支持外部配置化Docker环境所有模块

11)来自其他域名的跨域处理支持

12)对外提供的服务限速处理服务发现与注册支持直连

13ConsulZookeeper客户端侧的发现和负载平衡

14)消除代理层与Light-OAuth2紧密集成并支持可跟踪性

 

light-4j采用设计和测试驱动开发的方式来提高生产率。light-4j设计了OpenAPI规范并从中生成服务,该规范也是在运行时驱动安全验证和请求验证的框架的一部分。为了实现高质量产品的测试驱动,light-4j采用单元/端到端测试存根的形式。

此外light-4j内置的DevOps流程支持持续集成到生产中,light-4j可以生成DockerfileDevOps支持文件,以支持文档化和持续集成到生产中。

 

light-4j的组成

springcloud一样,light-4j也是多个组件构成。常见的有5种不同类型微服务的多个框架,分别是:

1light-rest-4j是一个RESTful微服务框架,具有OpenAPI规范,用于代码生成、运行时安全性和验证。

2light-graphql-4j是一个graphql微服务框架,支持从IDL和插件生成模式。

3light-hybrid-4j是一个混合微服务框架,它利用了单体服务和微服务体系结构的优势。

4light-eventuate是一个基于Kafka、事件源和CQRS的基于消息传递的微服务框架。

 

   除了上述常见的框架,还有其他几款框架可供选型,分别汇总如下:

1Light-tram-4j: 保证服务之间的事务性消息/命令/事件的传递

2Light-eventuate-4j : 基于事件源和CQRS的最终一致性框架

3Light-saga-4j: 跨多个微服务管理分布式事务的saga实现

4Light-spring-boot : 在spring-boot 中利用light-4j中间件处理程序

5Light-session-4j : 支持服务器集群的分布式会话管理器( RedisHazelcastJDBC )

6Light-spa-4j :一组用于单页应用程序的中间件处理程序。

  

   light-4j也支持Web Server WebSocket,其中 Web Server用于提供静态内容和应用程序接口网络服务器 ,WebSocket 支持客户端对客户端或客户端对服务器通信的WebSocket服务。

 

目前light-4j建立比较完备的基础设施服务,现已集成Consul KafkaElasticsearchInfluxDB PrometheusKubernetesOpenshift 等,并已经构建一些通用service,如:

1Light-oauth2 :为微服务提供OAuth 2.0服务;

2Light-portal :集成所有服务以管理服务生命周期的门户用户界面;

3Light-router :配合外部客户端或未在Java 8及更高版本中实现的客户端;

4Light-proxy :部署在遗留应用程序之前,以解决交叉问题;

5Light-config-server :集中式配置和秘钥管理服务;

6Light-tokenization :在将信息发送到公司网络之外之前,标记敏感信息。

 

light-4j提供的构建工具有:

<!--[if !supportLists]-->1)<!--[endif]-->Light-bot :基于微服务的DevOps代理,处理多个代码库和依赖关系;

<!--[if !supportLists]-->2)<!--[endif]-->Light-codegen :代码生成器;

3Swagger-bundler  一个实用程序,将多个Swagger规范文件合并到一个解析了外部引用的文件中;

4Openapi-bundler: 一个实用程序,将多个OpenAPI规范文件合并到一个解析了外部引用的文件中。

 

 

为了丰富其生态系统,light-4j正在逐步支持多语言。目前对Java语系的支持最好,当前的所有开源框架都是用Java构建的, Nodejs框架也正在开发中。

 

light-4j的使用

使用light-4j前,需进行环境准备,主要依赖的环境有JDK 8 GitmavenDocker

 

我们可以通过light-codegen生成一个工作项目。目前,它支持light-rest-4j, light-graphql-4j, light-hybrid-server-4j and light-hybrid-service-4j。在GitHub的项目中,light-codegen项目的README.md通过示例描述了使用生成器的四种方法,笔者建议使用light-codegen的命令行的形式生成代码。

我们可以克隆或下载light-example-4j项目,删除或重命名petstore 文件夹,并进入networknt,通过运行命令:

java -jar light-codegen/codegen-cli/target/codegen-cli.jar -f openapi -o light-example-4j/rest/openapi/petstore -m model-config/rest/openapi/petstore/1.0.0/openapi.json -c model-config/rest/openapi/petstore/1.0.0/config.json 来生产工程。

   

config.json描述了工程的生成配置文件

{

  "name": "petstore",

  "version": "3.0.1",

  "groupId": "com.networknt",

  "artifactId": "petstore",

  "rootPackage": "com.networknt.petstore",

  "handlerPackage":"com.networknt.petstore.handler",

  "modelPackage":"com.networknt.petstore.model",

  "overwriteHandler": true,

  "overwriteHandlerTest": true,

  "overwriteModel": true,

  "httpPort": 8080,

  "enableHttp": false,

  "httpsPort": 8443,

  "enableHttps": true,

  "enableHttp2": true,

  "enableRegistry": false,

  "supportDb": false,

  "supportH2ForTest": false,

  "supportClient": false,

  "dockerOrganization": "networknt"

}

 

工程生成完毕后,我们可以基于maven构建打包项目(暂不支持Gradle,后续会支持Gradle )。我们将目录切换到light-example-4j/rest/openapi/petstore下,在DOS界面运行命令:

mvn install exec:exec

即可启动服务,此时服务的访问端口是8443(详见配置中的  "httpsPort": 8443),同时支持HTTPHTTPS协议。而服务器的配置信息可以在server.yml进行配置,server.yml常用的字段如下:

# This is the default binding address if the service is dockerized.

ip: 0.0.0.0

 

# Http port if enableHttp is true. It will be ignored if dynamicPort is true.

httpPort:  8080

 

# Enable HTTP should be false by default. It should be only used for testing with clients or tools that don't support https or very hard to import the certificate.

enableHttp: false

 

# Https port if enableHttps is true. It will be ignored if dynamicPort is true.

httpsPort:  8443

 

# Enable HTTPS should be true on official environment and most dev environments.

enableHttps: true

 

# Http/2 is enabled by default for better performance and it works with the client module

enableHttp2: true

 

# Keystore file name in config folder. KeystorePass is in secret.yml to access it.

keystoreName: tls/server.keystore

 

# Flag that indicate if two way TLS is enabled. Not recommended in docker container.

enableTwoWayTls: false

 

# Truststore file name in config folder. TruststorePass is in secret.yml to access it.

truststoreName: tls/server.truststore

 

# Unique service identifier. Used in service registration and discovery etc.

serviceId: com.networknt.petstore-1.0.1

 

# Flag to enable self service registration. This should be turned on on official test and production. And dyanmicPort should be enabled if any orchestration tool is used like Kubernetes.

enableRegistry: false

 

# Dynamic port is used in situation that multiple services will be deployed on the same host and normally

# you will have enableRegistry set to true so that other services can find the dynamic port service. When

# deployed to Kubernetes cluster, the Pod must be annotated as hostNetwork: true

dynamicPort: false

 

# Minimum port range. This define a range for the dynamic allocated ports so that it is easier to setup

# firewall rule to enable this range. Default 2400 to 2500 block has 100 port numbers and should be

# enough for most cases unless you are using a big bare metal box as Kubernetes node that can run 1000s pods

minPort: 2400

 

# Maximum port rang. The range can be customized to adopt your network security policy and can be increased or

# reduced to ease firewall rules.

maxPort: 2500

 

# environment tag that will be registered on consul to support multiple instances per env for testing.

# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md

# This tag should only be set for testing env, not production. The production certification process will enforce it.

# environment: test1

 

我们可以通过访问测试URL来验证服务是否启动成功,如通过命令:

curl -k https://localhost:8443/v1/pets/111

如果服务器启动成功,则服务器返回类似结果:

{"id":1,"name":"Jessica Right","tag":"pet"}

 

基于light-4j的业务代码编写

我们以常见的controller-service模式来看一下light-4j框架下代码的编写。

 

controller入口demo代码如下:

package com.networknt.database;

 

import com.networknt.server.HandlerProvider;

import io.undertow.Handlers;

import io.undertow.server.HttpHandler;

import io.undertow.util.Methods;

import com.networknt.info.ServerInfoGetHandler;

import com.networknt.database.handler.*;

 

public class PathHandlerProvider implements HandlerProvider {

    @Override

    public HttpHandler getHandler() {

        return Handlers.routing()

            .add(Methods.GET, "/v1/queries", new QueriesGetHandler())

            .add(Methods.GET, "/v1/query", new QueryGetHandler())

            .add(Methods.GET, "/v1/server/info", new ServerInfoGetHandler())

            .add(Methods.GET, "/v1/updates", new UpdatesGetHandler())

        ;

    }

}

 

我们可以看到,light-4jURL的映射放到了HandlerProvider的接口实现类中集中配置。

那么多个路径对应的Handler是如何编写的呢?以“  .add(Methods.GET, "/v1/updates", new UpdatesGetHandler())”中的UpdatesGetHandler类为例,代码如下:

 

package com.networknt.database.handler;

 

import io.undertow.server.HttpHandler;

import io.undertow.server.HttpServerExchange;

import io.undertow.util.HttpString;

import java.util.HashMap;

import java.util.Map;

import org.apache.commons.lang3.StringEscapeUtils;

 

public class UpdatesGetHandler implements HttpHandler {

    @Override

    public void handleRequest(HttpServerExchange exchange) throws Exception {

        Map<String, Object> examples = new HashMap<>();

        examples.put("application/json", StringEscapeUtils.unescapeHtml4("[ {  randomNumber : 123,  id : 123} ]"));

        if(examples.size() > 0) {

            exchange.getResponseHeaders().add(new HttpString("Content-Type"), "application/json");

            exchange.getResponseSender().send((String)examples.get("application/json"));

        } else {

            exchange.endExchange();

        }

    }

}

 

那么如何操作数据库呢?我们以mongodb为例展示其操作方式。首先构建mongodb对应的配置类MongoConfig,代码如下:

package com.networknt.database.db;

 

import com.fasterxml.jackson.annotation.JsonIgnore;

 

public class MongoConfig {

    @JsonIgnore

    String description;

    String host;

    String name;

 

    public MongoConfig() {

    }

 

    public String getDescription() {

        return description;

    }

 

    public void setDescription(String description) {

        this.description = description;

    }

 

    public String getHost() {

        return host;

    }

 

    public void setHost(String host) {

        this.host = host;

    }

 

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name = name;

    }

}

 

mongodb DAO类需基于StartupHookProvider实现,代码如下:

 

package com.networknt.database.db;

 

import com.mongodb.DB;

import com.mongodb.MongoClient;

import com.mongodb.MongoClientOptions;

import com.mongodb.ServerAddress;

import com.mongodb.client.MongoDatabase;

import com.networknt.config.Config;

import com.networknt.server.StartupHookProvider;

 

public class MongoStartupHookProvider implements StartupHookProvider {

 

    static String CONFIG_NAME = "mongo";

    public static MongoDatabase db;

 

    public void onStartup() {

        System.out.println("MongoStartupHookProvider is called");

        initDataSource();

        System.out.println("MongoStartupHookProvider db = " + db);

 

    }

 

    static void initDataSource() {

        MongoConfig config = (MongoConfig) Config.getInstance().getJsonObjectConfig(CONFIG_NAME, MongoConfig.class);

        MongoClientOptions.Builder clientOptions = new MongoClientOptions.Builder();

        clientOptions.minConnectionsPerHost(10);//minPoolSize

        clientOptions.connectionsPerHost(50);//maxPoolSize

        MongoClient mongoClient = new MongoClient(new ServerAddress(config.getHost()), clientOptions.build());

        db = mongoClient.getDatabase(config.getName());

    }

}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值