|
| 1 | +[[search-benchmark]] |
| 2 | +== Benchmark |
| 3 | + |
| 4 | +.Experimental! |
| 5 | +[IMPORTANT] |
| 6 | +===== |
| 7 | +This feature is marked as experimental, and may be subject to change in the |
| 8 | +future. If you use this feature, please let us know your experience with it! |
| 9 | +===== |
| 10 | + |
| 11 | +The benchmark API provides a standard mechanism for submitting queries and |
| 12 | +measuring their performance relative to one another. |
| 13 | + |
| 14 | +[IMPORTANT] |
| 15 | +===== |
| 16 | +To be eligible to run benchmarks nodes must be started with: *es.node.bench=true*. This is just a way to mark certain nodes as "executors". Searches will still be distributed out to the cluster in the normal manner. This is primarily a defensive measure to prevent production nodes from being flooded with potentially many requests. Typically one would start a single node with this setting and sumbmit benchmark requests to it. |
| 17 | +===== |
| 18 | + |
| 19 | +[source,bash] |
| 20 | +-------------------------------------------------- |
| 21 | +$ ./bin/elasticsearch -Des.node.bench=true |
| 22 | +-------------------------------------------------- |
| 23 | + |
| 24 | +Benchmarking a search request is as simple as executing the following command: |
| 25 | + |
| 26 | +[source,js] |
| 27 | +-------------------------------------------------- |
| 28 | +$ curl -XPUT 'localhost:9200/_bench/?pretty=true' -d |
| 29 | +'{ |
| 30 | + "name": "my_benchmark", |
| 31 | + "competitors": [ { |
| 32 | + "name": "my_competitor", |
| 33 | + "requests": [ { |
| 34 | + "query": { |
| 35 | + "match": { "_all": "a*" } |
| 36 | + } |
| 37 | + } ] |
| 38 | + } ] |
| 39 | +}' |
| 40 | +-------------------------------------------------- |
| 41 | + |
| 42 | +Response: |
| 43 | + |
| 44 | +[source,js] |
| 45 | +-------------------------------------------------- |
| 46 | +{ |
| 47 | + "status" : "complete", |
| 48 | + "competitors" : { |
| 49 | + "my_competitor" : { |
| 50 | + "summary" : { |
| 51 | + "nodes" : [ "localhost" ], |
| 52 | + "total_iterations" : 5, |
| 53 | + "completed_iterations" : 5, |
| 54 | + "total_queries" : 1000, |
| 55 | + "concurrency" : 5, |
| 56 | + "multiplier" : 100, |
| 57 | + "avg_warmup_time" : 43.0, |
| 58 | + "statistics" : { |
| 59 | + "min" : 1, |
| 60 | + "max" : 10, |
| 61 | + "mean" : 4.19, |
| 62 | + "qps" : 238.663, |
| 63 | + "std_dev" : 1.938, |
| 64 | + "millis_per_hit" : 1.064, |
| 65 | + "percentile_10" : 2, |
| 66 | + "percentile_25" : 3, |
| 67 | + "percentile_50" : 4, |
| 68 | + "percentile_75" : 5, |
| 69 | + "percentile_90" : 7, |
| 70 | + "percentile_99" : 10 |
| 71 | + }, |
| 72 | + "slowest" : [ { |
| 73 | + "node" : "localhost", |
| 74 | + "max_time" : 15, |
| 75 | + "avg_time" : 4, |
| 76 | + "request":{"query":{"match":{"_all":"a*"}}} |
| 77 | + } ] |
| 78 | + } |
| 79 | + } |
| 80 | + } |
| 81 | +} |
| 82 | +-------------------------------------------------- |
| 83 | + |
| 84 | +A 'competitor' defines one or more search requests to execute along with parameters that describe how the search(es) should be run. |
| 85 | +Multiple competitors may be submitted as a group in which case they will execute one after the other. This makes it easy to compare various |
| 86 | +competing alternatives side-by-side. |
| 87 | + |
| 88 | +There are several parameters which may be set at the competition level: |
| 89 | +[horizontal] |
| 90 | +`name`:: Unique name for the competition |
| 91 | +`iterations`:: Number of times to run the competitors |
| 92 | +`concurrency`:: Within each iteration use this level of parallelism |
| 93 | +`multiplier`:: Within each iteration run the query this many times |
| 94 | +`warmup`:: Perform warmup of query |
| 95 | +`num_slowest`:: Record N slowest queries |
| 96 | +`search_type`:: Type of search, e.g. "query_then_fetch", "dfs_query_then_fetch", "count" |
| 97 | +`requests`:: Query DSL describing search requests |
| 98 | +`clear_caches`:: Whether caches should be cleared on each iteration, and if so, how |
| 99 | +`indices`:: Array of indices (and optional types) to search, e.g. ["my_index_1/my_type_1", "my_index_2", "my_index_3/my_type_3"] |
| 100 | + |
| 101 | +Cache clearing parameters: |
| 102 | +[horizontal] |
| 103 | +`clear_caches`:: Set to 'false' to disable cache clearing completely |
| 104 | +`clear_caches.filter`:: Whether to clear the filter cache |
| 105 | +`clear_caches.field_data`:: Whether to clear the field data cache |
| 106 | +`clear_caches.id`:: Whether to clear the id cache |
| 107 | +`clear_caches.recycler`:: Whether to clear the recycler cache |
| 108 | +`clear_caches.fields`:: Array of fields to clear |
| 109 | +`clear_caches.filter_keys`:: Array of filter keys to clear |
| 110 | + |
| 111 | +Global parameters: |
| 112 | +[horizontal] |
| 113 | +`name`:: Unique name for the benchmark |
| 114 | +`num_executor_nodes`:: Number of cluster nodes from which to submit and time benchmarks. Allows user to run a benchmark simultaneously on one or more nodes and compare timings. Note that this does not control how many nodes a search request will actually execute on. Defaults to: 1. |
| 115 | +`percentiles`:: Array of percentile values to report. Defaults to: [10, 25, 50, 75, 90, 99] |
| 116 | + |
| 117 | +Additionally, the following competition-level parameters may be set globally: iteration, concurrency, multiplier, warmup, and clear_caches. |
| 118 | + |
| 119 | +Using these parameters it is possible to describe precisely how to execute a benchmark under various conditions. In the following example we run a filtered query against two different indices using two different search types. |
| 120 | + |
| 121 | +[source,js] |
| 122 | +-------------------------------------------------- |
| 123 | +$ curl -XPUT 'localhost:9200/_bench/?pretty=true' -d |
| 124 | +{ |
| 125 | + "name": "my_benchmark", |
| 126 | + "num_executor_nodes": 1, |
| 127 | + "percentiles" : [ 25, 50, 75 ], |
| 128 | + "iterations": 5, |
| 129 | + "multiplier": 1000, |
| 130 | + "concurrency": 5, |
| 131 | + "num_slowest": 0, |
| 132 | + "warmup": true, |
| 133 | + "clear_caches": false, |
| 134 | +
|
| 135 | + "requests": [ { |
| 136 | + "query" : { |
| 137 | + "filtered" : { |
| 138 | + "query" : { "match" : { "_all" : "*" } }, |
| 139 | + "filter" : { |
| 140 | + "and" : [ { "term" : { "title" : "Spain" } }, |
| 141 | + { "term" : { "title" : "rain" } }, |
| 142 | + { "term" : { "title" : "plain" } } ] |
| 143 | + } |
| 144 | + } |
| 145 | + } |
| 146 | + } ], |
| 147 | +
|
| 148 | + "competitors": [ { |
| 149 | + "name": "competitor_1", |
| 150 | + "search_type": "query_then_fetch", |
| 151 | + "indices": [ "my_index_1" ], |
| 152 | + "clear_caches" : { |
| 153 | + "filter" : true, |
| 154 | + "field_data" : true, |
| 155 | + "id" : true, |
| 156 | + "recycler" : true, |
| 157 | + "fields": ["title"] |
| 158 | + } |
| 159 | + }, { |
| 160 | + "name": "competitor_2", |
| 161 | + "search_type": "dfs_query_then_fetch", |
| 162 | + "indices": [ "my_index_2" ], |
| 163 | + "clear_caches" : { |
| 164 | + "filter" : true, |
| 165 | + "field_data" : true, |
| 166 | + "id" : true, |
| 167 | + "recycler" : true, |
| 168 | + "fields": ["title"] |
| 169 | + } |
| 170 | + } ] |
| 171 | +} |
| 172 | +-------------------------------------------------- |
| 173 | + |
| 174 | +Response: |
| 175 | + |
| 176 | +[source,js] |
| 177 | +-------------------------------------------------- |
| 178 | +{ |
| 179 | + "status" : "complete", |
| 180 | + "competitors" : { |
| 181 | + "competitor_1" : { |
| 182 | + "summary" : { |
| 183 | + "nodes" : [ "localhost" ], |
| 184 | + "total_iterations" : 5, |
| 185 | + "completed_iterations" : 5, |
| 186 | + "total_queries" : 5000, |
| 187 | + "concurrency" : 5, |
| 188 | + "multiplier" : 1000, |
| 189 | + "avg_warmup_time" : 54.0, |
| 190 | + "statistics" : { |
| 191 | + "min" : 0, |
| 192 | + "max" : 3, |
| 193 | + "mean" : 0.533, |
| 194 | + "qps" : 1872.659, |
| 195 | + "std_dev" : 0.528, |
| 196 | + "millis_per_hit" : 0.0, |
| 197 | + "percentile_25" : 0.0, |
| 198 | + "percentile_50" : 1.0, |
| 199 | + "percentile_75" : 1.0 |
| 200 | + }, |
| 201 | + "slowest" : [ ] |
| 202 | + } |
| 203 | + }, |
| 204 | + "competitor_2" : { |
| 205 | + "summary" : { |
| 206 | + "nodes" : [ "localhost" ], |
| 207 | + "total_iterations" : 5, |
| 208 | + "completed_iterations" : 5, |
| 209 | + "total_queries" : 5000, |
| 210 | + "concurrency" : 5, |
| 211 | + "multiplier" : 1000, |
| 212 | + "avg_warmup_time" : 4.0, |
| 213 | + "statistics" : { |
| 214 | + "min" : 0, |
| 215 | + "max" : 4, |
| 216 | + "mean" : 0.487, |
| 217 | + "qps" : 2049.180, |
| 218 | + "std_dev" : 0.545, |
| 219 | + "millis_per_hit" : 0.0, |
| 220 | + "percentile_25" : 0.0, |
| 221 | + "percentile_50" : 0.0, |
| 222 | + "percentile_75" : 1.0 |
| 223 | + }, |
| 224 | + "slowest" : [ ] |
| 225 | + } |
| 226 | + } |
| 227 | + } |
| 228 | +} |
| 229 | +-------------------------------------------------- |
| 230 | + |
| 231 | +In some cases it may be desirable to view the progress of a long-running benchmark and optionally terminate it early. To view all active benchmarks use: |
| 232 | + |
| 233 | +[source,js] |
| 234 | +-------------------------------------------------- |
| 235 | +$ curl -XGET 'localhost:9200/_bench?pretty' |
| 236 | +-------------------------------------------------- |
| 237 | + |
| 238 | +This would display run-time statistics in the same format as the sample output above. |
| 239 | + |
| 240 | +To abort a long-running benchmark use the 'abort' endpoint: |
| 241 | + |
| 242 | +[source,js] |
| 243 | +-------------------------------------------------- |
| 244 | +$ curl -XPOST 'localhost:9200/_bench/abort/my_benchmark?pretty' |
| 245 | +-------------------------------------------------- |
| 246 | + |
| 247 | +Response: |
| 248 | + |
| 249 | +[source,js] |
| 250 | +-------------------------------------------------- |
| 251 | +{ |
| 252 | + "aborted_benchmarks" : [ |
| 253 | + "node" "localhost", |
| 254 | + "benchmark_name", "my_benchmark", |
| 255 | + "aborted", true |
| 256 | + ] |
| 257 | +} |
| 258 | +-------------------------------------------------- |
| 259 | + |
0 commit comments