-
client-go의 Reflector와 Watcher의 차이?Kubernetes 2025. 3. 2. 11:41728x90

Kubernetes client-go 라이브러리에서 Reflector와 Watcher는 둘 다 Kubernetes API 서버에서 데이터를 감시(watch)하는 역할을 하지만, 동작 방식과 목적이 다릅니다.
Watcher는 저수준 API, Reflector는 캐싱을 지원하는 고수준 API!
1️⃣ Watcher: API 서버의 watch 스트림을 직접 관리
🔹 개념
- Watcher는 API 서버의 watch 엔드포인트를 직접 호출하여 리소스 변경 사항을 실시간으로 감지하는 저수준(LOW-level) 인터페이스입니다.
- client-go에서 ListerWatcher 인터페이스를 사용하여 직접 구현할 수 있습니다.
🔹 동작 방식
- Kubernetes API 서버의 watch 엔드포인트를 호출하여 변경 사항을 실시간으로 스트리밍함.
- 새로운 이벤트(추가, 수정, 삭제)가 발생하면 이를 직접 받아서 처리해야 함.
- 연결이 끊어지면 직접 다시 연결해야 함 (재연결 로직 필요).
🔹 예제 코드 (Watcher 사용)
package main import ( "context" "fmt" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func main() { // Kubernetes 클라이언트 생성 config, _ := rest.InClusterConfig() clientset, _ := kubernetes.NewForConfig(config) // Pod 리소스에 대한 Watcher 실행 watcher, _ := clientset.CoreV1().Pods("").Watch(context.TODO(), metav1.ListOptions{}) // Watch 이벤트 처리 for event := range watcher.ResultChan() { fmt.Println("이벤트 발생:", event.Type, event.Object) } }🔹 특징
✅ API 서버와 직접 연결 → 네트워크 오버헤드가 클 수 있음.
✅ 단순하고 가벼움 → 필요한 리소스만 감시할 때 적합.
❌ 캐시가 없음 → 데이터를 저장하지 않으며, 모든 이벤트를 실시간으로 받아야 함.
❌ 연결이 끊어질 경우 직접 복구해야 함 → 재연결 로직이 필요함.2️⃣ Reflector: Watcher를 내부적으로 사용하여 데이터를 캐시에 저장
🔹 개념
- Reflector는 내부적으로 Watcher를 사용하여 API 서버에서 데이터를 가져온 후, 이를 로컬 캐시(Store)에 저장하는 역할을 합니다.
- 즉, Reflector는 Watcher보다 한 단계 높은 추상화된 구조입니다.
- Informer에서 사용되며, API 서버 부하를 줄이기 위해 캐시를 유지하면서 동작함.
🔹 동작 방식
- API 서버에서 LIST 요청을 보내 초기 데이터를 가져옴.
- API 서버에서 WATCH 스트림을 통해 실시간 변경 사항을 감지함.
- 데이터를 Store (캐시) 에 저장하여 빠른 조회 가능.
- 연결이 끊어지면 자동으로 다시 연결하여 Watcher를 복구함.
🔹 예제 코드 (Reflector 사용)
package main import ( "fmt" "time" "k8s.io/client-go/rest" "k8s.io/client-go/dynamic" "k8s.io/client-go/tools/cache" ) func main() { // Kubernetes 클라이언트 생성 config, _ := rest.InClusterConfig() client, _ := dynamic.NewForConfig(config) // 감시할 리소스 설정 (예: Pods) gvr := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} // Reflector 생성 및 실행 store := cache.NewStore(cache.MetaNamespaceKeyFunc) reflector := cache.NewReflector( cache.NewListWatchFromClient(client.Resource(gvr), "pods", "", cache.Indexers{}), &cache.ResourceEventHandlerFuncs{}, store, 5*time.Minute, ) stopCh := make(chan struct{}) go reflector.Run(stopCh) // 일정 시간 후 캐시 확인 time.Sleep(10 * time.Second) for _, obj := range store.List() { fmt.Println(obj) } }🔹 특징
✅ 캐시를 사용하여 빠른 조회 가능
✅ API 서버 부하 감소 → watch를 계속 요청하지 않고, 로컬에서 데이터를 유지
✅ 자동 재연결 지원 → 연결이 끊어져도 자동으로 복구
❌ 메모리 사용량 증가 → 데이터를 캐싱하므로 더 많은 메모리를 사용3️⃣ 🔥 Watcher vs. Reflector 비교

4️⃣ 어떤 경우에 Watcher와 Reflector를 사용할까?
✅ Watcher를 사용해야 하는 경우
- 간단한 이벤트 감지만 필요할 때 (예: 특정 Pod가 생성될 때 알림).
- 캐싱이 필요하지 않고, API 서버에서 직접 데이터를 가져와야 할 때.
- 데이터가 자주 변경되지 않으며, 한 번만 감시하면 되는 경우.
✅ Reflector를 사용해야 하는 경우
- API 서버에서 많은 데이터를 감시해야 할 때 (대량의 리소스를 처리하는 경우).
- 데이터를 빠르게 조회할 필요가 있을 때 (캐시가 필요한 경우).
- Informer와 함께 사용하여 자동화된 이벤트 처리가 필요할 때.
🔥 결론: Watcher는 저수준 API, Reflector는 캐싱을 지원하는 고수준 API!
- Watcher는 API 서버의 watch를 직접 사용하는 저수준 인터페이스
- Reflector는 Watcher를 사용하여 데이터를 캐시에 저장하고 자동으로 재연결하는 고수준 인터페이스
- Informer를 사용하면 내부적으로 Reflector가 자동으로 생성됨.
💡 즉, Reflector는 Watcher를 감싸서 더 효율적으로 동작하게 만든 것! 🚀
728x90'Kubernetes' 카테고리의 다른 글
CRD와 CR만 정의하는 경우 활용 사례 (0) 2025.03.02 client-go under the hood (0) 2025.03.02 go-client Informer 사용시 Indexer는 선택적으로 사용되는건가? (0) 2025.03.02 Informer을 하게 되면 reflector는 자동으로 생성되는가? (0) 2025.03.02 client-go library의 Reflector, Informer, Indexer 역할 (0) 2025.03.02