Sōzu 2.1.0은 프로그래머블 엣지를 위한 1급 UDP 로드 밸런싱, 결정론적 시뮬레이션, 강화된 테스트 및 운영 신뢰성을 도입합니다.
저희는 이 프로젝트를 이끌고 있으며 주요 기여자입니다(github.com/sozu-proxy/sozu). Sōzu 2.0에서는 프록시가 “리버스 프록시”에서 “프로그래머블 엣지”로 어떻게 이동했는지 설명했습니다. 새로운 HTTP/2 멀티플렉서, 더 강력한 기본 보안 설정, 더 넓어진 관측 가능성 표면, 트래픽 정책, 운영 강화, 그리고 암호화 민첩성이 그것입니다.
며칠 뒤 공개된 Sōzu 2.0.2는 더 작지만 많은 것을 드러내는 릴리스였습니다. 이 버전은 HTTP/2 bomb 계열에 대한 심층 방어를 추가했고, access log로부터 신뢰할 수 있는 OpenTelemetry span을 재구성하는 데 필요한 타임스탬프 기반을 수정했습니다. 이 릴리스는 저희가 엣지를 어떻게 운영하고자 하는지를 보여줬습니다. 프로토콜 수준의 공격 계열이 나타나면 프록시는 가능한 한 많은 부분을 흡수해야 하고, 관측 가능성이 미묘하게 잘못되어 있다면 그 위에 제품 기능을 쌓기 전에 먼저 기반을 바로잡아야 합니다.
Sōzu 2.1.0은 같은 이야기의 다음 단계입니다. 2.0에서 “작업대 위에 있다”고 설명했던 요소 중 하나가 반영되었습니다. 바로 1급 UDP 로드 밸런서 지원입니다.
이것은 단순히 프로토콜 체크박스 하나를 더 채운 것이 아닙니다. Sōzu는 이미 HTTP, HTTPS, TCP를 처리했습니다. 2.1.0에서는 UDP가 같은 모델의 일부가 됩니다. 같은 핫 리컨피규어 가능한 control plane, 같은 운영자 중심의 자세, 같은 메트릭 규율, 같은 오픈 소스 릴리스 프로세스를 따릅니다. 그 결과 Sōzu는 웹 엣지에서 더 넓은 인프라 로드 밸런서로 확장되어, DNS, syslog, NTP, 그리고 일반적인 UDP 워크로드 같은 데이터그램 서비스를 앞단에 둘 수 있게 되며, 운영자가 그 앞에 두 번째 로드 밸런서를 따로 두지 않아도 됩니다.
Clever Cloud에게 이것이 중요한 이유는 플랫폼 네트워킹이 HTTP보다 훨씬 넓기 때문입니다. Managed Kubernetes와 PaaS 모두 직접적인 전송 트래픽에 대한 깔끔한 이야기가 필요합니다. 직접 Sōzu를 운영하는 운영자에게는, Sōzu가 처음부터 유용했던 설계 특성을 유지하면서도 하나의 컴포넌트가 L4/L7 표면의 더 많은 부분을 담당할 수 있다는 뜻입니다.
웹에서 사용자 대면 트래픽의 대부분은 HTTP를 통과하며, 나머지 모든 것을 특수한 경우로 취급하고 싶어지기 쉽습니다. 하지만 실제 플랫폼에는 그런 사치가 허용되지 않습니다.
DNS는 기본적으로 UDP를 사용합니다. Syslog도 종종 UDP 위에서 동작합니다. NTP는 UDP입니다. 많은 내부 및 인프라 프로토콜은 단순하거나, 지연 시간에 민감하거나, 완전한 TCP 연결이 불필요할 정도로 요청/응답 형태가 충분하기 때문에 데이터그램을 사용합니다. Kubernetes 플랫폼과 PaaS 제품은 HTTP에서 종료되는 웹 애플리케이션뿐 아니라 직접 전송 서비스도 깔끔하게 노출해야 합니다.
Sōzu 2.1.0 이전에는 HTTP, TCP, UDP를 위한 단일 엣지를 원하는 운영자는 대개 여러 시스템을 조합해야 했습니다. Sōzu가 HTTP와 TCP 측면을 처리하고, 별도의 컴포넌트가 UDP를 처리하는 방식입니다. 이런 분리는 운영 비용을 수반합니다. 헬스 체크 모델이 두 개, 트래픽 관측 방식이 두 개, 릴리스 주기가 두 개, 장애 표면이 두 개, 설정 세트가 두 개, 그리고 라우팅 상태가 어긋날 수 있는 지점도 두 군데가 됩니다.
Sōzu에서 1급 UDP를 도입하는 목적은 수렴입니다. 이제 UDP 리스너는 tcp, http, https 리스너와 나란히 놓입니다. UDP 프런트엔드와 백엔드는 같은 명령, 설정, 상태 기계의 일부입니다. 운영자는 데이터그램 트래픽을 옆에서 따로 일어나는 일처럼 취급하는 대신 프록시에서 UDP 전용 메트릭을 얻을 수 있습니다.
고객이 체감하는 이점은 모든 애플리케이션이 갑자기 UDP를 필요로 하게 된다는 것이 아닙니다. 플랫폼이 더 많은 트래픽 클래스를 하나의 운영 모델 아래로 수렴시킬 수 있다는 점입니다. 핫 리컨피규레이션, 헬스 인식, 메트릭, 릴리스 규율, 그리고 프로토콜별 예외의 더미로 남는 대신 제품 기능으로 진화할 수 있는 단일 엣지 컴포넌트 말입니다.
Sōzu 2.1.0은 기존의 HTTP, HTTPS, TCP 리스너와 함께 새로운 protocol = “udp” 리스너 타입을 추가합니다. 이는 opt-in입니다. 기존 설정이 우연히 UDP 인식형이 되지는 않으며, 기존 sozu-command-lib 사용자는 통합을 다시 작성하지 않고도 2.0.2에서 2.1.0으로 이동할 수 있습니다.
핵심 아이디어는 UDP 트래픽을 가상 플로우로 모델링하는 것입니다. UDP 자체에는 연결도, 스트림도, accept loop도 없습니다. 데이터그램은 하나의 소켓으로 도착합니다. TCP처럼 커널이 클라이언트별 소켓을 따로 만들어주지 않습니다. 따라서 Sōzu는 사용자 공간에서 연결의 유용한 부분을 재구성합니다. 즉, 클라이언트 소스 주소를 키로 하는 플로우를 만들고, 워크로드에 따라 그 모델이 더 적절하다면 소스 포트도 선택적으로 포함합니다.
Sōzu가 플로우를 가지게 되면, 로드 밸런서가 어떤 전송 계층에서든 내려야 하는 종류의 결정을 내릴 수 있습니다.
이 릴리스는 UDP를 위한 두 가지 플로우 친화적 알고리즘을 추가합니다. 권장 기본값은 HRW이며, rendezvous hashing이라고도 부릅니다. HRW는 핫 리컨피규어 가능한 시스템에서 매우 중요한 성질을 가집니다. 백엔드 집합이 바뀔 때 미리 계산된 lookup table 없이도 이동을 최소화합니다. Sōzu는 또한 더 큰 백엔드 집합이나 더 높은 패킷 속도에서 O(1) 테이블 조회가 더 매력적인 경우를 위해 Maglev를 opt-in 알고리즘으로 제공합니다.
Sōzu는 UDP 백엔드로 PROXY protocol v2 정보도 보낼 수 있습니다. 이렇게 하면 실제 클라이언트 주소가 백엔드로 전달되어, 백엔드가 프록시만을 유일하게 보이는 피어로 취급하지 않아도 됩니다. 기본적으로 Sōzu는 플로우의 첫 번째 데이터그램에서 이를 전송하며, 백엔드가 그 컨텍스트를 반복적으로 필요로 하는 경우 모든 데이터그램에 전송하는 opt-in 모드도 제공합니다.
헬스 체크는 사후적인 덧붙임이 아니라 UDP 설계의 일부입니다. UDP 백엔드는 보조 TCP probe를 통해 점검할 수 있으며, 이는 순수 UDP만으로는 신뢰할 수 있는 “연결됨” 상태를 제공하지 않는 서비스에서 흔히 실용적인 생존 신호로 사용됩니다. 의미가 있는 경우에는 애플리케이션 수준 UDP probe도 사용할 수 있습니다. 이 체크는 rise/fall 히스테리시스와 fail-open 의미론을 지원하므로, 일시적이거나 전역적인 헬스 체크 실패가 자동으로 트래픽 블랙홀로 이어지지 않습니다.
마지막으로 UDP는 자체 메트릭 표면을 갖습니다. 들어오고 나가는 데이터그램, 들어오고 나가는 바이트, 활성 플로우, 생성·축출·차단된 플로우, 이유별 드롭된 데이터그램, 백엔드 헬스, 그리고 플로우 지속 시간입니다. 이는 2.0의 관측 가능성 작업과 같은 원칙을 따릅니다. 운영자가 무엇을 하고 있는지 볼 수 있기 전까지는 어떤 기능도 프로덕션 등급이 아닙니다.
UDP 로드 밸런싱에서 어려운 부분은 데이터그램을 받아 어딘가로 보내는 일이 아닙니다. 어려운 부분은 그 데이터그램 주변에 어떤 상태가 존재하는지를 결정하는 일입니다.
TCP는 프록시에 연결 생명주기를 제공합니다. HTTP는 요청, 응답, 헤더, 상태 코드를 제공합니다. UDP는 패킷만 제공합니다. 패킷은 순서 없이 도착할 수 있습니다. 사라질 수도 있습니다. 닫을 것이 없기 때문에 클라이언트는 아무것도 닫지 않고 전송을 멈출 수 있습니다. 가상 플로우가 여전히 그것을 가리키는 동안 백엔드는 비정상이 될 수 있습니다. 플로우가 활성인 동안 리컨피규레이션이 도착할 수 있습니다. 리스너가 플로우 상한에 도달할 수 있습니다. 타임아웃은 플로우가 갱신된 직후에 발화할 수 있습니다. 이런 것은 이례적인 경우가 아닙니다. 부하 상황의 데이터그램 트래픽에서는 이것이 정상적인 형태입니다.
그래서 Sōzu 2.1.0의 UDP 작업은 기능만큼이나 테스트 가능성에 관한 이야기이기도 합니다.
UDP 코어는 sans-io 분리를 중심으로 구성됩니다. 순수 코어는 플로우 테이블, 수용 결정, 타이머, 종료 정책, 로드 밸런싱 요청을 담당합니다. 비순수 셸은 소켓, 버퍼 풀, 헬스 체크, syscall, 메트릭 방출을 담당합니다. 코어는 소켓도 없고, 데이터패스에서 wall-clock 읽기도 없고, 내부에 숨겨진 난수 소스도 없습니다. 시간과 시드는 주입됩니다.
이 구조가 중요한 이유는 코어를 결정론적으로 시뮬레이션할 수 있게 해주기 때문입니다. 같은 시드는 같은 시퀀스를 구동합니다. 같은 가상 시계는 같은 시점으로 점프합니다. 같은 리컨피규레이션 폭풍이 같은 단계에서 발생합니다. 장애가 발생하면 시드를 출력하고 정확히 재생할 수 있습니다.
Sōzu 2.1.0은 UDP 코어를 위한 FoundationDB/VOPR 스타일의 결정론적 시뮬레이션 하네스를 포함합니다. 기본 스윕은 256개 시드를 실행하며, 각 시드는 무작위화된 적대적 워크로드를 통해 클라이언트 데이터그램, 백엔드 응답, 오래된 백엔드 해석, 리컨피규레이션 버스트, 플로우 상한 변경, 시계 점프, drain, 대량 종료를 구동합니다. 각 동작 후 하네스는 코어 출력들을 비우고 모델 불변식을 점검합니다.
그 위에, 이번 릴리스는 TigerBeetle의 TigerStyle에서 영감을 받은 assertion 밀도 스윕도 포함합니다. 프록시, command plane, supervisor 전반에 걸쳐 Sōzu는 이제 대략 1100****debug_assert!****검사와 여러 불변식 스윕을 포함합니다. 이 assertion들은 릴리스 빌드에서는 컴파일에서 제외되지만, 테스트, fuzzing, 엔드투엔드 실행, 시뮬레이션, 개발자 빌드에서는 살아 있습니다. 이들은 조용한 상태 드리프트를 시끄럽고 국소적인 실패로 바꿉니다.
이 숫자들이 유용한 이유는 그것들이 단순한 볼륨 메트릭이 아니기 때문입니다. 코드 줄 수는 신뢰성을 증명하지 않습니다. 256시드 시뮬레이션 스윕과 촘촘한 불변식은 분명한 의미를 전달합니다. 코드가 적대적인 상태 전이를 거치도록 구동되고 있으며, 데이터 구조가 여전히 말이 되는지를 지속적으로 증명하도록 요구받고 있다는 뜻입니다.
프록시에서는 이 차이가 중요합니다. 잘못된 카운터는 단순한 카운터가 아닙니다. 플로우 누수를 의미할 수 있습니다. 오래된 타이머는 단순한 타이머가 아닙니다. 상태는 그렇지 않다고 말하는데도 백엔드가 계속 트래픽을 받는다는 뜻일 수 있습니다. 라우팅 테이블과 slab 사이의 조용한 불일치는 단순한 내부 불일치가 아닙니다. 버그에서 여러 계층 떨어진 곳에서 프로덕션 증상으로 나타나는 종류의 문제입니다.
UDP 시뮬레이터는 또한 저희가 Sōzu 엔지니어링을 앞으로 어디로 이끌고 싶은지에 대한 신호이기도 합니다.
FoundationDB는 인프라 소프트웨어에서 결정론적 시뮬레이션을 유명하게 만들었습니다. 시스템을 시뮬레이션된 세계 안에서 실행하고, 장애를 주입하고, 수천 개의 스케줄을 탐색하며, 모든 실패를 하나의 시드로부터 재현 가능하게 만드는 방식입니다. TigerBeetle은 이를 보완하는 규율을 밀어붙입니다. 불변식을 코드에 직접 명시하고, 양의 공간과 음의 공간 모두를 assertion하며, 테스트 중에는 불법 상태를 무시할 수 없게 만듭니다.
Sōzu 2.1.0은 이러한 아이디어를 UDP 코어에 적용합니다. 다음 아키텍처 노력은 Sōzu의 더 많은 부분이 이런 형태에 맞도록 만드는 것입니다. 더 많은 sans-io 컴포넌트, 더 많은 주입형 시계와 결정론적 경계, 그리고 프로덕션 동작으로 노출되기 전에 OSI 스택의 관련 부분 전반에서 시뮬레이션할 수 있는 더 많은 계층이 필요합니다.
이것이 Moonpool이 Clever Cloud에 중요한 이유이기도 합니다. PierreZ가 개발한 Moonpool은, Rust에서 이 방향을 위해 Clever Cloud가 사용하는 결정론적 시뮬레이션 엔진입니다. 이제 0.7.0 버전이 moonpool과 moonpool-sim을 포함해 crates.io에 공개되었습니다. Sōzu의 UDP 하네스는 현재 순수 UDP 코어를 중심으로 구성된 인트리 동기 시뮬레이터이지만, 더 넓은 방향은 같습니다. 결정론적 워크로드, 가상 시간, 재현 가능한 시드, 그리고 프로덕션이 기회를 얻기 전에 실패시킬 수 있는 네트워크 시스템입니다.
가장 큰 이점은 신뢰성입니다. 저희는 프로토콜 및 리컨피규레이션 코드에서 엣지 케이스 버그를 더 줄이고 싶습니다. 두 번째 이점은 속도입니다. 프록시의 더 많은 부분이 명시적 I/O 경계를 가진 순수 상태 기계로 구성될수록, 새로운 프로토콜과 로드 밸런싱 동작을 더 안전하게 진화시킬 수 있습니다. 세 번째 이점은 운영 가능성입니다. 핫 리로드, 과부하, 장애 동작은 코드가 정확히 그런 형태 아래에서 이미 구동되었기 때문에 더 이해하기 쉬워집니다.
이것이 프로그래머블 엣지 아래의 다음 계층입니다. 사용자에게 노출되는 노브는, 그 아래의 기계장치가 신뢰할 만큼 충분히 결정론적일 때에만 노출할 가치가 있습니다.
Managed Kubernetes의 경우, UDP 지원은 직접 전송 서비스를 위한 더 강력한 기반을 Sōzu에 제공합니다. 플랫폼은 서로 무관한 컴포넌트 사이에 책임을 나누는 대신, 더 일관된 로드 밸런싱 모델 아래에서 웹 트래픽, TCP 서비스, UDP 서비스를 제공할 수 있습니다.
PaaS의 경우, 별도의 운영 스택에서 시작하지 않고도 데이터그램 워크로드를 둘러싼 제품 기능으로 나아갈 길을 엽니다. DNS 유사 서비스, syslog 유사 플로우, NTP 유사 probe, 일반적인 UDP 애플리케이션을 같은 프록시 어휘로 사고할 수 있습니다. 리스너, 클러스터, 백엔드, 헬스, 메트릭, 핫 리컨피규레이션이 그것입니다.
자체 호스팅 Sōzu 운영자에게는, 이 프로젝트가 인프라 엣지의 더 많은 부분을 포괄하게 되었다는 뜻입니다. 이미 서명된 릴리스와 감사 가능한 Rust 코드베이스를 갖춘 오픈 소스 핫 리컨피규어 가능 프록시를 원해서 Sōzu를 사용하고 있다면, 2.1.0은 그 우산 아래로 가져올 수 있는 트래픽 종류를 확장합니다.
관측 가능성 측면의 결과도 있습니다. 이제 UDP 트래픽에는 네이티브 프록시 메트릭이 있습니다. 얼마나 많은 플로우가 활성인지, 얼마나 많이 차단되었는지, 왜 데이터그램이 드롭되었는지, 백엔드가 건강한지, 플로우가 얼마나 오래 지속되는지를 물어볼 수 있습니다. 이것이 프로토콜 기능을 운영 가능한 무언가로 바꾸는 요소입니다.
헤드라인은 UDP이지만, 2.1.0은 2.0의 운영 작업도 계속 이어갑니다.
핫 리컨피규레이션은 Sōzu의 핵심 약속 중 하나이므로 상태 재생의 정확성이 중요합니다. 이번 릴리스는 설정이 바뀌었지만 활성 상태를 유지하던 리스너가 activation을 다시 방출하지 않은 채 remove plus add로 재생될 수 있던 경우를 수정합니다. 이런 종류의 버그야말로 상태 모델을 고립된 명령으로만이 아니라 생명주기로 테스트해야 하는 이유입니다.
또한 이번 릴리스는 가장 왼쪽 세그먼트가 정규식인 호스트명에 대한 pattern trie의 산술 언더플로 panic도 수정합니다. 그리고 도구 변경으로 2.0.2 릴리스 중 서명 아티팩트 흐름이 깨진 이후, cosign 바이너리를 2.x 계열로 고정하여 릴리스 파이프라인도 수정했습니다.
이것들은 사용자가 가장 먼저 보게 될 릴리스의 부분은 아닙니다. 하지만 여전히 제품의 일부입니다. Clever Cloud 규모에서는 운영의 고요함이 곧 고객 이점입니다. 안전하게 리컨피규어되고, 아티팩트에 예측 가능하게 서명하며, 엣지 케이스를 테스트로 바꾸는 프록시는, 플랫폼이 그 아래에서 움직이는 동안에도 애플리케이션이 계속 트래픽을 서비스할 수 있게 해주는 프록시입니다.
UDP 지원은 실제 사용과 함께 계속 성숙해질 것입니다. 성능 작업, 배치 처리, 더 넓은 운영 피드백을 위한 여지가 있습니다. 하지만 더 큰 방향은 아키텍처적입니다. Sōzu의 더 많은 부분을 결정론적으로 만들고, 적절한 곳에서는 더 많은 부분을 sans-io로 만들며, 더 많은 장애 모드를 사고로 이어지기 전에 재현 가능하게 만드는 것입니다.
이것이 Sōzu 2.1.0의 교훈입니다. 프로그래머블 엣지는 사용자 대면 토글들의 집합만이 아닙니다. 그것은 인프라 소프트웨어를 구축하는 하나의 방식이기도 합니다. 프로토콜 하나씩, 상태 기계 하나씩, 그것을 운영할 수 있을 만큼의 관측 가능성과 신뢰할 수 있을 만큼의 시뮬레이션을 갖추는 방식입니다.
Sōzu는 AGPL-3.0으로 오픈 소스 공개되어 있으며, command library는 LGPL-3.0을 따릅니다. 코드, 릴리스 노트, 이슈, 설계 논의는 github.com/sozu-proxy/sozu에서 확인할 수 있습니다. 더 넓고, 더 안전하며, 더 프로그래머블한 엣지를 향해 프로젝트를 계속 밀어주는 기여자와 운영자 여러분께 감사드립니다.