배경 및 목적
Elasticsearch는 대량의 로그나 이벤트 데이터를 실시간으로 검색할 수 있는 강력한 도구이지만, 시간이 지남에 따라 저장 용량이 급격히 증가하는 문제가 발생합니다. 특히 일자별로 인덱스를 생성하는 경우, 오래된 인덱스가 누적되어 클러스터 성능 저하 및 디스크 부족 현상이 나타날 수 있습니다. 기존에는 cron 기반 스크립트로 특정 날짜의 인덱스를 삭제했으나, 실행 누락 시 복구가 어렵고 유연성이 부족했습니다. 이를 해결하기 위해 Spring Boot 애플리케이션을 활용해 주기적으로 설정된 보관 기간을 초과한 인덱스를 자동으로 스캔하고 삭제하는 시스템을 구현합니다.
개발 환경
| 항목 | 버전 |
|---|---|
| Java | 8 |
| Spring Boot | 2.1.8.RELEASE |
| Spring Data Elasticsearch | 3.1.10.RELEASE |
| Elasticsearch | 6.2.2 |
구현 흐름
- application.properties에 보관 기간(일 단위)과 인덱스 접두사 설정
- 애플리케이션 시작 후 주기적으로 모든 인덱스 목록 조회
- 설정된 접두사에 해당하는 인덱스 필터링
- 각 인덱스 생성 시간 조회 후 현재 시간과 비교
- 보관 기간을 초과한 인덱스를 삭제 처리
- 10분 간격으로 반복 실행
의존성 설정 (Maven)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
</dependencies>
설정 파일 구성
application.properties에 인덱스 접두사별 보관 기간을 명시합니다.
# Elasticsearch 연결 정보
spring.data.elasticsearch.cluster-nodes=localhost:9300
spring.data.elasticsearch.cluster-name=my-cluster
# 인덱스 보관 기간 설정 (단위: 일)
index.retention.log-service=7
index.retention.metrics-data=14
index.retention.audit-log=30
설정 정보 바인딩 클래스
@ConfigurationProperties를 사용해 외부 설정 값을 자바 객체로 매핑합니다.
@Component
@ConfigurationProperties(prefix = "index.retention")
@Getter @Setter
public class IndexRetentionConfig {
private Map<String, Integer> policies = new HashMap<>();
}
핵심 비즈니스 로직
CommandLineRunner를 구현하여 애플리케이션 시작 후 주기적으로 작업을 수행합니다.
@Slf4j
@SpringBootApplication
public class IndexCleanupApplication implements CommandLineRunner {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Autowired
private IndexRetentionConfig retentionConfig;
public static void main(String[] args) {
SpringApplication.run(IndexCleanupApplication.class, args);
}
@Override
public void run(String... args) {
while (true) {
try {
processExpiredIndices();
TimeUnit.MINUTES.sleep(10); // 10분 대기
} catch (Exception e) {
log.error("Index cleanup job failed", e);
}
}
}
private void processExpiredIndices() {
Set<String> allIndices = fetchAllIndexNames();
if (allIndices.isEmpty()) return;
retentionConfig.getPolicies().forEach((prefix, days) -> {
log.info("Processing indices with prefix: '{}' (retention: {} days)", prefix, days);
List<String> expired = findExpiredIndices(allIndices, prefix, days);
performDeletion(expired);
});
}
private Set<String> fetchAllIndexNames() {
IndicesStatsResponse response = elasticsearchTemplate.getClient()
.admin().indices()
.stats(new IndicesStatsRequest().all())
.actionGet();
return response.getIndices().keySet();
}
private long getIndexCreationTime(String indexName) {
GetSettingsResponse settings = elasticsearchTemplate.getClient()
.admin().indices()
.getSettings(new GetSettingsRequest().indices(indexName))
.actionGet();
String timestamp = settings.getIndexToSettings().get(indexName)
.getAsSettings("index").get("creation_date");
return Long.parseLong(timestamp);
}
private List<String> findExpiredIndices(Set<String> indices, String prefix, int retentionDays) {
long threshold = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(retentionDays);
return indices.parallelStream()
.filter(name -> name.startsWith(prefix))
.filter(name -> {
try {
long created = getIndexCreationTime(name);
return created < threshold;
} catch (Exception e) {
log.warn("Failed to get creation time for index: {}", name, e);
return false;
}
})
.collect(Collectors.toList());
}
private void performDeletion(List<String> indicesToDelete) {
if (indicesToDelete.isEmpty()) {
log.info("No expired indices found.");
return;
}
log.info("Attempting to delete {} expired indices.", indicesToDelete.size());
for (String index : indicesToDelete) {
boolean deleted = elasticsearchTemplate.deleteIndex(index);
if (deleted) {
log.info("Successfully deleted index: {}", index);
} else {
log.warn("Failed to delete index: {}", index);
}
}
}
}
실행 결과
애플리케이션을 배포하면 지정된 간격으로 Elasticsearch 클러스터를 스캔하여 설정된 보관 기간을 넘긴 인덱스를 안정적으로 제거합니다. 예를 들어, log-service-2023.01.01과 같은 인덱스가 7일 이상 경과하면 자동으로 삭제 대상에 포함됩니다. 시스템 다운타임이나 스케줄링 누락에도 유연하게 대응할 수 있어 운영 안정성이 향상됩니다.