At the heart of Vert.x is a set of Java APIs that we call Vert.x Core
vert.x的核心是一个java api的集合
Vert.x core provides functionality for things like:
核心提供了以下功能:
-
Writing TCP clients and servers tcp的客户端、服务端
-
Writing HTTP clients and servers including support for WebSockets http的 客户端、服务端,支持websockets
-
The Event bus 事件总线
-
Shared data - local maps and clustered distributed maps 本地、集群共享数据
-
Periodic and delayed actions 周期、延时的动作
-
Deploying and undeploying Verticles 发布、卸载组件
-
Datagram Sockets 数据报的sockets
-
DNS client DNS客户端
-
File system access 文件系统
-
High availability 高可用
-
Clustering 集群
The functionality in core is fairly low level - you won’t find stuff like database access, authorisation or high level web functionality here - that kind of stuff you’ll find in Vert.x ext (extensions).
core里的功能是很低水平的,你将找不到类似数据库访问、授权、高级网络的功能在这里,这类的功能你可以在vertx ext里找
Vert.x core is small and lightweight. You just use the parts you want. It’s also entirely embeddable in your existing applications - we don’t force you to structure your applications in a special way just so you can use Vert.x.
vert.x core是小型、轻量的,你只用你想要的,它完全可以集成到你现有的系统里,我们不强迫你重构你的系统。
You can use core from any of the other languages that Vert.x supports. But here’a a cool bit - we don’t force you to use the Java API directly from, say, JavaScript or Ruby - after all, different languages have different conventions and idioms, and it would be odd to force Java idioms on Ruby developers (for example). Instead, we automatically generate an idiomatic equivalent of the core Java APIs for each language.
你可以使用任何vert.x支持的语言,我们不强迫你直接使用java api,javascript、ruby 还有其他语言的习惯,对应一个ruby开发者来说java语法是有些困难的。core对待任何一种语言都是平等的。
From now on we’ll just use the word core to refer to Vert.x core.
从现在开始我们Vert.x core来称为core。
If you are using Maven or Gradle, add the following dependency to the dependencies section of your project descriptor to access the Vert.x Core API:
如果你用的maven或gradle,增加下面的引用片段在你的项目里。
-
Maven (in your pom.xml):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>3.2.1</version>
</dependency>
-
Gradle (in your build.gradle file):
compile io.vertx:vertx-core:3.2.1
Let’s discuss the different concepts and features in core.
让我们讨论core的不用概念、和功能。
In the beginning there was Vert.x
NOTE |
Much of this is Java specific - need someway of swapping in language specific parts |
You can’t do much in Vert.x-land unless you can commune with a Vertx object!
你不用做任何事情,你就可以使用Vertx的对象。
It’s the control centre of Vert.x and is how you do pretty much everything, including creating clients and servers, getting a reference to the event bus, setting timers, as well as many other things.
它是vert.x的控制中心,你可以做很多事情,比如创建clients、服务端,获得事件总线、设置时间事件、等等很多其他的事情。
So how do you get an instance?
所以你如何获取一个实例呢?
If you’re embedding Vert.x then you simply create an instance as follows:
如果你集成了vert.x,你简单的写如下代码即可。
Vertx vertx = Vertx.vertx();
If you’re using Verticles
NOTE |
Most applications will only need a single Vert.x instance, but it’s possible to create multiple Vert.x instances if you require, for example, isolation between the event bus or different groups of servers and clients. |
Specifying options when creating a Vertx object
创建vertx对象设置特殊参数。
When creating a Vertx object you can also specify options if the defaults aren’t right for you:
当你创建一个vertx对象,如果默认值不合适,你也可以设置特殊的参数。
Vertx vertx = Vertx.vertx(new VertxOptions().setWorkerPoolSize(40));
The VertxOptions object has many settings and allows you to configure things like clustering, high availability, pool sizes and various other settings. The Javadoc describes all the settings in detail.
参数有很多选项例如设置集群、高可用,池子的大小和其他的设置,请参考其他相关的文档。
Creating a clustered Vert.x object
创建一个集群的vertx对象。
If you’re creating a clustered Vert.x (See the section on the event bus for more information on clustering the event bus), then you will normally use the asynchronous variant to create the Vertx object.
如果你要创建一个集群的vert.x,这是你通常可以用异步创建的方式创建。
This is because it usually takes some time (maybe a few seconds) for the different Vert.x instances in a cluster to group together. During that time, we don’t want to block the calling thread, so we give the result to you asynchronously.
因为它通常要消耗一定时间,在集群上设置分组等,这个时候我们不希望阻止调用线程,所以我们提供一种异步返回result的方式。
Are you fluent?
你是链式的吗。
You may have noticed that in the previous examples a fluent API was used.
你或许发现上面的例子用了链式的api。
A fluent API is where multiple methods calls can be chained together. For example:
一个链式的api是多个方法被链式调用,例如:
request.response().putHeader("Content-Type", "text/plain").write("some text").end();
This is a common pattern throughout Vert.x APIs, so get used to it.
这是一个通用模式在vert.xapi里,所以要习惯这样用。
Chaining calls like this allows you to write code that’s a little bit less verbose. Of course, if you don’t like
链式调用就不是很啰嗦。当然你如果不喜欢
the fluent approach we don’t force you to do it that way, you can happily ignore it if you prefer and write your code like this:
链式的写法,我们也不强迫你这样,你可以高兴的忽略这段,你可以写的像这样。
HttpServerResponse response = request.response();
response.putHeader("Content-Type", "text/plain");
response.write("some text");
response.end();
Don’t call us, we’ll call you.
不用调我,我来调你。
The Vert.x APIs are largely event driven. This means that when things happen in Vert.x that you are interested in, Vert.x will call you by sending you events.
这个vert.x主要是事件驱动,这意味着你感兴趣的vert.x会通过事件方式调用你。
Some example events are:
-
a timer has fired 时间事件
-
some data has arrived on a socket, socket收到数据
-
some data has been read from disk 从硬盘读到数据
-
an exception has occurred 异常产生
-
an HTTP server has received a request http服务收到请求
You handle events by providing handlers to the Vert.x APIs. For example to receive a timer event every second you would do:
你的事件处理程序提供给vertx,例如1秒收到一个事件。
vertx.setPeriodic(1000, id -> { // This handler will get called every second System.out.println("timer fired!");
});
Or to receive an HTTP request:
一个http请求
server.requestHandler(request -> { // This handler will be called every time an HTTP request is received at the server request.response().end("hello world!");
});
Some time later when Vert.x has an event to pass to your handler Vert.x will call it asynchronously.
vertx传递事件给你是异步的有一定的耗时。
This leads us to some important concepts in Vert.x:
让我们了解vertx的一些重要的概念
Don’t block me!
不要阻止我
With very few exceptions (i.e. some file system operations ending in 'Sync'), none of the APIs in Vert.x block the calling thread.
带有少量异常, vert.x里的api没有阻止线程的
If a result can be provided immediately, it will be returned immediately, otherwise you will usually provide a handler to receive events some time later.
如果结果可以马上提供,它会马上返回,其他情况你将提供一个handler异步延时接受。
Because none of the Vert.x APIs block threads that means you can use Vert.x to handle a lot of concurrency using just a small number of threads.
因为vert.x的api不阻塞线程,意味着你仅仅使用少量的线程就可以用vert.x处理大量的并发。
With a conventional blocking API the calling thread might block when:
使用传统的阻塞api调用线程会受到阻塞在以下场景:
-
Reading data from a socket 从socket读取数据
-
Writing data to disk 写数据
-
Sending a message to a recipient and waiting for a reply. 发送消息等待反馈
-
… Many other situations 其他的解决方案
In all the above cases, when your thread is waiting for a result it can’t do anything else - it’s effectively useless.
以上场景你的线程在等待反回结果,它不能做其他的事情,它的效率是低的。
This means that if you want a lot of concurrency using blocking APIs then you need a lot of threads to prevent your application grinding to a halt.
这意味着你要大的并发,使用阻塞的api你需要大量的线程,以防止你的系统停止工作。
Threads have overhead in terms of the memory they require (e.g. for their stack) and in context switching.
可是线程在上下文里也有大量的内存占用、却换开销
For the levels of concurrency required in many modern applications, a blocking approach just doesn’t scale.
在现在的大部分系统里并发场景是普遍存在的,阻塞的模式缺少伸缩性。
Reactor and Multi-Reactor
反应者和多反应者
We mentioned before that Vert.x APIs are event driven - Vert.x passes events to handlers when they are available.
我们之前提到的vert.x api 是事件驱动,vert.x发送事件到处理者上。
In most cases Vert.x calls your handlers using a thread called an event loop.
大部分场景 vert.x 通过一个线程的事件循环调处理者
As nothing in Vert.x or your application blocks, the event loop can merrily run around delivering events to different handlers in succession as they arrive.
任何vert.x和你的系统没有阻塞,事件循环快乐的提供事件到不同的处理者。
Because nothing blocks, an event loop can potentially deliver huge amounts of events in a short amount of time. For example a single event loop can handle many thousands of HTTP requests very quickly.
因为没有阻塞,事件循环可以在短时间内处理大量的事件。例如一个事件循环可以非常快的处理成千上万的http请求
We call this the Reactor Pattern.
我们成为反应器模式
You may have heard of this before - for example Node.js implements this pattern.
你或许请说过这个,例如nodejs实现了这个模式。
In a standard reactor implementation there is a single event loop thread which runs around in a loop delivering all events to all handlers as they arrive.
在一个标准的反应器实现里有一个事件循环来处理所有的事件。
The trouble with a single thread is it can only run on a single core at any one time, so if you want your single threaded reactor application (e.g. your Node.js application) to scale over your multi-core server you have to start up and manage many different processes.
问题是这样的单线程只能单独跑在一个内核上,所以如果你单线程反应器例如nodejs可以在多核的服务区上可以伸缩,你需要启动不同的进程。
Vert.x works differently here. Instead of a single event loop, each Vertx instance maintains several event loops. By default we choose the number based on the number of available cores on the machine, but this can be overridden.
vert.x的不同就在这里,而不是单个事件循环,每个vert.x实例保持着几个事件循环,默认我们可以设置个数量,基于有效的内核数量。
This means a single Vertx process can scale across your server, unlike Node.js.
这意味着单个vert.x进程可以伸缩扩展你的服务器,不像node.js。
We call this pattern the Multi-Reactor Pattern to distinguish it from the single threaded reactor pattern.
我们称为这个为多反应器模式来区分单反应器模式。
NOTE |
Even though a Vertx instance maintains multiple event loops, any particular handler will never be executed concurrently, and in most cases (with the exception of worker verticles) will always be called using the exact same event loop. |
The Golden Rule - Don’t Block the Event Loop
黄金原则,不要阻塞事件循环
We already know that the Vert.x APIs are non blocking and won’t block the event loop, but that’s not much help if you block the event loop yourself in a handler.
我们知道vert.x不会阻塞事件循环,但是如果你的处理程序是阻塞,也没什么帮助。
If you do that, then that event loop will not be able to do anything else while it’s blocked. If you block all of the event loops in Vertx instance then your application will grind to a complete halt!
如果你这样做,事件循环将什么都不能做当阻塞的时候,如果你阻塞了所有事件,你的应用就停止了。
So don’t do it! You have been warned.
所以不能这样做,你会收到警告。
Examples of blocking include:
阻塞的例子
-
Thread.sleep() 线程睡眠
-
Waiting on a lock 等一个锁
-
Waiting on a mutex or monitor (e.g. synchronized section) 等一个互斥
-
Doing a long lived database operation and waiting for a result 长时间的db操作
-
Doing a complex calculation that takes some significant time. 复杂的计算
-
Spinning in a loop 循环中循环
If any of the above stop the event loop from doing anything else for a significant amount of time then you should go immediately to the naughty step, and await further instructions.
在以上行为中阻塞了事件循环,你应该找到耗时的地方,用further的方式解决
So… what is a significant amount of time?
所以什么是耗时
How long is a piece of string? It really depends on your application and the amount of concurrency you require.
一个字符会有多长?这个取决于你的系统里的并发量。
If you have a single event loop, and you want to handle 10000 http requests per second, then it’s clear that each request can’t take more than 0.1 ms to process, so you can’t block for any more time than that.
你有个时间循环,你想每秒处理10000个请求,这样每个请求的处理时间要小于0.1ms,所以你不能阻塞任何一个时间段。
The maths is not hard and shall be left as an exercise for the reader.
数学并不难,我们做个练习
If your application is not responsive it might be a sign that you are blocking an event loop somewhere. To help you diagnose such issues, Vert.x will automatically log warnings if it detects an event loop hasn’t returned for some time. If you see warnings like these in your logs, then you should investigate.
你个系统如果没有响应或许在某个地方你正在阻塞这事件循环,为了帮助你解决这个问题,vert.x会自动输出log异常,如果它发现事件循环比较耗时。如果你收到这类的警告,你应该调查分析你的程序。
Thread vertx-eventloop-thread-3 has been blocked for 20458 ms
Vert.x will also provide stack traces to pinpoint exactly where the blocking is occurring.
vert.x也会输出堆栈告诉你阻塞产生了。
If you want to turn of these warnings or change the settings, you can do that in the VertxOptionsobject before creating the Vertx object.
如果你希望关掉这类的异常日志,你可以修改启动参数。
Running blocking code
执行阻塞耗时的代码
In a perfect world, there will be no war or hunger, all APIs will be written asynchronously and bunny rabbits will skip hand-in-hand with baby lambs across sunny green meadows.
完美的时间是没有战争、饥饿,api异步、兔子蹦蹦跳跳、羊羔在阳光明媚的草原上吃草。
But… the real world is not like that. (Have you watched the news lately?)
但是 ……现实不是这样的。你看最近的新闻了吗?
Fact is, many, if not most libraries, especially in the JVM ecosystem have synchronous APIs and many of the methods are likely to block. A good example is the JDBC API - it’s inherently synchronous, and no matter how hard it tries, Vert.x cannot sprinkle magic pixie dust on it to make it asynchronous.
事实是,不是大部分库,大量的jvm系统存在同步的api,大量的方法是阻塞的,一个很好的例子jdbc的api,它是同步的,无论如何强大,vert.x也不能变魔法般的把它变成异步的。
We’re not going to rewrite everything to be asynchronous overnight so we need to provide you a way to use "traditional" blocking APIs safely within a Vert.x application.
我们不打算把所有的重写为异步的,所以我们提供一个安全的方式把传统的、阻塞的整合到vert.x里。
As discussed before, you can’t call blocking operations directly from an event loop, as that would prevent it from doing any other useful work. So how can you do this?
之前讨论过,我们为了处理业务,不能阻塞事件循环,所以我们该如何做呢?
It’s done by calling executeBlocking specifying both the blocking code to execute and a result handler to be called back asynchronous when the blocking code has been executed.
通过执行executeBlocking,等待执行完成返回结果。
vertx.executeBlocking(future -> { // Call some blocking API that takes a significant amount of time to return String result = someAPI.blockingMethod("hello");
future.complete(result);
}, res -> {
System.out.println("The result is: " + res.result());
});
By default, if executeBlocking is called several times from the same context (e.g. the same verticle instance) then the different executeBlocking are executed serially (i.e. one after another).
默认,如果当前会话中某执行代码块儿被执行了多次,希望顺序执行。
If you don’t care about ordering you can call executeBlocking specifying false as the argument toordered. In this case any executeBlocking may be executed in parallel on the worker pool.
如果你不关心执行顺序,可以设置toordered参数为false,这样阻塞的代码就可以并行的被处理。
An alternative way to run blocking code is to use a worker verticle
一个替代的方式解决就是用verticle的工作者模式。
A worker verticle is always executed with a thread from the worker pool.
一个verticle工作者一直被线程池里一个线程执行
来源:oschina
链接:https://my.oschina.net/u/96029/blog/662480