spring boot에 Redis 붙여보기

최준호·2022년 5월 16일
0

redis

목록 보기
1/3
post-thumbnail

📕Redis?

redis란 어떻게 보면 인메모리 경량 DB 같으면서도 NoSql 기반의 다양한 자료구조를 사용하기도 하기 때문에 실제 db와 service 사이에서 cache 같은 역할을 하는거 같다.

실제 db에서 조회하면되지 왜 redis까지 사용하면서 함? 이라고 물어본다면 예를 들어 무신사 스토어에 페이지를 구성할 때 사용자들이 가장 많이 접속하는 페이지는 정문 페이지일 것이다. 그 페이지에는 최근 가장 많이 팔린 옷, 신발, 악세서리 등의 데이터들 노출되어지는데 만약 사용자가 한번에 10,000명이 접속한다면 해당 데이터를 10,000번 select해서 10,000번 정렬해야한다... db가 해당 작업만으로도 터질거 같은데 이외에 결제, 문의 글 등록, 수정 등 다양한 작업을 처리해야한다. 그래서 이런 db 데이터들을 redis와 같은 cache 같은 용도로 사용하며 실제 db는 중요한 업무 처리만 담당할 수 있도록 해준다.

그리고 나는 사실 무신사, 네이버 같은 큰 규모가 아니지만 redis를 사용하려고 하는 곳은 로그인 처리 쪽이다. 로그인을 jwt를 사용하여 토큰을 발급해서 처리하는데 여기서 문제가 로그아웃이다. 로그아웃의 경우 cookie 값을 없애줘야하는데 api 서버 자체에서는 토큰을 발급만 하지 따로 session에 접근하거나 cookie를 삭제하는 행위를 할수가 없다. 그래서 대부분 사용하는 방법이 발급한 토큰을 db에 저장시켜두고 로그아웃이 되었을 경우에는 해당 토큰을 로그아웃 상태로 변경해주는 방법을 사용하는거 같았다. 그래서 redis를 실습해보려고 한다.

📕redis 실습

참고 블로그의 글을 토대로 실습을 진행해보려고 한다.

docker redis 서버 시작

간단한 실습이므로 window 환경에서 진행했습니다.

docker hub에서 redis 이미지를 검색하여 확인한 후 설치해보자

docker pull redis

명령어를 통해 이미지를 다운받고

docker run --name some-redis -d redis

이미지를 실행시켜보자

컨테이너가 정상적으로 실행되었다.

docker exec -it some-redis /bin/bash

명령어로 redis docker container에 접속하고

redis-cli

redis에 접속한다.

그러면 mysql과 같은 db를 사용해보았다면 그런 비슷한 화면으로 전환된다.

set key1 "hello world"

명령어를 입력해보자

정상 실행되면 OK가 나오며

get key1


입력시 다음과 같은 결과를 확인할 수 있다.

이렇게 redis를 간단하게 사용해 볼 수 있었다.

📕Redis 사용 방법

apend value

append key1 "juno"

append를 통해

내용을 추가할 수도 있다.

delete key

del key1

key를 지우고 싶다면 다음과 같이 del을 통해 지울 수도 있다.

Set

sadd는 set 자료구조를 사용할 수 있다.

sadd test my
sadd test name
sadd test juno

를 등록하고

smembers test

smembers로 입력하면 다음과 같이 결과가 순서 보장 없이 나오는 것을 확인할 수 있다. set인지 확인하기 위해 같은 내용을 한번 더 등록해보자

sadd test juno

이미 중복되는 내용이므로 추가해도 0이 반환되며

실제로 데이터를 조회해도 추가되지 않고 이전 그대로 나온다.

Sorted Set

zadd rank 100 a
zadd rank 50 b
zadd rank 60 c
zadd rank 70 d

zadd로 데이터를 추가하며 sortedSet은 가중치-값으로 지정할 수 있다.

zadd를 통해 값을 등록해주었다.

zrange rank 0 -1

zrange를 통해 해당 데이터를 정렬하여 뽑아올 수 있는데 다음과 같이 입력은 0 ~ 전체 값을 검색하는 방법이다.

zrange rank 0 1

이렇게 입력하면 0 ~ 1 까지 데이터를 가져온다.

zrange rank 0 -1의 결과는 다음과 같이 나온다.

zrange rank 0 -1 rev

만약 역순으로 출력하고자 한다면 다음과 같이 입력하면 된다.

역순으로 잘 출력되어진다.

zrange rank 0 -1 withscores rev

점수와 함께 출력하고 싶으면 withscores 옵션을 추가해주면 된다.

Hash Map

hset user name juno
hset user lastname choi
hset user location seongnam

과 같이 입력한 뒤

hget user name
hget user lastname
hget user location
hgetall user

다음과 같이 결과를 확인해 볼 수 있다.

이제 redis가 어떻게 데이터를 저장하고 가져오는지 대략 파악할 수 있었다. 이걸 Spring에서는 어떻게 사용하는지 확인해보자.
또한 이 외의 redis 문법이 궁금하다면 reids 공식 홈페이지 command에서 검색해보면 된다. 참고로 어마어마하게 많다.

Spring에서 Redis 사용하기

백기선 강사님 spring boot 2.0 Redis 강의 내용을 토대로 진행했다.

docker redis container 생성

아까 생성했던 컨테이너는 지운 뒤 다시 컨테이너를 생성해서 진행해야한다.

docker stop some-redis
docker rm some-redis

으로 컨테이너를 지웠다.

docker run -p 6379:6379 --name redis -d redis

다음 명령어로 컨테이너를 실행한다. 아까랑 다른건 컨테이너 이름이랑 포트가 추가된것이다.

정상 실행을 확인하면 container가 정상 실행된거다.

spring 설정

<!-- <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.6.7</version>
</dependency>

redis를 해주면 끝이다.

spring:
  redis:
    host: localhost
    port: 6379

마지막으로 설정을 추가해준다.

기본값으로 localhost:6379 이기 때문에 따로 설정을 안해도 잘 작동하겠지만 ip와 port를 설정해야한다면 다음과 같이 yml 파일에 추가해주면 된다.

📕Redis에 객체를 저장하는 방법

class

@Getter
@Setter
@RedisHash("Meetings")
public class Meeting {
    @Id
    private String id;  //redis는 id를 string으로 사용한다고 함.
    private String title;
    private Date startAt;
}

객체를 하나 정의한다.

여기서 @RedisHash()로 data의 key값을 정의해주는 것이다. 그리고 @Id는 spring.data에서 제공하는 Id 어노테이션을 사용하면 된다.

repository

public interface MeetingRepository extends CrudRepository<Meeting, String> {
}

repository를 일반 db와 동일하게 사용해주고

Service

public interface MeetingService {
    String save();  //String type id 반환
}
@Service
@RequiredArgsConstructor
public class MeetingServiceImpl implements MeetingService{
    private final MeetingRepository meetingRepository;

    @Override
    public String save() {
        Meeting meeting = new Meeting();
        meeting.setTitle("juno");
        meeting.setStartAt(new Date());
        Meeting save = meetingRepository.save(meeting);
        return save.getId();
    }
}

builder 패턴이나 생성자 패턴으로 객체를 생성하는 것을 추천하는데 강의 따라서 하다보니 그냥 했다...ㅎ builder나 생성자의 경우 id 값을 안넣고 만들면 된다.

Test

@SpringBootTest
class MeetingServiceImplTest {
    @Autowired
    private MeetingService meetingService;

    @Test
    void redis_save_테스트(){
        //given
        //when
        String save = meetingService.save();
        //then
        Assertions.assertThat(save).isNotEmpty();
    }
}

실제로 데이터가 잘 들어가는지 Test를 위해 통합테스트로 구성해서 실행했고

결과는 성공으로 나왔다. 정말 성공했는지 redis에 접속하여 확인해보자.

공식문서의 cli로 바로 붙는 명령어가 있는데 network 설정이 없으면 안돼서 위에 내가 진행했던 방법으로 붙었다.

keys *

으로 검색하면

내가 저장했던 Meetings 데이터가 나오며 두번째 "Meetings:cdf30501-4968-4492-b038-3411e5dbe41a":id 값으로 저장된 것이다.

해당 객체 값을 검색해보는 방법은

hget Meetings:cdf30501-4968-4492-b038-3411e5dbe41a title

다음과 같이 검색하면

결과가 나오며 전체 내용을 보고 싶으면

hgetall Meetings:cdf30501-4968-4492-b038-3411e5dbe41a

과 같이 검색해볼 수 있다.

📕RedisTemplate 사용

RedisTemplate bean 등록

@Configuration
@EnableRedisRepositories
@RequiredArgsConstructor
public class RedisConfig {
    private final RedisProperties redisProperties;

    @Bean
    public RedisConnectionFactory redisConnectionFactory(){
        return new LettuceConnectionFactory(redisProperties.getHost(), redisProperties.getPort());
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(){
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());    //key serializer
        redisTemplate.setValueSerializer(new StringRedisSerializer());  //value serializer
        return redisTemplate;
    }
}

redisTemplate을 bean으로 등록해주고

redis client는 Jedis 와 Lettuce 두가지가 존재하는데 jedis는 최근 멀티 쓰레드, 비동기 방식 등 여러 최신 트렌드와 맞지 않는 부분이 많아 사용을 하지 않는 추세이고 Lettuce가 최신 트렌드와 맞게 잘 적용되어져 있어 해당 client가 spring boot에서도 default로 설정되어 있다.

service

public interface RedisTemplateService {
    void save();
}
@Service
@RequiredArgsConstructor
public class RedisTemplateServiceImpl implements RedisTemplateService{
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public void save() {
        ValueOperations<String, Object> value = redisTemplate.opsForValue();
        value.set("testKey", "testValue");
    }
}

위 코드와 같이 testKey라는 String key를 testValue라는String value 값으로 저장해보자.

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

Test

@SpringBootTest
class RedisTemplateServiceImplTest {
    @Autowired
    RedisTemplateService redisTemplateService;

    @Test
    void redisTemplate_테스트(){
        redisTemplateService.save();
    }
}

테스트 코드를 작성하고

성공적으로 반환한 것을 확인할 수 있다.

redis를 확인해보면 testKey가 들어가 있을것을 확인할 수 있고

value도 잘 저장된것을 확인할 수 있다.

profile
해당 주소로 이전하였습니다. 감사합니다. https://ililil9482.tistory.com

0개의 댓글