공부 내용을 정리하고 앞으로의 학습에 이해를 돕기 위해 작성합니다.
Redis란
Redis는 인메모리 데이터베이스로 다음과 같은 특징을 가진다:
- 빠른 속도: 메모리 기반이므로 디스크 기반의 데이터베이스보다 빠르다.
- 다양한 자료구조 지원: String, Hash, Set, List, Geospatial 등의 다양한 자료구조 제공.
- 주로 캐싱으로 사용: 데이터베이스보다 빠른 조회를 통해 성능 개선이 가능하다.
Redis는 특히 조회 빈도가 높고 데이터 변경이 적은 경우에 적합하다. 메모리에서 데이터를 처리하므로, 데이터 조회와 수정 속도가 빠르며, 캐시 또는 세션 관리 같은 실시간 성능이 중요한 애플리케이션에서 많이 사용된다.
자세한 내용은 https://redis.io/docs/data-types/tutorial/에서 확인할 수 있다.
Redis 주의사항
Redis를 사용할 때는 몇 가지 주의해야 할 점이 있다.
- 업데이트 빈도: 자주 업데이트되는 데이터는 캐싱의 효과가 적고, DB와의 동기화 비용이 커질 수 있다.
- 데이터 크기: Redis는 메모리를 사용하기 때문에 매우 큰 데이터를 저장할 경우 메모리 부족 현상이 발생할 수 있다.
- Failover와 이중화: Redis 장애 시 대비를 위해 이중화 및 백업 설정이 필요하다. Redis에 장애가 발생하면 DB에서 직접 데이터를 조회하는 등의 대안이 있어야 한다.
특히, Redis는 장애가 발생하면 데이터 손실 가능성이 있기 때문에 이중화(High Availability, HA)와 백업 전략을 잘 세워야 한다. Redis 클러스터를 통해 가용성을 높이거나, Redis Sentinel과 같은 도구를 사용해 자동 장애 복구 시스템을 구축할 수 있다.
Redis CLI
Redis를 시작하기 전, Redis CLI를 통해 기본적인 명령어들을 실습해 볼 수 있다.
Redis CLI 접속
먼저, Docker에서 실행 중인 Redis 컨테이너에 접속하기 위해 아래 명령어를 사용한다.
$ docker exec -it {컨테이너ID} redis-cli --raw
- 이 명령어를 통해 Redis CLI에 접속할 수 있다. 컨테이너 ID는 docker ps 명령어로 확인할 수 있다.
String 자료구조 실습
String 자료구조는 Redis에서 가장 기본적인 키-값(key-value) 쌍으로 데이터를 저장하는 방식이다.
데이터 저장
$ set myKey "Hello Redis"
데이터 조회
$ get myKey
데이터 삭제
$ del myKey
모든 키 조회
$ keys *
이렇게 간단하게 키-값 쌍으로 데이터를 저장하고, 다시 조회할 수 있다.
Hash 자료구조 실습
Hash 자료구조는 하나의 키에 여러 필드와 값을 저장할 수 있다. 이는 객체 데이터를 표현할 때 매우 유용하다.
데이터 저장
$ hset user:1001 name "John" age 30
특정 필드 조회
$ hget user:1001 name
모든 필드와 값 조회
$ hgetall user:1001
Hash 자료구조는 하나의 키에 여러 필드-값을 저장하여 객체처럼 데이터를 관리할 수 있다. 예를 들어, 사용자 정보를 저장할 때 이름과 나이를 각각 필드로 저장하는 방식이다.
Geospatial 자료구조 실습
Geospatial 자료구조는 좌표 데이터를 기반으로 거리 계산 및 특정 반경 내 위치를 조회하는 데 사용된다.
좌표 데이터 저장
두 약국의 좌표를 Geospatial 자료구조에 추가한다.
$ geoadd pharmacies 127.0817 37.5505 "pharmacy1"
$ geoadd pharmacies 127.0766 37.5410 "pharmacy2"
두 지점 사이 거리 계산
geodist 명령어를 사용해 두 약국 간의 거리를 계산한다.
$ geodist pharmacies pharmacy1 pharmacy2 km
여러 약국 위치 저장 (geopoints2)
다른 좌표로 약국 위치를 추가한다.
$ geoadd geopoints2 127.0569046 37.61040424 pharmacy1
$ geoadd geopoints2 127.029052 37.60894036 pharmacy2
$ geoadd geopoints2 127.236707811313 37.3825107393401 pharmacy3
반경 10km 이내의 약국 조회
특정 좌표를 기준으로 반경 10km 이내에 있는 약국을 가까운 순서대로 검색한다.
이때 거리(withdist)와 좌표(withcoord)도 함께 반환하며, 최대 3개의 결과를 얻는다.
$ georadius geopoints2 127.037033003036 37.596065045809 10 km withdist withcoord asc count 3
이 실습을 통해, Redis의 Geospatial 자료구조를 이용해 두 위치 간의 거리 계산과 특정 위치에서 반경 내 데이터를 검색하는 방법을 확인할 수 있다. 이는 특히 위치 기반 서비스에서 매우 유용한 기능으로, 약국 길찾기와 같은 서비스에 적용할 수 있다.
Spring에서 Redis 설정
Spring 애플리케이션에서 Redis를 사용하려면, 먼저 Redis를 빈으로 등록해야 한다. Redis 설정은 주로 LettuceConnectionFactory를 사용해 Redis 서버에 연결한 후, 이를 통해 RedisTemplate을 빈으로 등록하여 다양한 Redis 명령어를 실행할 수 있다.
- 의존성 추가: Spring Boot에서 Redis를 사용하려면 spring-boot-starter-data-redis 의존성을 추가해야 한다.
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
- RedisTemplate 설정: RedisTemplate은 Spring에서 Redis의 다양한 자료구조에 쉽게 접근할 수 있는 도구다. 이를 통해 문자열, 해시, 셋 등 다양한 자료구조를 다룰 수 있다.
Spring의 Redis 설정은 프로젝트에서 Redis 서버와 통신할 수 있도록 도와준다. 특히 RedisTemplate은 다양한 자료구조 연산을 쉽게 수행할 수 있도록 제공된다.
Redis 설정을 위한 Spring Config 클래스
Redis를 Spring 애플리케이션에서 사용하기 위해서는, Redis 서버와의 연결을 설정하고, 이를 이용해 데이터를 처리할 수 있는 템플릿을 설정해야 한다. 이를 위해 RedisConfig라는 설정 클래스를 만들어 필요한 Bean을 등록한다.
package com.example.phamnav.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisHost, redisPort);
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
return redisTemplate;
}
}
- RedisConnectionFactory 빈 설정
- LettuceConnectionFactory를 사용해 Redis 서버와 연결한다. 이때 Redis 서버의 호스트와 포트 정보는 애플리케이션 설정 파일(application.yml 또는 application.properties)에서 주입된다.
- 이 설정을 통해 Redis 서버와의 연결이 관리되고, Redis에 데이터를 읽고 쓸 수 있는 통로를 열어준다.
- RedisTemplate 빈 설정
- Redis와 상호작용하는 주요 클래스가 RedisTemplate이다. 이 템플릿을 이용해 다양한 Redis 명령어를 실행할 수 있다.
- redisTemplate.setKeySerializer(new StringRedisSerializer()) 부분은 Redis에 저장되는 키와 해시의 키, 값 모두를 String 형식으로 직렬화하기 위한 설정이다. 이를 통해 Redis에 저장되는 데이터가 직관적인 문자열로 처리될 수 있다.
- Redis는 기본적으로 바이너리 직렬화를 사용하는데, 이 설정을 통해 데이터를 사람이 읽기 쉽게 설정하고, 이후에 조회할 때도 문자열 형식으로 데이터를 확인할 수 있다.
이 두 개의 빈을 설정하면, Spring 애플리케이션에서 Redis와 쉽게 연결할 수 있고, 데이터를 처리하는 기본적인 틀을 완성할 수 있다.
다음으로 테스트 코드를 작성한다.
RedisTemplate을 이용한 테스트 클래스
이제 Redis 설정이 완료되었으므로, RedisTemplate을 이용해 Redis의 자료구조에 데이터를 저장하고 조회하는 테스트를 작성해 본다. 이 테스트를 통해 Redis가 올바르게 동작하고 있는지 확인할 수 있다.
package com.example.phamnav.pharmacy.cache
import com.example.phamnav.AbstractIntegrationContainerBaseTest
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.redis.core.RedisTemplate
class RedisTemplateTest extends AbstractIntegrationContainerBaseTest {
@Autowired
private RedisTemplate redisTemplate
def "RedisTemplate String operations"() {
given:
def valueOperations = redisTemplate.opsForValue()
def key = "stringKey"
def value = "hello"
when:
valueOperations.set(key, value)
then:
def result = valueOperations.get(key)
result == value
}
def "RedisTemplate set operations"() {
given:
def setOperations = redisTemplate.opsForSet()
def key = "setKey"
when:
setOperations.add(key, "h", "e", "l", "l", "o")
then:
def size = setOperations.size(key)
size == 4
}
def "RedisTemplate hash operations"() {
given:
def hashOperations = redisTemplate.opsForHash()
def key = "hashKey"
when:
hashOperations.put(key, "subKey", "value")
then:
def result = hashOperations.get(key, "subKey")
result == "value"
def entries = hashOperations.entries(key)
entries.keySet().contains("subKey")
entries.values().contains("value")
def size = hashOperations.size(key)
size == entries.size()
}
}
- String 자료구조 테스트 (RedisTemplate String operations)
- 이 테스트는 String 자료구조에 데이터를 저장하고, 다시 그 값을 조회하는 기능을 확인한다.
- 먼저 redisTemplate.opsForValue()를 통해 String 자료구조에 접근하고, set 메서드로 키-값 쌍을 저장한다.
- 이후 get 메서드를 사용해 저장된 값을 조회하여, 저장된 값과 동일한지 검증한다. 이를 통해 Redis에 데이터가 정상적으로 저장되고 조회되는지 확인할 수 있다.
- Set 자료구조 테스트 (RedisTemplate set operations)
- Redis의 Set 자료구조는 중복을 허용하지 않는 집합으로, 여러 개의 값을 저장할 수 있다. 이 테스트는 Set에 여러 개의 값을 추가하고, 그 크기가 올바른지 확인하는 방식이다.
- redisTemplate.opsForSet()을 통해 Set 자료구조에 접근한 후, add 메서드로 여러 값을 추가한다.
- size 메서드를 통해 추가된 값의 개수를 확인하는데, 중복된 값이 무시되는지 여부도 확인할 수 있다. Set 자료구조는 중복된 값을 허용하지 않기 때문에 동일한 문자가 여러 번 추가되더라도, 중복은 제거된다.
- Hash 자료구조 테스트 (RedisTemplate hash operations)
- Hash는 하나의 키에 여러 필드-값 쌍을 저장할 수 있는 자료구조다. 이 테스트에서는 Hash에 데이터를 저장한 후, 특정 필드의 값을 조회하고, 모든 필드-값 쌍을 조회하는 과정을 테스트한다.
- redisTemplate.opsForHash()로 Hash 자료구조에 접근하고, put 메서드로 특정 필드에 값을 저장한다.
- get 메서드를 사용해 특정 필드의 값을 조회하고, entries 메서드를 통해 모든 필드-값 쌍을 한 번에 가져온다. 이를 통해 데이터가 정상적으로 저장되고 조회되는지 확인할 수 있다.
테스트를 통한 검증 결과
위의 테스트는 모두 성공적으로 통과했으며, Redis 설정이 제대로 되었음을 확인할 수 있었다. 각 자료구조에 데이터를 저장하고 조회하는 과정에서 오류 없이 작동하는 것을 통해 Redis가 정상적으로 운영되고 있음을 알 수 있다.
- String 자료구조 테스트 결과: 문자열 데이터가 정상적으로 Redis에 저장되고, 다시 조회했을 때 동일한 값이 반환되었다.
- Set 자료구조 테스트 결과: 중복이 제거된 상태에서 Set 자료구조에 값들이 저장되었고, 값의 개수도 올바르게 반환되었다.
- Hash 자료구조 테스트 결과: 여러 필드와 값을 저장하고 조회하는 과정에서 오류 없이 데이터가 처리되었으며, Hash에 저장된 모든 데이터를 한 번에 가져오는 것도 성공적으로 이루어졌다.
이번 포스팅에서는 Redis의 다양한 자료구조를 활용해 데이터를 저장하고 처리하는 방법을 살펴보았다. 특히 Spring과 Redis를 연동한 설정과 테스트를 통해 성능 최적화를 확인할 수 있었다. 다음 시간에는 실제 프로젝트에 Redis를 적용해 보면서 성능 개선을 직접 확인해 보도록 한다.
'BackEnd > Project' 카테고리의 다른 글
[PharmNav] Ch08. Redis 테스트 코드 작성 (0) | 2024.09.05 |
---|---|
[PharmNav] Ch08. redis를 이용한 성능 개선 (0) | 2024.09.05 |
[PharmNav] Ch07. 테스트 코드 작성 (0) | 2024.09.05 |
[PharmNav] Ch07. shorten url 개발 및 전국 약국 데이터 추가 (1) | 2024.09.05 |
[PharmNav] Ch07. Kakao 지도 API를 이용한 길안내 개발 (0) | 2024.09.04 |