티스토리 뷰

728x90
반응형

Redis는 In-Memory로 데이터를 저장하고, Key-Value 방식으로 데이터를 입출력 연산을 지원하는 데이터베이스입니다. In-memory 저장소이므로, 프로그램이 종료되면 쌓여있던 데이터는 모두 유실될 수 있습니다. 그러므로, Redis는 캐시와 같은 용도로 사용하는 것이 좋습니다. 웹 서버에서 일시적으로 데이터를 저장하고 사용할 필요가 있는 경우는, In-Memory와 같은 데이터베이스를 사용하여 캐시 효과를 보는 게 성능의 이점을 가져올 수 있습니다.

이번 포스팅에서는 Springboot에서 In-memory 데이터베이스인 Redis와 통신하는 방법에 대해 알아보도록 하겠습니다.

Springboot Redis용 프로젝트 다운로드

https://start.spring.io/ 사이트에 접속하여, Spring Data Redis 디펜던시를 추가한 후 프로젝트를 생성합니다.

스프링부트 프로젝트 다운로드

다운로드한 프로젝트를 압축 해제한 후, Build.gradle 파일을 열어보면 redis 디펜던시가 추가된 것을 확인할 수 있습니다.

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

Redis를 사용하기 위해서는 Redis 공식 홈페이지인 https://redis.io/ 에서 다운로드를 하여 설치하시거나 또는 Docker의 Image를 다운로드하여 Container로 실행해도 됩니다. 저는 도커를 이용하여 Redis를 실행해보았습니다.

도커로 Redis 실행하기

도커로 Redis를 실행하기 위해서는 우선 도커를 먼저 설치해야 합니다. Docker를 설치하는 가이드는 아래 링크 참조 바랍니다.

 

[OS] 윈도우(Windows)에서 도커(Docker) 설치하기

도커(Docker)는 가상화를 이용한 프로세스를 격리하여 실행해주는 소프트웨어 플랫폼입니다. 도커를 이용하면, 어떠한 Host OS환경에서도 프로세스를 동일한 환경에서 실행할 수 있습니다. 마치 빈

shcheon.tistory.com

도커를 사용하실 때, Docker Desktop을 이용하셔도 되지만, Terminal에서 Docker 실행 명령어를 이용해도 됩니다. 저는 도커 데스크톱을 이용하여 Redis를 실행해보겠습니다. 도커 데스크톱의 홈 화면에서 Redis Image를 Run 하면 자동으로 Docker Hub로부터 Image를 다운로드합니다.

Redis Image가 다운로드 완료된 후, 해당 Image를 실행할 수 있는 버튼이 생성됩니다. Run 버튼을 누르면, Redis를 실행할 때 Port를 별도로 지정할 수 있습니다. 

Redis가 실행될 컨테이너 이름을 TestRedis로 명명하고, Port는 6379로 지정하였습니다. Redis가 구동되는 기본 port 6379이므로, Springboot에서 Redis에 연결을 시도할 때 별도의 Redis Port를 지정하지 않으면 6379 포트로 연결을 시도합니다.

Redis가 정상적으로 실행되었다면, TestRedis라는 컨테이너의 실행 로그를 확인해봅니다. 아래와 같이 Ready to accept connections 로그가 기록되었다면, Redis가 정상적으로 실행된 것입니다.

Redis에 Key-Value 데이터 저장하기

Redis 서버가 정상적으로 실행된 이후, redis-cli를 통해 도커 컨테이너로 실행된 redis 서버에 접속해보겠습니다. 명령어는 아래와 같습니다.

docker exec -it {Redis컨테이너이름} redis-cli

저는 Redis 컨테이너 이름을 TestRedis로 명명하였기 때문에, docker exec -it TestRedis redis-cli로 Redis 서버에 접속해보겠습니다. 

C:\>docker exec -it TestRedis redis-cli
127.0.0.1:6379>

자, 지금부터 Redis에서 저장된 Key값을 조회하고, 저장해보겠습니다. Key-Value 데이터를 조회하는 명령어는 Keys *를 이용하여 Redis에 저장된 모든 Key을 조회할 수 있고, get 명령어로 Key에 저장된 Value값도 조회가 가능합니다. Set명령어를 이용하면 Key-Value 쌍으로 데이터를 저장할 수 있습니다. 

127.0.0.1:6379> keys *
1) "backup2"
2) "backup3"
3) "backup1"
127.0.0.1:6379> set testkey1 testvalue1
OK
127.0.0.1:6379> set testkey2 testvalue2
OK
127.0.0.1:6379> keys *
1) "testkey1"
2) "backup1"
3) "backup2"
4) "backup3"
5) "testkey2"
127.0.0.1:6379> get testkey1
"testvalue1"
127.0.0.1:6379> get testkey2
"testvalue2"
127.0.0.1:6379>

다음으로 Redis와 연동하기 위한 Springboot 코드를 작성해보겠습니다.

SpringBoot에서 Redis API 코드 작성하기

Redis에서 testkey1, testkey2 Key값에 해당하는 Value를 가져와서 출력하는 springboot 애플리케이션을 작성해보겠습니다. SpringBoot의 main 함수에서 StringRedisTemplate를 이용하여 Redis에 접근해보겠습니다. SpringBoot에서 지원하는 Redis Client에서는 Redis서버에 접속하는 기본 포트가 6379로 지정되어 있으므로, 별다른 설정 없이도 Redis 서버에 접속이 됩니다.

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;

@SpringBootApplication
public class DemoApplication {

   public static void main(String[] args) {
      ApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
      StringRedisTemplate template = ctx.getBean(StringRedisTemplate.class);
      String val = template.opsForValue().get("testkey1");
      System.out.println(val);

      val = template.opsForValue().get("testkey2");
      System.out.println(val);
   }
}

RedisTemplate은 JDBCTemplate과 같이 Redis서버에 접속하기 위한 쿼리 처리를 위한 인터페이스 API와 같은 용도입니다. 앞서 사전에 Redis 서버에서 저장한 testkey1, testkey2를 opsForValue(). get함수로 조회해본 결과 정상적으로 testvalue1, testvalue2를 가져오는 것을 확인할 수 있습니다.

testvalue1
testvalue2

Redis를 이용한 Message Publish-Subscribe 구현

Redis는 Key-Value 방식으로 데이터를 저장할 뿐만 아니라, Publish-Subscribe 패턴으로 프로세스 간 데이터를 교환하는 방법도 제공하고 있습니다. Pub-Sub 메시지 교환 패턴은 특정 Topic에 메시지를 발행되면 메시지를 구독하여 받아 볼 수 있는 구조인데, 여기서 메시지를 구독하기 위한 클래스인 Receiver 클래스를 작성해보겠습니다.

package com.example.demo;

import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Receiver {
    private static final Logger LOGGER = LoggerFactory.getLogger(Receiver.class);

    private AtomicInteger counter = new AtomicInteger();

    public void receiveMessage(String message) {
        LOGGER.info("Received <" + message + ">");
        counter.incrementAndGet();
    }

    public int getCount() {
        return counter.get();
    }
}

Receiver 클래스는 단순히 메시지 수신받았을 때 로그를 출력하는 함수와, counter를 증가하는 것 이외에 특별한 기능은 없습니다. 다음으로, 토픽으로 메시지를 발행하는 구문을 보겠습니다.

StringRedisTemplate template = ctx.getBean(StringRedisTemplate.class);
template.convertAndSend("chat", "Hello from Redis!");

StringRedisTemplate 클래스를 이용하여 chat이라는 Topic에 "Hello from Redis!"라는 문자열을 발행하였네요. 이제, chat이라는 토픽을 Receiver가 구독하도록 설정하는 코드를 보겠습니다.

package com.example.demo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;

@SpringBootApplication
public class DemoApplication {
   private static final Logger LOGGER = LoggerFactory.getLogger(DemoApplication.class);

   @Bean
   RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                 MessageListenerAdapter listenerAdapter) {
      RedisMessageListenerContainer container = new RedisMessageListenerContainer();
      container.setConnectionFactory(connectionFactory);
      container.addMessageListener(listenerAdapter, new PatternTopic("chat"));
      return container;
   }

   @Bean
   MessageListenerAdapter listenerAdapter(Receiver receiver) {
      return new MessageListenerAdapter(receiver, "receiveMessage");
   }

   @Bean
   Receiver receiver() {
      return new Receiver();
   }

   @Bean
   StringRedisTemplate template(RedisConnectionFactory connectionFactory) {
      return new StringRedisTemplate(connectionFactory);
   }

   public static void main(String[] args) throws InterruptedException {
      ApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
      StringRedisTemplate template = ctx.getBean(StringRedisTemplate.class);
      Receiver receiver = ctx.getBean(Receiver.class);
      while (receiver.getCount() == 0) {
         LOGGER.info("Sending message...");
         template.convertAndSend("chat", "Hello from Redis!");
         Thread.sleep(500L);
      }
   }
}

container, listnerAdapter, receiver, template  함수를 이용하여 receiver 클래스가 chat 토픽을 구독할 수 있도록 설정하였습니다. 프로그램을 실행하면, chat 토픽에 메시지가 발생될 경우 Receiver 클래스에 receiveMessage가 호출되는 것을 확인할 수 있습니다.

com.example.demo.DemoApplication         : Sending message...
com.example.demo.Receiver                : Received <Hello from Redis!>

지금까지 Springboot 애플리케이션에서 Redis를 접근하는 방법에 대해 알아보았습니다.

728x90
반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함