콘텐츠로 이동

Application job queue와 backpressure

Execution 주제 목차 · 스펙 목차 · 이전: 03. 취소와 종료 · 다음: 05. Payload 소유권과 codec

이 문서는 Core byte HWM budget과 Framework Application job queue라는 서로 독립된 두 capacity authority가 ordinary ingress를 어떤 순서로 통과시키는지, 그 결과로 나타나는 pressure 상태를 Framework가 언제 어떻게 관측·전파하는지를 정의한다. Application·Core· Framework host·provider의 책임 경계를 caller가 의존하는 계약으로 서술하고, 그 계약을 여러 언어 runtime이 공통으로 만족해야 하는 구현 구조로 함께 담는다.

1. 두 독립된 capacity authority

Core와 Framework는 서로 다른 과부하를 관찰한다.

  • Core는 transport queue가 현재 보유한 physical-frame byte를 알고 connection·payload 크기로 인한 queue memory burst를 제한한다.
  • Framework는 handler가 시작되기 전에 대기하는 application job 수를 알고 application 처리 속도보다 빠른 유입을 제한한다.

  • Core byte HWM과 Application job queue는 설정, profile, 단위, 계상 경계와 관측값을 공유하지 않는다. 한 authority의 값을 다른 authority의 counter로 복사하면 책임이 겹친다 — Core가 handler 처리 능력을 추측하거나 Framework가 socket queue byte를 계산해서는 안 된다.

  • Core byte HWM은 전송 경로의 마지막 안전장치이고, Application job queue는 handler 유입 속도의 안전장치다 — 둘 다 필요하지만 같은 보호는 아니다. Framework pressure가 미리 remote traffic을 줄이더라도 이미 remote Core queue, OS buffer, network와 local Core queue에 들어간 data가 있다. 반대로 Core queue가 비어 있어도 handler job이 오래 대기할 수 있다.
Authority 제한하는 것 계상 또는 획득 시점 반환 시점
Core byte HWM Core application-direction queue가 현재 보유한 physical-frame charge Core queue가 frame을 소유할 때 Receive dequeue 등으로 Core queue가 frame 소유권을 내놓을 때
Application job queue Host가 callback 시작 전에 수용한 application job permit 수 Ordinary ingress를 receive·claim하기 직전에 예약하고 handler turn으로 전환할 때 Callback의 실제 첫 instruction 직전 또는 callback 전 terminal에서
  • Core byte HWM charge는 계약이 정한 payload와 metadata byte를 포함하고, Core queue가 record를 binding에 넘기면 그 record의 charge는 끝난다. Framework는 retained-credit lease를 요청하거나 Core byte charge를 handler·reply lifetime까지 연장하지 않는다.
  • Receive 뒤 payload storage는 Payload 소유권과 codec의 일반 message ownership 규칙을 따른다. Storage를 복사·이동·해제하는 것은 payload lifetime 관리이며 Core byte HWM credit, 두 번째 Application job queue permit이나 별도 byte-pressure authority가 아니다.

Framework pressure count(permits in use)는 다음 값이다.

application job permits in use
  = reserved supply permits
  + queued application jobs

Capacity waiter는 아직 permit을 받지 않았으므로 포함하지 않는다. Reservation이 queued job으로 바뀌어도 합계는 변하지 않고 permit을 반환할 때만 감소한다. 한 record가 1:N callback을 만들면 실제 callback turn마다 permit 하나를 사용한다.

2. 설정과 profile 경계

Core와 Framework profile은 같은 label을 사용할 수 있지만 서로 다른 public type과 계산이다.

설정군 소유자 기본 profile Manual override
CoreHwmMemoryLimitBytes, CoreHwmBudgetBytes, CoreHwmProfile Core Balanced Core memory 또는 budget byte
ApplicationJobQueueProfile, MaxQueuedApplicationJobs Framework host Balanced Host의 정확한 job permit 상한
  • Framework는 startup에서 Core 설정값을 binding context option으로 전달할 뿐, profile 비율을 계산하거나 budget을 connection 수로 나누지 않는다. Core snapshot을 Framework status에 투영하는 것도 읽기 전용 관측이며 Framework pressure 계산의 입력이 아니다.
  • Framework job pressure가 Core에 주는 feedback은 지원 socket에 적용하는 RUNNING· PAUSED receive-flow 절대 상태 하나뿐이다. Framework는 Core HWM 설정이나 queued-byte counter를 상태 전이에 맞춰 변경하지 않는다.
  • 상한은 host 하나에 하나다. Host 안에 MeshNode가 몇 개든, ClientServer channel이 몇 개든, socket과 연결이 몇 개든 MaxQueuedApplicationJobs 하나를 함께 사용한다.
  • 구성 요소마다 나누어 갖지 않는다.
  • 구성 요소 수만큼 곱하지 않는다.
  • 한 host 안에서 permit을 세는 자리는 하나뿐이다.

Pressure 상태도 host가 한 번 계산해 지원 socket 전부에 같은 값을 건다(§6).

3. Ordinary ingress permit 순서

Ordinary ingress — Core나 binding에서 아직 permit을 받지 못한 record를 receive·claim하는 모든 경로 — 는 어떤 문맥에서 도착했든 같은 규칙을 따른다.

같은 host 안에서 만든 job도 마찬가지다. 같은 host의 Spot이나 Actor에게 보내는 send, publish의 local target처럼 network를 거치지 않고 곧바로 실행 대기열에 들어가는 job도 넣기 전에 같은 host permit을 얻는다. 그러지 않으면 그 job이 대기열에서 기다려도 사용하는 permit이 늘지 않아 §6의 PAUSED가 나가지 않고, 한 host가 자기 자신을 밀어붙일 수 있다.

세는 것과 거는 것은 층이 다르다. permit은 이 host가 받아서 handler를 기다리는 job을 출처와 무관하게 모두 센다. PAUSED는 그중 멈추라고 알릴 상대가 있는 socket에만 건다(§6). 둘을 같은 범위로 맞추려 하면, 셀 수 없는 job이 생기거나 걸 수 없는 socket에 걸게 된다.

Messaging 유입이 이 경로의 본체다. 두 곳에서 들어온다.

어디서 받나 무엇을 받나
RouteMesh MeshNode의 ROUTER-ROUTER socket 다른 node가 보낸 request와 send, 그리고 Logical Multicast
ClientServer Channel의 Server ROUTER Client DEALER가 보낸 request와 send

Logical Multicast도 여기로 들어온다. 보내는 쪽이 remote node마다 한 번씩 보내고, 받은 node가 자기 local Spot을 정한다. 한 record가 이 node의 Spot N개로 가면 permit도 N개를 사용한다.

ClientServer에서 Server ROUTER는 Client DEALER에게 먼저 보내지 않는다. 그래서 Client DEALER가 받는 것은 자기가 보낸 호출의 답뿐이다. 답은 이 절 뒤에서 정하는 대로 permit을 거치지 않으므로, 이 방향에는 permit을 사용하는 유입이 없다.

그 밖에 STREAM application packet, cross-node Session application record(STREAM 서버 session, Session과 Actor binding 참고), handshake·bind· unbind와 그 밖의 모든 일반 application job 유입도 예외 없이 이 순서를 따른다.

Ordinary ingress는 다음 순서를 지킨다.

  1. 가장 오래 기다린 live source 순서로 host-shared permit을 기다린다.
  2. Permit을 얻은 뒤에만 Core·binding에서 record를 receive·claim한다.
  3. Application record는 permit을 owner mailbox나 serial queue의 handler turn으로 이전한다.
  4. Control 또는 malformed ordinary record는 유한한 내부 처리를 마친 뒤 permit을 반환한다.
  5. 각 job은 자신을 실행하는 callback handler가 시작되기 직전에 queue에서 빠지고 permit을 반환한다. 그 handler가 Node handler인지 Spot·Actor handler인지는 job마다 다르지만 반환 시점은 하나다 — 자기 handler의 첫 instruction 직전이다. 유입 종류에 따라 다른 시점을 두지 않는다.
%%{init: {'sequence': {'actorFontSize': '18px', 'messageFontSize': '18px', 'noteFontSize': '18px', 'boxMargin': 8, 'width': 140}, 'themeVariables': {'fontSize': '18px'}}}%%
sequenceDiagram
    participant S as 소켓·연결
    participant P as Host-shared permit
    participant Q as Owner queue
    participant H as Handler callback

    S->>P: 가장 오래 기다린 source 순서로 permit 요청
    alt permit 확보
        P-->>S: permit 승인
        S->>S: record receive·claim
        alt pre-receive에 terminal reply·error completion으로 식별됨
            S->>H: permit 우회, 즉시 처리 후 내부 처리 직후 반환
        else application record
            S->>Q: permit을 owner queue의 handler turn으로 이전
            Q->>H: handler turn 배정
            H-->>P: 실제 첫 instruction 직전에 permit 반환
        else control·malformed record
            S-->>P: 유한한 내부 처리 뒤 permit 반환
        end
    else 대기 중 cancel·close·shutdown
        P-->>S: cancellable wait 종료(reject·drop 아님)
    end

Handler가 시작한 뒤의 await, coroutine suspension, continuation과 reply 대기는 같은 permit을 다시 얻지 않는다. Relocation처럼 아직 실행 가능하지 않은 durable backlog는 해당 relocation spec이 정한 유한한 payload owner로 handoff한 뒤 initial reservation을 반환하고, runnable callback turn마다 새 permit을 얻는다.

Pre-receive에 terminal reply 또는 error completion으로 식별되는 supply만 이 permit을 우회한다. Ordinary connection에서 receive한 뒤 completion으로 분류해 우회를 소급 적용하지 않는다. 이 분리는 ordinary queue가 포화돼도 이미 시작한 operation의 terminal completion이 진행되게 한다.

ClientServer의 Client DEALER reply는 Framework permit을 얻기 전에 Core의 single Application connection FIFO와 byte HWM·PAUSED를 통과한다. 따라서 Core가 reply를 completion으로 식별한 뒤에는 permit을 우회하지만, 이 우회가 앞선 DATA를 건너뛰거나 Core transport progress를 보장하지는 않는다. RouteMesh ROUTER-ROUTER reply는 별도 Completion connection으로 이 permit 경계에 도달한다.

Source마다 outstanding permit waiter는 하나이며 가장 오래 기다린 source 순서로 handoff한다. Batch를 처리한 source는 대기열 tail로 이동한다.

Batch나 1:N callback도 확보한 permit 수보다 많은 application job을 게시하지 않는다.

Framework heartbeat, topology, relocation과 service-wire SendReady kind 12는 이 completion supply가 아니다. 이 control record는 application data line에 남아 기존 FIFO와 liveness 계약을 따르며, Core completion 연결이나 별도 Framework control queue로 옮기지 않는다.

다음 방식은 허용하지 않는다.

  • permit 없이 먼저 receive한 뒤 별도 counter만 증가시키기
  • retained-credit lease나 Framework byte-HWM으로 Core HWM을 다시 구현하기
  • 포화를 reject, drop, fixed-delay polling 또는 busy spin으로 바꾸기
  • spec이 소유하지 않는 unbounded 또는 hidden side backlog에 record 보관하기

준비된 owner 집합 (구현)

Record가 permit을 얻어 owner queue로 들어가려면, 그 owner에 지금 처리할 일이 있다는 사실을 실행 자원이 알아야 한다.

  • 지금 처리할 일이 있는 owner를 상태로 유지한다. 이 상태는 "무엇이 바뀌었다"는 1회성 알림이 아니라 "지금 이 상태다"를 나타내며, 같은 owner가 중복해서 들어가지 않는다. 알림이 유실돼도 처리할 일이 남은 owner는 결국 처리돼야 하므로, 깨어난 실행 자원은 언제나 이 상태를 다시 확인한다.

내부 확인 조건 — 알림이 유실되어도 깨어난 실행 자원이 준비된 owner 집합을 다시 확인해 missed wakeup이 없다는 것은 이 상태 관리의 white-box 불변 조건이다.

넣을지 판단하는 것과 넣는 것을 쪼개지 않는다 (구현)

Message를 어느 owner의 queue에 넣을지 정하려면 여러 조건을 본다 — 그 owner가 아직 이 node에 있는지, 자리가 있는지, 이동으로 봉인되지 않았는지.

  • 이 확인들과 실제로 넣는 동작은 같은 구간 안에서 끝난다. 확인과 넣기 사이에 owner가 바뀌면 message가 더 이상 owner가 아닌 node의 대기열에 들어가고, 그 대기열은 아무도 처리하지 않는다 — 보낸 쪽은 timeout까지 기다리게 된다.

한 구간 안에서 다음을 하나의 commit으로 처리한다.

  1. Host relocation §14·§15의 host·unit admission 판정을 확인한다.
  2. 대상 객체가 이 node에 있고 owner 정보가 유효한가
  3. 이동 봉인·생성 대기·session 연결 대기 중이 아닌가
  4. 수락 순서를 나타내는 sequence를 확정하고 owner queue 뒤에 넣는다
  5. 비어 있던 queue가 채워졌으면 준비된 owner 집합에 그 owner를 넣고 실행 자원에 즉시 알린다

  6. 확인에 실패한 message는 대기열에 나타나지 않는다. 일단 넣었다가 빼는 방식으로 만들지 않는다 — 넣었다 빼면 그 사이에 실행될 수 있고, 뺐다는 사실을 관측에서 구분할 수도 없다. 응답을 기다리는 호출은 실패 이유를 결과로 받는다. 대상·owner 검증에 실패한 경우에도 수락 sequence는 이전 값 그대로이며, 실패한 시도가 다음 정상 작업의 순서를 바꾸지 않는다.

언어별 재량 — 이 구간을 잠금으로 만들지 다른 방법으로 만들지는 자유다. 판정 기준은 확인과 넣기만 이 구간 안에 있고, 역직렬화나 handler 조회처럼 구간을 길게 만드는 일은 구간 밖에서 하는가이다 — 그 조건을 만족하는 한, 구간이 짧게 유지되고 owner가 확인·넣기 사이에 바뀌지 않는다는 관찰 결과는 어떤 구현 방식을 쓰든 같다.

내부 확인 조건 — 확인 시점과 넣는 시점 사이에 owner가 바뀐 message가 옛 owner의 대기열에 들어가지 않는다는 것은 위 commit 절차가 하나의 원자적 구간이라는 사실로만 확인되는 white-box 불변 조건이다.

Permit 반환과 대기 중 자원 점유 금지 (구현)

Application permit은 자신의 target callback 실제 첫 instruction에서 반환하고, control· malformed record의 permit은 내부 처리 직후 반환한다. 이 반환 시점은, STREAM 연결 하나를 수락한 때부터 닫을 때까지 유지하는 서버 실행 단위인 STREAM session callback이 시작하는 순간과 같은 지점이다 — 문맥마다 별도 규칙을 두지 않는다. Cancellation, source close와 shutdown은 waiter와 handoff permit을 정확히 한 번 정리한다.

  • Framework 내부 작업은 permit 반환에 필요한 gate·execution authority·resource를 쥔 채 같은 authority의 새 permit acquire를 기다려서는 안 된다. Framework 내부 작업은 same-host relay, fanout, serial owner, relocation 경로와 request의 deadline·terminal 처리다. 이 범위에서 지속되는 wait/capacity cycle은 우회를 정당화하는 근거가 아니라 protocol 또는 runtime bug다. Request의 deadline 처리는 application gate와 permit 획득을 기다리지 않는다.
  • Handler turn §6이 허용하는 request를 application handler가 gate를 유지한 채 기다리는 것은 위 금지의 대상이 아니다. 포화로 target ingress가 지연되는 동안 그 request의 결과는 Submit과 완료 §9의 완료 경쟁을 따른다. Deadline이 먼저 확정되어 request가 끝나는 것은 정상적인 포화 결과다. Gate 수명은 Handler turn §2가 정하며, target admission·handler 종료·포화 해소를 보장하지 않는다.

4. 소켓에서 여러 건 읽기 (구현)

owner를 가져온 뒤 모아서 처리하는 것과 별개로, 소켓에서 꺼내는 단계에도 같은 문제가 있다. 한 번 깨어났을 때 소켓에서 한 건만 읽고 돌아가면, 쌓여 있는 message 수만큼 깨우기와 읽기 호출이 반복돼 부하가 높을수록 비용이 커진다.

  • 한 번 깨어났을 때 한도 안에서 여러 건을 이어서 읽는다. 상대가 계속 보내는 동안 무한정 읽으면 그 연결 하나가 수신 단계를 독점하고, 다른 연결과 binding operation completion 처리가 밀린다.
  • 한도는 건수·byte·경과 시간 셋을 함께 두고 먼저 닿는 것을 적용한다. 건수만 두면 큰 message에서 시간이 길어지고, 시간만 두면 작은 message에서 시계를 너무 자주 읽는다.
  • 다음 회전은 이번에 멈춘 연결의 다음부터 시작한다(cursor 유지). 항상 처음부터 순회하면 앞쪽 연결이 계속 먼저 처리되어, 상한을 두어도 뒤쪽 연결이 밀린다.

이 규칙은 fanout뿐 아니라 RouteMesh, ClientServer, service connection, STREAM을 포함한 모든 multi-connection 수신 경로에 적용한다. 한도에 걸려 남은 것이 있으면 다음에 깨어날 때 이어서 읽는다.

건수 한도는 회전 하나당 최대 64개로 고정한다. Byte 한도와 경과 시간 한도는 언어별 재량이다 — 값이 달라도 회전 시작점이 항상 멈춘 연결의 다음부터 다시 시작하고 어떤 연결도 수신 단계를 무한정 독점하지 않으므로, 다른 연결이 진행할 기회를 얻는다는 관찰 가능한 결과는 같다. 확인 기준은 한 연결에 느린 consumer가 있어도 다른 연결의 진행이 멈추지 않는지다.

RouteMesh에 참여해 message를 보내거나 받는 runtime node인 MeshNode의 SendHighWaterMark· ReceiveHighWaterMark·ReceiveTimeout 같은 방향별 socket option 배선은 이 문서가 다루지 않는다 — channel-transport 주제가 RouteMesh topology와 MeshNode startup이 정한 공개 설정을 소유한다.

5. 수신 처리와 상태 변경 분리 (구현)

  • 수신 콜백은 받은 데이터의 소유권을 runtime 쪽 값으로 옮기고 바로 반환한다. 수신 문맥은 대개 전송 계층이 소유하므로 여기서 오래 머물면 그 연결의 다른 수신이 밀린다.
  • 형식 검사는 handler를 부르기 전에 끝낸다. 형식이 맞지 않는 입력은 handler에 도달하지 않는다 — 응답을 기다리는 호출은 ProtocolError로 끝나고, 기다리지 않는 호출은 기록만 남기고 끝난다.

내부 확인 조건 — 수신 콜백 안에서 handler를 부르거나, 주소와 상태를 가진 논리 instance인 Spot의 상태를 바꾸지 않는다는 것은 수신 경로가 handler 실행 gate를 거치지 않고 상태를 바꾸는 경로를 만들지 않기 위한 white-box 불변 조건이다.

6. Pressure 상태와 socket 제어

Effective maximum을 M, configured pause·resume percent를 P와 R이라 하면, startup에서 다음 경계를 계산한다.

pause permit count  = ceil(M * P / 100)
resume permit count = floor(M * R / 100)

P는 1..100이고 기본값은 80, R은 0..99이고 기본값은 60이다. R < P여야 한다. running에서는 permits in use가 pause count 이상이면 paused로 전이하고, paused에서는 resume count 이하이면 running으로 전이한다. 두 경계 사이에서는 현재 상태를 유지한다.

  • 상태를 거는 대상은 이 host에게 요청이 들어오는 socket뿐이다. PAUSED는 "나에게 그만 보내라"는 말이므로, 보낼 상대가 요청을 보내는 쪽일 때만 뜻이 있다. §3에서 permit을 사용하는 유입이 들어오는 socket과 같은 집합이다.
socket 이 host에게 요청이 오나 PAUSED를 거나
RouteMesh ROUTER-ROUTER 다른 node가 보낸다 건다
ClientServer Server ROUTER Client가 보낸다 건다
ClientServer Client DEALER 오지 않는다. 자기가 보낸 호출의 답만 온다 걸지 않는다
PUB/SUB, Classic fanout, STREAM — 걸지 않는다. 이 전송 방식은 Core byte HWM이 그대로 제어한다

Client DEALER에 걸지 않는 이유는 둘이다. 거기서 막히는 것은 상대의 요청이 아니라 자기가 기다리는 답이고, Server는 애초에 Client에게 요청을 보내지 않으므로 멈추라고 알릴 내용이 없다. - PAUSED는 Core HWM 값을 바꾸지 않는다. Core는 remote-pause blocker와 local byte-HWM blocker를 독립적으로 합성한다. RUNNING은 remote-pause 원인만 제거하므로 local HWM이 계속 full이면 send는 계속 대기한다. Pressure 상태 자체는 route ready나 transport liveness를 바꾸지 않는다. - Host queue owner는 permit count 변경 같은 synchronization 경계에서 pressure 상태를 계산한다. - 상태가 바뀌면 지원 socket snapshot에 새 절대 상태를 적용한다. - 같은 상태를 반복 적용하지 않고, stale transition이 최신 상태를 덮어쓰지 못하게 한다. - Shutdown은 마지막 상태 적용을 무기한 기다리지 않으며, 관측 counter를 정리해도 현재 상태와 pause duration은 유지한다. - 이 receive-flow state API가 Framework pressure와 Core send flow 사이의 유일한 runtime 제어 지점이다. Framework는 raw flow frame을 만들거나 Core control lane을 범용 Framework channel로 사용하지 않는다. - 경계를 넘어도 record를 버리거나 거부하지 않는다. PAUSED는 상대에게 그만 보내라고 알리는 것일 뿐, 이미 떠난 것을 되돌리지는 못하기 때문이다. 상대 queue와 OS buffer, network, 그리고 이쪽 Core queue에 이미 들어와 있던 것은 경계를 넘은 뒤에도 계속 도착한다.

도착한 것은 §3 순서대로 permit을 기다렸다가 하나도 빠짐없이 handler로 간다.

사용하고 있는 permit이 상한에 닿으면 더 받지 않는다. 받지 않은 것은 이쪽 Core queue에 그대로 쌓인다. 그러면 Core가 byte 상한에 걸리고, 보내는 쪽이 거기서 막힌다(§1).

내부 확인 조건 — 새 socket은 현재 host pressure 상태를 적용한 뒤 receive 대상 registry에 게시하고, close는 먼저 registry에서 socket을 제거한 뒤 진행한다는 순서는 registry 구현의 white-box 불변 조건이다. Binding 호출은 queue, registry와 user callback lock 밖에서 수행한다. Close와 경쟁한 lifecycle 결과 외의 설정 실패는 진단과 metric에 기록한다.

7. Send completion과의 합성

  • Send completion의 HWM 재시도와 재제출 경계는 Submit과 완료 §5가 정의한다.
  • Framework는 제거된 send_ready callback·event, readiness waiter 또는 retry adapter를 두지 않는다. 작업을 끝내야 하는 마지막 시점인 Deadline, cancellation, detach와 shutdown은 기존 operation state machine의 첫 terminal 규칙을 따른다. Framework service-wire의 SendReady kind 12는 Framework service control record이므로 제거된 binding callback과 다른 계약이다.

8. 보낼 때의 대기

Binding operation의 제출 횟수와 HWM 대기 소유는 Submit과 완료 §5가 정의한다.

  • 대기의 종료는 operation 계약이 정한다. Send 대기 종료는 Submit과 완료 §7, Logical Multicast 시작 전 대기는 Submit과 완료 §6과 Cancellation과 shutdown §4, request timeout은 Submit과 완료 §9를 따른다. 밀렸다는 사실 자체는 호출자가 받는 값이 아니다(Backpressured).
  • 자리가 없다는 것은 오류가 아니다. 어느 줄도 자리가 없다는 이유로 호출을 거부하거나 받은 것을 버리지 않는다(오류 모델 §5).
  • 이 규칙은 결과가 아직 정해지지 않은 구간에만 사용한다. 이미 끝난 호출 뒤에 생긴 실패는 호출자에게 돌려줄 결과가 없으므로 관측으로만 남긴다. publish가 시작된 뒤 local target을 건너뛴 경우, 이동 중 one-way를 버린 경우, 끝난 send의 target이 받지 못한 경우가 그렇다.
  • Framework 내부 작업이 송신 공간을 기다리는 동안 실행 권한을 쥐는지는 §3 Permit 반환과 대기 중 자원 점유 금지를 따른다.

StreamNode의 client→server complete-message MaxMessageSize는 이 capacity와 독립된 wire guard다. 6-byte prefix를 제외한 header+payload를 검사하고 기본값은 64 KiB이며 server→client outbound에는 적용하지 않는다.

한도 종류에 따라 terminal 의미를 구분하고 조용히 버리지 않는다.

한도 무엇으로 재는가 포화 의미
Core HWM 방향별 queued/accounted byte Core queue에서 sender까지 backpressure
Application job queue host instance의 reserved·queued·in-use permit cancellable shared-cap wait

어느 경로도 별도 unbounded backlog, polling, busy-spin이나 silent replay를 만들지 않는다.

9. 큰 payload

  • Framework는 job 개수만 센다. 빈 payload와 큰 payload는 각각 job 하나다. Framework의 상한은 process memory의 byte 상한이 아니다.
  • 메모리를 byte로 막는 것은 Core다. Framework가 permit이 없어 receive를 멈추면 byte가 local Core queue에 쌓이고, Core HWM과 TCP 흐름 제어가 보내는 쪽을 막는다. 큰 payload가 몰려도 이 경로가 그대로 동작하므로 Framework가 byte를 따로 세거나 job 상한을 payload 크기에 맞춰 조절할 필요가 없다.
  • 단일 message 크기는 MaxMessageSize로 따로 제한한다. Core profile을 Framework profile에 연결하거나 retained-credit lease를 되살리지 않는다.

10. 검증 요구

공개 표면(send·publish·request 결과 값, Application job queue pressure 상태 조회, socket receive-flow 절대 상태, Runtime metric 이름)만으로 다음을 확인한다. 각 항목은 contract test 하나로 이어진다.

두 capacity authority의 설정

  • Core profile과 Application job queue profile을 서로 다르게 설정할 수 있고, 둘의 기본값은 각각 Balanced다.
  • Reservation, queued job과 callback 첫 instruction의 permit count가 같은 규칙을 따른다.

Permit 획득과 순서

  • Permit이 없으면 다음 ordinary record를 먼저 receive하지 않는다.
  • 확인에 실패한 send·request는 owner queue의 sequence 관측값을 바꾸지 않는다.
  • Shared permit이 모두 예약되면 ordinary ingress가 cancellable wait하고, terminal reply·error completion은 계속 진행한다.
  • ClientServer reply가 Core physical head에 도달해 completion으로 식별된 뒤에는 permit을 얻지 않지만, 앞선 one-way DATA는 ordinary permit을 얻기 전 Core에서 dequeue하지 않는다. Permit 우회가 Core single FIFO·HWM을 건너뛰지 않는다.
  • 한 연결이 계속 보내는 동안에도 다른 연결의 수신이 진행된다.
  • 수신 한도가 건수·byte·경과 시간 셋 중 먼저 닿는 것으로 끊기고, 다음 수신 회전이 이번에 멈춘 연결의 다음부터 시작한다.
  • 한 socket이 여러 peer를 대표할 때 회계가 peer 단위로 이루어진다.
  • 형식이 맞지 않는 입력은 handler에 도달하지 않는다 — 응답을 기다리는 호출은 ProtocolError로 끝나고, 기다리지 않는 호출은 기록만 남는다.

Pressure 상태와 socket

  • 80% pause, 60% resume과 경계 사이 hysteresis가 정확하다.
  • 새 socket 동기화, close 경쟁과 stale transition이 최신 절대 상태를 깨지 않는다.
  • RouteMesh ROUTER-ROUTER socket과 ClientServer Server ROUTER에만 receive-flow state를 적용하고, ClientServer Client DEALER에는 어떤 상태도 적용하지 않는다.
  • Host가 PAUSED인 동안에도 Client가 보낸 request의 답이 Client에 도착한다.

Backpressure와 Core HWM

  • Framework 내부 작업의 송신 공간 대기가 §3 Permit 반환과 대기 중 자원 점유 금지를 지킨다.
  • 송신 공간을 기다리는 send는 시간을 이유로 끝나지 않고, request는 request timeout이 다 되면 DeadlineExceeded로 끝난다. 자리가 없다는 이유로 다른 오류를 받는 호출은 없다.
  • 실행 객체별 FIFO에 얼마를 넣어도 record를 거절하지 않는다.
  • 이미 완료된 호출 뒤의 실패(publish 시작 후 건너뜀, 완료된 send의 target 실패)는 caller 결과를 바꾸지 않고 관측에만 남는다.
  • Core receive byte HWM이 찼을 때 sender까지 backpressure가 전달되며 record를 버리지 않는다.
  • RouteMesh ROUTER-ROUTER Completion supply는 ordinary permit 포화와 독립적으로 진행한다.
  • ClientServer DEALER-ROUTER reply는 Core single FIFO의 앞선 DATA와 HWM·PAUSED 뒤에서 늦어질 수 있으며 configured request timeout이 먼저 끝나면 late reply가 두 번째 terminal을 만들지 않는다.
  • Framework가 retained receive, send_ready waiter 또는 별도 send retry를 사용하지 않는다.

설정의 구체적인 값은 Framework API가, 상태와 metric 이름은 Runtime 상태와 Runtime metric이 정의한다.


Execution 주제 목차 · 스펙 목차 · 이전: 03. 취소와 종료 · 다음: 05. Payload 소유권과 codec