ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • client-go의 Reflector와 Watcher의 차이?
    Kubernetes 2025. 3. 2. 11:41
    728x90

     

    Kubernetes client-go 라이브러리에서 ReflectorWatcher는 둘 다 Kubernetes API 서버에서 데이터를 감시(watch)하는 역할을 하지만, 동작 방식과 목적이 다릅니다.

     

    Watcher는 저수준 API, Reflector는 캐싱을 지원하는 고수준 API!

     

    1️⃣ Watcher: API 서버의 watch 스트림을 직접 관리

    🔹 개념

    • Watcher는 API 서버의 watch 엔드포인트를 직접 호출하여 리소스 변경 사항을 실시간으로 감지하는 저수준(LOW-level) 인터페이스입니다.
    • client-go에서 ListerWatcher 인터페이스를 사용하여 직접 구현할 수 있습니다.

    🔹 동작 방식

    1. Kubernetes API 서버의 watch 엔드포인트를 호출하여 변경 사항을 실시간으로 스트리밍함.
    2. 새로운 이벤트(추가, 수정, 삭제)가 발생하면 이를 직접 받아서 처리해야 함.
    3. 연결이 끊어지면 직접 다시 연결해야 함 (재연결 로직 필요).

     

    🔹 예제 코드 (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 서버 부하를 줄이기 위해 캐시를 유지하면서 동작함.

    🔹 동작 방식

    1. API 서버에서 LIST 요청을 보내 초기 데이터를 가져옴.
    2. API 서버에서 WATCH 스트림을 통해 실시간 변경 사항을 감지함.
    3. 데이터를 Store (캐시) 에 저장하여 빠른 조회 가능.
    4. 연결이 끊어지면 자동으로 다시 연결하여 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
Designed by Tistory.