플러팅 AI/Flask Server

다중 워커 간 메모리 공유 문제 이해

Solo.dev 2024. 11. 30. 23:48

문제 1: 다중 워커 간 connected_clients 상태 불일치

  • 현상: WebSocket 클라이언트가 연결된 상태인데도 특정 워커에서 connected_clients에 해당 클라이언트 ID (request.sid)가 없다고 판단합니다.
  • 원인:
    • Gunicorn의 다중 워커 환경에서는 각 워커가 별도의 프로세스로 실행됩니다.
    • connected_clients는 워커별로 독립적인 메모리에 저장되기 때문에, 한 워커에서 업데이트된 상태가 다른 워커에 반영되지 않습니다.
    • 클라이언트 연결(connect)은 워커 A에서 처리되었지만, 이후 이벤트 전송 요청(upload)은 워커 B에서 처리되는 경우가 발생할 수 있습니다.

문제 2: 작업이 다른 워커에서 처리되는 경우

  • 현상: 동일한 클라이언트와 관련된 작업(예: upload와 WebSocket 이벤트 전송)이 서로 다른 워커에서 처리됩니다.
  • 원인:
    • 다중 워커 환경에서는 요청이 라운드 로빈 방식으로 워커에 분배됩니다.
    • 특정 클라이언트에 대한 연결 관리 및 작업 처리가 동일한 워커에서 이루어지지 않을 수 있습니다.
    • 각 워커가 독립적으로 client_queues와 connected_clients를 관리하기 때문에 상태가 동기화되지 않을 가능성이 큽니다.

문제 3 상태 관리 방식 변경의 부작용 가능성

    • 현상: connected_clients를 upload 요청 시 업데이트하도록 변경했으나, 이 방식이 모든 시나리오에서 안정적으로 작동할지는 확신하기 어렵습니다.
    • 원인:
      • 클라이언트 연결 상태를 connect 이벤트 대신 upload 엔드포인트에서 처리하면, 업로드 요청을 보내지 않는 클라이언트에 대한 상태가 누락될 수 있습니다.
      • WebSocket 연결 자체의 상태를 반영하지 않고, upload 요청이 트리거될 때만 상태를 갱신하게 됩니다

문제 3  : WebSocket 연결 상태의 워커 간 불일치

  • 클라이언트가 WebSocket 연결을 설정하면, 해당 sid는 특정 워커(A)의 메모리에서만 관리됩니다.
  • 다른 워커(B)는 클라이언트가 연결된 상태인지 알 수 없고, sid를 전달받아도 WebSocket 통신이 불가능합니다.
  • 결과적으로, 워커 A에서 WebSocket 연결을 설정했는데 워커 B에서 데이터를 전송하려 하면 통신이 실패합니다.

문제 4 :HTTP 요청(upload)이 다른 워커에서 처리되는 문제

  • 클라이언트가 WebSocket 연결을 설정한 후 HTTP 요청(upload)을 보냅니다.
  • WebSocket 연결을 처리한 워커(A)와 HTTP 요청을 처리하는 워커(B)가 다를 수 있습니다.
  • HTTP 요청을 처리하는 워커(B)가 WebSocket 연결 상태(connected_clients)를 확인하면, 해당 워커의 메모리에서 sid가 없으므로 클라이언트가 연결되지 않은 것으로 판단할 수 있습니다.

문제 5 SID를 다른 워커에 전달해도 통신 불가

  • HTTP 요청 처리 중 워커 B에서 WebSocket 연결을 나타내는 sid를 알고 있다고 해도:
    • 실제 WebSocket 연결은 워커 A에서 유지되고 있습니다.
    • 워커 B는 WebSocket 연결이 없으므로 데이터를 클라이언트로 전송할 수 없습니다.