Database

[Redis] 레디스 입문 (SpringBoot 캐시서버 / 레디스 개념)

비전공자 기록광 2022. 8. 25. 17:53
반응형

캐시 서버 구축을 위해 레디스를 공부하게 됐다.

 

이전의 noSQL 글은 여기에...

2022.08.02 - [Database] - [NoSQL] NoSQL 입문 / 개념

 

[NoSQL] NoSQL 입문 / 개념

NoSQL NoSQL이란 Not Only SQL 라고 불리는 구조가 없는 데이터를 저장하기 위한 분산 저장 시스템을 말한다. 일반적으로 RDBMS와 반대 개념으로 사용된다. NoSQL의 예시로 MongoDB(Document DB), Redis(K..

datamoney.tistory.com

 

 

Redis (Remote Dictionary Server)

레디스는 비정형 데이터(noSQL) 저장 관리 위한 Key-Value 데이터 스토어를 말한다.

 

 

Redis의 활용사례

  • I/O가 많이 발생하는 데이터 처리할 때
    • 실시간 랭킹 형태 데이터
    • 조회수 카운트 형태 데이터 (유튜브 조회수 처리)
  • 사용자의 세션 관리 (개인화 빅데이터)
    • 사용자의 세션 유지, 활동 추적 형태의 데이터
    • 좋아요 기능
    • 장바구니 기능
  • API 캐싱
  • IOT 영역

 

레디스는 인메모리 구조로 I/O가 많이 발생하는 데이터를 처리할때 가장 큰 장점이 된다.

레디스가 없다면 실시간 랭킹 데이터의 경우 몇 초단위로  DB에 order by 요청을 해야한다.

또 조회수 카운트는 조회가 일어날 수록 계속해서 카운트를 업데이트해줘야한다.

이렇게 되면 서버에 큰 무리가 있을 것이다.

그래서 레디스를 이용해 메모리에 저장하고 이를 일정한 주기로 실제 rdb에 저장하며 활용한다고 한다.

 

 

데이터 구조

Table 데이터를 저장하는 논리적 구조
Data Set 테이블을 구성하는 논리적 단위
Key 하나 이상의 조합된 값으로 표현
Value Key에 대한 데이터 값 → 하나 이상의 field / element

 

String : 대부분의 데이터는 문자열로 처리 → 숫자, JPEG, Timestamp 등

set <Key><Value>
get <Key> 
getset <Key><Value>                 //존재하는 키에 새 값 추가하고 이전 값 출력 
append <Key> <Value>              //키가 존재하면 값 뒤에 값 추가 
 
//여러개 한번에 처리 
mset <Key1><Value1> <Key2><Value2> <Key3><Value3> 
mget <Key1> <Key2> <Key3> 
 
//숫자 
incr <Key>                        //키에 저장된 값 1 증가시킴 
decr <Key>                       //키에 저장된 값 1 감소시킴 
incrby <Key><Value>       //해당 키에 저장된 숫자에 값만큼 증가시킴 
decrby <Key><Value>      //해당 키에 저장된 숫자에 값만큼 감소시킴 
strlen <Key>                     //해당 키의 값인 문자열 길이 출력

 

 

 

List : 순서를 가진 데이터 구조 (Head --- tail)

Pub-Sub (생산자-소비자) 패턴에서 많이 사용

lpush <Key><Value> 
rpush <Key><Value> 
 
lpop <Key> 
rpop <Key> 
 
lrange <Key><Value>                     //-1은 인덱스의 끝 의미
lindex <Key><Index>                      //해당 키의 left부터 세서 해당 index의 값 출력

 

 

 

Set  → 데이터 존재 여부 확인에서 많이 사용

//set insert 
sadd <Key><Value> 
smember <Key>                              //모든 set 값 조회 
sismember <Key><Value>               // value 존재하면 1, 아니면 0 
 
sinter <Key> <Key>                        //해당 키에 저장된 값 교집합 출력 
scard <Key>                                   //해당 키에 저장된 값들의 개수 출력 
spop <Key><Value>                       //해당 키에 저장된 값 중 임의 값 삭제 
smove <Key><NewKey><Value>             //값의 이동

 

 

Sorted Set: 정렬된 set 데이터 처리

랭킹 처리, 정렬에서 많이 사용

score : 요소의 가중치 ⇒ 요소의 정렬 결정 (default 오름차순)

zadd <Key><Score><Value> 
zrange <Key><StartIndex><EndIndex>  [withscores]  // == score와 같이 조회하라
 
zrangebyscore <Key><MaxScore><MinScore> [withscores]     //score 범위의 값 조회 
zrangebyrank <Key><StartRank><EndRank>                           //rank 범위의 값 조회 
zrevrange <Key><StartIndex><EndIndex>        //범위에 따라 내림차순으로 정렬 조회 
zcount <Key><StartIndex><EndIndex>              //해당 범위 해당되는 값의 개수

 

 

 

Hash : 키-값 쌍으로 이뤄진 데이터 (자바의 map 구조)

Key - Value 밑에 sub Key - Value 형식의 데이터 구조

//필드에 insert 
hset <Key><Field><Value> 
hget <Key><Field> 
hgetall <Key>                                      //해당 키에 저장된 모든 필드, 값 출력 
 
//여러개 한번에 처리 
hmset <Key><Field1><Value1>  <Field2><Value2> <Field3><Value3> 
mget <Key><Field1> <Field2> <Field3> 
 
hlen <Key>                                             //해당 키의 필드 개수 출력 
hdel <Key>                                             //해당 키의 필드 삭제 
hkeys <Key>                                          //해당 키의 모든 필드 목록 출력 
hvals <Key>                               //해당 키의 모든 값에서 필드 이름 뺀 모든 값 목록 출력 

//숫자 
hincrby <Key><Field><Value                  //해당 키의 해당 필드의 값의 증감 처리
hincrbyfloat <Key><Field><Value>         //해당 키의 해당 필드의 값의 증감 처리 -> float

 

 

Bitmap : 0&1로 표현하는 데이터

Geospatial : 좌표 데이터 

stream → 로그 관리에서 많이 사용

 

 

Key 관리

keys *                                                                 //주의.. 부하 심한편 실제 서비스에선 사용 X
keys h*                                                                  //h로 시작하는 key 조회
del <Key>
exists <Key>                                                                  //해당 키 존재 여부 확인
rename <Key><new Key>                                              //해당 키 이름 변경
expire <Key><Time>                                               //해당 키의 만료시간 설정
ttl <Key>                                                                //해당 키의 남은 만료시간 조회
persist <Key>                                                        //해당 키의 만료시간 삭제

 

 

Redis 특징

  • Key-value 데이터 구조
  • 컬렉션 구조 지원
  • 인메모리로 데이터 처리해 빠르고 가벼움 
  • 디스크로 백업 가능 > Dump, AOF 방식

 

 

Redis 사용 방법

설치 방법

♣ 윈도우 설치

https://github.com/microsoftarchive/redis/releases

 

Releases · microsoftarchive/redis

Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported: Strings, Lists, Sets, Sorted Sets, Hashes - microsoftarchive/redis

github.com

 

 Linux 설치

https://yunhyeonglee.tistory.com/24

 

[Redis] Redis 설치

많은 회사들이Database cache server용으로 Redis를 이용한다는 말을 듣고 Redis에 대해 공부해보기로 하였다. 오늘은 간단한 Redis 설치 과정에대해 포스팅해야지.. 1. Redis란? - 레디스는 Key-Value 구조의..

yunhyeonglee.tistory.com

 

 

Redis Client

  • Lettuce  :자바 레디스 클라이언트 라이브러리
  • Jedis  :자바 레디스 클라이언트 라이브러리
  • Spring-boot-starter-data-redis : 스프링부트 레디스 캐시 설정 지원

 

 

Spring Boot + Redis 캐시서버 실습

이제 직접 스프링부트에 redis를 적용해 간단한 캐시 저장 실습만 해보겠다.

Spring-boot-starter-data-redis 라이브러리를 추가해준다.

 

<dependency>
    <groupId>org.springframework.boot</groupId> \
   <artifactId>spring-boot-starter-data-redis</artifactId>   
    <version>2.3.3.RELEASE</version>
</dependency>
dependencies {
    compile('org.springframework.boot:spring-boot-starter-data-redis')
}

 

 

DB 설정과 가져올 엔티티를 준비해준다.

 

application.yml

spring:
   cache:
       type: redis
    redis:
       host: 127.0.0.1
       port: 6379
   
    datasource:
        url: (db url)
        username: (db username)
        password:  (pw)

    jpa:
        show-sql: true
        hibernate:
             ddl-auto: update

 

캐시를 사용하기 위해 @EnableCaching 처리를 해준다

@EnableCaching
@SpringBootApplication
public class CachetestApplication {
     public static void main(String[] args) {
           SpringApplication.run(CachetestApplication.class, args);
     }
}

 

redis 사용을 위해 설정 정보를 작성해준다. RedisConfig

@Configuration
public class RedisConfig {
 
    @Value("${spring.redis.port}")
    public int port;

    @Value("${spring.redis.host}")
     public String host;

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

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
         return new LettuceConnectionFactory(host, port);
     }

    @Bean
     public CacheManager cacheManager() {
        RedisCacheManager.RedisCacheManagerBuilder builder =
        RedisCacheManager.RedisCacheManagerBuilder
       .fromConnectionFactory(redisConnectionFactory()); 
        RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig() 
        .serializeValuesWith(RedisSerializationContext.SerializationPair
       .fromSerializer(new GenericJackson2JsonRedisSerializer()))        // Value Serializer 변경
       .entryTtl(Duration.ofMinutes(5));                             // 캐시 수명 5분       
       builder.cacheDefaults(configuration);
       return builder.build();
    }
}

 

redis 연결과 캐시처리에 대한 설정을 한 redisTemplate을 만들어줬다.

이제 요청이 들어오면 캐시처리를 해준다.

 

Controller

@Controller
public class CacheTestController {

    private final CacheTestService service;
    public CacheTestController(CacheTestService service) { this.service = service; }

    @GetMapping("price/{chargerType}")
    public String getPriceList(@PathVariable String chargerType, Model model) {
        List<ChargingPrice> chargingPriceList = service.getPriceList(chargerType);
        model.addAttribute("list", chargingPriceList);
        return "price";
    }

    @GetMapping("price/all")
    public String getPriceList(Model model) {
        List<ChargingPrice> chargingPriceList = service.getPriceListAll();
        model.addAttribute("list", chargingPriceList);
        return "price";
    }
}

 

Service

@Service
public class CacheTestService {

    private final CacheTestRepository repository;

    public CacheTestService(CacheTestRepository repository) {
        this.repository = repository;
    }

    @Cacheable(key = "#chargerType", value = "ChargingPrice")
    public List<ChargingPrice> getPriceList(String chargerType) {
        List<ChargingPrice> chargingPriceList = repository.findByChargerType(chargerType);
        return chargingPriceList;
    }

    @Cacheable(value = "ChargingPrice")
    public List<ChargingPrice> getPriceListAll() {
        List<ChargingPrice> chargingPriceList = repository.findAll();
        return chargingPriceList;
    }
}

서비스단에서 캐시처리를 해줬는데

@Cacheable 로 간단하게 처리해줬다.

 

 

 

Repository

@Repository
public interface CacheTestRepository extends JpaRepository<ChargingPrice, Long> {
    List<ChargingPrice> findByChargerType(String chargerType);
}

 

레포지터리는 그냥 JpaRepository를 상속받아 줬다.

 

 

이제 실제 요청을해본다

충전 타입이 low인 충전요금을 불러왔다. 1392 ms가 걸렸다. 

 

오래걸린 것도 아니지만 다시 요청해보니 11 ms로 줄었다.

 

캐시를 확인해보니 잘 들어가 있는거 확인 할 수 있다.

확인을 위해 redis 실행

 

ChargingPrice::low 라는 이름으로 들어간 캐시 확인

 

값 확인해보니 잘 들어갔다.

 

 

이렇게 간단하게 캐시서버를 만들어 사용할 수있고 

자료구조별로도 처리할 수 있다. (자료구조별 메소드 제공)

 

 

 

참고

https://brunch.co.kr/@skykamja24/575

 

레디스(Redis)는 언제 어떻게 사용하는 게 좋을까

레디스를 사용해 본 적 없는 백엔드, 데이터베이스 개발자를 위해 | 레디스는 시스템 메모리를 사용하는 키-값 데이터 스토어입니다. 인메모리 상태에서 데이터를 처리함으로써 흔히 사용하는

brunch.co.kr

이것이 레디스다 | 정경석 | 한빛미디어 - 교보문고 (kyobobook.co.kr)

 

이것이 레디스다 - 교보문고

초고속 읽기 쓰기를 제공하는 인메모리 기반 NoSQL Redis | 이 책은 레디스를 실전 환경에서 사용할 수 있도록 설치부터 확장과 분산 기법 및 운영 시 고려사항과 튜닝 기법을 제시한다. 루아 스크

www.kyobobook.co.kr

 

반응형