[개발] Redis의 캐싱 기능을 이용해 조회 성능 높이기

이수진·2023년 9월 10일
1
post-thumbnail

Redis 도입 계기

날씨 어플리케이션을 개발하고 서비스를 운영하는 도중에
날씨 정보 조회시 로딩 속도가 너무 느림을 확인했고, 날씨 정보 조회 시 매번 상당히 많은 데이터들을 db로부터 가져오기 때문에 db가 병목 지점이라고 생각했고
날씨 정보가 업데이트가 일어나는 주기 동안은 해당 정보는 동일하므로, 같은 쿼리가 db에 나가는 것이 낭비라고 생각하였습니다.

즉, 날씨 업데이트 주기 동안에 같은 요청이 들어왔을 때에 이를 미리 캐싱해두면, 데이터베이스로 접근하지 않고 캐싱된 정보를 줄 수 있으므로 조회 성능을 높일 수 있다고 예측했습니다.

지역별 캐싱 전략

파레토 법칙(8:2 법칙)이란?

파레토 법칙이란 전체 결과의 80%가 전체 원인의 20%에서 일어나는 현상을 가리킵니다.
서비스에 빗대어 표현하자면 서비스의 총 80%의 활동을 20%의 유저가 하기 때문에 20%의 데이터만 캐싱해도 서비스 대부분의 데이터를 커버할 수 있다는 의미입니다.

즉, 캐시에 모든 데이터를 저장할 필요 없이 "파레토 법칙"에 따라 많이 사용되는 일부만 저장해도 대부분의 데이터를 커버할 수 있다는 저장 지침입니다.

즉, 캐싱을 하는 데이터는 자주 사용되며, 자주 변경되지 않는 데이터를 기준으로 하는 것이 좋습니다.

전체 요청의 70% 이상이었던 서울 지역을 중심으로 캐시 적용

현재 서비스는 시/군/구 단위까지의 세부적인 지역에 대한 날씨 정보를 제공하고 있습니다.
또한 모든 지역 단위에 대해 동일한 시간 간격으로 (동일한 업데이트 주기로) 날씨 데이터가 업데이트되므로, 사용자의 요청이 많은 지역에 대해서 캐시를 도입하기로 결정했습니다.

사용자의 요청과 트래픽 분포가 가장 많았던 서울 지역(총 25개 자치구)에 대해 캐시를 적용하기로 결정했습니다.

Django 환경에서 Redis로 Caching 하기

저는 docker 에서 Redis 서버를 띄우고, DJango에서 연결해서 이를 구현하였습니다.

간단히 그 방법을 소개해드리겠습니다.

1 - Docker에서 Redis 설치하고, Redis-net 띄우기

docker pull redis:alpine 을 입력합니다.

다음으로는
docker network create redis-net 을 입력하여 redis network를 만들어줍니다.

docker run --name djangoredisserver -p 6379:6379 --network redis-net -d redis:alpine redis-server --appendonly yes

docker run -it --network redis-net --rm redis:alpine redis-cli -h djangoredisserver

다음 두 명령어까지 모두 입력하면, redis 서버가 정상적으로 작동함을 확인할 수 있습니다.

2 - Django 설정파일에 Redis 설정 추가하기

그 다음 Django에서 해주어야 할 것들은 다음과 같습니다.

먼저 settings.py에 캐시 관련 정보를 추가해줍니다.

# Redis Cache
CACHE = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379"
    }
}

그리고 그 다음 pip install django-redis 로 라이브러리를 설치해주면 끝입니다!

이렇게 해 준 다음, 캐싱을 적용할 view에서

from django.core.cache import cache 를 이용하여 이를 써주면 됩니다.

튜토리얼이나 공식 문서에 이용법은 자세히 나와있으니, 이용법을 따로 설명하지는 않겠습니다

Redis 도입 전과 후 성능 비교하기

저는 서울시 25개의 자치구에 대해서 날씨 정보 조회 시 캐싱을 적용했고,
이를 적용하기 전과 후의 조회 성능 차이를 비교해보았습니다.

도입 전

도입 후

125ms -> 17ms 로 조회 성능이 크게 개선되었음을 확인할 수 있었습니다
날씨 정보 조회시 로딩 속도가 너무 느린 것을 db가 가장 큰 병목 지점이라고 예측했던 것도 예상에 부합한 것 같습니다.

현재의 사용자 요청이 서울 지역이 가장 많아 서울 지역을 중점으로 캐싱을 적용했지만, 이후 사용자의 접근 패턴이나 트래픽 분포에 따라 추가적인 다른 지역들에 대해서도 캐싱이 필요하다면 이를 도입하고자 합니다.

데이터 업데이트와 정합성 고려하기

캐시 이용 시, 중요한 부분 중 하나는 바로 실제 데이터와의 정합성을 잘 고려해주어야 합니다.
저는 비동기 작업으로 데이터베이스에 있는 날씨 데이터가 업데이트가 일어나는 시점에 동시에 캐시의 데이터도 업데이트 시켜주어 데이터베이스와 캐시 데이터 간의 데이터 정합성에 문제가 발생하지 않도록 해주었습니다.

데이터베이스 업데이트와 Redis 업데이트는 atomic하게 관리되어야 합니다. 예를들어, Redis 업데이트는 성공했지만, 데이터베이스 업데이트가 실패하면 불일치 문제가 발생할 수 있습니다.
이의 문제를 해결하기 위해 저는 데이터베이스의 업데이트가 성공적으로 완료된 후에 Redis를 업데이트 하는 방식으로 이를 설계하였습니다.

즉, 정리하자면

1. 데이터베이스 먼저 업데이트

  • 데이터베이스는 중요한 정보의 영구 저장소이므로, 여기에 데이터를 먼저 저장(업데이트)합니다. 이렇게하면 데이터 손실의 위험을 최소화할 수 있습니다.

2. 데이터베이스 업데이트 후 Redis 업데이트

  • 데이터베이스 업데이트가 성공적으로 완료된 후 Redis 캐시를 업데이트 합니다.
  • 만약 데이터베이스 업데이트에 문제가 발생한다면, Redis 업데이트는 수행되지 않아 불일치 문제를 방지할 수 있습니다.

데이터베이스와 캐시 메모리 간의 정합성 및 동기화는 애플리케이션의 성능과 안정성에 큰 영향을 미치므로, 캐싱 전략을 구현할 때 중요하게 고려해야합니다.

profile
꾸준히, 열심히, 그리고 잘하자

0개의 댓글