etcd 3.7.0: RangeStream·Protobuf 완전 교체·v2 제거로 다시 그은 운영 경계
왜 지금 봐야 하나
2026년 7월 8일, Kubernetes 프로젝트가 etcd v3.7.0 출시를 공식 발표했다.
etcd는 Kubernetes 클러스터의 모든 상태를 저장하는 단일 진실 공급원이다. 또한 Patroni 같은 PostgreSQL HA 솔루션, 분산 서비스 디스커버리, 분산 잠금의 백엔드로도 쓰인다. etcd의 릴리스는 Kubernetes 운영자뿐 아니라 DBA에게도 직접적인 영향을 준다.
3.7.0의 핵심 변화는 세 가지다.
- RangeStream: 큰 결과를 청크로 스트리밍, 메모리 버퍼 제어 가능
- Protobuf 완전 교체:
gogo/protobuf→google.golang.org/protobuf, gRPC 미들웨어 v2 전환 - v2 스토어·클라이언트·디스커버리 완전 제거: 마이그레이션 창이 닫혔다
이 챕터에서는 각 변화의 기술 배경, 운영 영향, 업그레이드 판단 기준을 정리한다.
etcd 아키텍처 요약
쓰기 처리
(v3 store)
읽기 가능
(v3 store)
읽기 가능
(v3 store)
RangeStream: 큰 결과 세트를 청크로 받는다
기존 Range RPC의 한계
Range RPC는 조건에 맞는 모든 키-값 쌍을 한 번에 버퍼링해 반환한다. Kubernetes 클러스터에 수천 개의 Pod/Service/ConfigMap이 있으면 단일 응답이 수 MB에 달할 수 있다.
클라이언트는 전체 응답이 도착할 때까지 대기해야 하고, 응답을 모두 메모리에 올려야 한다. list-and-watch 패턴에서 초기 list 단계가 메모리·지연의 병목이 되는 이유다.
RangeStream RPC
RangeStream은 서버 사이드 커서와 gRPC 서버 스트리밍을 조합해 결과를 청크로 전달한다. 클라이언트는 첫 청크 도착 즉시 처리를 시작할 수 있고, 버퍼 메모리 사용량을 예측 가능한 수준으로 유지한다.
Kubernetes controller-manager와 scheduler의 list 단계, 대규모 클러스터에서의 etcdctl get --prefix 작업이 직접 수혜를 받는다.
3.7.0에서의 상태: RangeStream은 현재 베타 단계다. Kubernetes-style feature gate를 통해 활성화한다. GA 전에는 기존 Range RPC가 기본값으로 유지된다.
Protobuf 완전 교체: gogo/protobuf → google.golang.org/protobuf
교체 배경
etcd는 오랫동안 gogo/protobuf를 사용했다. 이 라이브러리는 Go 1.x 초기에 표준 proto 라이브러리보다 성능이 좋았지만, 현재는 유지보수가 중단됐다. 보안 패치가 오지 않고, 최신 protobuf 사양과의 호환성도 떨어진다.
3.7.0에서 이 교체를 완료했다.
| 항목 | 이전 | 3.7.0 이후 |
|---|---|---|
| Protobuf 라이브러리 | github.com/gogo/protobuf | google.golang.org/protobuf |
| gRPC 미들웨어 | go-grpc-middleware/v1 | go-grpc-middleware/v2 |
| Go 버전 | Go 1.21.x | Go 1.26.5 |
| bbolt | v1.4.x | v1.5.1 |
| raft | v3.6.x | v3.7.0 |
운영자 관점의 영향
프로토콜 수준에서는 하위 호환성이 유지된다. etcd 3.7.0 클러스터에 3.5·3.6 클라이언트로 접속할 수 있다.
단, 직접 gRPC로 etcd에 접속하는 커스텀 코드가 있다면 검토가 필요하다. gogo/protobuf에서 생성된 .pb.go 파일은 google.golang.org/protobuf와 함께 컴파일되지 않는다. etcd 클라이언트 라이브러리를 직접 임포트하는 Go 코드는 의존성을 업그레이드해야 한다.
v2 완전 제거
3.7.0에서 v2 관련 코드가 완전히 제거됐다.
| 제거된 항목 | 설명 |
|---|---|
client/v2 패키지 | HTTP 기반 v2 클라이언트 라이브러리 |
v2discovery | v2 기반 클러스터 디스커버리 |
v2 요청 처리 (apply_v2.go) | 서버 사이드 v2 요청 핸들러 |
| v2 스냅샷 파일 로드 | 부트스트랩 시 v2 스냅샷 파일 로드 지원 |
| v2store 메모리 트리 | 메모리 내 v2 데이터 트리 구조 |
이미 v3 클라이언트를 쓰고 있다면 이 제거는 영향이 없다.
영향이 있는 경우:
go.etcd.io/etcd/client/v2임포트를 사용하는 Go 코드- etcd HTTP v2 API (
/v2/keys/*)에 직접 요청하는 서비스 - v2 discovery URL로 클러스터를 부트스트랩하는 자동화 스크립트
특히 오래된 coreos/etcd 문서를 참고해 작성된 스크립트나 서비스가 있다면 점검이 필요하다.
성능 개선
SharedBufReadTxMode: 리스·인증 작업 2배 빠르게
SharedBufReadTxMode는 읽기 전용 트랜잭션에서 버퍼를 공유해 메모리 할당과 복사를 줄인다. 이 모드가 직접 적용되는 작업은 리스 갱신(Lease KeepAlive), 사용자·역할 조회다.
리스를 집중적으로 쓰는 환경(Kubernetes 노드가 많을수록 리스 갱신 빈도가 높다)에서 etcd CPU와 지연이 체감적으로 개선된다.
FastLeaseKeepAlive
리스 갱신 시 applied index 대기를 건너뛰는 feature gate다. 리스 갱신은 Raft 로그에 기록되지만, 이전에는 갱신이 실제로 적용됐다는 인덱스 확인을 기다렸다. FastLeaseKeepAlive는 이 대기를 제거해 갱신 지연을 줄인다.
키-전용 Range 최적화
WithKeysOnly() 옵션을 쓰는 Range 요청이 이제 값을 읽지 않고 메모리 인덱스에서만 결과를 구성한다. 키 목록 조회(Pod 이름 목록 등)의 I/O와 메모리 사용량이 낮아진다.
새 메트릭
| 메트릭 | 설명 |
|---|---|
etcd_server_request_duration_seconds | 서버 요청 처리 시간 (히스토그램) |
etcd_network_watch_send_total | Watch 이벤트 송신 카운터 |
etcd_network_watch_send_errors_total | Watch 송신 오류 카운터 |
etcd_network_watch_send_bytes_total | Watch 송신 바이트 합계 |
etcd_network_watch_send_latency_seconds | Watch 송신 지연 히스토그램 |
Watch 지연 메트릭은 특히 유용하다. Kubernetes controller가 오브젝트 변경을 얼마나 빨리 인식하는지를 etcd 수준에서 확인할 수 있다.
업그레이드 판단 기준
현재 etcd 버전별 권장 경로
| 현재 버전 | 권장 경로 | 비고 |
|---|---|---|
| 3.4.x | 3.5 → 3.6 → 3.7 순차 업그레이드 | 한 번에 두 메이저 버전 이상 건너뛰기 비권장 |
| 3.5.x | 3.6 → 3.7 또는 3.5 → 3.7 | 3.6은 2026년 6월 EOL 예정, 3.7 직접도 가능 |
| 3.6.x | 3.7 직접 업그레이드 가능 | 하위 호환 데이터 포맷 유지 |
업그레이드 전 확인 사항
- [ ] v2 클라이언트 코드 감사:
client/v2임포트 또는 HTTP/v2/keys호출이 있는지 확인. - [ ] custom Go 코드 점검:
gogo/protobuf에서 생성된.pb.go파일을 직접 쓰는 코드가 있는지 확인. 있다면protoc-gen-go재생성 필요. - [ ] 클러스터 정상 확인: 업그레이드 전
etcdctl endpoint status로 리더, 팔로워 상태와 DB 크기를 기록. - [ ] 스냅샷 백업: 업그레이드 전
etcdctl snapshot save실행. v2 스냅샷 파일이 있다면 v2store 데이터를 v3로 마이그레이션했는지 확인. - [ ] 한 번에 한 노드씩: Kubernetes 환경에서는 컨트롤플레인 노드를 순서대로 업그레이드. 각 노드 업그레이드 후
endpoint health로 quorum 유지 확인. - [ ] Kubernetes 버전 호환성 확인: etcd compatibility matrix를 통해 현재 K8s 버전과 etcd 3.7의 호환성을 확인.
RangeStream 베타 도입 결정 기준
RangeStream은 기본값이 아니므로 명시적으로 활성화해야 한다.
| 상황 | 권장 여부 |
|---|---|
| 3,000 노드 이상 대형 클러스터 | 검토 권장 (list 단계 병목이 확인된 경우) |
| 클러스터 크기 1,000 노드 미만 | 기본값(Range) 유지 권장 |
| list-and-watch 초기화 지연이 SLO에 영향 | 병목 측정 후 결정 |
| 안정성 우선 운영 환경 | GA까지 대기 권장 |
Open Questions
- RangeStream의 청크 크기 제어 파라미터가 문서화되어 있지 않다. 서버가 자동으로 결정하는지, 클라이언트가 힌트를 줄 수 있는지 미확인이다.
SharedBufReadTxMode2배 성능 개선의 기준 워크로드(리스 수, 클러스터 크기)가 공개되지 않았다. 실제 환경에서 측정이 필요하다.- etcd 3.7이 Kubernetes 1.34 이상에서 기본값이 되는 시점이 Kubernetes 릴리스 팀에서 아직 확정되지 않았다.
- feature gate 목록 전체가 안정화된 문서로 아직 정리되지 않았다.
References
- Announcing etcd v3.7.0 — Kubernetes Blog (2026-07-08)
- Announcing etcd v3.7.0 — etcd Blog
- etcd CHANGELOG-3.7.md — GitHub
- etcd v3.7.0-rc.0 Now Available for Testing
- Announcing etcd v3.7.0-beta.0 — etcd Blog
- Apache Kafka 4.3.0: A Guide for Platform Engineers — Factor House
- Etcd Patch Releases: v3.7.1, v3.6.14, v3.5.33 — etcd Blog (2026-07-23)