아직 공부중이기 때문에 더 추가하거나 수정이 있을 예정입니다.
1. Redis란 무엇인가?
레디스는 모든 데이터를 메모리에 저장하고 조회합니다. 즉, 인메모리 데이터베이스 입니다. 또한 NoSQL로서 Key-Value 타입의 저장소입니다. 여기서 NoSQL은 비관계형 데이터베이스를 지칭합니다. 즉, 관계형 데이터 모델을 지양 하며 대량의 분산된 데이터를 저장하고 조회하는 데 특화되었으며 스키마 없이 사용 가능하거나 느슨한 스키마를 제공하는 저장소를 말한다. 다른 인메모리 디비들과의 가장 큰 차이점은 레디스의 다양한 자료구조 입니다.
Redis는 영속성을 지원하긴하지만 영속성의 목적으로 Redis를 잘 사용하지는 않는다. 왜냐하면 레디스의 데이터를 파일로 보관하기 위한 persistence 기능(RDB, AOF)으로 인한 장애발생 가능성이 굉장히 크기 때문입니다. 따라서 거의 Redis를 보조적인 캐시서버로 사용하는 경우가 많습니다. 여기서 캐시란 자주사용하는 데이터를 미리 복사해 놓은 저장소를 의미합니다. Redis를 캐시서버로 사용한다는 것은 클라이언트가 서버에 요청을 보내면 서버는 DB를 조회하기 전에 Redis에 데이터가 있는지 확인하고 만약 존재한다면 DB 조회없이 바로 데이터를 반환하는 것이고, 존재하지 않는다면 DB를 조회하여 데이터를 반환하고 캐시에 저장해두는 방식을 의미합니다.
2. Redis의 간단한 강점
- 다양한 데이터 형식을 지원하기 때문에 리스트, 배열과 같은 데이터를 처리하는데 유용하다.
- I/O이 MySQL같은 DB에 비해서 빠르다.
- 특히 리스트형 데이터 입력과 삭제가 MySql에 비해 10배정도 빠르다.
3. 서버에 Redis 설치 및 환경설정하기(ubuntu)
1 패키지를 업그레이드 해줍니다.
sudo apt-get update
sudo apt-get upgrade
2 레디스를 설치합니다.
sudo apt-get install redis-server
3 레디스 환경설정을 위해 vim으로 redis.conf를 조회합니다.
sudo vim /etc/redis/redis.conf
4 만약 로컬 뿐만이 아니라 외부에서도 접속 가능하게 하고 싶다면 redis.conf에서 bind 부분에 해당 외부 ip를 추가해줍니다.
참고: 저 같은 경우 redis.conf에 bind 설정이 위아래로 두개가 존재하는 바람에 외부에서 접속이 되질 않아서 엄청 고생했던 기억이 있습니다! 반드시 bind설정이 하나만 존재하는지 확인합시다!
5 외부에서 접근하려면 보안을 위해서 비밀번호를 설정해줍니다. requirepass부분을 수정해줍니다.
6 redis서버가 잘 돌아가고 있는지 확인하고 재실행해줍니다.
systemctl status redis-server.service
systemctl restart redis-server.service
4. RedisTemplate vs Redis Repository
Spring에서 레디스를 다루는 방법에는 RedisTemplate과 Redis Repository 방식 두가지가 존재합니다. 저는 그 중에서도 RedisTemplate 방식을 선택했습니다. 그 이유는 다음과 같습니다.
- 제가 redis를 붙여본 프로젝트에서는 트랜잭션 처리가 굉장히 많았습니다. 하지만 Redis Repository의 경우 트랜잭션을 지원하지 않습니다.
- 프로젝트를 위해서 redis를 도입하기 보다는 개인적인 공부를 위한 목적이 크므로 비교적 간단하게 객체를 저장하고 조회가 가능한 Redis Repository 방식을 선택하지 않았습니다.
5. Lettuce vs Jedis
Lettuce와 Jedis 둘다 Redis Client로 레디스 서버와 소통할 수 있게 해주는 라이브러리(레디스 드라이버)이다. 하지만 성능면에서 압도적으로 Lettuce가 좋습니다. 또한 Jedis는 Issue에 대한 피드백이 늦지만 Lettuce는 현재도 피드백이 활발하게 이뤄지고 있다. Lettuce를 안 쓸 이유가 없었다.
둘의 성능을 구체적으로 비교하는 글은 아래 글을 참고하자
https://jojoldu.tistory.com/418
6. Redis Serializer에 대한 고민
Redis에 데이터들은 바이트 형식으로 저장이 되어야한다. 따라서 스프링의 데이터들을 redis에 저장하기 위해서는 직렬화 과정이 필요하고 반대로 redis의 값들을 redis에 가져오기 위해서는 역직렬화가 필요하다. Spring에서는 이 기능을 위한 여러 인터페이스들을 제공한다. 대표적으로 3가지가 존재하는데 GenericJackson2JsonRedisSerializer, Jackson2JsonRedisSerializer, StringRedisSerializer이다.
GenericJackson2JsonRedisSerializer의 경우 초반에 RedisTemplate을 @Bean 등록시 Class Type을 명시하지 않아도 자동으로 Object를 Json으로 직렬화해준다. 하지만 Object의 클래스 타입을 redis에 같이 저장하기 때문에 이후에 동일한 패키지의 동일한 Dto로 가져와야만 한다는 제약이 생긴다. 따라서 선택에서 제외하였다.
Jackson2JsonRedisSerializer의 경우 초반에 RedisTemplate을 @Bean 등록시 Class Type을 반드시 명시해야한다. 이는 데이터의 타입이 바뀔때마다 매번 Class Type을 명시해줘야한다는 것을 의미한다. 또한 여러가지 Class Type을 명시하여 여러번 RedisTemplate에 만들면 여러 Serializer가 꼬여서 제대로 역직렬화가 되질 않는 현상이 발생할 수 있다. 따라서 이것 또한 제외하였다.
StringRedisSerializer의 경우 반드시 String형태로만 Serialize가 가능하기 때문에 데이터를 redis에 저장하기 위해서는 반드시 String으로 바꿔줘야한다는 단점이 있다. 하지만 이 방식으로 통일하고 String으로 변환하여 직렬화하고 반대로 String으로 꺼내온 데이터를 다시 원하는 형식으로 바꿔주는 방식이 깔끔하다고 생각하여 선택했다.
참고한 사이트: https://mongsil-jeong.tistory.com/25
7. Spring Boot에서 redis 연결하기
application-aws.properties(또는 사용하고자 하시는 properties)에 위 사진처럼 추가해줍니다. 다만 저 같은 경우는 Spring과 redis가 같은 서버에서 돌아가고 있기 때문에 host를 localhost로 했는데 외부에서 접속하는 경우 해당 외부 ip를 써줍니다. port같은 경우 별도의 변경이 없었다면 기본적으로 6379입니다. password는 아까 redis.conf에서 설정한 비밀번호를 써줍니다.
위 사진처럼 스프링에서 RedisConfig클래스를 만들어 줍니다. 일종의 스프링에서 redis를 사용하기 위한 환경설정이라 보시면 됩니다. RedisTemplate을 @Bean 설정할때 Hash값을 redis에 처리하고 싶다면 별도로 setHashKeySerializer와 setHashValueSerializer을 설정해줘야한다.
실제 service에서 사용할 때는 이런식으로 Bean을 찾아서 DI 하였다. 참고로 @RequiredArgsConstructor방식으로 주입하였다.
해시 값의 형태로 넣고 싶었기 때문에 opsForHash()로 선언해줬지만 만약 다른 형태로 넣고 싶다면 아래를 참고하자.
opsForValue | Strings를 쉽게 Serialize / Deserialize 해주는 Interface |
opsForList | List를 쉽게 Serialize / Deserialize 해주는 Interface |
opsForSet | Set를 쉽게 Serialize / Deserialize 해주는 Interface |
opsForZSet | ZSet를 쉽게 Serialize / Deserialize 해주는 Interface |
opsForHash | Hash를 쉽게 Serialize / Deserialize 해주는 Interface |
roomList라는 key에 roomName(String)을 필드키로하고 room객체를 String으로 바꿔서 redis에 값을 넣어준다. 실제로 잘 들어가는지 서버에서 redis-cli를 통해서 직접 확인해보자.
실제로 잘 들어간 것을 확인할 수 있다.
redis에서 값을 가져온 String형태의 room을 Room Class로 변환하여 읽으면 Spring에서 room 값을 다시 자유롭게 이용이 가능하다.
위를 보면 성공적으로 조회를 해왔음을 확인할 수 있다.
8. Hash를 선택한 이유
roomList에는 여러 객체들이 들어가야한다. 이때 roomList 전체를 조회하는 경우도 있지만 room 하나만 조회를 하는 경우가 있다. 따라서 각각의 객체들은 구분이 되야하고 이를 위해선 key -value 형태인 Hash로 roomList를 만드는 것이 맞다고 생각했다.
9. 참고
List는 중복이 가능하지만 Set은 중복이 안된다.
sorted set은 랭킹 처럼 특정 score를 기준으로 정렬하여 관리할 수 있다.
10. 참고한 사이트
https://jojoldu.tistory.com/418
https://mongsil-jeong.tistory.com/25
https://sabarada.tistory.com/105
'웹 > 스프링' 카테고리의 다른 글
AOP란? 프록시 패턴이란? 스프링 AOP란? @Transactional 원리 (0) | 2022.06.03 |
---|---|
IOC란? IOC 컨테이너란? DI란? DI 방법 (0) | 2022.06.02 |
Spring MVC란? (0) | 2022.05.31 |
Spring Boot에서 통합 테스트코드 구현하기(JUnit5 + Mockito) (0) | 2022.04.17 |
SQL이란? MVC란? (0) | 2022.02.06 |