관리 메뉴

ballqs 님의 블로그

[Spring] Redis 적용 (Window 환경) 본문

코딩 공부/Spring

[Spring] Redis 적용 (Window 환경)

ballqs 2024. 9. 8. 16:51

Redis 공부해야지 공부해야지 생각만 했었는데 이제서야 들여다보면서 알아보고 적용해보았다.

작성하는데 도움이 된 참조글 : https://akku-dev.tistory.com/102

 

Redis란?

Remote Dictionary Server의 약자로, 오픈 소스 기반의 인메모리 데이터 구조 저장소이다.

데이터베이스, 캐시, 메시지 브로커 등의 용도로 사용할 수 있고 Redis는 매우 빠른 속도로 데이터를 처리할 수 있어 성능이 중요한 애플리케이션에 많이 사용된다.


Redis 특징

 

  • 인메모리 저장소: Redis는 데이터를 메모리(RAM)에 저장하여 빠른 읽기 및 쓰기 성능을 제공한다. 이 덕분에 캐싱 서버나 세션 저장소로 많이 활용된다.
  • 다양한 자료 구조 지원: 일반적인 키-값(Key-Value) 구조뿐만 아니라, 다음과 같은 다양한 자료 구조를 지원한다.
    • 문자열(String)
    • 리스트(List)
    • 셋(Set)
    • 정렬된 셋(Sorted Set)
    • 해시(Hash)
    • 비트맵(Bitmap), 하이퍼로그로그(HyperLogLog), 스트림(Stream)
  • 데이터 영속성: Redis는 주로 인메모리 방식으로 동작하지만, 데이터를 영구 저장하기 위한 옵션도 제공한다. 이를 위해 두 가지 방식의 영속성을 지원한다.
    • RDB (Redis Database): 주기적으로 데이터를 디스크에 덤프하는 방식.
    • AOF (Append Only File): 모든 쓰기 작업을 로그 파일에 기록하는 방식.
  • 빠른 성능: Redis는 메모리 기반이고, 싱글 스레드로 동작하지만 비동기 I/O를 사용하여 매우 높은 처리 속도를 제공한다. 10만 이상의 요청을 초당 처리할 수 있는 성능이 특징을 가지고 있다.
  • 복제 및 클러스터링: Redis는 마스터-슬레이브 구조의 복제(replication)를 지원하여 데이터의 고가용성을 보장한다. 또한, Redis 클러스터링 기능을 통해 여러 Redis 인스턴스에 데이터를 분산 저장할 수 있다.
  • 원자성: Redis는 모든 명령어가 원자적으로 실행된다. 즉, 하나의 명령어가 실행되면 다른 명령어가 그 중간에 끼어들 수 없다는 의미! 또한, Redis는 트랜잭션 기능도 지원하며, 여러 명령어를 하나의 단위로 묶어 실행할 수 있는 MULTI/EXEC 명령어를 제공한다.

 

Window 환경에서의 Redis를 사용할 수 있도록 하는 방법

WSL install

wsl --install

redis라는 글을 쓰기 전에 테스트해볼때 스크린샷을 찍지 못해서 설치를 하게 된다면 아래와 같이 나올 것이다.

출처 링크 : https://yongbba.tistory.com/entry/Linux-WSL-%EC%9C%88%EB%8F%84%EC%9A%B0-10%EC%97%90%EC%84%9C-%EB%A6%AC%EB%88%85%EC%8A%A4-%ED%99%98%EA%B2%BD-%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-%EC%84%A4%EC%B9%98-%ED%95%98%EA%B8%B0

 

안내문구에 따라 컴퓨터를 재시작해주면 ubuntu가 설치되며 자동으로 실행 된다.

ubuntu가 실행되면 해당 os의 명을 어떻게 할지 비밀번호도 설정하라는 안내가 뜨는데 설정하면 이와 같이 나온다.

 

Docker install

curl -fsSL https://get.docker.com/ | sudo sh
sudo usermod -aG docker `whoami`

 

Docker 에 redis 받아오기

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

 

이렇게 하면 Docker가 설치가 완료된다.

 

redis-cli 접속

// redis로 해서 접근이 되는 이유 : -name redis로 해놓았기에 해당 docker의 이름이다.
docker exec -it redis sh

 

접속이 안되는 경우!

더보기

docker 리스트 확인하는 명령어 : docker ps -a

 

docker의 상태를 확인하여 실행하자!

 

docker 실행하기 : docker container start [CONTAINER ID]

docker 재실행하기 : docker container restart [CONTAINER ID]

docker 중지하기 : docker container stop [CONTAINER ID]

docker 삭제하기 : docker container rm [CONTAINER ID]

 

[CONTAINER ID] 를 다 작성하지 않은 이유!!

docker list 내에서 내가 작성한 값이 일치하는게 1개이면 알아서 그 docker라고 인식이 되기에 실행하는데 지장없다.

 

redis-cli 명령어

redis-cli

 

redis의 간단한 명령어

명령어 설명
FLUSHDB 데이터 모두 삭제
KEYS * 모든 키 검색
SET [key] [data] [key] 값에 [data]에 삽입
GET [key] [key] 조회
DEL [key] [key] 삭제
TYPE [key] [key]의 TYPE 조회
리스트 : LRANGE , LINDEX
해시 : HGET , HGETALL
셋 : SMEMBERS
HGETALL [key] 해시일때 [key] 를 통해 데이터 가져오는 방법

 


Spring boot 적용

gradle 추가

implementation 'org.springframework.boot:spring-boot-starter-data-redis'

 

application.properties 추가

# redis
spring.data.redis.host=localhost
spring.data.redis.port=6379

 

Configuration 작성

@Configuration
public class RedisConfig {
    @Value("${spring.data.redis.host}")
    private String host;

    @Value("${spring.data.redis.port}")
    private int port;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
        redisConfiguration.setHostName(host);
        redisConfiguration.setPort(port);
        return new LettuceConnectionFactory(redisConfiguration);
    }

    @Primary
    @Bean
    public RedisTemplate<String, String> redisTemplate() {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

 

추가 설명!

더보기

RedisConnectionFactory redisConnectionFactory()

  • 이 메서드는 Redis와의 연결을 관리하는 공장 클래스인 RedisConnectionFactory를 반환합니다.
  • RedisStandaloneConfiguration을 사용해 단일 인스턴스의 Redis 서버에 대한 구성을 설정합니다. 여기에서 호스트와 포트 정보를 설정합니다.
  • LettuceConnectionFactory는 Lettuce 클라이언트를 이용해 Redis와의 연결을 관리합니다. Lettuce는 널리 사용되는 Redis 클라이언트 중 하나입니다.
  • 이 부분은 Redis와의 물리적 연결을 생성하고 관리하는 역할을 합니다.

RedisTemplate<String, String> redisTemplate()

  • RedisTemplate은 Redis에 데이터를 저장하고 가져올 때 사용하는 주요 도구입니다. 이 템플릿은 Redis와의 상호작용을 위한 다양한 메서드(예: set, get, delete 등)를 제공합니다.
  • 이 메서드는 RedisTemplate 객체를 생성하고, 이 객체를 사용하여 Redis에 키-값(String, String)의 형태로 데이터를 저장하고 조회할 수 있습니다.

설정된 사항:

  • ConnectionFactory: Redis와의 실제 연결을 관리하는 redisConnectionFactory()를 설정합니다.
  • KeySerializer: Redis에서 사용하는 키를 문자열로 직렬화하기 위한 StringRedisSerializer로 설정합니다.
  • ValueSerializer: Redis에서 사용하는 값을 문자열로 직렬화하기 위한 StringRedisSerializer로 설정합니다.
    • 이는 기본적으로 모든 데이터가 문자열로 처리된다는 것을 의미합니다.

Controller 작성

@RestController
@RequiredArgsConstructor
@RequestMapping("/redis")
public class RedisController {

    private final RedisService redisService;

    @PostMapping
    public void createRedis() {
        redisService.createRedis();
    }

    @DeleteMapping
    public void deleteRedis() {
        redisService.deleteRedis();
    }
}

 

Service 작성

@Service
@RequiredArgsConstructor
public class RedisService {

    private final RedisRepository redisRepository;

    public void createRedis() {
        redisRepository.save(new UserVo("id", "Daniel", "New York")); // 저장

        // 값 제대로 저장되었는지 확인
        Optional<UserVo> result = redisRepository.findById("id"); // 불러오기
        if(result.isPresent()) {
            UserVo userVo = result.get();
            System.out.println(userVo.getName());
        }
    }

    public void deleteRedis() {
        Optional<UserVo> result = redisRepository.findById("id"); // 불러오기
        if(result.isPresent()) {
            redisRepository.deleteById("id"); // 삭제
            UserVo userVo = result.get();
            System.out.println(userVo.getId());
            System.out.println(userVo.getName());
            System.out.println(userVo.getAddress());
        }
    }
}

 

Repository 작성

public interface RedisRepository extends CrudRepository<UserVo , String> {
}

 

※JpaRepository가 아닌 CrudRepository를 사용한 이유

더보기

CrudRepository vs JpaRepository

  • CrudRepository: 기본적인 CRUD(Create, Read, Update, Delete) 작업을 처리하는 메서드를 제공합니다. findAll(), save(), delete() 같은 기본적인 데이터 접근 작업에 적합합니다.
  • JpaRepository: CrudRepository를 확장하며, 추가적으로 JPA에 특화된 기능을 제공합니다. 예를 들어, 페이징 및 정렬 기능을 제공하는 findAll(Pageable pageable) 등의 메서드를 포함합니다. 또한 더 많은 JPA 관련 기능을 사용할 수 있습니다.

Redis에서는 CrudRepository?

Redis는 일반적으로 비관계형(NoSQL) 데이터베이스로, JPA가 제공하는 관계형 데이터베이스에 맞춘 기능들은 불필요할 수 있습니다. Redis에서는 단순한 CRUD 작업이 주로 사용되므로, CrudRepository를 사용하는 것이 더 적합할 수 있습니다. 물론 Redis를 더 복잡하게 활용하고 싶다면 상황에 맞게 다른 인터페이스나 커스텀 기능을 추가할 수도 있습니다.

따라서 Redis에서는 CrudRepository만으로도 충분한 경우가 많고, JPA 관련 기능은 필요하지 않습니다.

 

Entity 작성

/**
 * redis에 저장할 객체
 * RedisHash 설정은 Redis에 Hash 형태로 저장하고, timeToLive가 남아있는 시간을 의미
 * 600 => 60초 * 10 => 10분
 * */
@RedisHash(value = "user", timeToLive = 600)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserVo {
    @Id
    private String id;
    private String name;
    private String address;
}

테스트

insert

 

 

insert 했더니 set형태로도 hash형태로도 둘다 들어가 있는 것을 확인했다.

이부분은 다음에 상세하게 보도록 하자

 

delete

 

 

delete 후 확인해보니 데이터가 없는 것을 확인했다.


마무리

Redis가 어렵다는 생각밖에 없었는데 글을 잘 작성해주신 분에게 감사드리며 오늘도 이렇게 하나를 배워 갑니다.