Solr -> ElasticSearch, Redis, DB 전환기

    최근 회사에서 Solr에 다양한 문제들이 있어 ElasticSearch로 전환하게되었다.

    기존 문제점

    • 1. 40대의 서버로 인해 비용이 비싸다.
    • 2. 초기에 세팅을 잘못해 제어가 불가능한 부분들이 있었다.
      • - 배치가 돌아 데이터가 수정이 될때 풀색인을 진행해 1시간 가량 소요된다.
    • 3. 웹, 앱, BackOffice 등 다양한 곳에서 동일한 부분을 각각 다르게  Solr, DB를 호출하고 있어 하나로 통합하는 작업 필요

    6~8개 가량의 작업을 하였는데 가장 기억에 남은 부분을 기록하려고 한다.

     

     

    1. 검색(자동완성)

    기존에 Solr를 사용하고 있어서 Elastic과 Redis를 고민 중 트래픽도 많이 줄고, 키워드도 그렇게 많지 않아(약 3~5만개) Redis로 하기로 하고 개발을 시작하였다. (Elastic은 오버스펙 느낌)

     

     

    1차 Redis로 개발 (운영 배포 - 약 4시간 만에 사망)

    우선 자동완성 키워드들은 내부 로직에 의해 생성이 되고 배치서버를 통해 Redis에 HashMap 형태로 데이터가 적재되는 형태

    Redis에서 scan을 통해서 아래와 같은 형태로 자동완성 키워드를 가져와서 return 해주게끔 했다.

    List<String> autoComplete = new ArrayList<>();
    
    HashOperations<String, String, String> hashOps = redisTemplate.opsForHash();
    ScanOptions options = ScanOptions.scanOptions()
            .match(keyword + "*") 
            .count(10000)
            .build();
    
    try (Cursor<Map.Entry<String, String>> cursor = hashOps.scan("autocomplete:20240415", options)) {
        while (cursor.hasNext()) {
            Map.Entry<String, String> entry = cursor.next();
            if (autoComplete.size() < 10) {
                autoComplete.add(entry.getKey());
            }else {
                break;
            }
        }
    }

    운영 반영 후 모니터링을 하는데 몇시간 후 해당 프로젝트가 멈춰버리는 현상이 생겼다.

     

    원인 분석

    알고보니 기존에 redis를 사용중인 곳들이 몇군데 있었는데 그중에 배치가 몇개 있었는데 1200 ~ 1500ms 걸리는게 8개 정도 있었다. redis는 싱글스레드라 한개의 작업씩 처리하는데 자동완성과 같이 작동하게 되면서 밀려버린것이다. 어쩐지 redis slog log가 좀 남아있었다.. 그래서 해당프로젝트가 멈춰버리는 증상이 발생했던것이다...

     

     

    2차 Redis scan count 줄이기 및 메모리로 관리 (운영 배포)

    1차에서 여러가지 문제점이 있어서 Redis count 도 적절하게 100으로 줄이고 자동완성 키워드 들을 1시간마다 배치 형식으로 1시간마다 데이터를 가져와 메모리에서 관리하는 형태로 변경 (가져온 데이터는 싱글톤으로 관리)

    private static List<String> autoCompleteList = new ArrayList<>();
    
    List<String> autoComplete = new ArrayList<>();
    int count = 0;
    if (autoCompleteList != null) {
        for (String item : autoCompleteList) {
            if (item.startsWith(keyword) && count<10) {
                autoComplete.add(item);
                count++;
            }
        }
    }

    원인분석

    모니터링 후 괜찮나 싶었는데 3일마다 해당 프로젝트 서버가 다운되는 증상이 발견되었다.

     

    pinpoint와 zabbix로 모니터링을 진행했는데 cpu ram 사용량 모두 이상이 없었고, pinpoint에서도 별다른 증상이 없었는데 알고보니 기존에 Netty와 Jetty를 혼용해서 사용중이었고 두WAS의 설정이 꼬여있어 쓰레드풀이 부족해 발생한 에러였다. 그래서 메모리로 관리하는 방식은 포기하고 다른 방법을 찾았다.

     

     

    3차 데이터베이스로 관리(MariaDB) (운영 배포)

    트래픽도 그렇게 많지 않아 데이터베이스로 시도를 해보고자 데이터베이스 커넥션 설정을 하고 해당 테이블에 키워드 컬럼을 index 설정을 해두고 테스트를 진행 하였다.

    성능 테스트 결과 평균 0.2초가 나왔고 성공적으로 마무리 되나 싶었다...

     

    원인분석

    zabbix를 통해 slack에 해당 서버가 503에러가 발생 하였다.

    503에러가 발생한 원인은 더이상 연결할 소켓이 없어서 이다.
    연결할 소켓이 없는 이유는 디비 커넥션 설정을 하지 않았기 때문에
    기존에 다른 프로젝트들에서 해당 디비에 커넥션을 다 가지고 있었을경우
    커넥션 디폴트 설정으로 watetime 30초를 기다리게 되는데
    트래픽이 몰리면서 더이상 연결할 커넥션이 없어 watetime이 누적되어 앞쪽에 커넥션이 close 되면 503 에러가 해지되게 된다. 

     

     

    4차 데이터베이스 커넥션 설정

    마지막으로 데이터 베이스 커넥션 설정을 추가하고 모니터링 중인데 아직까진 문제가 발생하지 않았다...

    댓글

    Designed by JB FACTORY