Vert.x in Action

- 9 mins

What is Vert.x ?

Vert.x is a tool-kit for building reactive applications on the JVM.

Maven 构建 Verticle 并部署

使用 maven-shade-plugin 插件构建 fat-jar 包,包含了所有依赖,可以独立运行的包

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.3</version
        <executions>
            <execution>
               <phase>package</phase>
               <goals>
                   <goal>shade</goal>
               </goals>
               <configuration>
                   <transformers>
                       <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                           <manifestEntries>
                               <Main-Class>io.vertx.core.Launcher</Main-Class>
                               <Main-Verticle>${main.verticle}</Main-Verticle>
                           </manifestEntries>
                       </transformer>
                       <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                           <resource>META-INF/services/io.vertx.core.spi.VerticleFactory</resource>
                       </transformer>
                   </transformers>
                   <artifactSet>
                   </artifactSet>
                   <outputFile>${project.build.directory}/${project.artifactId}-${project.version}-fat.jar</outputFile>
               </configuration>
            </execution>
        </executions>
    </plugin>
    mvn clean package

运行 fat-jar

    java -jar target/maven-verticle-3.4.2-fat.jar

通过 -instances 参数部署多个 Verticle 实例,释放多核的能力

    java -jar target/maven-verticle-3.4.2-fat.jar -instances 8

通过 -cluster && -ha 参数部署 Verticle 实例,开启集群和高可用模式

    java -jar target/maven-verticle-3.4.2-fat.jar -cluster
    java -jar target/maven-verticle-3.4.2-fat.jar -ha

通过 -conf 参数部署 Verticle 实例,动态加载配置文件

    java -jar target/maven-verticle-3.4.2-fat.jar -conf src/conf/conf.json

BlockingHandler & ExecuteBlocking vs WorkerVerticle

每一个阻塞的耗时操作单独 deploy 一个 worker verticle 处理,一个 worker verticle 一直被线程池中的一个线程执行。

ExecuteBlocking 示例

    vertx.createHttpServer().requestHandler(request -> vertx.<String>executeBlocking(future -> {
            // do blocking operation
            try {
                Thread.sleep(500);
            } catch (Exception e) {
                // ignore
            }

            String result = "jiangew";
            future.complete(result);
        }, res -> {
            if (res.succeeded()) {
                request.response().putHeader("content-type", "text/plain").end(res.result());
            } else {
                res.cause().printStackTrace();
            }
        })).listen(8080);

BlockingHandler 示例

        // blocking handler && ordered false && future
        router.get("/chaptersAsync").blockingHandler(this::handleGetChaptersAsync, false).failureHandler(this::handleWorkerTimeout);

动态部署 Verticle 实例

通过动态部署 Verticle 实例,可以指定 DeploymentOptions 的各种属性,可以对比 VertxOptions,包括 workerPoolSize, isWorker, isHA 等。

        // different ways of deploying verticles
        // 01 deploy a verticle and do not wait for it to start
        vertx.deployVerticle("com.qq.reader.ts.verticle.DownloadVerticle");

        // 02 deploy a verticle and wait for it to start
        vertx.deployVerticle("com.qq.reader.ts.verticle.DownloadVerticle", res -> {
            if (res.succeeded()) {
                String deployId = res.result();
                System.out.println("DeployVerticle deployed ok, deployId = " + deployId);
            }
        });

        // 03 deploy a verticle with options
        int core = Runtime.getRuntime().availableProcessors();
        vertx.deployVerticle("com.qq.reader.ts.verticle.DownloadVerticle",
                new DeploymentOptions()
                        .setInstances(core)
                        .setHa(true)
                        .setWorkerPoolName("vertx-work-pool-ts")
                        .setWorkerPoolSize(core * 50)
                        .setMaxWorkerExecuteTime(VertxOptions.DEFAULT_MAX_WORKER_EXECUTE_TIME)
        );    

日志

可以通过启动 Vert.x 实例时,动态设置环境变量加载日志实例。

/**
 * Author: Jiangew
 * Date: 20/07/2017
 */
public class Launcher extends io.vertx.core.Launcher {

    public static void main(String[] args) {
        // Force to use slf4j
        System.setProperty("vertx.logger-delegate-factory-class-name", "io.vertx.core.logging.SLF4JLogDelegateFactory");

        new Launcher().dispatch(args);
    }

    @Override
    public void beforeStartingVertx(VertxOptions options) {
        // Start dropwizard monitor
        options.setMetricsOptions(
                new DropwizardMetricsOptions()
                        .setEnabled(true)
                        .setJmxEnabled(true)
                        .setJmxDomain("vertx-metrics-minerva")
        );
    }

}

Vert.x 运行时性能指标监控「Dropwizard && Jolokia && Hawtio」

关于 Vert.x 运行态的性能监控,官方提供了 Dropwizard 和 Hawkular 两种开箱即用的工具。本人实践了使用 Dropwizard Metrics 实现 Vert.x 性能统计的过程「当然踩了很多坑」。
开启 Vert.x 的 Metrics 监控有两种方式,如下:

通过运行 fat-jar 时指定参数

    java -jar xxx-fat.jar
    -Dvertx.metrics.options.enabled=true
    -Dvertx.metrics.options.jmxEnabled=true
    -Dvertx.metrics.options.jmxDomain=vertx-metrics-jew

通过设置 VertxOptions 属性

要想通过 VertxOptions 属性赋值方式,需要想办法自定义 Vertx 实例,因为运行时 Vertx 实例已经初始化完成,无法修改 VertxOptions 各属性值。由于项目框架搭建时,我是使用 Main Verticle 去动态 deploy 业务 Verticle,这样可以给业务 Verticle 通过 DeploymentOptions 指定 instances、workPoolSize、ha、cluster 等指标,所以最终选择了扩展 Launcher 启动类来实现。方式如下:

public class Launcher extends io.vertx.core.Launcher {

    public static void main(String[] args) {
        new Launcher().dispatch(args);
    }

    @Override
    public void beforeStartingVertx(VertxOptions options) {
        // Start dropwizard monitor
        options.setMetricsOptions(
                new DropwizardMetricsOptions()
                        .setEnabled(true)
                        .setJmxEnabled(true)
                        .setJmxDomain("vertx-metrics-jew")
        );
    }

}

动态部署 Verticle 实例,并指定 instances、workPoolSize、ha、cluster 等指标。

public class DeployVerticle extends AbstractVerticle {

    public static void main(String[] args) {
        Runner.runExample(DeployVerticle.class);
    }

    @Override
    public void start() {
        System.out.println("Main verticle has started, let's deploy some others ...");

        // 03 deploy a verticle with options
        int core = Runtime.getRuntime().availableProcessors();
        vertx.deployVerticle("com.qq.reader.ts.verticle.DownloadVerticle",
                new DeploymentOptions()
                        .setInstances(core)
                        .setHa(true)
                        .setWorkerPoolName("vertx-work-pool-ts")
                        .setWorkerPoolSize(core * 50)
                        .setMaxWorkerExecuteTime(VertxOptions.DEFAULT_MAX_WORKER_EXECUTE_TIME)
        );

    }
}

别忘了 maven 依赖

    <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-dropwizard-metrics</artifactId>
            <version>${vertx.version}</version>
    </dependency>

下载 Jolokia,用来获取运行时 Vert.x 实例的性能指标

去官网下载 jolokia agent 包,通过「java -javaagent:」方式运行 fat-jar Vert.x 项目,并启动 Jolokia 监控,设置 jolokia 端口和 Vert.x 实例的 host,jolokia-agent.jar 务必是绝对路径。

    java -javaagent:/.../jolokia-jvm-1.3.7-agent.jar=port=8888,host=localhost -jar xxx-fat.jar

    java -javaagent:/.../jolokia-jvm-1.3.7-agent.jar=port=8888,host=localhost -jar xxx-fat.jar
    -Dvertx.metrics.options.enabled=true
    -Dvertx.metrics.options.jmxEnabled=true
    -Dvertx.metrics.options.jmxDomain=vertx-metrics-jew

参数设置:
Dropwizard Metrics 用于指标收集
Jmx 暴露桥接接口
Jolokia 提供指标数据 Rest 接口
备注:部署到服务器环境时,不要忘记把 Host「local」换成「0.0.0.0」,否则内部端口不同,不能外部监听端口。

下载 Hawtio,Hawtio 可以远程连接 Jolokia,以图形化形式监控 Vert.x 运行时状态

去官网 hawtio app 包,下载有两种方式启动 Hawtio,一种是以 jar 包的形式运行,一种是以 war 包的形式运行。
jar 包方式启动,指定一个未被占用的端口。

    java -jar hawtio-app-1.5.2.jar -p 9999

基于 Tomcat 部署监控图形化

war 包方式启动,将下载的 hawtio-default-1.5.2.war 重命名为 hawtio.war,放入 tomcat 的 webapps 目录,重新启动 tomcat 即可通过 http://localhost:8080/hawtio/ 来访问。
修改 tomcat 监听和转发端口配置,「tomcat/conf/server.xml」:

    <Connector port="9999" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

开启 Tomcat 登录鉴权

修改 tomcat 鉴权用户配置,「tomcat/conf/tomcat-users.xml」:

    <role rolename="manager"/>
    <user username="jiangew" password="123456" roles="manager"/>

开启 tomcat 鉴权有两种方式,一种是通过在 tomcat 启动脚本中加入环境变量设置,一种是修改 hawtio 的配置文件。
方式一:修改 tomcat 启动脚本,在「tomcat/bin/catalina.sh」中加入:

    export CATALINA_OPTS='-Dhawtio.authenticationEnabled=true -Dhawtio.role=manager'

方式二:修改部署在 tomcat 中的 hawtio war 的配置文件,在「tomcat/webapps/hawtio/WEB-INF/web.xml」中修改:

    <env-entry>
        <description>Enable/disable hawtio's authentication filter, value is really a boolean</description>
        <env-entry-name>hawtio/authenticationEnabled</env-entry-name>
        <env-entry-type>java.lang.String</env-entry-type>
        <env-entry-value>true</env-entry-value>
    </env-entry>

    <env-entry>
        <description>Authorized user role, empty string disables authorization</description>
        <env-entry-name>hawtio/role</env-entry-name>
        <env-entry-type>java.lang.String</env-entry-type>
        <env-entry-value>manager</env-entry-value>
    </env-entry>

还可以设置 jolokia agent 代理服务器 ip 白名单:

    <servlet>
        <servlet-name>jolokia-proxy</servlet-name>
        <servlet-class>io.hawt.web.ProxyServlet</servlet-class>
        <init-param>
            <param-name>proxyWhitelist</param-name>
            <param-value>
                localhost,
                127.0.0.1,
                10.211.0.199,
                10.211.0.211
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>jolokia-proxy</servlet-name>
        <url-pattern>/proxy/*</url-pattern>
    </servlet-mapping>

图形化监控面板示例

图形化监控界面启动后,设置监控信息,并保存,可以看到各个维度的监控数据,很赞。。。
Portal Menu

配置 Vert.x 监控实例

配置指定 Port 和 Host

JMX Metrics 监控

Dashboard

Using Jolokia and JMX4Perl to expose metrics to Nagios

    java -javaagent:/.../jolokia-jvm-1.3.7-agent.jar=port=8888,host=localhost -jar xxx-fat.jar ...
    check_jmx4perl --url http://127.0.0.1:8888/jolokia --name eventloops --mbean vertx:name=vertx.event-loop-size --attribute Value --warning 4

Jolokia && Hawtio 监控参考

健康检查「Health Checks」

数据打点统计「Hawkular && Cassandra && Grafana」

comments powered by Disqus
rss github weibo twitter instagram pinterest facebook linkedin stackoverflow reddit quora mail