[SW정글 129일차] Redis

rg.log·2023년 1월 25일
0

SW 사관학교 JUNGLE

목록 보기
28/31


친구들끼리 돈을 모아 함께 친구 생일 선물하기 위해
공유 장바구니에 생일인 친구가 선호하는 카테고리별 아이템을 추천받아 담고, 각자 선물해 주고픈 선물들도 담았지만 아직 무엇을 살지 결정을 하지 못했다. 질질 오래 끄는 의사결정이 아닌 실시간으로 함께 모여 한순간에 의사결정을 끝내고 싶었다. 바로 살 수 있도록!

그러려면 공유 장바구니에 참여하는 사용자들끼리 어떤 상품을 원하는지 좋아요 등을 통해 표현하고 순위를 매겨야 했다.

좋아요 구현 시 우리는 MySQL을 이미 사용하고 있기에 유니크 조건을 걸어 구현할 수 있지만, 이렇게 insert와 update가 자주 발생하는 경우 RDBMS 성능 저하가 필연적으로 발생하게 되므로 Redis의 set을 활용해 간단하게 구현하고, 빠른 시간에 처리하기로 했다.

그리고 MySQL과 같은 RDBMS는 새로운 컬럼을 추가하려면 기존 데이터도 업데이트 해야 했기에 MySQL의 스키마가 유연하지 못한 것도 한 몫했고, 실시간으로 아이템별 좋아요 싫어요를 표현한 데이터는 오래 간직(저장)할 데이터가 아니기에 redis의 ttl을 활용하면 좋을 것 같았다.

Redis

Redis는 시스템 메모리를 사용하는 키-값 데이터 스토어로 인메모리 상태에서 데이터를 처리함으로 흔히 사용하는 관계형 데이터베이스, 몽고 DB로 대표되는 문서형 데이터베이스보다 빠르고 가볍게 동작한다.
빠른 성능 덕에 Redis는 캐싱, 세션 관리, 실시간 분석, 채팅/메시징, 미디어 스트리밍 및 게시/구독 앱에서 주로 사용된다.

채팅/메시징에 redis를 사용하고자 잠시 알아보기도 했지만, 시간상 우선순위에 밀려 적용이 어려울 것 같다.

시행착오 및 적용

application.yml에 아래와 같이 추가한다.
local에서 진행한다면 host는 localhost이다.

  redis:
    host: api.sendwish.link
    port: 6379
@Configuration
public class RedisConfig {

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

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


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

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

}
@Getter
@RedisHash(value = "like", timeToLive = 30)
public class Like {

    @Id
    private String id;
    private String nickname;

}
  • timeToLive
    만료시간을 seconds 단위로 설정할 수 있다. 기본값은 만료시간이 없는 -1L 이다.
@Transactional
public ChatVoteResponseDto like(ChatVoteRequestDto dto) {
    ValueOperations<String, String> like = redisTemplate.opsForValue();
    String key = dto.getRoomId() + ":" + dto.getItemId();
    String value = dto.getNickname();

    log.info("맴버 [ID] : {} 가, [좋아요] : {} 를 눌렀습니다.", dto.getNickname(), dto.getIsLike());
    String find = like.get(key);
    if (dto.getIsLike()) { // 좋아요 누른 경우
        if (find == null) {
            like.set(key, value);
        } else {
            if (!find.contains(value)) {
                if (find.equals("")) {
                    like.set(key, value);
                } else {
                    like.set(key, find + "," + value);
                }
            }
        }
        } else {
            if (find != null && find.contains(value)) {
                if(find.contains(",")) {
                    like.set(key, find.replace("," + value, ""));
                }else{
                    like.set(key, "");
                }
            }
        }

        String result = like.get(key);
        Integer count = 0;
        if (!Objects.equals(result, "")) {
            count = result.length()
                    - result.replace(",", "").length() + 1;
        }
        log.info("투표 [roomId] : {}, [itemId] : {}, [like count] : {}", dto.getRoomId(), dto.getItemId(), count);

        return ChatVoteResponseDto.builder()
                .itemId(dto.getItemId())
                .like(count)
                .build();
    }

참고. 레디스는 언제 어떻게 사용하는게 좋을까


오늘의 나는

시간이 부족하다 보니 개발 넘 빡센데 너무 재밌다.
나중에 회사가면 모니터 큰 거 2개 띄우고 하고 싶따.

0개의 댓글