-
Redis에서의 KEYS와 SCAN 명령어 비교Spring 2024. 4. 16. 07:10
Redis는 효율적인 키-값 저장소로 널리 사용되고 있으며, 데이터를 조회하는 두 가지 주요 명령어인 KEYS와 SCAN에 대해 자세히 알아보고, 어떤 상황에서 각각을 사용하는 것이 적합한지 살펴보겠습니다.
KEYS 명령의 이해
KEYS 명령은 지정된 패턴에 일치하는 모든 키를 한 번의 호출로 반환합니다. 예를 들어, KEYS user:*는 'user:'로 시작하는 모든 키를 찾아 리스트로 반환합니다. 이 방식은 간단하고 직관적이지만, 큰 데이터베이스에서는 몇 가지 문제점을 유발할 수 있습니다.
장점
사용이 간단하며 작은 데이터 세트에서 빠르게 결과를 제공합니다.단점
대규모 데이터 세트에서 사용할 경우, 서버를 블로킹하여 다른 모든 연산이 중단될 수 있습니다.
매우 CPU 및 메모리 집약적이어서 서버의 성능에 부정적인 영향을 줄 수 있습니다.SCAN 명령의 이해
SCAN 명령은 KEYS의 대안으로 개발되었으며, 대용량 데이터를 처리할 때 서버의 블로킹 없이 점진적으로 키를 반환합니다. SCAN은 커서와 함께 사용되며, 커서는 각 호출 후 다음 조회 시작점을 알려줍니다.
장점
대규모 데이터베이스에서도 서버의 블로킹 없이 사용할 수 있습니다.
count 옵션을 조정하여 한 번에 반환하는 키의 수를 통제할 수 있습니다.// RedisTemplate을 사용한 SCAN 명령 예시 Set<String> keys = redisTemplate.execute((RedisCallback<Set<String>>) connection -> { Set<String> keysTemporary = new HashSet<>(); Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match("testKey:*").count(100).build()); while (cursor.hasNext()) { keysTemporary.add(new String(cursor.next())); } return keysTemporary; });
성능 비교 및 사용 사례
실제 테스트에서 KEYS 명령은 작은 데이터 세트에서 빠르게 결과를 반환하지만, 데이터베이스 크기가 증가함에 따라 그 성능이 급격히 저하됩니다. 반면, SCAN 명령은 더 일관된 성능을 보이며, 대용량 데이터 처리에 적합합니다.
테스트 코드
@Slf4j @RequiredArgsConstructor @Component public class RedisKeySearch { private final RedisTemplate<String, String> redisTemplate; @PostConstruct public void createTestKeys() throws InterruptedException { final ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 0; i < 10; i++) { int threadNum = i; executorService.submit(() -> { for (int j = threadNum * 100_000; j < (threadNum + 1) * 10_000; j++) { redisTemplate.opsForSet().add("test:" + j, "value:" + j); } }); } executorService.shutdown();; executorService.awaitTermination(100, TimeUnit.SECONDS); } public void findKeysWithKeysCommand() { final Set<String> keys = redisTemplate.keys("test:*"); log(keys); } private static void log(Set<String> keys) { log.info("=== key size : {}", Objects.requireNonNull(keys).size()); } public void findKeysWithScanCommand() { final Set<String> keys = redisTemplate.execute((RedisCallback<Set<String>>) action -> { final Set<String> keyTemporary = new HashSet<>(); final Cursor<byte[]> cursor = action.scan(ScanOptions.scanOptions() .match("test:*").count(100) .build()); while (cursor.hasNext()) { keyTemporary.add(new String(cursor.next())); } return keyTemporary; }); log(keys); } }
output
2024-04-16T06:51:26.529+09:00 INFO 54976 --- [redis-playground] [ main] j.s.r.search.RedisKeySearch : === key size : 1000000 2024-04-16T06:51:26.538+09:00 INFO 54976 --- [redis-playground] [ main] j.s.r.search.RedisKeySearchStopWatch : === findKeysWithKeysCommand - runningTime : StopWatch '': 2.250488346 seconds ---------------------------------------- Seconds % Task name ---------------------------------------- 2.250488346 100% 2024-04-16T06:51:34.663+09:00 INFO 54976 --- [redis-playground] [ main] j.s.r.search.RedisKeySearch : === key size : 1000000 2024-04-16T06:51:34.663+09:00 INFO 54976 --- [redis-playground] [ main] j.s.r.search.RedisKeySearchStopWatch : === findKeysWithScanCommand - runningTime : StopWatch '': 8.12487944 seconds ---------------------------------------- Seconds % Task name ---------------------------------------- 8.12487944 100%
Keys 명령 사용 금지 설정
Redis에서 KEYS 명령을 사용하지 못하게 하려면, Redis 서버 구성을 수정하여 특정 명령들을 비활성화할 수 있습니다. 이는 보안과 성능을 향상시키기 위해 특히 중요할 수 있습니다. KEYS 명령은 리소스를 매우 집중적으로 사용하며, 대규모 데이터 세트에 미치는 영향 때문에 프로덕션 환경에서의 사용을 제한하거나 금지하는 것이 일반적입니다.
Redis 구성 파일을 통한 명령 비활성화
Redis 서버의 구성 파일(redis.conf)에서 rename-command 지시어를 사용하여 KEYS 명령을 다른 이름으로 변경하거나 완전히 비활성화할 수 있습니다. 명령을 비활성화하려면 다음과 같이 설정하면 됩니다
rename-command KEYS ""
실행 중인 Redis 서버에서 명령 비활성화
실행 중인 Redis 인스턴스에서는 CONFIG SET 명령을 사용하여 rename-command 옵션을 동적으로 변경할 수 있습니다. 다음과 같이 실행하세요
redis-cli CONFIG SET rename-command KEYS ""
이 방법은 Redis 서버를 재시작하지 않고도 변경을 적용할 수 있습니다. 하지만, 이 설정은 Redis 서버가 재시작될 경우 사라지므로, 영구적으로 적용하고 싶다면 redis.conf 파일을 수정해야 합니다.
베스트 프랙티스
작은 데이터 세트와 테스트 환경에서는 KEYS 명령을 사용할 수 있지만, 프로덕션 환경에서는 SCAN 명령을 사용하는 것이 좋습니다.
SCAN의 count 옵션을 조절하여 네트워크 비용과 성능 사이의 균형을 맞추는 것이 좋습니다.'Spring' 카테고리의 다른 글
엔티티의 생성 및 수정 시간 자동화하기 (0) 2024.04.09 프로젝트 회고 - 수업 스케줄 일괄 변경 배치 처리 (0) 2024.04.08 프로젝트 회고 - 스케줄 자동 공개 성능 최적화 (1) 2024.04.04 Spring Version에 맞는 h2Database 설치 (0) 2023.04.16 @Transactional 제대로 알고 쓰기 (0) 2021.11.18