Blog

2015.11.04 - 번역 - Elasticsearch as a Time Series Data Store ...

drscg 2019. 1. 6. 17:44

As the project manager of stagemonitor, an open source performance monitoring tool, I've recently been looking for a database to replace the cool-but-aging Graphite Time Series DataBase (TSDB) as the backend. TSDBs are specialised packages for storing (performance) metric data, like the response time of your app or the CPU utilisation of a server. Ultimately, we were looking for a datastore that is easy to install, scalable, supports a variety of functions, and has great support for visualizing the metrics.

open source 성능 모니터링 도구인 stagemonitor의 프로젝트 관리자로서, 저는 최근에 cool-but-aging(?) Graphite Time Series DataBase(TSDB)를 백엔드로 대체할 database를 찾고 있었다. TSDB는 app의 response time 또는 server의 CPU 사용률 같은, (성능) metric data를 저장하는 특별한 package이다. 궁극적으로, 설치하기 쉽고, 확장 가능하며, 다양한 기능을 지원하고, metric을 시각화하는 데 큰 지원을 하는 data 저장소를 찾고 있었다.

We've previously worked with Elasticsearch, so we know it is easy to install, scaleable, offers many aggregations, and has a great visualisation tool in Kibana. But we didn't know if Elasticsearch was suited for time series data. We were not the only one asking the question. In fact, CERN (you know, those folks who shoot protons in circles) did a performance comparison between Elasticsearch, InfluxDB and OpenTSDB and declared Elasticsearch the winner.

우리는 이전에 Elasticsearch와 함께 작업했기 때문에, 설치가 쉽고, 확장 가능하며, 많은 aggregation을 제공하고, Kibana에서 훌륭한 시각화 도구를 가지고 있다는 것을 알고 있었다. 그러나 Elasticsearch가 시계열 data에 적합한 지 여부는 알지 못 했다. 우리만 질문한 것이 아니었다. 실제로, CERN은 Elasticsearch, InfluxDB 및 OpenTSDB 간의 성능 비교를 하고, Elasticsearch를 승자로 선언했다.

The Decision Process

Elasticsearch is a fantastic tool for storing, searching, and analyzing structured and unstructured data — including free text, system logs, database records, and more. With the right tweaking, you also get a great platform to store your time series metrics from tools like collectd or statsd.

Elasticsearch는 text, system log, database record 등을 비롯한, 구조화 된 그리고 구조화되지 않은 data를 저장, 검색 및 분석하는 환상적인 도구이다. 올바른 옵션 조정을 통해, collectd나 statsd와 같은 도구에서 시계열 metric을 저장할 수 있는 훌륭한 platform을 얻을 수 있다.

It also scales very easily as you add more metrics. Elasticsearch has built in redundancy thanks to shard replicas and allows simple backups with Snapshot & Restore, which makes management of your cluster and your data a lot easier.

또한 metric을 추가 할 때, 매우 쉽게 확장된다. Elasticsearch는 shard replica 덕분에 이중화 기능을 내장했으며, Snapshot & Restore를 통해 간단한 backup이 가능하여, cluster와 data 관리가 훨씬 쉽다.

Elasticsearch is also highly API driven, and with integration tools like Logstash, it's simple to build data processing pipelines that can handle very large amounts of data with great efficiency. Once you add Kibana to the mix you have a platform that allows you to ingest and analyse multiple datasets and draw correlations from metric and other data side-by-side.

Elasticsearch는 또한 고도의 API를 기반으로 하며, Logstash와 같은 통합 도구를 사용하면, 대용량 데이터를 매우 효율적으로 처리할 수 있는, data 처리 pipeline을 간단하게 구축 할 수 있다. Kibana를 추가하면, 여러 data 집합을 색인하고 분석할 수 있고, metric과 다른 data의 상관 관계를 나란히 나타낼 수 있는 platform을 가질 수 있다.

Another benefit that isn't immediately obvious is instead of storing metrics that have been transformed via a calculation to provide an endpoint value that gets graphed, you are storing the raw value and then running the suite of powerful aggregations built into Elasticsearch over these values. This means that if you change your mind after a few months of monitoring a metric and you want to calculate or display the metric differently, it's as simple as changing the aggregation over the dataset, for both historic and current data. Or to put it another way: You have the ability to ask and answer questions that you didn't think about when the data was stored!

즉시 파악할 수 없는 또 다른 이점은, 그래프로 표시되는 값을 제공하기 위해 계산을 통해, 변환된 metric을 저장하는 대신, 원시 값(raw value)을 저장 한 다음, 이들 값을 통해 Elasticsearch에 내장된 강력한 aggregation을 실행하는 것이다. 즉, metric을 모니터링 한 몇 개월 후, 마음이 바뀌어, metric을 다르게 계산하거나 나타내려는 경우, 과거 및 현재 data 모두의 data 집합에 대한 aggregation을 변경하는 것처럼 간단하다. 다시 말해서, data를 저장할 때 생각하지 않은 질문에 대해, 질문하고 대답할 수있는 능력이 있다!

With all that in mind, the obvious question we wanted to answer is: What's the best method for setting up Elasticsearch as a time series database?

모든 것을 염두에 두고 우리가 답하고자 하는 질문은: Elasticsearch를 시계열 database로 설정하는 가장 좋은 방법은 무엇일까?

First Stop: Mappings

The most important part to start is your mapping. Defining your mapping ahead of time means that the analysis and storage of data in Elasticsearch is as optimal as possible.

시작할 때 가장 중요한 부분은 mapping이다. 사전에 mapping을 정의한다는 것은 Elasticsearch에서 data의 분석 및 저장이, 가능한 한 최적임을 의미한다.

Here's an example of how we do the mappings at stagemonitor. You can find the original over in our Github repo:

다음은 stagemonitor에서 한 mapping 방법의 예이다. Github repo에서 원본을 볼 수 있다.

{ "template": "stagemonitor-metrics-*", "settings": { "index": { "refresh_interval": "5s" } }, "mappings": { "_default_": { "dynamic_templates": [ { "strings": { "match": "*", "match_mapping_type": "string", "mapping": { "type": "string", "doc_values": true, "index": "not_analyzed" } } } ], "_all": { "enabled": false }, "_source": { "enabled": false }, "properties": { "@timestamp": { "type": "date", "doc_values": true }, "count": { "type": "integer", "doc_values": true, "index": "no" }, "m1_rate": { "type": "float", "doc_values": true, "index": "no" }, "m5_rate": { "type": "float", "doc_values": true, "index": "no" }, "m15_rate": { "type": "float", "doc_values": true, "index": "no" }, "max": { "type": "integer", "doc_values": true, "index": "no" }, "mean": { "type": "integer", "doc_values": true, "index": "no" }, "mean_rate": { "type": "float", "doc_values": true, "index": "no" }, "median": { "type": "float", "doc_values": true, "index": "no" }, "min": { "type": "float", "doc_values": true, "index": "no" }, "p25": { "type": "float", "doc_values": true, "index": "no" }, "p75": { "type": "float", "doc_values": true, "index": "no" }, "p95": { "type": "float", "doc_values": true, "index": "no" }, "p98": { "type": "float", "doc_values": true, "index": "no" }, "p99": { "type": "float", "doc_values": true, "index": "no" }, "p999": { "type": "float", "doc_values": true, "index": "no" }, "std": { "type": "float", "doc_values": true, "index": "no" }, "value": { "type": "float", "doc_values": true, "index": "no" }, "value_boolean": { "type": "boolean", "doc_values": true, "index": "no" }, "value_string": { "type": "string", "doc_values": true, "index": "no" } } } } }

You can see here we have disabled _source and _all as we are only ever going to be building aggregations, so we save on disk space as the document stored will be smaller. The downside is that we won't be able to see the actual JSON documents or to reindex to a new mapping or index structure (see the documentation for disabling source for more information), but for our metrics based use case this isn't a major worry for us.

aggregation만 사용할 것이기 때문에,  _source_all을 비활성화했다는 것을 알 수 있다. 따라서, 저장된 document가 더 작아져, disk 공간을 절약할 수 있다. 단점은 실제 JSON document를 볼 수 없고, 새로운 mapping이나 index 구조로 reindex할 수 없다는 것이다(자세한 내용은 source 비활성화를 참조하자). metric 기반 사용 사례의 경우, 큰 문제가 아니다.

Just to reiterate: For most use cases you do not want to disable source!

다시 말하면, 대부분의 사용 사례에서 source를 비활성화하지 않는다!

We are also not analyzing string values, as we won't perform full text searches on the metric documents. In this case, we only want to filter by exact names or perform term aggregations on fields like metricNamehost or application so that we can filter our metrics by certain hosts or to get a list of all hosts. It's also better to use doc_values as much as possible to reduce heap use.

metric document에 대한 full text search를 하지 않기 때문에, string 값도 분석하지 않는다. 이 경우, 특정 host로 metric을 filtering하거나 모든 host의 목록을 얻기 위하여, metricNamehost 또는 application 같은 field에서 exact name으로 filtering하거나 term aggregation을 수행하면 된다. 또한 heap 사용을 줄이려면, doc_values를 최대한 사용하는 것이 좋다.

There are two more quite aggressive optimisations which may not be suitable for all use cases. The first one is to use "index": "no" for all metric values. This reduces the index size but also means we can't search the values — which is fine if we want to show all values in a graph and not only a subset, like values between 2.7182 and 3.1415. By using the smallest numeric type (for us it was float) we can optimize the index further. if your case request values are out of the range of a float you could use doubles.

모든 사용 사례에 적합하지 않을 수 있는, 두 가지 더 적극적인 최적화가 있다. 첫 번째는 모든 metric 값에 대해 "index": "no" 를 사용하는 것이다. 이렇게 하면, index 크기가 줄어 들지만, 값을 검색할 수 없다는 것을 의미한다.— 그래프에, 2.7182에서 3.1415 사이 같은 특정 하위 집합이 아닌, 모든 값을 표시하려는 경우에는 문제가 없다. 가장 작은 numeric type을 사용하여(우리의 경우 float), index를 더욱 최적화할 수 있다. 여러분들은 요청 값이 float의 범위를 벗어나면 double을 사용할 수 있다.

Next Up: Optimising for long term storage

The next important step in optimising this data for long term storage is to force merge (previously known as optimize) the indices after all the data has been indexed into them. This involves merging the existing shards into just a few and removing any deleted documents in the same step. “Optimize”, as it was known, is a bit of a misleading term in Elasticsearch — the process does improve resource use, but may require a lot of CPU and disk resources as the system purges any deleted documents and then merges all the underlying Lucene segments. This is why we recommend force merging during off peak periods or running it on nodes with more CPU and disk resources.

장기 저장을 위해, 이 data를 최적화하는 중요한 다음 단계는, 모든 data가 indexing된 후, indext를 강제 병합(force merge, 이전의 optimize)하는 것이다. 여기에는 기존 shard를 몇 개로 merge하고, 동일한 단계에서 삭제된 document를 제거하는 작업이 포함된다. 알려진 대로 "최적화(optimize)"는 Elasticsearch에서 오해의 소지가 있는 용어이다.  process는 resource 사용을 개선시키지만, system이 삭제된 document를 제거한 다음, 모든 기본 Lucene segment를 merge하면서, 많은 CPU 및 disk resource가 필요할 수 있다. 따라서 peak time이 아닌 시간나, CPU 및 disk resource 많은 node에서 강제 merge를 실행하는 것이 좋다.

The merging process does happen automatically in the background, but only while data is being written to the index. We want to explicitly call it once we are sure all the events have been sent to Elasticsearch and the index is no longer being modified by additions, updates, or deletions.

merge process는 data가 index에 기록되는 동안에만, background에서 자동으로 수행된다. 모든 event가 Elasticsearch로 전송되었고, index가 추가, 업데이트 또는 삭제에 의해 더 이상 수정되지 않음을 확인한 후, 이를 명시적으로 호출한다.

An optimize is usually best left until 24-48 hours after the newest index has been created (be it hourly, daily, weekly, etc) to allow any late events to reach Elasticsearch. After that period we can easily use Curator to handle the optimize call:

일반적으로 optimize 늦은 event가 Elasticsearch에 도달 할 수 있도록, 최신 index가 생성된(시간별, 매일별, 매주마다 등) 후, 24-48 시간까지 기다리는 것이 가장 좋다. 그 후에는, Curator를 사용하여 optimize 호출을 쉽게 처리할 수 있다.

$ curator optimize --delay 2 --max_num_segments 1 indices --older-than 1 --time-unit days --timestring %Y.%m.%d --prefix stagemonitor-metrics-

Another great benefit of running this optimise after all data has been written is that we automatically apply synced flush that assists in cluster recovery speed and restarts of nodes.

모든 data가 기록된 후, 이 optimize를 실행하는 또 다른 커다란 이점은, cluster 복구(discovery) 속도와 node 재시작을 지원하는 synced flush가 자동으로 적용된다는 것이다.

If you are using stagemonitor the optimize process is triggered automatically every night, so you don't even need to use curator in that case.

stagemonitor를 사용하는 경우, optimize process가 매일 밤 자동으로 실행되므로, 이 경우 curator를 사용할 필요조차 없다.

The Outcome

To test this, we sent a randomised set of just over 23 million data points from our platform to Elasticsearch, equal to roughly a week's worth. This is a sample of what the data looks like:

이를 test하기 위해, 우리 platform에서 Elasticsearch로 대략 2,300 만개가 넘는 무작위 data를 보냈다. 대략 1 주일 정도 소요되었다. 다음은 data의 sample이다.

{
    "@timestamp": 1442165810,
"name": "timer_1",
    "application": "Metrics Store Benchmark",
    "host": "my_hostname",
    "instance": "Local",
    "count": 21,
    "mean": 714.86,
    "min": 248.00,
    "max": 979.00,
    "stddev": 216.63,
    "p50": 741.00,
    "p75": 925.00,
    "p95": 977.00,
    "p98": 979.00,
    "p99": 979.00,
    "p999": 979.00,
    "mean_rate": 2.03,
    "m1_rate": 2.18,
    "m5_rate": 2.20,
    "m15_rate": 2.20
}

After running a few indexing and optimising cycles we saw the following figures:

몇 번의 indexing과 optimize 사이클을 실행한 후, 다음과 같은 수치가 나타났다.

 Initial SizePost Optimize
Sample Run 12.2G508.6M
Sample Run 2514.1M
Sample Run 3510.9M
Sample Run 4510.9M
Sample Run 5510.9M

You can see how important the optimize process was. Even with Elasticsearch doing this work in the background, it is well worth running for long term storage alone.

optimize process가 얼마나 중요한지 알 수 있다. background에서 이 작업을 수행하는 Elasticsearch를 사용하는 경우에도, 장기간 저장하는 storage에서 실행할만 하다.

Now with the all this data in Elasticsearch, what can we discover? Well, here's a few samples of what we have built with the system:

이제 Elasticsearch의 이 모든 data를 통해 무엇을 발견할 수 있을까? 다음은 우리가 시스템으로 구축한 몇 가지 sample이다.

stagemonitor-applications-metrics.png
stagemonitor-hosts-metrics.png
stagemonitor-instances-metrics.png
stagemonitor-response-times.png
stagemonitor-throughputstatuscode-line.png
stagemonitor-toprequests-metric.png
stagemonitor-pageloadtime-line.png
stagemonitor-slowestrequestsmedian-line.png
stagemonitor-highestthroughput-line.png
stagemonitor-slowestrequests-line.png
stagemonitor-mosterrors-line.png

If you'd like to replicate the testing that we did here you can find the code in the stagemonitor Github repo.

여기에서 수행한 test를 복제하려면, stagemonitor Github repo에서 code를 찾을 수 있다.

The Future

With Elasticsearch 2.0 there are a lot of features that make it even more flexible and suitable for time series data users.

Elasticsearch 2.0에는 시계열 data 사용자에게 더욱 유연하고 적합한 많은 기능이 있다.

Pipeline aggregations open a whole new level for analyzing and transforming of data points. For example, it is possible to smooth graphs with moving averages, use a Holt Winters forecast to check if the data matches historic patterns, or even calculate derivatives.

Pipeline aggregations는 data를 분석하고 변환하기 위해 완전히 새로운 차원을 열어준다. 예를 들어, 이동 평균(moving averages)을 사용하여 그래프를 매끄럽게 만들거나, data가 과거 pattern과 일치하는지를 확인하기 위하여 Holt Winters forecast를 사용거나, 도함수(導函數, derivatives)를 계산할 수 있다.

And finally, in the mapping described above we had to manually enable doc_values to improve heap efficiency. In 2.0, doc_values are enabled by default for any not_analyzed field which means less work for you!

마지막으로, 위에 설명된 mapping에서, heap 효율성을 개선하기 위해, doc_values를 수동으로 활성화해야 한다. 2.0에서는, not_analyzed field에 대해 doc_values가 기본적으로 활성화되므로, 작업이 줄어든다.

About the Author — Felix Barnsteiner

felix-barsteiner.jpegFelix Barnsteiner is the developer of the open source performance monitoring project stagemonitor. During the day he works on eCommerce solutions at iSYS Software GmbH in Munich, Germany.

Felix Barnsteiner는 open source 성능 모니터링 프로젝트 stagemonitor의 개발자이다. 그는 뮌헨(독일)의 iSYS Software GmbH에서 전자 상거래 솔루션을 연구하고 있다.

원문 : Elasticsearch as a Time Series Data Store