Redis

NestJS에서 Redis를 활용한 좋아요 성능 개선

Dev갱이 2024. 9. 23. 16:32
728x90

현재 구조의 문제

memberId와 feedId가 식별자 관계로 중복 데이터가 존재하지 않게 무결성을 보장 하지만 잦은 insert와 update는 성능 저하를 일으킨다.
  • 피드 좋아요 개선
  • 댓글 좋아요 개선

1. Redis의 `Set` 자료구조를 이용하여 개선하기

  • set 자료구조를 사용한 이유는 RDBMS에서도 무결성을 보장하기 위해 유니크 제약조건을 지키기 위해 식별자 관계로 PK를 사용 했는데 Redis의 set 자료구조를 사용하면 중복된 데이터가 없기 때문에 무결성을 보장할 수 있다
  • 레디스의 `set` 을 이용하여 이 기능을 간단하게 구현할 수 있으며, 빠른 시간 안에 처리할 수 있다. 

1. 피드의 아이디를 사용해서 key를 생성
2. 해당 피드에 좋아요를 누른 사용자의 ID를 아이템으로 추가하면 동일한 ID값을 저장할 수 없으므로 한 명의 사용자는 하나의 댓글에 한번 만 좋아요를 누를 수 있게 된다.

 

2. Redis 캐싱 전략 선택

  • Look-asideWrite-through 전략을 함께 사용

사용자가 특정 피드에 좋아요를 누르면:

  1. Redis Set에 해당 피드의 좋아요 사용자 ID가 있는지 확인 (캐시 조회).
  2. 없다면, Redis에 ID를 추가하고 데이터베이스에도 동시 기록 (쓰기 작업: Write-through).
  3. 좋아요 수를 조회할 때는 Redis에서 바로 가져오고, 캐시 미스 시 데이터베이스에서 읽어온 뒤 캐시에 저장 (읽기 작업: Look-aside).

3. 구현

feeds.service.ts

 

onModuleInit 메서드를 통해 서버 시작 시 모든 피드의 좋아요를 Redis와 동기화 (Cache Warming)이 필요한 이유

Cache Miss를 방지하기 위해서

서버가 처음 시작되거나 재시작되면, Redis 캐시는 초기 상태로 비어 있어 있다. Redis는 휘발성 메모리이기 때문이다.
이때 클라이언트가 서버로 요청을 보낼 경우 캐시에서 데이터를 찾지 못해 Cache Miss가 발생한다.
Cache Miss가 발생한 상태에서 사용자 요청이 몰리면서 과도한 트래픽이 발생하여 모든 요청이 데이터베이스를 조회하게 되어 성능 이슈가 발생 할 수 있다.
이를 방지하기 위해 서버가 시작될 때 미리 Redis에 필요한 데이터를 로드(Cache Warming) 해서 처음부터 캐시가 준비된 상태에서 빠른 응답을 제공 할 수 있게 된다.

feeds.service.ts - updateLikesFeeId

likes-feed.cache.ts

4. 트랜잭션 고려

updateLikesFeedId 메서드의 코드를 살펴보면 좋아요를 removeLike나 addLike 할 때 에러가 발생하면 qr: QueryRunner를 통해서 롤백 해주는데 Redis에서는 없기 때문에 이렇게 되면 캐시 데이터와 RDBMS 데이터가 일치하지 않는 문제가 발생한다.

 

QueryRunner와 redisMulti 트랜잭션을 함께 사용할 수 있는 interceptor 생성

 

transaction-with-redis.interceptor.ts

query-runner-with-redis.decorator.ts

feeds.service.ts - updateLikesFeedId

이제 RDBMS와 Redis의 일관성을 유지할 수 있다.

 

 

(읽기 작업: Look-aside)
조회할 때는 Redis에서 바로 가져오고, 캐시 미스 시 데이터베이스에서 읽어온 뒤 캐시에 저장.

 

5. 확인

 

현재 피드 좋아요는 1개가 존재한다.
만약 production 환경에서 서버가 처음 시작되거나 재시작되었다고 가정. 처음엔 cache가 모두 비어있어야 하지만 (Cache Warming)을 통해서 Database에 있는 좋아요를 Redis 캐시에 밀어넣어주면서 동기화 시켜준다.
OnModuleInit를 implements 받아서 onModuleInit 메서드로 실행 시켜줌.

 

 

그 결과 redis에 SMEMBERS 명령어로 해당 key에 접속 해보면 해당 key를 가진 좋아요 데이터가 존재하는걸 알 수 있다.

 

트랜잭션 테스트

 

 

haLiked 좋아요가 존재 할 때 취소하는것이기 때문에 removeLike에서 에러가 발생하게 된다면 롤백이 되어야 한다.
1. 캐시에서도 삭제되면 안된다.
2. repository에서도 삭제되면 안된다.

 

 

 

  • 데이터베이스에서 롤백이 잘되었다.

 

  • redis에서도 롤백이 잘되었다.

 

Look-aside

 

 

 

이제 사용자가 특정 피드를 조회 하게 되면 해당 피드의 좋아요 갯수와 자신의 좋아요 상태는 Redis에 먼저 확인하고 redis에 있는 데이터를 반환하여 RDBMS접근하지 않고 성능을 개선 할 수 있게 되었다.
728x90