Vert.x 入门以及与SpringBoot的一些联动

作者: 人形大叔 | 来源:发表于2019-06-14 22:36 被阅读0次
    • 小字:这篇文章探讨的仅仅是Vert.x入门,简要实现以及帮助理解

    按照我的习惯先上结论

    生而为了微服务,生而为了高并发,去除了锁概念的框架,Vertx。因为有EventBus的存在打散了传统开发层于层之间的关系,让层的关系变得"松散而有序",每个Vertx实例都会维护一个队列,所以也就没有了锁的需要(本来在现实中锁这个概念就有点不符合逻辑),这大大的提升了效率。
    举一个不太恰当的例子,以前的开发就好比有一个马厩,里面有一个水槽,一次只能容纳一匹马喝水,其他的马想喝水那么就必须排队(阻塞)。好了现在有那么几匹马不太守规矩,从宁一边来抢这个水槽(高并发),为了阻止这种情况出现,我们有了围栏让马儿依次喝水(锁)。
    现在有了Vertx,里面的EvevtBus干了一件事情,把这个水槽拉得很长,长到所有的马都可以喝水,不但马可以喝水,其他鹿啊,狗啊,猫啊都可以来喝水,牛逼~

    并且Vertx里面还有个执行单元的概念,一个执行单元被注册好之后,开启。如果现在吞吐量到顶了,好了现在骚操作来了,你可以再开启一次。吞吐量翻倍,Vertx里里面的x居然是复数的意思。

    Vert.x:你随便啊,你有机器我没在怕啊。

    1. Vert.x 简介

    • JVM上的Reative开发套件。Vert.x目前是见过最功能最强大,第三方库依赖最少的Java框架,它只依赖Netty4以及Jacskon
    • Vert.x最大的特点就在于异步(底层基于Netty),通过事件循环(EventLoop)来调起存储在异步任务队列(CallBackQueue)中的任务,大大降低了传统阻塞模型中线程对于操作系统的开销。因此相比较传统的阻塞模型,异步模型能够很大层度的提高系统的并发量。
    • Vert.x除了异步之外,还提供了非常多的吸引人的技术,比如EventBus,通过EventBus可以非常简单的实现分布式消息,进而为分布式系统调用,微服务奠定基础。除此之外,还提供了对多种客户端的支持,比如RedisRabbitMQKafka等等。
    • 多语言使用
    • Java版本实现HTTP服务
    public class MyHttpServer extends AbstractVerticle {
        public static void main(String[] args) {
            // 创建服务
            MyHttpServer verticle = new MyHttpServer();
            Vertx vertx = Vertx.vertx();
            // 部署服务,会执行MyHttpServer的start方法
            vertx.deployVerticle(verticle);
        }
        @Override
        public void start() throws Exception {
            // 在这里可以通过this.vertx获取到当前的Vertx
            Vertx vertx = this.vertx;
            // 创建一个HttpServer
            HttpServer server = vertx.createHttpServer();
            server.requestHandler(request -> {
                // 获取到response对象
                HttpServerResponse response = request.response();
                // 设置响应头
                response.putHeader("Content-type", "text/html;charset=utf-8");
                // 响应数据
                response.end("SUCCESS");
            });
            // 指定监听80端口
            server.listen(80);
        }
    }
    
    • JavaScript实现HTTP服务
    vertx.createHttpServer()
    .requestHandler(function (req) {
        req.response()
        .putHeader("content-type", "text/plain")
        .end("Hello from ``Vert.x``!");
    }).listen(8080);
    
    • 另外还可以使用Groovy, Ruby, Ceylon, Scala , Kotlin;

    • 不依赖中间件

    • 完善的生态

    • 为微服务而生

    2. Vert.x 能做什么事情?

    Java能做的,Vert.x都能做。Node能做的Vert.x也能做

    • Web开发,Vert.x封装了Web开发常用的组件,支持路由Session管理模板等,可以非常方便的进行Web开发。重要的是不需要容器
    • TCP/UDP开发,Vert.x底层基于Netty,并且进行了完善的封装。
    • 原生提供了WebSocket的支持。
    • EventBus(事件总线)是Vert.x的神经系统,通过EventBus可以实现分布式消息,远程方法调用等等。正是因为EventBus的存在,Vert.x可以非常便捷的开发微服务应用。
    • 支持主流的数据和消息的访问redis,mongodb,rabbitmq,kafka

    3. 什么是异步编程?

    对于习惯使用springboot的我来说异步编程是一个新名词。异步编程是Vert.x的一大特性,也是Vert.x的核心。可以用Ajax来做类比。

    //$.ajax方法并不会阻塞,
    //而是直接向下执行,
    //等到远程服务器响应之后,才会回调success方法,
    //那么这时候success方法才会执行。
    //ajax下面的代码不会等到success方法执行完毕之后再执行
    console.log("1");
    $.ajax({
        "url" : "/hello",
        "type" : "post",
        "dataType" : "json",
        "success" : function(val) {
            console.log("2");
        }
    });
    console.log("3");
    

    类比Vert.x

    //可以看到是极为相似的
    System.out.println("1")
    WebClient
        .create(vertx)
        .postAbs(REQUEST_URL) // 这里指定的是请求的地址
        .sendBuffer(buffer, res -> { // buffer是请求的数据
            if (res.succeeded()) {  
                // 请求远程服务成功
                System.out.println("2")
            } else {
                // 请求失败
                resultHandler.handle(Future.failedFuture("请求服务器失败..."));
            }
        });
    System.out.println("3")
    

    4.性能

    • 先看图

    [站外图片上传中...(image-fa87bd-1560523010556)]


    错误率
    平均响应时间

    该测试使用jmeter完成,模拟一秒内10000用户同时发出http请求,服务端返回Json数据这样一个流程。第一套架构是Vert.x家族自己的Vert.x-web框架加上Vert.x-JDBC持久化框架;第二套是Vert.x-web与Spring Boot和JPA两个框架整合;第三套是传统的Spring MVC,Spring Boot和JPA框架。三个测试用例均为单http服务器,前两者是Vert.x自带的netty,后者是内嵌的Tomcat。数据库使用的是hsqldb内存数据库,连接池是hikariCP,最大连接数设置为100。Tomcat的线程池最大连接数设置为了1000,可以认为是已经设置到最大值了。出错时,报的错误均为java.net.ConnectException异常,错误消息为Connection refused: connect。应该是并发链接超过了上限,请求被拒绝了。

    从结果上看,第二套架构性能最优,其吞吐量约为第三套传统架构的3.3倍,错误率也相对较低,第一套虽然错误率高,单吞吐量也大幅超越了传统架构。因此在较为极限的并发测试下,Vert.x架构的性能较传统Spring Boot是有明显优势的。

    测试框架版本:
    Vert.x系列:3.5.1
    Spring Boot系列:1.5.10.RELEASE
    测试环境:
    OS:windows 7 64位
    CPU:英特尔 至强 E3-1231 V3
    内存:8G

    5.思考

    Vert.x确实非常好,把Java8的新特性用得淋漓尽致,而且从上面的性能分析来看,优于传统框架。

    • 但是:异步编程以及面向函数的思想和以前太不一样了。还有大量使用Java8的新特性。比如lambda表达式,可以简化匿名内部类的编写。所以要写好Vert.x你必须熟悉Java的新特性,不然写出来的代码难以维护。其次是Vert.x没有对关系型数据库的ORM支持,在传统开发种我们可以选择Hibernate或者是MyBatits这种ORM框架来对数据库进行操作。但Vert.x这方面就比较弱了,但也不是不能用只不过封装的比较浅。总之就是一句话,东西是好东西,就是用起来不习惯尤其是数据库操作很繁琐还有大量的匿名内部类。

    6.整合

    • 终于说到重点了,那就是springboot处理具体业务对接Vert.x的URL控制,而且上面的性能分析也指出这种模式比纯Vert.x还要好一点,而且兼顾了传统开发的语法,算是一种过渡,并且积极拥抱新技术,对Java新特性的理解也非常友好。

    • 首先建立一个springboot项目,并且去掉内置tomcat,我们使用Vert.x来接管路由。
      新建一个StaticServer类来创建一个http服务

    /**
     * 交给springboot管理周期
     */
    @Component
    public class StaticServer extends AbstractVerticle {
        private final AppConfiguration configuration;
        private final IServicePrint2Page iServicePrint2Page;
    
        @Autowired
        public StaticServer(AppConfiguration configuration, IServicePrint2Page iServicePrint2Page) {
            //加载配置文件
            this.configuration = configuration;
            this.iServicePrint2Page = iServicePrint2Page;
        }
        @Override
        public void start() {
            //创建路由对象
            Router router = Router.router(vertx);
            //获取整个消息体 放进RoutingContext
            router.route().handler(BodyHandler.create());
            //创建http服务
            HttpServer server = vertx.createHttpServer();
            //发送消息
            //如果后期添加上mybaitis需要用blockingHandler方法来执行操作
            //创建新的线程执行(一般用于执行阻塞调用)
            router.get("/text").blockingHandler(iServicePrint2Page::sendMsg);
            //启动监听
            server.requestHandler(router::accept).listen(configuration.httpPort());
        }
    
    
        /**
         * 结束的时候可以进行一些操作
         * <p>
         * throws Exception
         */
        @Override
        public void stop() throws Exception {
            super.stop();
        }
    }
    
    • 在SpringBoot启动类上添加initVerticle方法添加@PostConstruct注解来让SpringBoot启动的时候执行一次
    
        private final StaticServer staticServer;
        /****
         * 注入Http服务类
         * @param staticServer
         */
        @Autowired
        public SptingvertxApplication(StaticServer staticServer) {
            this.staticServer = staticServer;
        }
        /**
         * 部署Vertx方法
         * <p>
         * PostConstruct 修饰的方法会在服务器加载的时候运行,并且只会被服务器执行一次
         */
        @PostConstruct
        public void initVerticle() {
            Vertx.vertx().deployVerticle(staticServer);
        }
    

    7.EventBus

    • 它是Vert.X的核心,在集群中容器之间的通信,各个Verticle之间的通讯都是经过Event Bus来实现的

    • 概念

      • 寻址
        消息EventBus发送到一个字符串地址上(address)。任意字符串都是合法的。
      • 处理器
        消息在处理器(Handler)中被接收。您可以在某个地址上注册一个处理器来接收消息。
        同一个地址可以注册许多不同的处理器,一个处理器也可以注册在多个不同的地址上。(说人话就是:地址可以重复,并且向这个重复的地址发送消息的时候,所有用这个地址注册的Handler都会执行
      • EventBus发布消息
        消息将被发布到一个地址中,发布意味着会将信息传递给 所有 注册在该地址上的处理器。这和 发布/订阅模式 很类似。
    • 简要实现

    1. EventBus发送一条消息
    //唤起一个时间总线
    EventBus eventBus = routingContext.vertx().eventBus();
    //发布消息
    //地址上的所有方法都会收到消息
    //eventBus.send(
    //发送一个简单消息
    //如果使用send。就是点对点模式
    //消息将被发送到一个地址中,
    //Vert.x将会把消息分发到某个注册在该地址上的处理器。
    //若这个地址上有不止一个注册过的处理器,
    //它将使用 不严格的轮询算法 选择其中一个。
    eventBus.send(
        // 消息地址
        SpringVerticle.GET_HELLO_MSG_SERVICE_ADDRESS,
        // 消息内容
        "测试", info -> {//异步处理结果
        if (info.succeeded()) {
            //访问成功
            response.end(info.result().body().toString());
        } else {
            //访问失败
            response.setStatusCode(400).end(info.cause().toString());
        }
    });
    
    1. EventBus消息提取
    //唤起时间总线,注册一个事件处理者(时间消费者
    EventBus eventBus = this.vertx.eventBus();
    eventBus.consumer(GET_HELLO_MSG_SERVICE_ADDRESS).handler(msg -> {
        //获取时间内容吼,调用service服务
        System.out.println("eventBus里面的消息是" + msg.body());
        List<User> users = userService.getAll();
        //把结果返回消息体
        msg.reply(users.toString());
    });
    
    1. 注册执行端元
    //我们需要需要把这俩执行端元放在一个Vertx实例里面
    Vertx vertx = Vertx.vertx();
    //注册服务
    vertx.deployVerticle(staticServer);
    vertx.deployVerticle(springVerticle);
    

    参考

    Vert.x(vertx) 简明介绍

    Spring Boot同步架构与Vert.x异步架构高并发性能对比

    相关文章

      网友评论

        本文标题:Vert.x 入门以及与SpringBoot的一些联动

        本文链接:https://www.haomeiwen.com/subject/cawmfctx.html