Blog

2015.05.26 - 번역 - A Dive into the Elasticsearch Storage ...

drscg 2019. 1. 6. 17:32

UPDATE: This article refers to our hosted Elasticsearch offering by an older name, Found. Please note that Found is now known as Elastic Cloud.

이 게시물은 기존에 Found라는 이름으로 제공된 Elasticsearch 서비스에 관한 것이다. Found은 이제 Elasticsearch Cloud로 알려져 있다.

In this article we'll investigate the files written to the data directory by various parts of Elasticsearch. We will look at node, index and shard level files and give a short explanation of their contents in order to establish an understanding of the data written to disk by Elasticsearch.

이 게시물에서는 Elasticsearch의 여러 부분에서 data directory에 기록되는 file을 살펴볼 것이다. Elasticsearch에 의해 disk에 기록된 data에 대한 이해를 돕기 위해, node, index 그리고, shard level의 file을 살펴보고, 그 내용을 간략하게 설명할 것이다.

Elasticsearch Paths

Elasticsearch is configured with several paths:

Elasticsearch는 다음과 같은 여러가지 경로로 구성된다.

  • path.home: Home directory of the user running the Elasticsearch process. Defaults to the Java system property user.dir, which is the default home directory for the process owner.
    Elasticsearch process를 실행하는 사용자의 Home directory. 기본값은 process의 소유자의 home directory인 Java system property user.dir 이다.
  • path.conf: A directory containing the configuration files. This is usually set by setting the Java system property es.config, as it naturally has to be resolved before the configuration file is found.
    설정 파일을 가지고 있는 directory. 일반적으로 이 설정은 Java 시스템 속성 es.config를 설정하여 설정한다. 이 속성은 설정 파일을 찾기 전에 자연스럽게 해결해야 하기 때문이다.
  • path.plugins: A directory whose sub-folders are Elasticsearch plugins. Sym-links are supported here, which can be used to selectively enable/disable a set of plugins for a certain Elasticsearch instance when multiple Elasticsearch instances are run from the same executable.
    하위 folder가 Elasticsearch plugin인 directory. 여기에서는 sym-link가 지원된다. 이 link는 여러 개의 Elasticsearch instance가 동일한 실행 파일에서 실행될 경우, 특정 Elasticsearch instance에 대한 plugin을 선택적으로 활성화/비활성화하는 데 사용할 수 있다.
  • path.work: A directory that was used to store working/temporary files for Elasticsearch. It’s no longer used.
    Elasticsearch에 대한 작업/임시 파일을 저장하는 데 사용된 directory. 더 이상 사용되지 않는다.
  • path.logs: Where the generated logs are stored. It might make sense to have this on a separate volume from the data directory in case one of the volumes runs out of disk space.
    생성된 log가 저장되는 위치. volimn 중 하나가 disk 공간이 부족한 경우, data directory와 별도의 volimn에 지정하는 것이 좋다.
  • path.data: Path to a folder containing the data stored by Elasticsearch.
    Elasticsearch에 의해 저장된 data가 들어있는 folder의 경로.

In this article, we’ll have a closer look at the actual contents of the data directory (path.data) and try to gain an understanding of what all the files are used for.

이 게시물에서는, data directory(path.data)의 실제 내용을 자세히 살펴보고, 모든 파일의 용도를 이해해 보도록 하자.

Where Do the Files Come from?

Since Elasticsearch uses Lucene under the hood to handle the indexing and querying on the shard level, the files in the data directory are written by both Elasticsearch and Lucene.

Elasticsearch는 shard level에서 index 및 query를 처리하기 위해 Lucene을 사용하기 때문에, data directory의 file은 Elasticsearch 및 Lucene이 작성한다.

The responsibilities of each is quite clear: Lucene is responsible for writing and maintaining the Lucene index files while Elasticsearch writes metadata related to features on top of Lucene, such as field mappings, index settings and other cluster metadata – end user and supporting features that do not exist in the low-level Lucene but are provided by Elasticsearch.

각각의 역활은 분명하다. Lucene은 Lucene index file의 작성 및 유지 관리를 담당하며, Elasticsearch는 field mapping, index 설정, 기타 cluster metadata(Lucene에는 존재하지 않지만 Elasticsearch가 제공하는 최종 사용자 기능과 지원 지능) 같은 Lucene을 기반으로 하는 기능과 관련된 metadata를 작성한다.

Let’s look at the outer levels of data written by Elasticsearch before we dive deeper and eventually find the Lucene index files.

먼저, Elasticsearch가 작성하는 외부의 data를 살펴보고, 최종적으로 Lucene index file을 자세히 살펴보자.

Node Data

Simply starting Elasticsearch from a empty data directory yields the following directory tree:

비어 있는 data directory에서 Elasticsearch를 단순히 실행하면, 다음과 같은 directory tree가 생성된다.

$ tree data
data
└── elasticsearch
    └── nodes
        └── 0
            ├── _state
               └── global-0.st
            └── node.lock

The node.lock file is there to ensure that only one Elasticsearch installation is reading/writing from a single data directory at a time.

node.lock file은 한 번에 하나의 Elasticsearch만 단일 data directory에서 읽거나 쓰도록 하기 위한 것이다.

More interesting is the global-0.st-file. The global-prefix indicates that this is a global state file while the .stextension indicates that this is a state file that contains metadata. As you might have guessed, this binary file contains global metadata about your cluster and the number after the prefix indicates the cluster metadata version, a strictly increasing versioning scheme that follows your cluster.

더 흥미로운 것은 global-0.st file이다. global이라는 접두어는 이것이 전역 상태(global state) file임을 나타내며, .st 확장자는 이것이 meatadata를 포함하는 상태(state) file임을 나타낸다. 짐작하겠지만, 이 binary file에는 cluster에 대한 전역(global) metadata가 포함되어 있으며, 접두사 뒤의 숫자는 cluster metadata 버전을 나타내다. cluster metadata 버전은 cluster에 따라 엄격하게 증가하는 버전 관리 체계이다.

While it is technically possible to edit these files with an hex editor in an emergency, it is strongly discouraged because it can quickly lead to data loss.

비상시에는 hex editor로 이 file을 편집하는 것이 기술적으로 가능하지만, data 손실로 이어질 수 있기 때문에, 사용하지 않는 것이 좋다.

Index Data

Let’s create a single shard index and look at the files changed by Elasticsearch:

단일 shard index를 생성하고, Elasticsearch에 의해 변경되는 file을 살펴보자.

$ curl localhost:9200/foo -XPOST -H 'Content-Type: application/json' -d '{"settings":{"index.number_of_shards": 1}}'
{"acknowledged":true}

$ tree -h data
data
└── [ 102]  elasticsearch
    └── [ 102]  nodes
        └── [ 170]  0
            ├── [ 102]  _state
               └── [ 109]  global-0.st
            ├── [ 102]  indices
               └── [ 136]  foo
                   ├── [ 170]  0
                      ├── .....
                   └── [ 102]  _state
                       └── [ 256]  state-0.st
            └── [   0]  node.lock

We see that a new directory has been created corresponding to the index name. This directory has two sub-folders: _state and 0. The former contains what’s called a index state file (indices/{index-name}/_state/state-{version}.st), which contains metadata about the index, such as its creation timestamp. It also contains a unique identifier as well as the settings and the mappings for the index. The latter contains data relevant for the first (and only) shard of the index (shard 0). Next up, we’ll have a closer look at this.

index 이름에 해당하는 새로운 directory가 생성된 것을 볼 수 있다. 이 directory에는 _state0이라는 2개의 하위 folder가 있다. 전자는 index 상태(state) file(indexes/{index-name}/_state/state-{version}.st)을 포함한다. 그것의 생성 timestamp 같은 index에 대한 metadata를 포함한다. 또한, 유일한 식별자와 index의 설정 및 mapping을 포함한다. 후자에는 index의 첫 번째(그리고 유일한) shard(shard 0)와 관련된 data가 들어 있다.  다음에서, 이 부분을 자세히 살펴볼 것이다.

Shard Data

The shard data directory contains a state file for the shard that includes versioning as well as information about whether the shard is considered a primary shard or a replica.

$ tree -h data/elasticsearch/nodes/0/indices/foo/0
data/elasticsearch/nodes/0/indices/foo/0
├── [ 102]  _state
   └── [  81]  state-0.st
├── [ 170]  index
   ├── [  36]  segments.gen
   ├── [  79]  segments_1
   └── [   0]  write.lock
└── [ 102]  translog
    └── [  17]  translog-1429697028120

In earlier Elasticsearch versions, separate {shard_id}/index/_checksums- files (and .cks-files) were also found in the shard data directory. In current versions these checksums are now found in the footers of the Lucene files instead, as Lucene has added end-to-end checksumming for all their index files.

Elasticsearch 초기 version에서는 shard data directory에 별도의 {shard_id}/index/_checksums- file (과 .cks-file)도 있었다. 최근 버전에서는, Lucene이 모든 index file에 대해 종단간(end-to-end) checksum을 추가했기 때문에, 이들 checksum이 Lucene file의 footer에 대신 표시된다.

The {shard_id}/index directory contains files owned by Lucene. Elasticsearch generally does not write directly to this folder (except for older checksum implementation found in earlier versions). The files in these directories constitute the bulk of the size of any Elasticsearch data directory.

{shard_id}/index directory에는 Lucene이 소유한 file이 들어 있다. Elasticsearch는 일반적으로 이 folder에 직접 쓰지 않는다(이전 버전에서 발견된 이전 checksum 구현 제외). 이 directory의 file은 Elasticsearch data directory 크기의 대부분이다.

Before we enter the world of Lucene, we’ll have a look at the Elasticsearch transaction log, which is unsurprisingly found in the per-shard translog directory with the prefix translog-. The transaction log is very important for the functionality and performance of Elasticsearch, so we’ll explain its use a bit closer in the next section.

Lucene의 세계에 들어가기 전에, Elasticsearch transaction log를 살펴볼 것이다. 이 log는 shard별 translog directory에서 translog- 접두어로 찾을 수 있다. transaction log는 Elasticsearch의 기능 및 성능에 매우 중요하므로, 다음 섹션에서 사용법을 조금 더 자세히 설명하겠다.

Per-Shard Transaction Log


The Elasticsearch transaction log makes sure that data can safely be indexed into Elasticsearch without having to perform a low-level Lucene commit for every document. Committing a Lucene index creates a new segment on the Lucene level which is fsync()-ed and results in a significant amount of disk I/O which affects performance.

Elasticsearch transaction log는 모든 document에 대해 낮은 수준의 Lucene commit을 수행하지 않고도 data를 Elasticsearch로 안전하게 indexing할 수 있도록 한다. Lucene index를 commit하면 Lucene 단에 새로운 segment를 생성하는데, 이것이 fsync()이다. 이로 인해 성능에 영향을 주는 상당한 량의 disk I/O가 발생한다.

In order to accept a document for indexing and make it searchable without requiring a full Lucene commit, Elasticsearch adds it to the Lucene IndexWriter and appends it to the transaction log. After each refresh_intervalit will call reopen() on the Lucene indexes, which will make the data searchable without requiring a commit. This is part of the Lucene Near Real Time API. When the IndexWriter eventually commits due to either an automatic flush of the transaction log or due to an explicit flush operation, the previous transaction log is discarded and a new one takes its place.

index를 위해 document를 받아들이고, 이를 전체 Lucene commit 없이 검색 가능하도록 하기 위해, Elasticsearch는 이를 Lucene IndexWriter 에 추가하고, transaction log에 추가한다. refresh_interval후에, Lucene index에서 reopen() 을 호출하면, commit을 하지 않고도 data 검색이 가능해진다. 이것은 Lucene Near Real Time API의 일부이다. IndexWriter가 transaction log의 자동 flush 또는 명시적인 flush operation으로 인해 최종적으로 commit되면, 이전 transaction log가 폐기되고 새로운 transaction log가 생성된다.

Should recovery be required, the segments written to disk in Lucene will be recovered first, then the transaction log will be replayed in order to prevent the loss of operations not yet fully committed to disk.

복구(recovery)가 필요할 경우, Lucene의 disk에 기록된 segment가 먼저 복구된 다음, disk에 아직 완전히 commit되지 않은 연산의 손실을 방지하기 위해, transaction log가 재생된다.

Lucene Index Files

Lucene has done a good job at documenting the files in the Lucene index directory, reproduced here for your convenience (the linked documentation in Lucene also goes into detail about the changes these files have gone through since all the way back to Lucene 2.1, so check it out):

Lucene은 Lucene index directory에 있는 file에 대해 잘 정리해 두었다. 여기에 편의를 위해 다시 한번 정리하였다(Lucene의 링크된 문서는 Lucene 2.1 이후로 이들 file의 변경 사항에 대해 자세히 설명하고 있으니, 잘 살펴보자).

NameExtensionBrief Description
Segments Filesegments_NStores information about a commit point
commit point에 대한 정보를 저장
Lock Filewrite.lock

The Write lock prevents multiple IndexWriters from writing to the same file.
Write lock은 다수의 IndexWriter가 동일항 file에 기록하는 것을 방지

Segment Info.siStores metadata about a segment
segment에 대한 metadata를 저장
Compound File.cfs, .cfe

An optional “virtual” file consisting of all the other index files for systems that frequently run out of file handles.
file handle이 자주 소모되는 system의 다른 모든 index file로 구성된 선택적 “가상(virtual)” file

Fields.fnmStores information about the fields
field에 대한 정보를 저장
Field Index.fdx

Contains pointers to field data
field data의 pointer를 포함

Field Data.fdtThe stored fields for documents
document에 대한 stored field
Term Dictionary.tim

The term dictionary, stores term info
term dictionary, term 정보를 저장

Term Index.tip

The index into the Term Dictionary
Term Dictionary에 대한 index

Frequencies.doc

Contains the list of docs which contain each term along with frequency
빈도(frequency)와 함쎄 각 단어(term)을 포함한 document의 목록을 포함

Positions.pos

Stores position information about where a term occurs in the index
index에서 단어(term)가 나타나는 위치(position) 정보를 저장

Payloads.pay

Stores additional per-position metadata information such as character offsets and user payloads
character offset 및 user payload 같은 위치(position)별 metadata를 추가로 저장

Norms.nvd, .nvm

Encodes length and boost factors for docs and fields
document와 field에 대한 길이(length) 및 boost 요소의 encode

Per-Document Values.dvd, .dvm

Encodes additional scoring factors or other per-document information.
추가 scoring 요소 또는 기타 document별 정보를 encode

Term Vector Index.tvxStores offset into the document data file
document data file에 offset을 저장
Term Vector Documents.tvd

Contains information about each document that has term vectors
term vector를 가진 각 document에 대한 정보를 포함

Term Vector Fields.tvf

The field level info about term vectors
term vector에 대한 field level 정보

Live Documents.liv

Info about what files are live
live file에 대한 정보

Often, you’ll also see a segments.gen file in the Lucene index directory, which is a helper file that contains information about the current/latest segments_N file and is used for filesystems that might not return enough information via directory listings to determine the latest generation segments file.

가끔, Lucene index directory에서 segments.gen 도 볼 수 있는데, 이 file은 현재 또는 최신 segments_N file에 대한 정보를 포함하고 있으며, 최신 segment file을 판별하기 위해, directory 목록을 통해 충분한 정보를 반환하지 못하는 filesystem에 사용된다.

In older Lucene versions you’ll also find files with the .del suffix. These serve the same purpose as the Live Documents (.liv) files – in other words, these are the deletion lists. If you’re wondering what all this talk about Live Documents and deletion lists are about, you might want to read up on it in the section about building indexes in our Elasticsearch from the bottom-up article.

이전 Lucene 버전에서는 .del접미어가 붙은 파일도 있다. 이것은 Live Documents(.liv) file과 동일한 용도로 사용된다. 즉, 삭제 목록이다. Live Document 및 삭제 목록에 대한 모든 내용에 대해 궁금한 점이 있다면, Elasticsearch from the bottom-up article에서 index를 작성하는 방법에 대한 항목을 읽도록 하자.

Fixing Problematic Shards

Since an Elasticsearch shard contains a Lucene Index, we can use Lucene’s wonderful CheckIndex tool, which enables us to scan and fix problematic segments with usually minimal data loss. We would generally recommend Elasticsearch users to simply re-index the data, but if for some reason that’s not possible and the data is very important, it’s a route that’s possible to take, even if it requires quite a bit of manual work and time, depending on the number of shards and their sizes.

Elasticsearch shard에는 Lucene Index가 포함되어 있으므로, Lucene의 멋진 CheckIndex tool를 사용하면, 문제가 있는 segment를 검사하고, 최소한의 data 손실로 수정할 수 있다. 일반적으로 Elasticsearch 사용자에게 단순히 data를 다시 index하라고 권장하지만, 어떤 이유로 그것이 불가능하고, data를 매우 중요하게 생각하는 경우, 상다한 양의 수동 작업과 시간이 많이 걸리더라도 취할 수있는 방법이다. shard의 수와 크기에 따라 다르다.

The Lucene CheckIndex tool is included in the default Elasticsearch distribution and requires no additional downloads.
Lucene CheckIndex tool은 Elasticsearch 배포판에 포함되어 있으며, 추가로 내려받을 필요가 없다.
# change this to reflect your shard path, the format is
# {path.data}/{cluster_name}/nodes/{node_id}/indices/{index_name}/{shard_id}/index/

$ export SHARD_PATH=data/elasticsearch/nodes/0/indices/foo/0/index/
$ java -cp lib/elasticsearch-*.jar:lib/*:lib/sigar/* -ea:org.apache.lucene... org.apache.lucene.index.CheckIndex $SHARD_PATH

If CheckIndex detects a problem and its suggestion to fix it looks sensible, you can tell CheckIndex to apply the fix(es) by adding the -fix command line parameter.

CheckIndex가 문제점을 발견하고, 수정할 방법이 합리적이라면, 매개변수에 -fix 를 추가하여, CheckIndex가 fix를 적용하도록 할 수 있다.

Storing Snapshots

You might wonder how all these files translate into the storage used by the snapshot repositories. Wonder no more: taking this cluster, snapshotting it as my-snapshot to a filesystem based gateway and inspecting the files in the repository we’ll find these files (some files omitted for brevity):

이러한 모든 파일이 snapshot repositories에서 사용되는 저장소로 어떻게 변환되는지 궁금할 것이다. 이 cluster를 사용하여 filesystem 기반 gateway에 my-snapshot 으로 snapshot을 만들고, repository에서 file을 검사하면, 다음과 같은 file을 찾을 수 있다 (일부 파일 생략).

$ tree -h snapshots
snapshots
├── [  31]  index
├── [ 102]  indices
   └── [ 136]  foo
       ├── [1.2K]  0
          ├── [ 350]  __0
          ├── [1.8K]  __1
...
          ├── [ 350]  __w
          ├── [ 380]  __x
          └── [8.2K]  snapshot-my-snapshot
       └── [ 249]  snapshot-my-snapshot
├── [  79]  metadata-my-snapshot
└── [ 171]  snapshot-my-snapshot

At the root we have an index file that contains information about all the snapshots in this repository and each snapshot has an associated snapshot- and a metadata- file. The snapshot- file at the root contains information about the state of the snapshot, which indexes it contains and so on. The metadata- file at the root contains the cluster metadata at the time of the snapshot.

root에는 이 repository에 있는 모든 snapshot에 대한 정보가 들어있는 index file을 가지고 있으며, 각 snapshot은 연관된 snapshot- 과 metadata- file이 있다. root의 snapshot- file에는 snapshot의 상태에 대한 정보가 포함되어 있다. root의 metadata- file에는 snapshot 시점의 cluster metadata 포함된다.

When compress: true is set, metadata- and snapshot- files are compressed using LZF, which focuses on compressing and decompressing speed, which makes it a great fit for Elasticsearch. The data is stored with a header: ZV + 1 byte indicating whether the data is compressed. After the header there will be one or more compressed 64K blocks on the format: 2 byte block length + 2 byte uncompressed size + compressed data. Using this information you can use any LibLZF compatible decompressor. If you want to learn more about LZF, check out this great description of the format.
compress: true 가 설정되면, metadata- 와 snapshot- file은 압축 및 압축 해제 속도에 중점을 둔 LZF를 사용하여 압축되므로, Elasticsearch에 가장 적합하다. data는 header와 함께 저장된다: ZV + 1 byte는 압축 여부를 나타낸다.header 다음에는 2 byte block length + 2 byte uncompressed size + compressed data 형식의 하나 이상의 압축된 64K block이 있다. 이 정보를 사용하면, LibLZF 호환 decompressor를 사용할 수 있다. LZF에 대해 더 자세히 알고 싶다면, 이 형식에 대한 설명을 확인하자.

At the index level there is another file, indices/{index_name}/snapshot-{snapshot_name} that contains the index metadata, such as settings and mappings for the index at the time of the snapshot.

index level에는, snapshot 시점의 index에 대한 설정 및 mapping과 같은, index metadata가 들어있는, indices/{index_name}/snapshot-{snapshot_name} 이라는 또 다른 file이 있다.

At the shard level you’ll find two kinds of files: renamed Lucene index files and the shard snapshot file: indices/{index_name}/{shard_id}/snapshot-{snapshot_name}. This file contains information about which of the files in the shard directory are used in the snapshot and a mapping from the logical file names in the snapshot to the concrete filenames they should be stored as on-disk when being restored. It also contains the checksum, Lucene versioning and size information for all relevant files that can be used to detect and prevent data corruption.

shard level에서는, Lucene index file의 이름을 변경한 것과 shard snapshot file인 indices/{index_name}/{shard_id}/snapshot-{snapshot_name}의 두 가지 file이 있다. 이 file은 snapshot에 사용되는 shard directory에 있는 file에 대한 정보와, 복원시에 disk에 저장해야 하는 구체적인 file 이름과 snapshot의 논리적 file 이름간의ㅣ mapping 정보를 포함한다. 또한 data 손상을 감지하고 방지하는 데 사용할 수 있는, 모든 관련 file에 대한 checksum, Lucene version 및 크기 정보를 포함한다.

You might wonder why these files have been renamed instead of just keeping their original file names, which potentially would have been easier to work with directly on disk. The reason is simple: it’s possible to snapshot an index, delete and re-create it before snapshotting it again. In this case, several files would end up having the same names, but different contents.

원래 file 이름을 유지하지 않고, 이들 file의 이름이 변경된 이유가 궁금할 것이다.이로 인해 disk에서 직접 작업하는 것이 더 쉬워질 수 있다. 그 이유는 간단합니다. 다시 snapshot하기 전에, index를 shanshot하고, index를 삭제하고 다시 만들 수 있다. 이 경우 여러 file이 동일한 이름을 가지지만, 다른 내용을 가진다.

Summary

In this article we have looked at the files written to the data directory by various levels of Elasticsearch: the node, index and shard level. We’ve seen where the Lucene indexes are stored on disk, and briefly described how to use the Lucene CheckIndex tool to verify and fix problematic shards.

이 게시물에서는, Elasticsearch의 다양한 level인 node, index 및 shard level에 따라, data directory에 작성된 file을 살펴 보았다. Lucene index가 disk에 저장되는 위치를 살펴본 후, Lucene CheckIndex 도구를 사용하여, 문제가 있는 shard를 확인하고, 수정하는 방법을 간략하게 설명했다.

Hopefully, you won’t ever need to perform any operations on the contents of the Elasticsearch data directory, but having some insight into what kind of data is written to your file system by your favorite search based database is always a good idea.

Elasticsearch data directory의 내용에 대한 작업을 수행 할 필요는 없지만, 선호하는 검색 기반 데이터베이스의 file system이 사용하는 data의 종류를 파악할 수 있기를 바란다.

Editor’s Note (May 1, 2017): Starting with 6.0, any curl command to Elasticsearch containing content will require a valid content type header. As a result, this post has been updated to reflect this change and to set readers of this post up for success with future versions.

편집자 주 (2017 년 5 월 1 일) : 6.0부터, content를 포함한 Elasticsearch에 대한 curl command는 유효한 content header가 필요하다. 결과적으로, 이 변경 사항을 반영하고, 이 게시물의 독자들이 향후 버전에서도 이 게시물을 이용할 수 있도록, 이 게시물을 업데이트하였다.

원문 : A Dive into the Elasticsearch Storage