문제
채팅 서비스를 개발하는 과정에서, 서버가 종료된 후에도 Redis에 기존 WebSocket 연결 정보가 남아 있는 문제가 발생했습니다. 개발 환경에서는 비활성화된 채팅방 데이터를 수동으로 삭제할 수 있었지만, 배포 환경에서는 다음과 같은 문제가 예상됐다.
- disconnect 함수 미작동 시: 의도치 않게 채팅방 데이터가 남아 있을 가능성.
- 사용하지 않는 데이터 방치: 서버 자원을 지속적으로 점유하며, 비활성화된 채팅방 데이터로 인해 성능 저하 발생.
비활성화된 채팅방 관리 문제로 인해 Redis 서버의 저장 공간을 낭비하고, 전체 서버 성능이 저하될 수 있다는 판단 했다.
해결 방법 1 cache 사용하기
채팅방 관리를 위해 Redis의 Cache 기능을 사용하여 각 채팅방의 상태(마지막 활동 시간)를 저장하고 주기적으로 갱신하도록 설계했다.
- 채팅방 생성 시: Cache에 생성 시간 저장
- 메시지 전송 시: Cache의 마지막 활동 시간 갱신
- 비활성화 채팅방 판단 기준: 10분 이상 대화가 없는 경우
- 비활성화 채팅방 처리: 기준을 초과한 채팅방은 삭제
구현 코드
cache를 활용한 생성 시간 저장
# consumers.py
#redls에 상태 값을 저장해서 관리
group_status = cache.get('group_status', default=json.dumps({}))
group_status = json.loads(group_status)
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
...
# 채팅방 생성 시간 기록
group_status[self.group_name] = int(time.time())
cache.set(key='group_status',value=json.dumps(group_status))
Cache 활용의 한계점
Cache 방식으로 관리했지만 아래와 같은 문제가 발생했다..
- 이벤트 기반 동작: 사용자의 메시지나 특정 이벤트가 발생하지 않으면 데이터가 갱신되지 않음.
- 자동화 부족: 비활성화된 채팅방을 자동으로 삭제하지 못함.
이러한 한계로 인해 주기적으로 채팅방 상태를 점검하고 처리할 수 있는 비동기 작업 스케줄러(Celery)가 필요하다고 판단했다.
해결 방법 2 Celery적용 - Celery란?
Celery를 활용한 비동기 작업 스케줄링으로 채팅방 상태를 지속적으로 점검
- 비활성화 채팅방 확인 및 삭제: Celery 작업이 10분 이상 대화가 없는 채팅방을 Redis에서 삭제.
- 자동화된 주기적 실행: Celery Beat를 사용해 5분마다 작업 실행.
구현 코드
주기적으로 실행될 코드
group의 시간을 확인하고 10분간 비활성화 상태라면 삭제한다.
#tasks.py
...
@app.task()
def task_group_delete():
#redis에 있는 group_status값 가져오기
group_status = cache.get("group_status")
keys_to_delete = []
# group_status가 빈값이 아닌 경우에만 실행
if group_status:
group_status = json.loads(group_status)
for key, value in group_status.items():
#10분간 비활성화 상태이면 group에서 삭제
if int(time.time()) - value > 600:
rd.delete(f"asgi:group:{key}")
keys_to_delete.append(key)
#group_status 안에 있는 값 삭제
for key in keys_to_delete:
del group_status[key]
#redis에 group_status 업데이트
cache.set(key="group_status",value=json.dumps(group_status))
return "tesk_group_delet"
주기적 실행 설정
Celery Beat를 활용해 task_group_delete 작업이 자동 실행되도록 설정한다.
#celery.py
...
#주기적으로 동작하게 작성
app.conf.beat_schedule = {
"no-activate-delete": {
"task": "chat.tasks.task_group_delete",
"schedule": crontab(minute='*/5')
}
}
결과
Redis 메모리 사용량 감소
비활성화된 채팅방 데이터를 삭제하여 Redis 메모리 자원 확보.
Celery를 활용한 주기적 스케줄링으로 Redis 메모리를 효율적으로 관리해 불필요한 자원 낭비를 줄이고, 시스템 자원의 활용도를 높였다.