Post

실시간 메시지 저장 및 WebSocket 최적화 (Redis 활용)

Django와 WebSocket을 사용하여 실시간 메시지를 저장하고, Redis를 활용하여 성능을 최적화하며, JWT 인증을 통해 보안을 강화하는 방법을 다룹니다.

실시간 메시지 저장 및 WebSocket 최적화 (Redis 활용)

1. WebSocket 메시지를 데이터베이스에 저장하기

이제 Django에서 WebSocket을 통해 받은 메시지를 데이터베이스에 저장하여 채팅 기록을 유지할 수 있도록 만듭니다.

1.1. Message 모델 생성

chat/models.py에서 메시지를 저장할 모델을 정의합니다.

1
2
3
4
5
6
7
8
9
10
11
# chat/models.py
from django.db import models
from django.contrib.auth.models import User

class Message(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField()
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.user.username}: {self.content}"

모델 필드 설명

  • user: 메시지를 보낸 사용자
  • content: 메시지 내용
  • timestamp: 메시지가 전송된 시간

1.2. 마이그레이션 적용

1
2
python manage.py makemigrations chat
python manage.py migrate

이제 메시지를 저장할 데이터베이스 테이블이 생성되었습니다.

2. WebSocket 메시지를 DB에 저장하기

2.1. ChatConsumer 수정

이제 메시지를 받으면 데이터베이스에 저장하도록 consumers.py를 수정합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# chat/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from django.contrib.auth.models import User
from .models import Message

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.user = self.scope["user"]
        await self.accept()

    async def disconnect(self, close_code):
        pass

    async def receive(self, text_data):
        data = json.loads(text_data)
        message = data['message']

        if self.user.is_authenticated:
            new_message = Message.objects.create(user=self.user, content=message)
            await self.send(text_data=json.dumps({
                'user': self.user.username,
                'message': message,
                'timestamp': str(new_message.timestamp)
            }))

이제 메시지가 데이터베이스에 저장되며, 저장된 메시지와 함께 클라이언트에 응답이 전달됩니다.

3. Redis를 활용한 WebSocket 성능 최적화

3.1. Redis를 WebSocket 메시지 브로커로 사용

Django Channels는 기본적으로 InMemoryChannelLayer를 사용하지만, 실제 서비스에서는 Redis를 메시지 브로커로 사용해야 합니다.

settings.py에서 Redis 설정을 추가합니다.

1
2
3
4
5
6
7
8
9
# settings.py
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": ["redis://localhost:6379"],
        },
    },
}

3.2. Redis 실행

Redis가 실행 중인지 확인하고, 실행되지 않았다면 아래 명령어로 실행합니다.

1
redis-server

이제 Django Channels는 Redis를 사용하여 WebSocket 메시지를 더 빠르고 안정적으로 처리할 수 있습니다.

4. JWT 인증을 통한 WebSocket 보안 강화

4.1. WebSocket에서 JWT 토큰 검증하기

웹소켓은 기본적으로 Django의 session을 사용하지 않기 때문에 JWT 토큰을 검증하는 방식을 적용해야 합니다.

consumers.py에서 WebSocket이 연결될 때 JWT 토큰을 검증하는 로직을 추가합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# chat/consumers.py
from channels.db import database_sync_to_async
from rest_framework_simplejwt.tokens import AccessToken

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        token = self.scope["query_string"].decode().split("=")[1]
        user = await self.get_user_from_token(token)
        if user:
            self.user = user
            await self.accept()
        else:
            await self.close()

    @database_sync_to_async
    def get_user_from_token(self, token):
        try:
            access_token = AccessToken(token)
            return User.objects.get(id=access_token["user_id"])
        except Exception:
            return None

이제 WebSocket 연결 시, JWT 토큰을 검증하여 인증된 사용자만 접속할 수 있도록 보안이 강화됩니다.

5. 테스트 및 실행

5.1. Django 서버 실행

1
python manage.py runserver

5.2. Redis 실행 (이미 실행되지 않았다면)

1
redis-server

5.3. React에서 WebSocket 연결 시 JWT 포함하기

React 클라이언트에서 WebSocket 연결할 때 JWT 토큰을 포함해야 합니다.

1
2
const token = localStorage.getItem("access_token");
const socket = new WebSocket(`ws://localhost:8000/ws/chat/?token=${token}`);

6. 다음 단계

이제 Django에서 WebSocket 메시지를 데이터베이스에 저장하고, Redis를 활용하여 성능을 최적화하며, JWT 인증을 통해 보안을 강화하였습니다.

프로젝트를 실서비스로 배포하는 방법은 다음과 같습니다다:

  • Gunicorn + Daphne + Redis를 사용한 WebSocket 배포
  • Nginx 리버스 프록시 설정 및 HTTPS 적용
  • Docker를 활용한 WebSocket 서비스 배포

정리 Django에서 WebSocket 메시지를 데이터베이스에 저장 완료
Redis를 활용한 WebSocket 성능 최적화 완료
JWT 인증을 통한 WebSocket 보안 강화 완료

This post is licensed under CC BY 4.0 by the author.