data engineering

elasticsearch disk full 관련 해결법, 리텐션

qkqhxla1 2020. 5. 16. 11:22

es에 데이터를 넣으려고 하는데  u'error': {u'reason': u'blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];', u'type': u'cluster_block_exception'} 요런 메시지가 뜨면서 데이터가 es로 들어가지 않는다.


구글링해보니 https://dev-yeon.tistory.com/12 에서 디스크가 거의 차서 발생하는 에러라고 한다. 디스크가 찼으면.. 인덱스를 좀 지워주면 되겠네? 하고 지우려했더니 read only라고 에러가 뜬다.저 블로그에서 나온것처럼 read only모드를 풀어주자.

PUT _all/_settings
{
    "index": {
        "blocks": {
        "read_only_allow_delete": "false"
        }
    }
}

이후 인덱스들을 지우기 전에 여기에 나온걸 활용해 디스크 용량을 알아보자.


curl -XGET 'http://localhost:9200/_cat/allocation?v'


돌려보면 avail disk가 거의 안 남아있다. 이제 DELETE로 도큐먼트를 반정도 지워주고 다시 돌려봤는데 용량 차이가 별로 없다. 왜그러지.. 하고 찾아보니


https://stackoverflow.com/questions/20608417/elasticsearch-how-to-free-store-size-after-deleting-documents 여기에 document를 delete한 후 optimizing 이나 merge를 해 줘야 디스크 공간이 생긴다고 한다.


이전 버전은 다른 명령어를 쓰지만 es 2.x버전부터는 optimize는 deprecated되고,


curl -XPOST 'http://localhost:9200/_forcemerge?only_expunge_deletes=true'


이 명령어를 써서 merge한다고 한다. 로컬에서 es주소만 바꿔서 실행해보니, disk check를 했을때 아래처럼 공간이 생겼음을 확인할 수 있다.


shards disk.indices disk.used disk.avail disk.total disk.percent host         ip           node
   281       30.6gb    33.7gb     15.2gb     48.9gb           68 x.x.x.x x.x.x.x elasticsearch-data-0
   281       30.6gb    32.9gb       16gb     48.9gb           67 x.x.x.x  x.x.x.x  elasticsearch-data-1


그럼 이제는 공간이 조금 생겼으니 다시는 이런 일이 발생하지 않도록 리텐션을 설정해야 한다. 근데 es에는 리텐션 설정하는 옵션이 딱히 없는것같다.

https://stackoverflow.com/questions/24874787/how-do-i-configure-elasticsearch-to-retain-documents-up-to-30-days


음 그러면 내가 코딩으로 리텐션을 구현해야겠다. 인덱스 저장시 '인덱스명-2020-05' 이렇게 월로 저장해놓고 지울때 월 단위로 지우거나, 또는 도큐먼트 자체에 time필드를 넣고 delete by query방식으로time이 한달 이후 것들을 검색한다음 지우면 되겠다.


공식 api문서에 forcemerge가 있다.

from elasticsearch import Elasticsearch
from elasticsearch.client import IndicesClient
~~~~
self.es = Elasticsearch([{'host': self.host, 'port': self.port}], timeout=120)
self.indicesclient = IndicesClient(self.es)
~~~~~
self.es.delete_by_query(index='인덱스 네임',
                body={'query': {
                "bool": {
                   "must": [
                       {"range": {format[1]: {'lt': format[2].format(self.month_ago)}}},
                    ]
                }
           }
           })
print self.indicesclient.forcemerge(only_expunge_deletes=True)

위처럼 적당히 코드를 짜고 1달 이전의 time이 있으면 지우도록 delete by query를 이용해서 짜고 forcemerge를 출력해보면 curl로 돌렸을때와 같은 결과값이 리턴됨을 확인할 수 있다.


이제 위 코드를 크론탭 등에 등록해놓으면 수동 리텐션 설정 끝.