At the heart of Vert.x is a set of Java APIs that we call Vert.x Core javascript
vert.x的核心是一個java api的集合 html
Repository. java
Vert.x core provides functionality for things like: node
核心提供瞭如下功能: react
Writing TCP clients and servers tcp的客戶端、服務端 git
Writing HTTP clients and servers including support for WebSockets http的 客戶端、服務端,支持websockets github
The Event bus 事件總線 web
Shared data - local maps and clustered distributed maps 本地、集羣共享數據 數據庫
Periodic and delayed actions 週期、延時的動做 api
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. |
建立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.
參數有不少選項例如設置集羣、高可用,池子的大小和其餘的設置,請參考其餘相關的文檔。
建立一個集羣的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的方式。
你是鏈式的嗎。
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();
不用調我,我來調你。
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的一些重要的概念
不要阻止我
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.
在如今的大部分系統裏併發場景是廣泛存在的,阻塞的模式缺乏伸縮性。
反應者和多反應者
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. |
黃金原則,不要阻塞事件循環
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.
若是你但願關掉這類的異常日誌,你能夠修改啓動參數。
執行阻塞耗時的代碼
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工做者一直被線程池裏一個線程執行