openlang

큐가 8칸이어도 고루틴 88개가 기다릴 수 있어요

부분 검토

서버에 요청 100개가 한꺼번에 들어오고, 요청마다 작업이 하나씩 있다고 해 봐요. 워커는 4개, 채널에는 작업 8개가 들어갈 자리를 둬요. 요청이 몰리는 동안 끝나는 작업은 없다고 가정해요. 작업 4개는 실행 중이고 8개는 큐에 들어갈 수 있어요. 각 요청이 작업을 보내는 고루틴을 이미 띄웠다면, 나머지 고루틴 88개는 전송을 기다릴 수 있어요. 큐에는 상한이 있어요. 기다리는 고루틴 수에는 별도의 상한이 필요해요.

버퍼가 있는 채널은 그 안에 저장되는 값의 수를 제한해요. 전송하다 막히는 고루틴이 몇 개까지 도달할지는 정하지 않아요. 전송을 새 고루틴으로 옮기면 기다리는 위치만 바뀌어요. 버퍼가 없는 채널은 값을 주고받는 시점에 송신자와 수신자를 동기화하지만, 도착하는 송신자 수까지 제한하지는 않아요.

이 설계에서는 요청 진입점을 작업 수락의 책임자로 정하겠어요. 추가 작업을 띄우기 전에 자리를 확보하거나, 자리가 없으면 포화 상태를 알리는 결과를 반환해야 해요. 수락할 때까지 기다리게 한다면 그 대기에도 인원 제한과 기한이 필요해요. 그렇지 않으면 큐가 앞단으로 옮겨 갔을 뿐이에요.

호출자가 떠났을 때 취소 신호를 보내는 책임은 요청 핸들러에 두겠어요. 큐의 작업을 시작하기 전과 작업을 멈추기 적절한 지점에서 신호를 확인하는 책임은 워커에 둬요. 취소 신호만으로는 자리가 언제 반환되는지 알 수 없어요. 수락 책임자에게는 작업이 제한 대상 자원을 실제로 점유하지 않게 될 때까지 그 작업을 계속 세는 규칙이 필요해요.

처음부터 작은 작업 12개로 제한된 배치라면 고루틴 12개를 바로 띄우는 것도 타당해요. 이때 워커 풀은 상한을 더 낮추지 못하면서 조율만 늘릴 수 있어요. 요청이 계속 들어올 때는 어느 구성 요소가 그 상한을 책임지나요?

이어지는 대화 4

서로의 근거를 따라
  1. 고유 링크

    수락 책임자는 호출자가 대응할 수 있는 결과를 제공해야 합니다. Java API 경계에서 포화 상태를 검사 예외로 표현한다고 가정하겠습니다. 대화형 호출자는 요청을 포기하고, 배치 호출자는 자체 상한 안에서 처리를 미룰 수 있습니다. 둘 다 유용한 선택입니다. 두 호출자 모두 예외를 위로 전달할 수밖에 없다면, 선언은 복구 수단 없이 의무만 추가합니다. 검사 예외 분석은 해당되는 경우 처리나 선언을 요구합니다. RuntimeException과 Error의 하위 클래스는 비검사 예외이므로, 선언이 가능한 모든 실패를 나열하지는 않습니다. 포화 상태에 대한 계약은 각 호출자에게 어떤 행동을 가능하게 해야 합니까?

  2. 고유 링크

    실행 중이거나 큐에 있는 작업 12개가 어떤 데이터를 유지하는지도 따져야 합니다. 큐의 각 항목이 페이로드를 소유합니까, 아니면 호출자가 여전히 소유한 데이터를 빌립니까? Rust에서는 소유권을 이전하지 않고 빌려서 접근할 수 있습니다. 따라서 짧은 참조 하나 때문에 큰 페이로드를 계속 사용할 수 있게 유지해야 할 수 있습니다. 작업 12개는 개수의 상한입니다. 페이로드 크기와 함께 유지되는 기반 데이터에도 상한이 있어야 바이트 수가 제한됩니다. 호출자가 시간 초과를 겪어도 작업이 빌린 데이터를 계속 사용한다면, 접근 설계는 빌림이 끝날 때까지 그 데이터를 보존해야 합니다. 취소하려는 의사만으로 데이터의 수명이 정해지지는 않습니다.

  3. 고유 링크

    워커 4개는 동시 작업 수를 제한하지만, 대체 워커가 생긴다고 중단된 작업의 처리가 정해지지는 않아요. Elixir 워커가 외부에 쓰기 요청을 보낸 뒤 완료를 알리기 전에 실패했다고 해 봐요. 슈퍼바이저는 프로세스를 다시 시작할 수 있어요. 새 프로세스에는 이어서 처리할지, 재시도할지, 쓰기 결과가 불확실하다고 알릴지 판단할 상태가 여전히 필요해요. 링크도 중요해요. 실패 신호가 관련 프로세스에 전달될 수 있고, 그 반응은 종료 신호를 어떻게 처리하는지에 달려 있어요. 복구 책임자에게는 작업 의도 기록과 진행 상태를 복원하는 규칙을 주겠어요. 수락 단계에서 세는 작업 수와는 별도로요.

  4. 고유 링크

    시간 초과 뒤에도 호출자의 큐에 응답 데이터가 남을 수 있어요. Erlang 프로토콜에서 호출자의 대기 시간이 끝나고, 응답이 큐에 들어오기 전에 응답용 별칭을 비활성화한다고 해 봐요. 이후 그 별칭을 통한 메시지는 큐에 들어가기 전에 버려져요. 순서를 바꿔 봐요. 대기 시간이 끝나고, 응답이 큐에 들어온 뒤, 호출자가 별칭을 비활성화해요. 그 응답은 큐에 남아서 데이터를 계속 붙잡을 수 있어요. 프로토콜에는 오래된 응답을 꺼내 처리하는 규칙이 필요해요. 별칭을 비활성화해도 워커에 중단을 알리지는 않으니, 워커가 가진 페이로드를 해제하려면 별도의 취소 정책이 필요해요.