이슈
이번 프로젝트간 우리 서버는 총 두대이다. (편의상 본체 서버 A, 서브 서버 B로 부르겠다.)
ElasticSearch(특히 kibana)와 스크래퍼가 자원을 많이 먹기에, 보조 서버 B에 기능을 할당해놓은 상태이다.
그리고 주요 로직은 A 서버에 집중되어 있다.
따라서 A 서버의 springboot와 B 서버의 ElasticSearch를 연동해야 한다.
이 과정에서 자연스럽게 원격 접근을 위해 X-pack등의 보안 기능을 고려해야 한다는 점을 이제야 깨닫았다.
다행스럽게도 7.1~7.2 버전부터 해당 기능이 부분적으로 무료로 풀린 듯 하다.
7.2 version x-pack 공식 docs : https://www.elastic.co/guide/en/elasticsearch/reference/7.2/setup-xpack.html
yml config
sudo nano /etc/elasticsearch/elasticsearch.yml 를 통해 설정에 들어가보자.
대략적인 yml 내용은 다음과 같다.
Cluster 설정
- cluster.name: my-application: 클러스터의 이름을 설정한다. 여러 노드를 하나로 묶을 때 사용
Node 설정
- node.name: node-1: 노드의 이름을 설정한다. 클러스터 내에서 각 노드를 구분하기 위해 사용한다.
- node.attr.rack: r1: 노드에 커스텀 속성을 추가한다. 이런 속성을 사용하여 특정 노드에 작업을 분배할 수 있다.
Paths 설정
- path.data: /var/lib/elasticsearch: Elasticsearch 데이터가 저장될 디렉토리 경로를 설정한다.
- path.logs: /var/log/elasticsearch: 로그 파일이 저장될 디렉토리 경로를 설정한다.
Memory 설정
- bootstrap.memory_lock: true: 메모리를 시작 시 잠근다. 이를 통해 Elasticsearch가 swap 메모리를 사용하지 않게 한다.
Network 설정
- network.host: 192.168.0.1: Elasticsearch가 바인딩할 네트워크 주소를 설정한다.
- http.port: 9200: HTTP 통신을 위한 포트를 설정한다.
Discovery 설정
- discovery.seed_hosts: ["host1", "host2"]: 클러스터 형성이나 노드 발견을 위한 초기 호스트 리스트를 설정한다.
- cluster.initial_master_nodes: ["node-1", "node-2"]: 최초 마스터 노드 후보를 설정한다.
Gateway 설정
- gateway.recover_after_nodes: 3: 전체 클러스터 재시작 후 몇 개의 노드가 시작되어야 복구를 시작할지 설정한다.
Various 설정
- action.destructive_requires_name: true: 인덱스를 삭제할 때 명시적으로 이름을 지정해야 하는지 설정한다.
이정도 보았으니, 실제 설정을 해 보자.
우리가 건드려야 할 것은 크게 두 가지이다. 1. HTTP 설정, 2. 보안 설정
1. HTTP 설정
+ 수정
7.x 이상 버전부터 호스트와 노드 설정을 해야 한다고 한다.
이 부분을 추가해주자.
Springboot - gradle
깡통 서버 생성
ES Date Repo docs : 버전에 따라 빠르게 바뀌는 듯 하다. 4.2 버전을 사용해야 한다.
https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#new-features
이 분의 블로그와, docs 공식 분서를 비교해가며 감을 잡았다.
공식 문서가 좋긴 하지만.. 처음부터 읽어가면서 코드를 짜기는 쉽지 않았다.
spring:
elasticsearch:
uris: http://127.0.0.1:9200
username: "당신의 이름"
password: "당신의 비밀번호"
connection-timeout: 5s
socket-timeout: 30s
host: 127.0.0.1
port: 9200
Config file
Docs 예제를 살펴보면서 구현해보자.
- ClientConfiguration 설정:
- ClientConfiguration 객체를 생성하는 데 사용되는 빌더 패턴이다.
- .connectedTo("localhost:9200"): Elasticsearch 서버의 주소를 설정한다.
- RestHighLevelClient 생성:
- RestClients.create(clientConfiguration).rest(): 위에서 설정한 clientConfiguration을 기반으로 RestHighLevelClient를 생성한다고 한다.
- RestHighLevelClient는 Elasticsearch과 통신을 위한 고수준 클라이언트다.
- LowLevelClient 획득:
- 통신용 고수준 클라이언트에서 저수준 클라이언트를 가져오는 듯 하다
고수준 클라이언트와 저수준은 다음과 같은 차이가 있다.
고수준의 경우 ElasticSearch를 쉽게 구현하는(직렬화나 메인 API를 쉽게 구현) 클라이언트이다. 주요 기능을 직관적이고 쉽게 사용할 수 있다.
저수준의 경우 반대로 조금 더 어렵지만, 유연하고 사용자 관점에서 원하는 기능을 추가할 수 있을 것이다.
연결 확인
@RestController
public class TestController {
@Autowired
private RestHighLevelClient client;
@RequestMapping("test")
public String Test() {
try {
MainResponse response = client.info(RequestOptions.DEFAULT);
System.out.println("Elasticsearch 연결 성공: " + response.getVersion().toString());
} catch (Exception e) {
System.out.println("Elasticsearch 연결 실패: " + e.getMessage());
}
return "Well Done";
}
}
일단 인덱스명으로 도큐먼트를 전부 꺼내보자
CRUD 연산 위주로 사용하고,
검색 기능 등의 고급 기능은 Kibana를 통해 직접 설정할 예정이기에 이번 프로젝트에서는 Spring Data Elasticsearch를 사용하려고 한다.
간단한 예제로 먼저 부딪혀보겠다.
https://tecoble.techcourse.co.kr/post/2021-10-19-elasticsearch/
Document
@Document(indexName = "accommodation") //인덱스 매핑
@Getter
public class Accommodation {
@Id
private String id;
@Field(name = "accommodation_lng")
private String accommodationLng;
@Field(name = "accommodation_lat")
private String accommodationLat;
@Field(name = "accommodation_name")
private String accommodationName;
@Field(name = "accommodation_type")
private String accommodationType;
@Field(name = "accommodation_addr")
private String accommodationAddr;
@Field(name = "accommodation_pic")
private String accommodationPic;
@Field(name = "accommodation_score")
private String accommodationScore;
@Field(name = "accommodation_price")
private String accommodationPrice;
}
service 로직
@Service
@Slf4j
public class AccommodationService {
AccommodationRepository accommodationRepository;
public AccommodationService(AccommodationRepository accommodationRepository) {
this.accommodationRepository = accommodationRepository;
}
public Iterable<Accommodation> getAllResidences() {
Iterable<Accommodation> accommodations = accommodationRepository.findAll();
return accommodations;
}
public List<Accommodation> search(String input) {
return accommodationRepository.findByAccommodationName(input);
}
}
'프로젝트 > 여행지 오픈 API' 카테고리의 다른 글
[ElasticSearch, LogStash] LogStash로 csv 파일 적재 (0) | 2023.10.31 |
---|---|
[ElasticSearch] Nori 분석기, 오타 보정(fuzzy), 로그스태시(logStash) (0) | 2023.10.30 |
짧게 진행하는 이번주 회고 (0) | 2023.10.27 |
[ElasticSearch] 8. 클러스터와 노드의 구조 (0) | 2023.10.26 |
여행지 오픈 API 설명과 Elastic Search를 사용한 아이디어. (0) | 2023.10.26 |