현재 테스트 중입니다: 완료되면 GitHub 코드를 오픈할 예정입니다.

설정 (환경변수)

서버 설정은 환경변수로만 받습니다. 키는 대소문자를 구분하지 않고, 빈 값은 미설정으로 취급하며, flag는 1/true/yes/on만 참입니다. 범위나 조합이 잘못되면 시작 단계에서 중단합니다.

공통과 자원 상한

변수기본값허용 범위내용
SERVER_PORT5225유효한 u16 portsingle client port. non-Docker cluster는 CLUSTER_SELF, Docker cluster는 내부 5225 사용
SOCKET_BIND0.0.0.0bind 가능한 주소client와 Raft listener의 bind host
DEBUG_MODE빌드 설정flagdebug log 기본값
DOCKER_MODEfalseflagcluster 내부 bind port를 5225/6225로 고정. 공식 image는 true
MAX_CONNECTIONS10241..8192동시 client connection. 초과 connection은 즉시 닫음
MAX_RAFT_CONNECTIONS641..256동시 Raft/control connection. client와 별도 예약
MAX_WAITERS20481..16384key당 waiter. 초과 acquire는 B
MAX_TOTAL_WAITERS16384MAX_WAITERS..65536전체 waiter. 초과 acquire는 B

설정으로 바꿀 수 없는 안전 상한도 있습니다.

항목포화 시 동작
connection당 in-flight acquire64해당 acquire에 B
전체 in-flight acquire4096해당 acquire에 B
전체 in-flight release512 별도 laneconnection 종료 전까지 bounded 대기
connection당 밀린 reply256느린 client connection 종료
coordinator channel4096sender에 backpressure
cluster active key65536신규 key acquire에 B
Raft frame64MiBRPC 거부
snapshot encoded bytes64MiB - 64KiBbuild/install 거부
동시 Raft decode budget72MiBpermit이 생길 때까지 bounded 대기 또는 timeout

기본 profile은 512MiB memory limit에서 시작하는 구성입니다. 최대 snapshot, TLS connection과 learner catch-up이 겹치는 peak RSS는 workload로 다시 확인해야 합니다. hard ceiling을 넘겨 시작할 수 없으며 무제한 값은 없습니다. 전체 in-flight acquire, 신규 key와 전체 waiter admission은 각 hard limit의 90%에서 닫히고 사용량이 75% 미만으로 내려온 뒤 다시 열립니다. 이 high/low watermark는 한계 부근의 accept/reject 진동을 막습니다. wire에는 모두 상관 가능한 B로 보이지만 서버는 key_busy, per_key_limit, connection_limit, global_overload 누적값과 현재 사용량을 분당 통계에 남기고, 원인별 경고는 10초에 한 번으로 제한합니다.

client 인증과 TLS

변수기본값내용
CLIENT_TOKENS빈 token 1개comma-separated client 인증 token. production은 nonblank secret 권장
TLS_CERT / TLS_KEY없음함께 설정하는 server certificate chain과 private key PEM 경로
TLS_CAsystem roots이 서버가 다른 peer의 인증서를 검증할 때 쓰는 CA PEM
TLS_SKIP_VERIFYfalsepeer 인증서 chain/hostname 검증 생략. 테스트 전용
CLUSTER_ALLOW_PLAINTEXT_PRIVATEfalseTLS 없는 cluster를 명시적으로 허용. 격리된 private network 전용

현재 TLS는 server certificate를 검증하는 단방향 TLS이고 peer 권한은 별도 challenge-response token으로 검증합니다. plaintext opt-out은 기밀성이나 인증서 기반 node identity를 제공하지 않습니다.

안정 voter identity

cluster identity 항목은 함께 설정하거나 모두 생략해야 합니다. 생략하면 single 모드입니다.

변수조건내용
CLUSTER_ID1~128자의 ASCII 영숫자, ., _, -fencing domain을 구분하는 이름
CLUSTER_NODE_IDu64이 process의 Raft ID. 종료 뒤 재사용 금지
CLUSTER_INCARNATIONnon-zero u128process마다 외부 start authority가 새로 발급. stale env 재사용 금지
CLUSTER_SELFhost:client-portstable client address slot과 redirect 주소
CLUSTER_RAFT_SELFhost:raft-port이 process만 쓰는 Raft/control 주소
CLUSTER_PEERS정확히 3개 또는 5개NodeId@incarnation@client-address@raft-address 목록

client port와 Raft port는 각각 명시하며 일반적인 +1000 규칙은 없습니다. 단 DOCKER_MODE=true인 공식 image 내부 bind만 52256225로 고정됩니다. 모든 NodeId, incarnation, client address, Raft address는 중복되면 안 되며 자기 identity가 목록과 정확히 일치해야 합니다.

무디스크 서버는 동일 환경변수로 재실행된 process와 원래 process를 로컬에서 구분할 수 없습니다. 따라서 자동 restart를 끄고 외부 operator가 매 process start마다 새 incarnation을 발급해야 합니다. 기존 quorum은 membership과 incarnation이 다른 stale process를 거부합니다. 이 start authority를 지키지 않는 same-NodeId/same-incarnation 재실행은 지원 failure model 밖이며 Raft 안전성을 주장할 수 없습니다.

서버 내부의 startup_admission은 이 외부 불변식을 방어하는 추가 gate입니다. 최초 cluster는 모든 설정 peer가 서로 빈 membership·미사용 bootstrap 상태임을 확인하고 Prepared barrier를 통과해야 Open이 됩니다. replacement는 leader가 one-shot Join을 승인한 뒤에만 Open이 됩니다. Pending이나 Prepared에서는 status/Join 같은 control 요청만 허용하고 Vote, Append, Snapshot, client mutation은 거부합니다. peer unreachable을 빈 상태로 간주하는 fallback은 없습니다. Rejected는 terminal이며 새 NodeId와 incarnation으로 다시 준비해야 합니다.

Raft와 clock

변수기본값제약
CLUSTER_HEARTBEAT_MS50010 이상
CLUSTER_ELECTION_TIMEOUT_MS2000600 이상, heartbeat의 4배 이상
CLUSTER_SNAPSHOT_TIMEOUT_MS1200001000 이상
RAFT_PROGRESS_TIMEOUT_MS100001000 이상
CLUSTER_CLOCK_AGENT_ENDPOINT없음cluster에서 필수인 numeric IP:port
CLUSTER_CLOCK_AGENT_SECRET없음cluster에서 필수, 32바이트 이상, 다른 token과 분리
CLUSTER_CLOCK_PAIRWISE_DELTA_MS202..=60000, 모든 voter/learner가 동일
CLUSTER_CLOCK_MAX_STALENESS_MS5000sample interval + timeout보다 큼
CLUSTER_CLOCK_SAMPLE_INTERVAL_MS10000보다 크고 staleness보다 작음
CLUSTER_CLOCK_TIMEOUT_MS2500보다 크고 staleness보다 작음
CLUSTER_CLOCK_MAX_RTT_MS500보다 크고 timeout 이하
CLUSTER_CLOCK_MAX_UNCERTAINTY_MS2pairwise delta / 2 이하
CLUSTER_CLOCK_MAX_SOURCE_AGE_MS20000보다 큼

clock endpoint는 인증된 외부 기준시각, uncertainty, sync 여부와 source age를 반환해야 합니다. startup, Grant/Expire 직전 또는 주기 probe에서 인증·freshness·RTT·Δ·wall-step 검증이 실패하면 node는 새 mutation을 멈추고 client를 drain한 뒤 Raft를 종료합니다. 정확한 TCKCLK 2 계약은 clock health를 따릅니다.

cluster와 control 인증

변수조건내용
CLUSTER_TOKENScluster에서 nonblank 목록 필수첫 token으로 송신, 목록 전체로 peer 수신 검증
CLUSTER_CONTROL_TOKENScluster에서 nonblank 목록 필수status와 replacement 관리 권한
CLUSTER_BOOTSTRAP_CREDENTIAL첫 cluster process에만 설정복제 상태에 한 번 기록되는 bootstrap 자격

cluster token과 control token은 서로 겹치면 안 됩니다. clock secret, bootstrap credential과 join credential도 다른 인증 domain의 token을 재사용하면 시작을 거부합니다.

leader가 출력하는 join 설정

다음 값은 수동으로 만들지 않습니다. prepare-replacement가 발급한 출력을 그대로 replacement process에 넣습니다.

  • CLUSTER_JOIN_LEADER
  • CLUSTER_JOIN_LEADER_NODE_ID
  • CLUSTER_JOIN_LEADER_INCARNATION
  • CLUSTER_JOIN_CREDENTIAL
  • CLUSTER_JOIN_SEED_PEERS
  • CLUSTER_NODE_ID, CLUSTER_INCARNATION, CLUSTER_SELF, CLUSTER_RAFT_SELF, CLUSTER_PEERS

join 관련 다섯 값은 전부 함께 있어야 하고 bootstrap credential과 함께 쓸 수 없습니다. join credential은 one-shot이며 기본 60초, 허용 TTL은 5~300초입니다. old/new process만 같은 stable client slot을 공유하고 Raft address와 incarnation은 반드시 달라야 합니다.

bootstrap과 교체 명령은 무정지 새 NodeId learner 교체에 정리되어 있습니다. peer wire는 CLUSTER_WIRE_VERSION=1 exact match이고 server package version은 호환 판정에 사용하지 않습니다.