Redis
Redis란?
- 시스템 메모리를 사용하여 Key - Value 구조로 비정형 데이터를 저장하고 관리하는 인메모리 데이터 저장소.
- 메모리를 사용하다 보니 보통 캐시, 서버 용도로 많이 사용됨. => 캐시로 사용하여 성능을 향상시키는 것이 주 목적.
Redis의 특징
:메모리 DB의 특징을 가지게 됨.
- 물리 DB(ex, mysql)를 거치지 않고 메모리에서 값을 가져오기 때문에 속도가 빠름.
- 메모리이기 때문에 기본적으로 휘발성임. (영속성을 지원하긴 하지만, 서버의 물리 DB에 저장하는것보다 당연히 불안정함.)
- 다양한 자료구조를 지원(ex, Lists, Sets, Hashes 등)
Redis 서버 구축방법
-
Single
-
Sentinel
-
Cluster
-
여러 인스턴스를 활용하며, 각 서버당 1개의
Master Node
와 N-1개의Slave Node
를 둠. -
Slave Node
는Master Node
의 자료를 복제함. 단, 복제본은 같은 서버가 아니라 다른 서버에 둠. -
이렇게 구성하여 서버가 죽었을 때 다른 서버를 활용하여 정상 운영을 가능하게 함. (마치 NAS의 RAID 개념과 비슷하네)
-
Redis 명령어
set key value // 키와 벨류를 저장함
get key // 키에 해당하는 벨류를 호출
del key // 키-벨류 삭제
keys * // 모든 키 리턴
# redis 서비스 실행
redis-server
# redis-cli 동작
redis-cli
-> ip:port>
# (비밀번호 설정이 되어 있는 경우)
auth 비밀번호
-> OK
# 비밀번호(계정) 확인
config get requirepass
"requirepass"
"" -> 비밀번호 세팅 안 된 상태
# 비밀번호 세팅
config set requirepass 비밀번호
-> OK
# 비밀번호 세팅 적용
auth 비밀번호
-> OK
# 제대로 동작하는지 확인
ping
-> PONG
# 레디스 설정파일
sudo vi /etc/redis/redis.conf
# 외부에서 redis 접근방법
redis-cli -h 3.34.206.181 -p 6379
Springboot 프로젝트에서 Redis를 사용하여 캐시 사용
-
application.yml
spring: redis: host: localhost port: 6379 (레디스 포트번호)
-
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
-
CacheConfig.java (config 클래스)
package com.dayone.config; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.CacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration @RequiredArgsConstructor public class CacheConfig { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Bean public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheConfiguration conf = RedisCacheConfiguration.defaultCacheConfig() .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); //.entryTtl(Duration.of(주기)); Redis 전체에 대한 Ttl 설정 (주기적으로 삭제) return RedisCacheManager.RedisCacheManagerBuilder .fromConnectionFactory(redisConnectionFactory) .cacheDefaults(conf) .build(); } @Bean public RedisConnectionFactory redisConnectionFactory() { RedisStandaloneConfiguration conf = new RedisStandaloneConfiguration(); conf.setHostName(host); conf.setPort(port); return new LettuceConnectionFactory(conf); // 이걸로 RedisConnectionFactory 빈으로 사용하게 됨. } }
-
FinanceService.java (캐시를 사용할 메서드가 있는 클래스)
@Service @AllArgsConstructor public class FinanceService { private final CompanyRepository companyRepository; private final DividendRepository dividendRepository; // 캐시에 데이터가 있으면 로직수행하지 않고 캐시에서 가져옴. / 캐시에 데이터가 없으면 로직 수행하고 결과를 캐시에 저장. // 캐시는 내용이 업데이트되어서 새로운 정보가 필요하거나, 캐시 메모리가 다 차게 되면 비워줘야 함. -> 스캐쥴러 활용 가능. @Cacheable(key = "#companyName", value = CacheKey.KEY_FINANCE) //#companyName은 파라미터에서 주입받는 것. public ScrapedResult getDividendByCompanyName(String companyName) { // 서비스 로직 } }
-
호출 시 실제 로그
Hibernate: select companyent0_.id as col_0_0_ from company companyent0_ where companyent0_.ticker=? limit ? Hibernate: insert into company (id, name, ticker) values (null, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: insert into dividend (id, company_id, date, dividend) values (null, ?, ?, ?) Hibernate: select companyent0_.id as id1_0_, companyent0_.name as name2_0_, companyent0_.ticker as ticker3_0_ from company companyent0_ limit ?
- 한번 insert 후 처음 조회시 select로 빼오지만, 그 이후에는 캐시에서 빼우기 때문에 아무리 조회해도 Redis 캐시에서 가져옴.
-
캐시를 사용할지 말지?
- 요청이 자주 들어오는가? -> 요청이 빈번하면 캐시에서 꺼내오는 것이 효율적.
- 데이터가 자주 변경되는가? -> update 될때마다 캐시에 있는 데이터도 변경해주어야 하기 때문에 이럴 경우 캐시를 활용하지 않는 것이 좋을 수 있음.
-
[실무팁] 캐시 사용 이슈!!
- 캐시 데이터도 제한된 용량이 있기 때문에 주기적으로 관리가 필요함 -> 스케쥴링 활용이 가능함!
- 내용이 업데이트 될 경우, 캐시를 삭제한 후 다시 올리거나 혹은 캐시에 있는 데이터도 업데이트하여 데이터 정합성을 유지해야 함!
마지막 수정일시: 2022-11-07 21:59
댓글남기기