由于 Elasticsearch(后文簡稱es) 的簡單易用及其在大數(shù)據(jù)處理方面的良好性能,越來越多的公司選用 es 作為自己的業(yè)務解決方案。然而在引入新的解決方案前,不免要做一番調(diào)研和測試,本文便是介紹官方的一個 es 壓測工具 esrally,希望能為大家?guī)韼椭?/p>
為什么要壓測?
關(guān)于壓測,我們先來看下百度百科上的一個定義。
壓測,即壓力測試,是確立系統(tǒng)穩(wěn)定性的一種測試方法,通常在系統(tǒng)正常運作范圍之外進行,以考察其功能極限和隱患。
從定義不難看出壓測的目的,是要測出一個系統(tǒng)的極限,提早發(fā)現(xiàn)隱患,早作打算。那么對于 es 來講,我認為壓測一般有以下幾個目的:
- 驗證 es 的性能,盡管網(wǎng)上把 es 的性能夸上天了,還是自己跑一下才放心。
- 針對 es 的某些配置做試驗性測試,比如關(guān)閉索引的 _all 特性,是否能提高寫性能,具體能提高多少。
- 對比 es 新版本和舊版本的性能差異。眾所周知,es 的版本升級非???,用著 2.x 的同學們還沒來得及升級 5.x ,眼看 6.x 都要發(fā)布了。此時,你到底要不要升級呢?答案雖然是肯定的,但是你怎么說服你的 leader 呢?很簡單:壓測新版本,和舊版本做對比,用表格、圖表指明新版本在寫性能、讀性能方面的改善等等,搞定。
- 對 es 集群做容量規(guī)劃。俗話說“人無遠慮,必有近憂”,容量規(guī)劃就是“遠慮”。簡單講就是你線上的 es 集群一共需要多少節(jié)點?每個節(jié)點的配置如何?這個集群的寫性能極限是多少?讀性能呢?如果你回答不了這些問題,那就說明你沒有做過容量規(guī)劃,只是兩眼一抹黑,說干就干,上了再說,好在有驚無險,沒有碰到性能問題。至于什么時候會遇到問題,你也說不準,感覺是個概率和人品問題……對面的老板已經(jīng)黑臉了…… 對于這個問題我們在最后再來詳細討論。
如何進行壓測?
現(xiàn)在我們知道壓測的目的了,接下來該如何進行壓測呢?一般有以下幾個方案:
- 自己寫代碼。無需多言,想怎么寫怎么寫,難點在于如果確保測試代碼的專業(yè)性。這里有一些開源項目,留給大家自己探索:esperf 和 elasticsearch-stress-test
- http壓測工具。es 對外暴露了 Restful API,因此所有的針對 http 協(xié)議的壓測工具都可以用來測試 es,比如 JMeter、httpload等等。
- elastic 官方工具 esrally。
各個壓測方案各有優(yōu)劣,大家可以根據(jù)自己的需求和工具熟悉度來選擇自己的壓測工具。接下來我們就來具體了解下 esrally。
入門
簡介
esrally 是 elastic 官方開源的一款基于 python3 實現(xiàn)的針對 es 的壓測工具,源碼地址為https://github.com/elastic/rally,相關(guān)博客介紹在這里。esrally主要功能如下:
- 自動創(chuàng)建、壓測和銷毀 es 集群
- 可分 es 版本管理壓測數(shù)據(jù)和方案
- 完善的壓測數(shù)據(jù)展示,支持不同壓測之間的數(shù)據(jù)對比分析,也可以將數(shù)據(jù)存儲到指定的es中進行二次分析
- 支持收集 JVM 詳細信息,比如內(nèi)存、GC等數(shù)據(jù)來定位性能問題
elastic 官方也是基于 esrally 進行 es 的性能測試,并將結(jié)果實時發(fā)布到 https://elasticsearch-benchmarks.elastic.co/ ,大家可以從該網(wǎng)站上直接查看 es 的性能。官方使用兩臺服務器進行壓測,一臺運行 esrally ,一臺運行 es,服務器的配置如下:
CPU: Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz
RAM: 32 GB
SSD: Crucial MX200
OS: Linux Kernel version 4.8.0-53
JVM: Oracle JDK 1.8.0_131-b11
網(wǎng)站頂部的 Geonames、Geopoint、Percolator等都是針對不同的數(shù)據(jù)集做的壓測,比如下面這些圖展示了 logging 日志類數(shù)據(jù)的壓測結(jié)果。



快速入門
esrally 的文檔在這里,這里簡單說下安裝與運行。
esrally 對于軟件環(huán)境的要求如下:
- Python 3.4+ 和 pip3
- JDK 8
- git 1.9+
安裝方法為:
pip3 install esrally
Tips:
可以使用國內(nèi)的pip源,比如豆瓣或者阿里的,這樣安裝會快很多。
安裝完畢后執(zhí)行如下的配置命令,確認一些數(shù)據(jù)存放的路徑即可。
esrally configure
接下來就可以開跑了,比如下面這條命令是針對 es 5.0.0 版本進行壓力測試。
esrally --distribution-version=5.0.0
運行結(jié)束后,會得到如下的結(jié)果。

對于第一次見到壓測結(jié)果的同學來說可能有些暈,這么多數(shù)據(jù),該怎么看?!別急,一步步來!
Tips:
由于 esrally 的測試數(shù)據(jù)存儲在國外 aws 上,導致下載很慢甚至會超時失敗,從而導致整個壓測無法進行。后面我會把這些測試數(shù)據(jù)的壓縮包放到國內(nèi),大家可以下載后直接放到 esrally 的數(shù)據(jù)文件夾下面,保證壓測的正常進行。另外由于數(shù)據(jù)量過大,壓測的時間一般會很久,可能在1個小時左右,所以大家要有耐心哦~
如果你只是想體驗下,可以加上 --test-mode 的參數(shù),此時只會下載1000條文檔進行測試。
相關(guān)術(shù)語
rally 是汽車拉力賽的意思,也就是說 esrally 是將壓測比作了汽車拉力賽,因此其中的很多術(shù)語都是從汽車拉力賽中借鑒來的。
track
track 是賽道的意思,在這里是指壓測用的數(shù)據(jù)和測試策略,詳細文檔在這里。esrally 自帶的track都在 github 上,地址在這里 https://github.com/elastic/rally-tracks。在該 repository 中,有很多測試數(shù)據(jù),比如 geonames geopoint logging nested 等,每個數(shù)據(jù)文件夾中的 README.md 中有詳細的數(shù)據(jù)介紹,而 track.json 便是壓測策略的定義文件。
我們來看下 loggins/track.json 文件
{% import "rally.helpers" as rally with context %}
{
"short-description": "Logging benchmark",
"description": "This benchmark indexes HTTP server log data from the 1998 world cup.",
"data-url": "http://benchmarks.elasticsearch.org.s3.amazonaws.com/corpora/logging",
"indices": [
{
"name": "logs-181998",
"types": [
{
"name": "type",
"mapping": "mappings.json",
"documents": "documents-181998.json.bz2",
"document-count": 2708746,
"compressed-bytes": 13815456,
"uncompressed-bytes": 363512754
}
]
},
{
"name": "logs-191998",
"types": [
{
"name": "type",
"mapping": "mappings.json",
"documents": "documents-191998.json.bz2",
"document-count": 9697882,
"compressed-bytes": 49439633,
"uncompressed-bytes": 1301732149
}
]
}
],
"operations": [
{{ rally.collect(parts="operations/*.json") }}
],
"challenges": [
{{ rally.collect(parts="challenges/*.json") }}
]
}
該 json 文件主要包含下面幾個部分:
- description 和 short-description: track 的描述文字
- data-url: 一個url地址,指明測試數(shù)據(jù)的下載根路徑,與下方 indices 中的 documents 結(jié)合,可得到數(shù)據(jù)的下載地址。
- indices: 指定該track可以操作的索引,包括創(chuàng)建、更新、刪除等操作。詳細信息可以參見這里。
- operations: 指定具體的操作,比如 index 索引數(shù)據(jù)的操作、force-merge 強制合并segment的操作、search 搜索的操作等等。具體例子可以看下面的示例。詳細信息可以參見這里。
- challenges: 通過組合 operations 定義一系列 task ,再組合成一個壓測的流程,請參照下方的 例子。詳細信息可以參見這里。
operations/default.json 中的一個定義如下:
{
"name": "index-append",
"operation-type": "index",
"bulk-size": 5000
}
其中 operation-type 包含 index、force-merge、index-stats、node-stats、search等,每一個operation-type都有自己的可定義參數(shù),比如 index 中可以通過指定 bulk-size 來決定批量寫入的文檔數(shù)。
challenges/default.json 中的一個定義如下:
{
"name": "append-no-conflicts",
"description": "",
"default": true,
"index-settings": {
"index.number_of_replicas": 0
},
"schedule": [
{
"operation": "index-append",
"warmup-time-period": 240,
"clients": 8
},
{
"operation": "force-merge",
"clients": 1
},
{
"operation": "index-stats",
"clients": 1,
"warmup-iterations": 100,
"iterations": 100,
"target-throughput": 50
},
{
"operation": "node-stats",
"clients": 1,
"warmup-iterations": 100,
"iterations": 100,
"target-throughput": 50
},
{
"operation": "default",
"clients": 1,
"warmup-iterations": 100,
"iterations": 500,
"target-throughput": 10
},
{
"operation": "term",
"clients": 1,
"warmup-iterations": 100,
"iterations": 500,
"target-throughput": 60
},
{
"operation": "range",
"clients": 1,
"warmup-iterations": 100,
"iterations": 200,
"target-throughput": 2
},
{
"operation": "hourly_agg",
"clients": 1,
"warmup-iterations": 100,
"iterations": 100,
"target-throughput": 0.2
},
{
"operation": "scroll",
"clients": 1,
"warmup-iterations": 100,
"iterations": 200,
"target-throughput": 10
}
]
}
這里定義了一個名為 append-no-conflicts 的 challenge。由于每次壓測只能運行一個challenge,這里的 default 參數(shù)是指當壓測未指定時默認運行的 challenge。schedule 中指定了該 challenge 中按順序執(zhí)行 index-append、force-merge、index-stats、node-stats、default、term、range、hourly_agg、scroll 等 9 個task,其中每個 task 都指定了 一個 operation,除此之外還可以設(shè)定 clients (并發(fā)客戶端數(shù))、warmup-iterations(預熱的循環(huán)次數(shù))、iterations(operation 執(zhí)行的循環(huán)次數(shù))等,詳情請參見此處。
通過下面的命令可以查看當前 esrally 可用使用的track。
esrally list tracks
esrally 的 track 數(shù)據(jù)位于 rally 目錄(mac默認是 ~/.rally)中 benchmarks/tracks/ 下面。
car
car 是賽車的意思,這里是指不同配置的 es 實例。通過下面的命令可以查看 esrally 當前可用的 car。
esrally list cars
Name
----------
16gheap
1gheap
2gheap
4gheap
8gheap
defaults
ea
verbose_iw
cars 的配置位于 rally 目錄(mac默認是 ~/.rally)中 benchmarks/teams/default/cars/ 下面。具體配置可以參見 cars 的文檔,除了 heap 的配置,所有的 es 配置都可以修改。
race
race 是一次比賽的意思,這里是指某一次壓測。要比賽,就要有賽道和賽車,如果不指定賽車,就用 default 配置,如果不指定賽道,則默認使用 geonames track。通過下面的命令來執(zhí)行一次 race。
esrally race --track=logging --challenge=append-no-conflicts --car="4gheap"
上面的命令便是執(zhí)行一次壓測,并指定使用 logging 的track,運行該 track 中的 append-no-conflicts 的 challenge,指定的 car 為 4gheap 的 es 實例。詳情可以查看 race 相關(guān)文檔。
Tournament
tournament 是錦標賽的意思,是由多個 race 組成的。通過下面的命令可以查看所有的 race。
esrally list races
Recent races:
Race Timestamp Track Challenge Car User Tag
---------------- ------- ------------------- -------- ------------------------------
20160518T122341Z pmc append-no-conflicts defaults intention:reduce_alloc_1234
20160518T112057Z pmc append-no-conflicts defaults intention:baseline_github_1234
20160518T101957Z pmc append-no-conflicts defaults
當有了多個 race 后,可以通過下面的命令方便地比較不同 race 之間的數(shù)據(jù)。
esrally compare --baseline=20160518T112057Z --contender=20160518T112341Z

詳細信息可以參見 tournament 的文檔。
Pipeline
Pipeline 在這里是指壓測的一個流程,通過下面的命令可以查看已有的pipeline。
esrally list pipeline
Name Description
----------------------- ---------------------------------------------------------------------------------------------
from-sources-complete Builds and provisions Elasticsearch, runs a benchmark and reports results.
from-sources-skip-build Provisions Elasticsearch (skips the build), runs a benchmark and reports results.
from-distribution Downloads an Elasticsearch distribution, provisions it, runs a benchmark and reports results.
benchmark-only Assumes an already running Elasticsearch instance, runs a benchmark and reports results
- from-sources-complete 是從源代碼編譯 es 后再運行,可以通過 --revision 參數(shù)指明要編譯的commit hash ,這樣就可以針對某一個提交版本就行測試了。
- from-sources-skip-build 如果已經(jīng)編譯好了,使用該 pipeline,可以跳過編譯的流程,節(jié)省測試時間
- from-distribution 通過 --distribution-version 指定 es 版本,esrally 會從官網(wǎng)直接下載該版本的可執(zhí)行文件,然后進行測試。
- benchmark-only 此 pipeline 將 es 集群的管理交由用戶來處理, esrally 只做壓測。如果你想針對已有集群進行測試,那么要將pipeline設(shè)定為該模式。
詳細信息請參見 pipeline 的文檔。
壓測流程
esrally 的壓測流程主要分為以下三個步驟:
- 根據(jù)參數(shù)設(shè)定自行編譯或者下載 es 可執(zhí)行實例,然后根據(jù) car 的約定,創(chuàng)建并啟動 es 集群。如果使用 benchmark-only 的pipeline,則該步驟省略。
- 根據(jù)指定 track 去下載數(shù)據(jù),然后按照指定的 challenge 進行操作。
- 記錄并輸出壓測結(jié)果數(shù)據(jù)。
壓測結(jié)果分析
壓測結(jié)束后,esrally 會將結(jié)果輸出到終端和結(jié)果文件(位于 esrally 目錄logs 和 benchmarks/races)中,如下圖所示:

在 Metric 一欄,有非常多的指標數(shù)據(jù),詳細的解釋可以參見該文檔。一般要關(guān)注的數(shù)據(jù)有:
- throughput 每個操作的吞吐量,比如 index、search等
- latency 每個操作的響應時長數(shù)據(jù)
- Heap used for x 記錄堆棧的使用情況
先搞懂每個 metric 的含義,然后根據(jù)自己的需求去確認自己要關(guān)注的指標。
每一次壓測都會以壓測時的時間命名,比如 logs/rally_out_20170822T082858Z.log ,這個日志便是記錄的 2017年8月22日 8:28:58開始的壓測日志。而在 benchmarks/races/2017-08-22-08-28-58 中記錄著最終的結(jié)果和 es 的運行日志。
另外對于 benchmark-only 模式的測試,即針對已有集群的壓力測試,也可以通過安裝 X-Pack Basic 版本進行監(jiān)控(Monitoring),在壓測的過程中就能查看相關(guān)指標。

esrally 可以在配置的時候指定將所有的 race 壓測結(jié)果數(shù)據(jù)存入一個指定的 es 實例中,配置如下(在 esrally 目錄中 rally.ini 文件中):
[reporting]
datastore.type = elasticsearch
datastore.host = localhost
datastore.port = 9200
datastore.secure = False
datastore.user =
datastore.password =
esrally 會將數(shù)據(jù)存儲在如下 3 個index中,下面 * 代指月份,即按月存儲結(jié)果數(shù)據(jù)。
- rally-metrics-* 該索引分指標記錄每次 race 的結(jié)果,如下圖所示為某一次race的所有 metric 數(shù)據(jù)。

第一列時間是指某一次壓測的時間,第二列時間是指標采集的時間,第三列 operation 指具體執(zhí)行的操作,operation 為空的指標都是總計類的,比如indexing total time 記錄的是總索引數(shù)據(jù)的時間、segments_count 是總段數(shù)等等。其他的 operation 都記錄了每一個操作的數(shù)據(jù)。需要注意的是,這里記錄的是 operation 的所有采樣數(shù)據(jù),不是一個最終的匯總數(shù)據(jù)。上面截圖中也可以看出同一個 hour_agg 的operation 有多項名為 service_time 的指標數(shù)據(jù),但他們的采集時間是不同的?;谶@些數(shù)據(jù),我們可以做出某一次 race 中某個指標的可視化圖表,比如你想觀察本次 race 中 index-log 這個 task 的 throughput 指標數(shù)據(jù),便可以通過如下圖的方式實現(xiàn)。

- rally-result-* 該索引分指標記錄了每次 race 的最終匯總結(jié)果,比如下面這條數(shù)據(jù)。
{
"user-tag": "shardSizeTest:size6",
"distribution-major-version": 5,
"environment": "local",
"car": "external",
"plugins": [
"x-pack"
],
"track": "logging",
"active": true,
"distribution-version": "5.5.2",
"node-count": 1,
"value": {
"50_0": 19.147876358032228,
"90_0": 21.03116340637207,
"99_0": 41.644479789733886,
"100_0": 47.20634460449219
},
"operation": "term",
"challenge": "default-index",
"trial-timestamp": "20170831T063724Z",
"name": "latency"
}
這個記錄了 term operation 的 latency 指標數(shù)據(jù),匯總值以 percentile(百分位數(shù)) 的形式展示?;谠摂?shù)據(jù),我們可以繪制針對某個指標的多race對比,比如下圖便是對比多 race 之間 hourly_agg(按小時做聚合)、default(match_all 查詢)、term(term查詢)、range(range查詢)的latency(延遲時間)對比。

-
rally-races-* 該索引記錄了所有 race 的最終結(jié)果,即命令行執(zhí)行的輸出結(jié)果。
除了es相關(guān)指標數(shù)據(jù)外,esrally 還會同時記錄測試的一些環(huán)境信息,比如操作系統(tǒng)、JVM等等,你可以方便的查看本次測試的軟硬件環(huán)境。
實戰(zhàn)
終于到了開賽的時候,下面我們采用問答的形式來進行,希望大家看到問題后先自己思考下再看答案。
問題一
提問:如何對比 5.5.0 相比 2.4.6 的性能改進?
回答:
分別針對 5.5.0 和 2.4.6 做一次壓測,然后比較兩者兩者的相關(guān)指標即可,這里我們的 track 和 challenge 如下:
- track: nyc_taxis
- challenge: append-no-conflicts
測試步驟如下:
- 測試 2.4.6 的性能
esrally race --distribution-version=2.4.6 --track=nyc_taxis --challenge=append-no-conflicts --user-tag="version:2.4.6"
- 測試 5.5.0 的性能
esrally race --distribution-version=5.5.0 --track=nyc_taxis --challenge=append-no-conflicts --user-tag="version:5.5.0"
- 對比兩次 race 的結(jié)果
esrally list races
esrally compare --baseline=[2.4.6 race] --contender=[5.5.0 race]
Tips:
--user-tag 用于為 race 打標簽,方便后續(xù)查找
如果只是試一下,可以加上 --test-mode ,用測試數(shù)據(jù)來跑,很快。
問題二
提問:如何測試 _all 關(guān)閉后對于寫性能的影響?
回答:
針對 5.5.0 版本的 es 做兩次測試,第一次開啟 _all,第二次關(guān)閉 _all,對比兩次的結(jié)果,由于只測試寫性能,所以我們只需要 index 類型的 operation執(zhí)行。這里我們的 track 和 challenge 如下:
- track: nyc_taxis
- challenge: append-no-conflicts
測試步驟如下:
- 默認 nyc_taxis 的 mapping 設(shè)置是將 _all 關(guān)閉的,直接測試 _all 關(guān)閉時的性能。
esrally race --distribution-version=5.5.0 --track=nyc_taxis --challenge=append-no-conflicts --user-tag="enableAll:false" --include-tasks="type:index"
- 修改 nyc_taxis 的 mapping 設(shè)置,打開 _all。mapping 文件位于 rally 主目錄
benchmarks/tracks/default/nyc_taxis/mappings.json,修改 _all.enabled 為 true。
esrally race --distribution-version=5.5.0 --track=nyc_taxis --challenge=append-no-conflicts --user-tag="enableAll:true" --include-tasks="type:index"
- 對比兩次 race 的結(jié)果
esrally list races
esrally compare --baseline=[enableAll race] --contender=[disableAll race]
下圖是我在 --test-mode 模式下運行的對比結(jié)果,也可以看出關(guān)閉 _all 可以提升寫性能。

Tips:
--include-tasks 用于只運行 challenge 中的部分 task
問題三
提問:如何測試已有集群的性能?
回答:
使用 benchmark-only 的 pipeline 即可,這里我們的 track 和 challenge 如下:
- track: nyc_taxis
- challenge: append-no-conflicts
測試步驟如下:
- 執(zhí)行下方命令即可測試已有集群
esrally race --pipeline=benchmark-only --target-hosts=127.0.0.1:9200 --cluster-health=yellow --track=nyc_taxis --challenge=append-no-conflicts
Tips:
--cluster-health=yellow 默認 esrally 會檢查集群狀態(tài),非 green 狀態(tài)會直接退出。添加該參數(shù)可以避免該情況
希望這三個問答可以幫助到大家快速掌握 esrally 的用法。
進階
自定義 car
前面講解 car 的時候,我們提到 esrally 已經(jīng)自帶了一些可用的 es 配置,但是如果這些還不能滿足你的時候,可以通過下面兩個方案解決。
定制自己的car
car 的配置文件位于 esrally 目錄benchmarks/teams/default/cars,在這里新增一個自己的 car 配置文件就可以了。這里就不贅述了,感興趣的可以查閱 car 的文檔。自己搭建集群
最簡單的方式是脫離 esrally 的管理,自行搭建集群,這樣想怎么配置就怎么配置了。
自定義 track
雖然 esrally 自帶了很多 track,而且這些數(shù)據(jù)本身也不小,簡單列在下面:
| Track | 壓縮數(shù)據(jù)大小 | 解壓數(shù)據(jù)大小 | 文檔數(shù) |
|---|---|---|---|
| geonames | 252 MB | 3.3 GB | 11396505 |
| geopoint | 482 MB | 2.3 GB | 60844404 |
| logging | 1.2 GB | 31 GB | 247249096 |
| nested | 663 MB | 3.3 GB | 11203029 |
| noaa | 947 MB | 9 GB | 33659481 |
| nyc_taxis | 4.5 GB | 74 GB | 165346692 |
| percolator | 103KB | 105 MB | 2000000 |
| pmc | 5.5 GB | 22 GB | 574199 |
這些數(shù)據(jù)文件位于 esrally 目錄 benchmarks/data 下面。不同的 Track 有不同的測試目的,詳情可以去該 github repo 下面去查看。
當我們做定向測試的時候,還是希望針對自己的數(shù)據(jù)進行壓測,此時可以自定義 track。操作也很簡單,詳情可以參考官方文檔。這里簡單列一下操作步驟。
- 在 上文提到的 data 目錄中創(chuàng)建自己的數(shù)據(jù)目錄。
- 準備壓測數(shù)據(jù)文件。 esrally 使用的是一個json文件,其實是一個一個 json object。
- 將準備好的數(shù)據(jù)文件壓縮成 bz2 格式,然后復制到步驟 1 創(chuàng)建的目錄中去。
- 新增自定義的track??梢灾苯訌椭?geoname 目錄,然后修改相關(guān)的配置文件,將測試數(shù)據(jù)與 track 綁定。
- 添加完后,通過
esrally list rack就可以看到自定義的 track。
分布式壓測
esrally 還支持分布式壓測,即如果一個節(jié)點的 esrally 無法達到要求的并發(fā)數(shù)、請求數(shù),那么可以將 esrally 分布到多臺機器上去同時執(zhí)行。分布式壓測文檔在這里,此處用到了 esrally dameon,對應命令是 esrallyd 。簡單講就是 esrally 通過 esrallyd 將多臺機器組合成一個集群,然后 esrally 在執(zhí)行測試任務的時候通過制定 --load-driver-hosts 便可以將測試任務分發(fā)到對應的機器上執(zhí)行。這里便不贅述了,感興趣的去看前面提到的文檔。
最后一個問題
讓我們回到開頭提到的容量規(guī)劃的問題吧!
提問:一個 index 的 shard 數(shù)該如何確認?
回答:
其實針對這個提問,還可以再問下面兩個問題。
- shard 設(shè)置過少是否有問題?比如一直都采用默認的 5個分片
- shard 設(shè)置過多是否有問題?比如直接設(shè)置為100個分片
要回到這兩個問題,我們得先知道 shard 的作用。shard 是 es 實現(xiàn)分布式特性的基石,文檔在索引進 es 時,es 會根據(jù)一個路由算法,將每一個文檔分配到對應的 shard 上。每個 shard 實際對應一個 lucene index。那么每個 shard 能存儲的文檔數(shù)是否有上限呢?答案是有!每個shard最多存儲 2^31 個文檔,即 20億。這是 lucene 設(shè)計決定的。那是不是只要我的文檔數(shù)沒有超過20億,就可以只用一個或者很少的shard 呢?不盡然。因為隨著 shard 體積的增大,其查詢效率會下降,而且數(shù)據(jù)遷移和恢復的成本也會增高。官方建議單個 shard 大小不要超過 50GB,可以參見討論一和討論二。
現(xiàn)在回答上面的兩個問題。
shard數(shù)過小不一定好,如果數(shù)據(jù)量很大,導致每個 shard 體積過大,會影響查詢性能。
shard數(shù)過大也不一定好,因為 es 的每次查詢是要分發(fā)給所有的 shard 來查詢,然后再對結(jié)果做聚合處理,如果 shard 數(shù)過多也會影響查詢性能。因此 shard 的數(shù)量需要根據(jù)自己的情況測出來。
官方文檔有一節(jié)關(guān)于容量規(guī)劃的章節(jié),建議大家去看一下,鏈接在這里,其給出的步驟如下:
- 使用生產(chǎn)環(huán)境的硬件配置創(chuàng)建單節(jié)點集群
- 創(chuàng)建一個只有一個主分片無副本的索引,設(shè)置相關(guān)的mapping信息
- 將真實的文檔導入到步驟 2 的索引中
- 測試實際會用到的查詢語句
測試的過程中,關(guān)注相關(guān)指標數(shù)據(jù),比如索引性能、查詢性能,如果在某一個點相關(guān)性能數(shù)據(jù)超出了你的預期值,那么此時的 shard size大小便是符合你預期的單個 shard size的大小。接下來通過下面這個簡單的計算公式便大致能確定一個 index 需要設(shè)定的 shard 數(shù)了。
shard數(shù) = index 的數(shù)據(jù)總大小/單個shard size的極限值
比如你測出單個 shard size 最大為 20 GB,而你預測該索引數(shù)據(jù)最大量在1年或者2年內(nèi)不會超過 200GB,那么你的 shard 數(shù)就可以設(shè)置為10。
接下來要做的事情也很明確,我們要用 esrally 完成上面的壓測步驟:
自行維護 es 節(jié)點的創(chuàng)建和運行,esrally 運行的時候采用 benchmark-only 模式.
-
自定義 track,這里有以下兩個重點:
- 生成真實數(shù)據(jù)。如果你的數(shù)據(jù)無法生成很多,那么可以在 track 的 schedule 中設(shè)置
iterations參數(shù),即循環(huán)進行同一個操作,這樣也可以測試大數(shù)據(jù)量的寫性能。 - 定義自己的查詢?nèi)蝿?。?track 的
operations中是可以定義自己的查詢語句的,比如下面這個
{ "name": "hourly_agg", "operation-type": "search", "index": "logs-*", "type": "type", "body": { "size": 0, "aggs": { "by_hour": { "date_histogram": { "field": "@timestamp", "interval": "hour" } } } } }其中的 body 便是自定義的查詢語句,所以你可以通過自己的需求來設(shè)定查詢語句,以貼近實際使用的情況。
- 生成真實數(shù)據(jù)。如果你的數(shù)據(jù)無法生成很多,那么可以在 track 的 schedule 中設(shè)置
- 還要記得設(shè)置索引的 mapping 與線上一致,比如是否啟用 _all 等設(shè)置。
- 基于自定義的track來進行壓測即可。要注意的是運行 esrally 的機器要和 es 機器分開,防止對 es 性能產(chǎn)生干擾。
Tips:
esrally 默認在每次壓測是會刪除已有的索引后再重新創(chuàng)建索引,如果你不想這樣,可以在每個 index 的配置中設(shè)置auto-managed為 false,具體文檔在這里。
通過這個參數(shù),你就可以單獨壓測查詢性能了,而不用每次都要先經(jīng)過漫長的導入數(shù)據(jù)的過程。
總結(jié)
esrally 針對 es 的壓測設(shè)計了一套完備的基于配置文件的測試流程,極大地簡化了操作難度,并且提供了可重復驗證的方式。對國內(nèi)用戶來講,我認為最大的難處還是在于 esrally 自帶的 track 文件太大,從 國外 aws 下載很慢。好在可以自定義 track,不必完全依賴自帶的 track。
其他沒啥好說的,esrally 棒棒噠,大家趕緊去試試吧,如果有問題歡迎來討論!