django Cacheops vs Cachalot

런던행·2021년 5월 21일
0

Django 업그레이드

목록 보기
17/17

Cacheops나 Cachalot는 장고의 ORM 캐싱을 쉽게 도와주는 패키지이다.

두 패키지가 어떻게 ORM을 캐싱하는지 실습으로 간단하게 사용해보자. 테스트로 사용할 모델은 아래와 같다

class LogMessage(models.Model):
    channel_name = models.CharField(max_length=255)
    channel_group = models.CharField(max_length=255)
    message = models.TextField()
    created_at 

Cachalot

However, it’s not suited for projects where there is a high number of modifications per second on each table, like a social network with more than a 50 messages per second. Django-cachalot may still give a small speedup in such cases, but it may also slow things a bit (in the worst case scenario, a 20% slowdown, according to the benchmark). If you have a website like that, optimising your SQL database and queries is the number one thing you have to do.

여기서 유의해야할 점은 테이블에 변경사항이 많은 프로젝트에서는 Cachalot이 좋지 않다는 것이다. 그 이유는 실습을 통해서 확인하려고 한다.

설치법은 아래 메뉴얼로 확인

https://django-cachalot.readthedocs.io/en/latest/introduction.html

장고 쉘로 실습

python3 ./manage.py shell_plus --print-sql

In [1]: log3 = LogMessage.objects.get(id=3)
SELECT @@SQL_AUTO_IS_NULL

Execution time: 0.001003s [Database: default]
   SET
SESSION
TRANSACTION
ISOLATION LEVEL READ COMMITTED

Execution time: 0.001113s [Database: default]
SELECT `chat_logmessage`.`id`,
       `chat_logmessage`.`channel_name`,
       `chat_logmessage`.`channel_group`,
       `chat_logmessage`.`message`,
       `chat_logmessage`.`created_at`
  FROM `chat_logmessage`
 WHERE `chat_logmessage`.`id` = 3
 LIMIT 21

Execution time: 0.000719s [Database: default]

In [2]: log3 = LogMessage.objects.get(id=3)
In [3]: 

log3 = LogMessage.objects.get(id=3)

첫 번째로 모델을 get(id=3) 가져올 때 쿼리문이 실행 되었고. 그 다음 다시 get(id=3) 할때는 쿼리문이 실행되지 않았다.

모델을 추가 한 다음 다시 get(id=3) 가져오면 쿼리문이 실행된다.

In [3]: LogMessage.objects.create(channel_name='aaa', channel_group='bb', message='dd')
SELECT VERSION()

Execution time: 0.000732s [Database: default]
INSERT INTO `chat_logmessage` (`channel_name`, `channel_group`, `message`, `created_at`)
VALUES ('aaa', 'bb', 'dd', '2021-05-23 05:24:22.198760')

Execution time: 0.005244s [Database: default]
Out[3]: <LogMessage: LogMessage object (5)>

In [4]: log3 = LogMessage.objects.get(id=3)
SELECT `chat_logmessage`.`id`,
       `chat_logmessage`.`channel_name`,
       `chat_logmessage`.`channel_group`,
       `chat_logmessage`.`message`,
       `chat_logmessage`.`created_at`
  FROM `chat_logmessage`
 WHERE `chat_logmessage`.`id` = 3
 LIMIT 21

Execution time: 0.009044s [Database: default]

테이블에 row가 하나 추가가 되었는데 get(id=3)는 다시 쿼리로 질의를 하게 된다. 생각해 보면 id=3인 row가 변경 된 일이 없는데 다시 호출하게 이유는 cachalot는 테이블 단위로 invalidation을 하기 때문이다. 테이블에 어떠한 row가 변경이 되면 그 테이블에 관련된 모든 orm이 invalidation 되기 때문에 테이블에 변경사항이 많은 프로젝트는 적합하지 않다. 대안으로는 row 단위로 ivalidation 하는 cacheops가 있다.

Cacheops

설치법은 아래 메뉴얼로 확인

https://github.com/Suor/django-cacheops

In [1]: log3 = LogMessage.objects.get(id=3)
SELECT @@SQL_AUTO_IS_NULL

Execution time: 0.000543s [Database: default]
   SET
SESSION
TRANSACTION
ISOLATION LEVEL READ COMMITTED

Execution time: 0.000954s [Database: default]
SELECT `chat_logmessage`.`id`,
       `chat_logmessage`.`channel_name`,
       `chat_logmessage`.`channel_group`,
       `chat_logmessage`.`message`,
       `chat_logmessage`.`created_at`
  FROM `chat_logmessage`
 WHERE `chat_logmessage`.`id` = 3
 LIMIT 21

Execution time: 0.001151s [Database: default]

In [2]: log3 = LogMessage.objects.get(id=3)

In [3]: LogMessage.objects.create(channel_name='aaa', channel_group='bb', message='dd')
SELECT VERSION()

Execution time: 0.000969s [Database: default]
INSERT INTO `chat_logmessage` (`channel_name`, `channel_group`, `message`, `created_at`)
VALUES ('aaa', 'bb', 'dd', '2021-05-23 05:41:02.460593')

Execution time: 0.002365s [Database: default]
Out[3]: <LogMessage: LogMessage object (6)>

In [4]: log3 = LogMessage.objects.get(id=3)

In [5]: 

Cacheops는 row 단위로 invalidation을 하기에 테이블에 row가 추가되도 cachalot처럼 디비에 다시 호출하지 않는다.

반면에 Cacheops 유의해야 할 점은 개발자가 Cacheops 내부 원리를 잘 알고 코딩해야한다 ㅡㅡ;

  • 쿼리셋 update() 사용하는 경우 캐시 무효화가 안 된다. 이때는 invalidation_update()함수로 일일이 변경해줘야 한다.
  • prefetch_related() 만 사용해야 한다. select_related() 는 캐시 무효화가 안 된다.
profile
unit test, tdd, bdd, laravel, django, android native, vuejs, react, embedded linux, typescript

0개의 댓글