기존 elasticCloud를 사용했던 서비스를 opensearch로 변경해야 하는 업무가 할당되었다.
[이슈]
변경 업무에 대해서 몇가지 이슈가 있는데
- 현재 사용하고 있는 elasticCloud는 elasticsearch 8.5.3 버전을 사용하고 있다.
- elasticCloud와 opensearch에서 지원하는 라이브러리는 서로 다르다.
이로 인해서 elasticCloud에서 opensearch로 넘어간다면 라이브러리도 변경해야하고 기존의 rest-client 문법이 아닌, HighLevelClient 문법으로 변경해야 하는 크나큰 작업을 해야 한다.
큰 작업을 하는 것보다는 elasticsearch-rest-client를 이용하여 opensearch를 연결하는 방법이 있지 않을까 하여 구글링을 시작을 해봤는데 자료가 그렇게 많지는 않았다.
자료를 찾다가 할 수 없지, 이제 바꿔야 하는 날이 온 것인가?라는 생각이 들었다. 그런데 또 하나의 생각이 들었다. 회사에서 만약 엘라스틱서치를 온프레미스 환경으로 구축한다면 똑같은 작업을 한번 더 해야 하지 않을까?라는 생각을 하게 됐다. 전혀 이펙티브 하지 않아..
[해결]
그런데, 가장 큰 힌트는 매우 가까이에 있었고 세 가지나 있었다.
1. rest-client는 HighLevelClient와 LowLevelClient로 만들어졌다는 것
2. elasticCloud에서 High Level Client에서 마이그레이션 하는 방법을 알려줬다는 것
3. elasticSearch는 REST API로 되어있다!
나는 어떻게는 rest-client가 API 통신으로 동작을 한다는 조건을 찾아야만 했다.
rest-client의 조회에 대한 request 요청은 아래와 같이 실행된다.
1. search를 통하여 query와 매퍼 클래스를 실행시킨다.
2.query와 매퍼 클래스를 이용하여 Request를 수행하도록 만든다.
3. 만들어진 request로 요청을 만들고, 요청을 통하여 응답을 받아 결과를 반환한다.
여기서 Request는 SearchRequest: POST /board/_search?typed_keys=true {"query":{"bool":{"filter":[...} 라는 내가 그토록 찾던 API를 만들어 냈다. 이 안에는 HttpMethod, URL, Query를 볼 수 있었다.
실행 후에 clientReq 안에서 데이터가 보정된 후에는 쿼리를 볼 수가 없었다. 과연 어디로 갔을까?
그렇다. entity가 elasticClient의 query였고, entity는 RestClientTransPort에서 바이트코드 화하는 것이었다.
디버깅한 지 30분 만에 찾은 것 같다. 구현을 분석하기 위한 디버깅은 띄엄띄엄하지 말고 한 줄씩 해 나아가 야한 것을 깨달았던 순간.
이렇게 만들어낸 Request 값을 이제 rest-client는 apache의 InternalHttpAsyncClient를 통하여 요청을 보낸다.
이로써 rest-client도 API 통신을 통하여 elasticsearch에 요청을 보낸다는 것을 알았다. 그러면? 하나의 인사이트가 생긴다.
elasticCloud든, opensearch든 elasticSearch로 구현되어 있고, 이를 모두 API 통신을 통하여 결과를 가져오니깐, rest-client의 통신 부분만 변경을 해주면 되겠다!라고 말이다!
통신 부분을 고쳐주기 위하여 elasticConfig를 가보자.
이 코드는 elasticCloud에서 제공하는 가장 베이직한 rest-client의 연결 코드다. 매우 간단하다. 처음에 나는 opensearch로 변경해 주려면 host와 port만 변경해 주면 되겠지라는 생각과 함께 opensearch에 대한 정보로 변경해서 실행을 해보았다.
결과는 null이었다.??????????????
하지만, 그 뒤에 있는 내용이 진짜였다.
Caused by: org.elasticsearch.client.ResponseException: method [POST], host [url], URI [/board/_search?typed_keys=true], status line [HTTP/1.1 406 Not Acceptable]
{"error":"Content-Type header [application/vnd.elasticsearch+json; compatible-with=8] is not supported","status":406}
바로 rest-client 연결 부에 json 관련 정보를 넣으라는 것이었다. ( https://stackoverflow.com/questions/72496582/elasticsearch-post-my-index-count-error-406-not-acceptable )
그래서 Header에 Json 관련 정보를 넣어주었다.
그 뒤에 이제 정말로 되는 거겠지?라고 생각하여 다시 한번 요청을 날려봤다.
Caused by: co.elastic.clients.transport.TransportException: [es/search] Missing [X-Elastic-Product] header. Please check that you are connecting to an Elasticsearch instance, and that any networking filters are preserving that header.
이제 X-Elastic-Product를 넣어달라고 한다. 이게 뭐지?라는 생각에 elastic 진영에 들어가서 서치를 해봤다. 다행히 파이썬 진영에서 아주 욕을 먹고 있었던 글이 하나 있었는데, 그게 나의 마지막 희망이 될 줄은 몰랐다.
즉, elastic 8.5.3에 X-Elastic-Product를 넣어야 한다고 한다. 그렇다 내가 지금 쓰고 있는 rest-client가 8.5.3 버전 용이라서 저 부분을 꼭 넣어야 결과 값에 대해서 제대로 인식한다는 것이었다.
결과적으로 아래와 같이 Header에 X-ElasticProduct를 넣어서 연결부를 마무리해줬다.
실행해 본 결과. 요청이 제대로 왔다.
크으.. 200! 성공했도다 성공했어! 그토록 싸우던 elasticCloud와 openSearch를 화합하도록 만들었어요!! ㅜㅜ... 서로 친해집시다..
[결론]
오래간만에 하나의 라이브러리를 통하여 다이브딥 할 수 있었고 성공의 맛을 맛볼 수도 있었습니다. 앞으로도 이러한 기회가 많이 있었으면 좋겠고, 저 또한 이러한 기회가 생겼을 때 깊게 다이브딥 할 수 있도록 연습을 자주자주 해야 되겠다는 생각이 드네요. 스프링 까는 것부터 시작을 해봐야 하나(?) 아무튼! 긴 글 읽어주셔서 감사합니다.
[링크]
- https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/connecting.html
- https://github.com/elastic/elasticsearch-py/pull/1623
'Spring' 카테고리의 다른 글
SpringBoot LogBack 간단설정 (0) | 2021.06.07 |
---|---|
SpringBoot Dynamic Log (0) | 2021.06.07 |
SpringBoot Kotlin Log(AOP/Filter) (0) | 2021.06.06 |
@Transactional 사용 시 주의해야하는 8가지 (0) | 2021.03.21 |
@Transactional을 아시나요? (0) | 2021.03.21 |