Reference/How To ...

4. Tune for indexing speed

drscg 2018. 10. 5. 18:02

Use bulk requests

Bulk requests will yield much better performance than single-document index requests. In order to know the optimal size of a bulk request, you should run a benchmark on a single node with a single shard. First try to index 100 documents at once, then 200, then 400, etc. doubling the number of documents in a bulk request in every benchmark run. When the indexing speed starts to plateau then you know you reached the optimal size of a bulk request for your data. In case of tie, it is better to err in the direction of too few rather than too many documents. Beware that too large bulk requests might put the cluster under memory pressure when many of them are sent concurrently, so it is advisable to avoid going beyond a couple tens of megabytes per request even if larger requests seem to perform better.

bulk request는 단일 document index request보더 훨씬 우수한 성능을 제공한다. bulk request의 최적 크기를 파악하기 위해서는 단일 shard를 가진 단일 index에서 test를 해야 한다. 먼저 한 번에 100개의 document를 index해 보자. 그 다음에 200, 400 등 매 test를 수행할 때마다 document의 수를 2배로 늘리자. index 속도가 안정적인 상태에 이르면, data에 대한 bulk request의 최적 크기에 도달했음을 알 수 있다. 같은 수일 경우, 너무 많은 document보다는 더  적은 방향으로 하는 것이 더 좋다. 너무 큰 bulk request는 그것들이 동시에 전송될 경우, cluster에서 memory 문제가 발생할 수 있으므로, 더 큰 request가 더 잘 수행되더라도, request 당 수십 MB를 초과하지 않는 것이 좋다. 

Use multiple workers/threads to send data to Elasticsearch

A single thread sending bulk requests is unlikely to be able to max out the indexing capacity of an Elasticsearch cluster. In order to use all resources of the cluster, you should send data from multiple threads or processes. In addition to making better use of the resources of the cluster, this should help reduce the cost of each fsync.

bulk request를 전송하는 단일 thread는 Elasticsearch cluster를 최대한 활용할 수 없다. cluster의 모든 resource를 최대한 활용하기 위해서, 멀티 thread나 process로 data를 전송해야 한다. 이렇게 하면, cluster의 resource를 더 잘 활용할 수 있을 뿐 아니라 fsync의 비용을 줄일 수 있다.

Make sure to watch for TOO_MANY_REQUESTS (429) response codes (EsRejectedExecutionExceptionwith the Java client), which is the way that Elasticsearch tells you that it cannot keep up with the current indexing rate. When it happens, you should pause indexing a bit before trying again, ideally with randomized exponential backoff.

Elasticsearch에서 현재 index 속도를 감당할 수 없다고 알려주는 TOO_MANY_REQUESTS (429) response code ( Java client에서 EsRejectedExecutionException ) 를 확인하자. 이 상황이 발생하면, 다시 시도하기 전에 index를 중단해야 한다. 

Similarly to sizing bulk requests, only testing can tell what the optimal number of workers is. This can be tested by progressively increasing the number of workers until either I/O or CPU is saturated on the cluster.

bulk request의 크기 조절과 마찬가지로, test만이 최적화된 worker의 수를 알 수 있는 방법이다. cluster의 I/O 나 CPU가 포화상태에 이를 때까지, 계속해서 worker의 수를 늘리면서 test할 수 있다.

Increase the refresh interval

The default index.refresh_interval is 1s, which forces Elasticsearch to create a new segment every second. Increasing this value (to say, 30s) will allow larger segments to flush and decreases future merge pressure.

index.refresh_interval 의 기본값은 1s 이므로, Elasticsearch는 매 초마다 새로운 segment를 생성한다. 이 값을 증가(예를 들어, 30s)시키면, 더 큰 segment는 flush하고, 향후 merge도 감소시킨다.

Disable refresh and replicas for initial loads

If you need to load a large amount of data at once, you should disable refresh by setting index.refresh_interval to -1 and set index.number_of_replicas to 0. This will temporarily put your index at risk since the loss of any shard will cause data loss, but at the same time indexing will be faster since documents will be indexed only once. Once the initial loading is finished, you can set index.refresh_interval and index.number_of_replicas back to their original values.

대량의 data를 한번에 load해야 한다면, index.refresh_interval 를 -1 로, index.number_of_replicas 를 0 으로 설정하여 refresh를 비활성화시켜야 한다. 이 경우 shard에 문제가 발생하면 data 손실이 발생할 수 있어, index가 위험에 노출되지만, document가 한 번만 index되므로, 동일한 시간에 index가 더 빨라진다. 일단 초기 load가 끝나면, index.refresh_interval 와 index.number_of_replicas 를 원래의 값으로 되돌릴 수 있다.

Disable swapping

You should make sure that the operating system is not swapping out the java process by disabling swapping.

swap을 비활성화하여 OS가 java process를 swap하지 않도록 해야 한다.

Give memory to the filesystem cache

The filesystem cache will be used in order to buffer I/O operations. You should make sure to give at least half the memory of the machine running Elasticsearch to the filesystem cache.

filesystem cache는 I/O 연산을 buffering하는데 사용된다. Elasticsearch가 동작하고 있는 시스템의 memory 중 적어도 절반 이상을 filesystem cache에 할당해야 한다.

Use auto-generated ids

When indexing a document that has an explicit id, Elasticsearch needs to check whether a document with the same id already exists within the same shard, which is a costly operation and gets even more costly as the index grows. By using auto-generated ids, Elasticsearch can skip this check, which makes indexing faster.

명시적인 id를 가진 document를 index하면, Elasticsearch는 동일한 id를 가진 document가 동일한 shard내애 존재하는 여부를 확인해야 한다. 이는 비용이 많이 드는 작업이고 index가 커질수록 더 많은 비용이 소모된다. 자동 생성 id를 사용함으로써, Elasticsearch는 이 확인 작업을 생략할 수 있어, index 속도가 더 빨라진다.

Use faster hardware

If indexing is I/O bound, you should investigate giving more memory to the filesystem cache (see above) or buying faster drives. In particular SSD drives are known to perform better than spinning disks. Always use local storage, remote filesystems such as NFS or SMB should be avoided. Also beware of virtualized storage such as Amazon’s Elastic Block Storage. Virtualized storage works very well with Elasticsearch, and it is appealing since it is so fast and simple to set up, but it is also unfortunately inherently slower on an ongoing basis when compared to dedicated local storage. If you put an index on EBS, be sure to use provisioned IOPS otherwise operations could be quickly throttled.

index시에 I/O 문제가 있다면 filesysterm cache에 더 많은 memory를 할당(위 참조)하거나 더 빠른 driver를 구매하는 것을 고려해야 한다. 특히 SSD driver는 일반 회전 disk보다 성능이 뛰어나다고 알려져 있다. 항상 local storage를 사용하자. NFS나 SMB 같은 remote filesystem은 피해야 한다. 또한 Amazon의 Elastic Block Storage 같은 가상 storage도 주의하자. Elasticsearch는 가상 storage에서 매우 잘 동작하며, 매우 빠르고 설치가 간단해 매력적이만, 전용 local storage와 비교해보면, 불행하게도 본질적으로 더 느리다. index를 EBS 에 둔다면, provisioned IOPS를 사용햐여 한다. 그렇지 않으면 연산이 느려질 수 있다.

Stripe your index across multiple SSDs by configuring a RAID 0 array. Remember that it will increase the risk of failure since the failure of any one SSD destroys the index. However this is typically the right tradeoff to make: optimize single shards for maximum performance, and then add replicas across different nodes so there’s redundancy for any node failures. You can also use snapshot and restore to backup the index for further insurance.

RAID 0 array를 구성하여 다수의 SSD를 통해 index를 stripe하자. SSD 하나에 장애가 발생하면 index가 망가지므로, 장애의 위험성이 증가한다는 점을 기억하자. 그러나 이는 일반적으로 단일 shard를 최적화하고 성능을 극대화한 여러 node에 replica를 추가하여, node 장애에 대한 이중화를 실현한다. 또한 추가로 index를 backup하기 위해 snapshot and restore 를 사용할 수 있다.

Indexing buffer size

If your node is doing only heavy indexing, be sure indices.memory.index_buffer_size is large enough to give at most 512 MB indexing buffer per shard doing heavy indexing (beyond that indexing performance does not typically improve). Elasticsearch takes that setting (a percentage of the java heap or an absolute byte-size), and uses it as a shared buffer across all active shards. Very active shards will naturally use this buffer more than shards that are performing lightweight indexing.

node가 대량의 index만 수행한다면, indices.memory.index_buffer_size 가 대량의 index를 수행하는 shard별로 최대 512 MB의 index buffer를 제공할 수 있을 정도록 커야 한다.(일반적으로 그 이상이어도 index 성능은 향상되지 않는다) Elasticsearch는 해당 설정(java heap이나 byte로 된 절대값의 백분율)으로 모든 활성 shard에 대해 공유 buffer로 사용한다. 매우 활동적인 shard는 당연히 가벼운 index를 수행하는 shard보다 이 buffer를 더 많이 사용한다.

The default is 10% which is often plenty: for example, if you give the JVM 10GB of memory, it will give 1GB to the index buffer, which is enough to host two shards that are heavily indexing.

기본값은 자주 많이 사용되는 10% 이다. 예를 들자면, JVM에 10GB를 할당했다면, index buffer에는 1GB가 할당될 것이다. 이는 index 작업이 많은 2개의 shard에 충분하다.

Disable _field_names

The _field_names field introduces some index-time overhead, so you might want to disable it if you never need to run exists queries.

_field_names field 는 index시에 약간의 overhead를 발생키므로, exist query를 사용하지 않는다면, 이를 비활성화할 수 있다.

Additional optimizations

Many of the strategies outlined in Tune for disk usage also provide an improvement in the speed of indexing.

Tune for disk usage 에서 설명한 많은 부분 또한 index 속도를 향상시킨다.

'Reference > How To ...' 카테고리의 다른 글

6. Tune for disk usage  (0) 2018.10.05
5. Tune for search speed  (0) 2018.10.05
3. Getting consistent scoring  (0) 2018.10.05
2. Mixing exact search with stemming  (0) 2018.10.05
1. General recommendations  (0) 2018.10.05