diff options
Diffstat (limited to 'docs/design/017-apps-on-one-host.md')
| -rw-r--r-- | docs/design/017-apps-on-one-host.md | 77 |
1 files changed, 76 insertions, 1 deletions
diff --git a/docs/design/017-apps-on-one-host.md b/docs/design/017-apps-on-one-host.md index 3ffdc0f..f9ff765 100644 --- a/docs/design/017-apps-on-one-host.md +++ b/docs/design/017-apps-on-one-host.md @@ -1,7 +1,7 @@ # 017 — 한 호스트의 여러 앱: 차례, 예산, 실패 경계 작성일: 2026-10-01. 상태: 1·2단계와 2b 구현, 검사로 고정하고 쟀다([111](../research/111-apps-on-one-host.md), -[112](../research/112-sending-between-apps.md), [113](../research/113-one-sending-loop.md)). 3단계는 설계. +[112](../research/112-sending-between-apps.md), [113](../research/113-one-sending-loop.md)). 3단계는 착수 기준을 적었다(2026-10-04). [외부 리뷰 004](../outside-feedback/feedback-004.md)의 "구현 방향에 대한 평가" 셋째에서 시작한다. 작은 OS의 운영 모델( [007](007-execution-domains.md))을 Pure가 실제로 갖게 하는 단계다. @@ -231,6 +231,81 @@ counter apps/count.pmod stores/counter 모양과 이름으로 받는 모양, 메모리가 찬 앱에 보내는 것이 `kill -9`를 지나도 한 번씩 순서대로 간다. 커밋: Pure `8f75b32`(앱마다의 배선, 링크 포트 하나), `b7b86df`(안쪽 출구). +## 3단계: 앱의 수명 + +**구성 파일이 호스트의 모습이다.** `--apps FILE`은 시작할 때만 읽지 않는다. 호스트가 SIGHUP을 받으면 파일을 다시 읽고, 달리는 +앱들을 파일의 모습에 맞춘다. + +- 새 줄의 앱은 시작한다. 1단계의 시작과 같다(모듈 검증, 저장소, 배선, 실패하면 그 앱만 멈추고 까닭을 남긴다). +- 없어진 줄의 앱은 멈춘다(아래의 순서). 그 뒤로 그 경로는 404 `no_app`이다. +- 바뀐 줄의 앱은 멈추고 새 줄로 다시 시작한다. 모듈 파일의 내용, 저장소, 예산, 배선 가운데 하나라도 바뀐 줄이다. 상태는 + 저장소에서 이름으로 이어받는다(지금 다른 모듈로 다시 띄울 때와 같다, `server_upgrade`). +- 그대로인 줄의 앱은 건드리지 않는다. 멈춰 있거나(시작하지 못했거나) 불확실해진 앱만 다시 시작한다. 저장소에서 다시 연다. +- 다 맞추면 시작할 때와 같은 꼴의 줄 하나를 stdout에 낸다. 앱마다 상태와 까닭, 그리고 이번에 한 일(시작, 멈춤, 다시 시작)이다. +- 파일을 읽지 못하거나 틀린 줄이 있으면 아무것도 바꾸지 않고 까닭을 낸다. + +HTTP로 앱을 더하는 길을 두지 않는 까닭은 인증이다. 그 길은 경로의 인증(3b)을 먼저 요구한다. 신호는 프로세스의 주인만 보낼 수 있고, +파일은 호스트의 구성을 그대로 남긴다(다시 띄워도 같은 모습이다). 다시 읽기는 호스트의 스레드 하나(`pure-apps`)가 한다. 연결 +스레드와 실행 스레드는 기다리지 않는다. + +**멈추는 순서.** 앱 하나를 멈추는 것은 이렇다. + +1. 새 일을 받지 않는다. 그 앱의 경로는 503 `stopped`다. 링크와 안쪽 출구의 기록은 받지 않는다(보내는 쪽이 쥐고 다시 보낸다). +2. 소유자가 이미 받은 일을 다 적용하고, 저장하고, 답한다. +3. 그 앱의 보냄(전달선, 링크, 안쪽 출구)을 닫는다. 아직 가지 않은 것은 outbox에 남는다. 다른 앱에 가 있는 묶음은 돌아올 때까지 + 기다린다. +4. 저장소를 닫는다. 다른 프로세스가 열 수 있다. + +**모듈이 바뀌는 사이의 일.** 요청의 경로는 연결 스레드가 해석하고 적용은 실행 스레드가 한다. 그 사이에 모듈이 바뀌면 입력의 +번호와, JSON에서 이미 바꾼 페이로드의 배치가 새 모듈과 맞지 않는다. + +- 요청은 해석한 모듈을 들고 다닌다. 소유자는 지금의 모듈과 다른 모듈로 해석된 요청을 적용하지 않고 503 `stopped`로 답한다. + 클라이언트가 다시 보내면 새 모듈로 해석된다. 보기도 같다. 스냅숏의 모듈과 해석한 모듈이 다르면 503이다. +- 링크의 스트림은 받는 쪽 입력을 처음에 한 번 푼다(번호, 모양이 같은지, 이름으로 받는지). 앱이 다른 모듈로 다시 시작하면 + 링크를 받는 쪽에 그 앱의 스트림을 다시 풀게 한다. 그 사이에 넘어온 묶음은 받지 않는다(보내는 쪽이 다시 보낸다). +- 안쪽 출구는 받는 앱의 모듈이 바뀌면 그 입력을 이름으로 다시 찾는다(모양, 이름으로 받기). 찾지 못하면 쥐고 까닭을 남긴다. +- 모듈이 그대로면(예산이나 배선만 바뀌었거나 불확실해서 다시 연 것이면) 해석한 것이 그대로 맞다. 그대로 적용한다. + +**바뀐 모듈의 메모리.** 스냅숏과 연결 스레드의 리더가 모듈을 가리킨다. 그래서 바뀐 모듈은 호스트가 멈출 때까지 놓지 않는다. +한 번 바꿀 때 모듈 하나(18.7 KB와 모듈의 바이트)다. 잰다. + +**앱의 자리.** 앱의 자리는 호스트가 시작할 때 잡는다(`--app-slots N`, 기본 256, 처음의 앱 수보다 작지 않다). 자리는 이름과 +소유자, 그리고 연결 스레드마다의 리더다. 이름은 자리를 떠나지 않는다. 지운 앱의 이름을 다시 쓰면 그 자리로 간다. 연결 스레드가 +이름으로 자리를 찾는 동안 이름이 바뀌지 않기 때문이다. 쓰지 않은 자리는 손대지 않은 메모리라 상주하지 않는다. 자리가 다 차면 +새 앱은 까닭 "no slot"으로 멈춘다. + +**실행 스레드.** 달리는 앱이 실행 스레드보다 많아지면 CPU 수까지 하나씩 더한다(1단계의 규칙과 같다. 앱 수와 CPU 수 가운데 +작은 것이다). 줄이지는 않는다. 일 없는 실행 스레드는 잔다. + +**하지 않는 것.** + +- 끊김 없는 교체(새 모듈을 옆에서 띄우고 넘기기). 멈추고 다시 여는 동안 그 앱은 503을 답한다. 그 시간을 잰다. +- HTTP로 앱을 더하고 바꾸는 길. 경로의 인증(3b) 뒤에 따로 정한다. + +**3b: 경로의 인증.** 앱의 경로를 누가 부를 수 있는지다(CHECKPOINT의 남은 것). 3단계의 수명과 따로 설계한다. + +## 3단계의 착수 기준 + +- **바꿀 결정:** 달리는 호스트의 앱을 SIGHUP과 구성 파일로 더하고, 멈추고, 바꿀지다. 아래를 채우지 못하면 앱을 바꿀 때 호스트를 + 다시 띄운다(지금과 같다). +- **최소 확인**(`tests/check.py`의 `server_apps_lifecycle`): + - 한 호스트에서 앱을 더하면 그 앱이 바로 답한다. 지우면 그 경로가 404 `no_app`이고, 그 저장소를 다른 프로세스가 연다. 모듈을 + 바꾸면 상태를 이름으로 이어받는다. 그동안 다른 앱의 요청은 하나도 실패하지 않는다. + - 모듈을 바꾸는 동안에도 그 앱에 쓰기를 계속 보낸다. 200을 받은 쓰기는 모두 한 번씩 적용되고, 503 `stopped`를 받은 쓰기는 + 적용되지 않는다(합이 맞는다). + - 바뀌는 앱이 같은 호스트의 앱(안쪽 출구)과 다른 노드(링크)에서 받는 동안 입력의 번호가 바뀌는 모듈로 바꿔도, 보낸 것이 모두 한 + 번씩 순서대로 도착한다. 보내는 앱을 바꿔도 outbox의 것이 이어 간다. + - 저장소를 열지 못해 시작하지 못한 앱이, 고친 뒤의 SIGHUP에 시작한다. 틀린 줄이 있는 파일은 아무것도 바꾸지 않는다. + - 다시 읽은 뒤에 `kill -9`하고 다시 띄워도 상태와 앱들이 파일 그대로다. + - 1·2단계의 검사가 모두 초록이다. +- **통과 조건**(RAM의 Pi 5): + - 바꾸는 앱이 503을 답하는 시간(첫 503부터 첫 200까지)이 그 호스트를 다시 띄울 때 그 앱이 답하지 못하는 시간보다 짧다. 상태가 + 작은 앱(항목 1,000개)과 큰 앱(항목 100만 개)에서 각각 잰다. + - 한 앱을 거듭 바꾸는 동안 다른 앱(한 연결)의 p99가 바꾸지 않을 때의 1.5배를 넘지 않는다. + - 앱 하나의 호스트는 그대로다. TPC-C와 은행 질의를 전과 후 번갈아 재서 중앙값이 3% 넘게 느려지지 않고, 은행 질의의 명령 수가 + 1% 넘게 늘지 않는다. + - 바꿀 때마다 남는 메모리를 잰다(기준은 두지 않고 밝힌다). + ## 하지 않는 것 - 이벤트를 중간에 멈추고 다른 앱에 넘기는 선점. 이벤트는 원자적이고 끝까지 돈다. 그 대신 실행량 예산이 한 이벤트의 길이를, |
