본문 바로가기
카테고리 없음

Celery를 활용한 채팅 서버 자원 최적화[WhoAU]

by Byeong 2024. 11. 17.

문제

 

 채팅 서비스를 개발하는 과정에서, 서버가 종료된 후에도 Redis에 기존 WebSocket 연결 정보가 남아 있는 문제가 발생했습니다. 개발 환경에서는 비활성화된 채팅방 데이터를 수동으로 삭제할 수 있었지만, 배포 환경에서는 다음과 같은 문제가 예상됐다. 

  1. disconnect 함수 미작동 시: 의도치 않게 채팅방 데이터가 남아 있을 가능성.
  2. 사용하지 않는 데이터 방치: 서버 자원을 지속적으로 점유하며, 비활성화된 채팅방 데이터로 인해 성능 저하 발생.

비활성화된 채팅방 관리 문제로 인해 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를 활용한 비동기 작업 스케줄링으로 채팅방 상태를 지속적으로 점검

 

  1. 비활성화 채팅방 확인 및 삭제: Celery 작업이 10분 이상 대화가 없는 채팅방을 Redis에서 삭제.
  2. 자동화된 주기적 실행: 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 메모리를 효율적으로 관리해 불필요한 자원 낭비를 줄이고, 시스템 자원의 활용도를 높였다.