개요
Redis는 다양한 언어와 함께 사용할 수 있다.
이번 포스팅에서는 spring boot 프로젝트에서 사용하는 Redis에 대해 알아보도록 한다.
현재 개발 운영 방식에 알맞은 방법으로 Redis를 도입할 수 있도록 각각의 라이브러리와 방식을 공부하는 것이 목적이다.
전체 코드는 깃허브에서 확인 가능하다.
Lettuce와 Jedis
스프링 프로젝트에서 사용하는 레디스는 두 가지 종류가 있다.
Lettuce
Lettuce는 Netty 기반 라이브러리로 Asynchronous & Non-blocking으로 구현되어 있다.
- Netty란?
- 네트워크 애플리케이션 개발을 위한 오픈소스 자바 프레임워크로, 비동기 이벤트 기반의 네트워크 애플리케이션을 쉽게 개발할 수 있도록 관련 도구와 라이브러리를 제공한다.
- 자세한 내용은 여기서 확인할 수 있다.
여기서 비동기 방식이 핵심이다. 비동기 방식은 싱크를 맞추는 것과 상관없음. 즉, 하나의 작업이 완료될 때까지 대기하지 않고 다른 작업을 처리할 수 있는 특징이 있다. 이러한 비동기 방식으로 동작하는 Lettuce는 Redis와 하나의 커넥션만으로 여러 요청을 비동기적으로 처리할 수 있기에, 리소스를 효율적으로 사용하고 응답시간을 최적화한다.
또한, 비동기 논블로킹이므로 spring boot 애플리케이션이 멀티 스레드를 사용하더라도 안전한 프로그래밍을 할 수 있다.(Lettuce는 Synchronous도 제공한다.)
이러한 thread-safe 특성으로, spring boot 2.0부터는 Jedis가 기본 클라이언트에서 deprecated되고 Lettuce가 탑재되었다.
더 자세한 사항은 공식 문서와 해당 이슈에서 확인 가능하다.
Jedis
Lettuce와 비교하여 thread-non-safe하다는 점, java 기반 애플리케이션이라는 점만 알아두자.
Spring boot에서 Redis를 사용하는 방법
Lettuce를 통해 스프링 프로젝트와 레디스를 사용하는 방법은 두 가지다.
- o.s.data.redis.core의 RedisTemplate 클래스
- Spring Data 프로젝트에서 제공하는 CrudRepository를 확장한 RedisRepository 사용
RedisTemplate
첫 번째 방법인 RedisTemplate을 사용하는 것은 RedisRepository를 사용하는 것에 비해서 Redis 서버를 더 세밀하게 다루는 방법이다. Spring Data Redis에서 제공하는 다양한 Operations를 통해서 특정 데이터 타입을 다루거나 명령어를 수행함으로써 가능하다.
RedisTemplate으로 SpringBoot와 Redis 사용
일단 SpringBoot Redis를 사용하기 위해 의존성 및 빈 설정을 진행한다.
필자는 pom.xml 파일을 통해 여러 의존성과 라이브러리를 관리하고 있으므로 pom.xml 파일에 다음과 같이 추가해준다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.2.7.RELEASE</version>
</dependency>
그리고 빈등록을 위해 application.properties 파일에 필요한 속성들을 추가해준다. (디폴트값으로 설정된 값을 사용하기에 따로 추가를 해주지 않아도 된다. 하지만 프로퍼티 파일을 잘 쓰는 것은 하드코딩을 막을 수있고, 가시적으로 보이는 값들이기에 협업을 할 때에도 많은 도움을 받을 수 있다고 느꼈기에 직접 추가해주었다. - @Config 파일의 @Value로 사용할 수 있다.)
일단은 간단하게 아래 두 가지만 추가
application.properties
spring.data.redis.host=localhost
spring.data.redis.port=6379
빈등록을 위해 Config 파일에 RedisTemplate을 세팅한다.
config/AppConfig.Java
@Configuration
public class AppConfig {
@Value("localhost")
private String host;
@Value("6379")
private int port;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(new RedisStandaloneConfiguration(host, port));
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
return redisTemplate;
}
}
이렇게 되면 SpringBoot와 Redis를 사용할 준비가 얼추 끝났다.
Template에 추가적으로 값을 세팅하여 더 세밀하게 Redis 서버를 다룰 수 있다.
이제 클라이언트 측에서 요청을 날리고 redis 서버에 원하는 동작이 이루어지는지 확인해보자.
RedisController.java
@RestController
@RequestMapping("/redis")
public class RedisController {
@Autowired
private StringRedisTemplate redisTemplate;
@GetMapping("/{key}/{value}")
public String stringsSet(@PathVariable String key, @PathVariable String value) {
final ValueOperations<String, String> stringStringValueOperations = redisTemplate.opsForValue();
stringStringValueOperations.set(key, value); // redis set 명령어
System.out.println("stringStringValueOperations's key = " + stringStringValueOperations.get(key));
return "ok";
}
}
설정한 RedisTemplate의 의존성을 주입하고, URL 상으로 key와 value를 받아 이를 redis에 저장해본다. 위 코드를 실행하고 http://localhost:8080/redis/1/10이런식으로 요청을 날린 후 Redis에 값이 set되었는지 확인해보자.
요청 URL과 ok를 확인해주고, 여기서 key는 1, value는 10이다.
모든 key 값을 출력하는 keys 명령어를 통해 Redis에 저장된 Key를 확인해보면 좀 전에 controller로 요청한 1이 저장되어있다.
이 key 값을 통해 value도 출력해보면 value 값인 10이 잘 올라가있음을 확인할 수 있다.
RedisRepository
Spring Data Redis의 RedisRepository는 Spring JPA와 비슷한 방식으로 Redis에 접근할 수 있어, 스프링 개발자에게 좀 더 친숙한 방식이다.
- Config 설정, pom.xml, application.properties 설정은 Redis Template 방식과 동일하므로 생략한다.
우선 Repository 사용을 위해 간단한 Entity를 만들어 준다.
@Data
@RedisHash("member")
public class Member {
@Id
private String id; // redis는 key- value 쌍이기 떄문에 member:<Id> 이런식으로 들어감
private String name;
private int age;
public Member(String name, int age) {
this.name = name;
this.age = age;
}
}
- RedisHash: Member 클래스의 객체가 레디스에 저장될 때 Hash의 이름을 member로 저장하고, Hash 형태로 저장된다는 뜻이다. 일반적으로 레디스는 Key-Value 저장소이다. 그런데 Spring Data Redis는 객체를 레디스에 저장할 때 Hash 자료구조를 사용한다.
- 위를 예로 들면 Member 객체를 레디스에 저장하면 다음과 같은 형태로 저장된다.
member:1 = {"id": "1", "name": "spring-redis", "age": 20}
RedisRepository는 간단하게 CrudRepository만 잘 상속받아 주면 된다. 이를 상속받음으로써 기본적인 CRUD 연산을 수행할 수 있는 메소드들이 제공된다. (필요 시 Override 가능)
public interface RedisRepository extends CrudRepository<Member, String> {
}
클라이언트에서 요청을 날리고, 이를 Redis 서버에 반영할 Controller와 Service 함수는 다음과 같다.
MemberController.java
@RestController
public class MemberController {
private final RedisService redisService;
public MemberController(RedisService redisService) {
this.redisService = redisService;
}
@GetMapping
public String setPersonInfo() {
redisService.setRedisData();
return "ok";
}
}
MemberServiceImpl.java
@Service
public class RedisServiceImpl implements RedisService{
@Autowired
private final RedisRepository redisRepository;
public RedisServiceImpl(RedisRepository redisRepository) {
this.redisRepository = redisRepository;
}
public void setRedisData() {
Member member = new Member("springredis", 99);
redisRepository.save(member);
}
}
localhost 서버를 띄워 요청을 날리고 Redis를 확인해보면 다음과 같이 값이 Hash로 잘 저장되어있음을 확인할 수 있다.
레디스는 생각보다 공식문서들이 잘 되어있어서 진입하는 데에는 그리 어렵지는 않았다.
앞으로 캐시를 위한 레디스 업무를 맡을것같은데... 일단 인프런 강의를 통해서 레디스의 주요 명령어들을 잘 배우고, 캐시를 위한 레디스는 어떻게 사용할 것인지에 대해 더 정리해보면 좋을 듯하다.
그리고 실제 업무 환경에서 어떻게 호스팅할지? 알아봐야한다.
'DevOps > DevOps' 카테고리의 다른 글
[DevOps] 멀티모듈 프로젝트 CI/CD 적용 - 설계 구상 편 (3) | 2024.07.22 |
---|---|
[Redis] Redis 4편. 운영 방식과 호스팅 (0) | 2024.01.08 |
[Redis] Redis 2편. 기본 자료형 (0) | 2024.01.04 |
[Redis] Redis 1편. 개념과 특징, 설치 및 간단한 사용법 (2) | 2024.01.04 |