Telemetry API로 확장용 실시간 원격 측정 데이터 접근하기

Telemetry API로 확장용 실시간 원격 측정 데이터 접근하기 (Accessing real-time telemetry data for extensions using the Telemetry API)

Telemetry API는 확장(extension)이 Lambda에서 직접 원격 측정 데이터를 받을 수 있게 해줘요. 함수 초기화와 호출 동안 Lambda는 로그, 플랫폼 지표, 플랫폼 트레이스를 포함한 원격 측정을 자동으로 캡처해요. Telemetry API는 확장이 이 원격 측정 데이터를 Lambda에서 거의 실시간으로 직접 접근할 수 있게 해줘요.

Lambda 실행 환경 안에서 Lambda 확장을 원격 측정 스트림에 구독할 수 있어요. 구독 후 Lambda는 모든 원격 측정 데이터를 확장에게 자동으로 보내요. 그런 다음 데이터를 처리·필터링·전달해 Amazon Simple Storage Service(Amazon S3) 버킷이나 타사 관측성 도구 제공자 같은 선호하는 대상으로 보낼 수 있어요.

중요

Lambda Telemetry API는 Lambda Logs API를 대체해요. Logs API가 완전히 작동하지만 앞으로는 Telemetry API만 사용할 것을 권장해요. Telemetry API나 Logs API 중 하나로 확장을 원격 측정 스트림에 구독할 수 있어요. 둘 중 하나로 구독한 후 다른 API로 구독하려 하면 오류가 반환돼요.

참고

Lambda Managed Instances는 Telemetry API의 2025-01-29 스키마 버전만 지원해요. Managed Instance 함수의 원격 측정 스트림에 구독할 때 구독 요청에 "schemaVersion": "2025-01-29"를 사용해야 해요. 이전 스키마 버전을 사용하면 Lambda가 이벤트를 거부해요.

2025-01-29 스키마 버전은 하위 호환되며 Lambda Managed Instances와 Lambda(기본값) 함수 모두에 사용할 수 있어요. 두 배포 모델에서의 호환성을 위해 모든 새 확장에 이 버전을 사용하는 것을 권장해요.

확장은 Telemetry API로 세 가지 서로 다른 원격 측정 스트림에 구독할 수 있어요.

  • 플랫폼 원격 측정(Platform telemetry) – 실행 환경 런타임 수명 주기, 확장 수명 주기, 함수 호출과 관련된 이벤트와 오류를 설명하는 로그, 지표, 트레이스.
  • 함수 로그(Function logs) – Lambda 함수 코드가 생성하는 커스텀 로그.
  • 확장 로그(Extension logs) – Lambda 확장 코드가 생성하는 커스텀 로그.

참고

확장이 원격 측정 스트림에 구독해도 Lambda는 로그와 지표를 CloudWatch로, 트레이스는 X-Ray로(추적을 활성화한 경우) 계속 보내요.

출처: AWS Lambda 개발자 안내서

본문

Telemetry API로 확장 만들기

Lambda 확장은 실행 환경의 독립 프로세스로 실행돼요. 확장은 함수 호출이 완료된 후에도 계속 실행될 수 있어요. 확장은 별도 프로세스이므로 함수 코드와 다른 언어로 작성할 수 있어요. Golang이나 Rust 같은 컴파일 언어로 확장을 작성할 것을 권장해요. 이렇게 하면 확장이 자체 포함 이진 파일이 되어 어떤 지원 런타임과도 호환될 수 있어요.

Telemetry API를 사용해 원격 측정 데이터를 받고 처리하는 확장을 만드는 4단계 프로세스는 다음과 같아요.

  1. Lambda Extensions API를 사용해 확장을 등록합니다. 이렇게 하면 다음 단계에서 필요한 Lambda-Extension-Identifier를 얻습니다.
  2. 원격 측정 리스너를 만듭니다. 기본 HTTP 또는 TCP 서버일 수 있습니다. Lambda는 원격 측정 리스너의 URI를 사용해 원격 측정 데이터를 확장에게 보냅니다.
  3. Telemetry API의 Subscribe API를 사용해 확장을 원하는 원격 측정 스트림에 구독합니다. 이 단계에서는 원격 측정 리스너의 URI가 필요합니다.
  4. 원격 측정 리스너를 통해 Lambda에서 원격 측정 데이터를 받습니다. 이 데이터에 Amazon S3로의 전달이나 외부 관측성 서비스로의 전송 같은 커스텀 처리를 할 수 있습니다.

참고

Lambda 함수의 실행 환경은 수명 주기의 일부로 여러 번 시작·중지될 수 있어요. 일반적으로 확장 코드는 함수 호출 중과 종료(Shutdown) 단계에서 최대 2초 동안 실행돼요. 원격 측정이 리스너에 도착할 때 배치하는 것을 권장해요. 그런 다음 Invoke와 Shutdown 수명 주기 이벤트를 사용해 각 배치를 원하는 대상으로 보내세요.

확장 등록

원격 측정 데이터를 구독하기 전에 Lambda 확장을 등록해야 해요. 등록은 확장 초기화 단계에서 발생해요. 다음 예시는 확장을 등록하는 HTTP 요청이에요.

POST http://${AWS_LAMBDA_RUNTIME_API}/2020-01-01/extension/register
 Lambda-Extension-Name: lambda_extension_name
{
    'events': [ 'INVOKE', 'SHUTDOWN']
}

요청이 성공하면 구독자는 HTTP 200 성공 응답을 받아요. 응답 헤더에는 Lambda-Extension-Identifier가 포함돼요. 응답 본문에는 함수의 다른 속성이 포함돼요.

HTTP/1.1 200 OK
Lambda-Extension-Identifier: a1b2c3d4-5678-90ab-cdef-EXAMPLE11111
{
    "functionName": "lambda_function",
    "functionVersion": "$LATEST",
    "handler": "lambda_handler",
    "accountId": "123456789012"
}

원격 측정 리스너 만들기

Lambda 확장에는 Telemetry API의 들어오는 요청을 처리하는 리스너가 있어야 해요. 다음 코드는 Golang으로 된 예시 원격 측정 리스너 구현이에요.

// Starts the server in a goroutine where the log events will be sent
func (s *TelemetryApiListener) Start() (string, error) {
	address := listenOnAddress()
	l.Info("[listener:Start] Starting on address", address)
	s.httpServer = &http.Server{Addr: address}
	http.HandleFunc("/", s.http_handler)
	go func() {
		err := s.httpServer.ListenAndServe()
		if err != http.ErrServerClosed {
			l.Error("[listener:goroutine] Unexpected stop on Http Server:", err)
			s.Shutdown()
		} else {
			l.Info("[listener:goroutine] Http Server closed:", err)
		}
	}()
	return fmt.Sprintf("http://%s/", address), nil
}

// http_handler handles the requests coming from the Telemetry API.
// Everytime Telemetry API sends log events, this function will read them from the response body
// and put into a synchronous queue to be dispatched later.
// Logging or printing besides the error cases below is not recommended if you have subscribed to
// receive extension logs. Otherwise, logging here will cause Telemetry API to send new logs for
// the printed lines which may create an infinite loop.
func (s *TelemetryApiListener) http_handler(w http.ResponseWriter, r *http.Request) {
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		l.Error("[listener:http_handler] Error reading body:", err)
		return
	}

	// Parse and put the log messages into the queue
	var slice []interface{}
	_ = json.Unmarshal(body, &slice)

	for _, el := range slice {
		s.LogEventsQueue.Put(el)
	}

	l.Info("[listener:http_handler] logEvents received:", len(slice), " LogEventsQueue length:", s.LogEventsQueue.Len())
	slice = nil
}

대상 프로토콜 지정

Telemetry API로 원격 측정을 받도록 구독할 때 대상 URI에 더해 대상 프로토콜을 지정할 수 있어요.

{
    "destination": {
        "protocol": "HTTP",
        "URI": "http://sandbox.localdomain:8080"
    }
}

Lambda는 원격 측정을 받는 두 가지 프로토콜을 허용해요.

  • HTTP(권장) – Lambda는 JSON 형식의 레코드 배열로 로컬 HTTP 엔드포인트(http://sandbox.localdomain:${PORT}/${PATH})에 원격 측정을 전달합니다. $PATH 파라미터는 선택 사항입니다. Lambda는 HTTP만 지원하며 HTTPS는 지원하지 않습니다. Lambda는 POST 요청으로 원격 측정을 전달합니다.
  • TCP – Lambda는 NDJSON(Newline delimited JSON) 형식으로 TCP 포트에 원격 측정을 전달합니다.

참고

TCP보다 HTTP를 사용할 것을 강력히 권장해요. TCP에서는 Lambda 플랫폼이 애플리케이션 계층에 원격 측정을 전달했는지 확인할 수 없어요. 따라서 확장이 크래시하면 원격 측정을 잃을 수 있어요. HTTP에는 이 제한이 없어요.

원격 측정을 받도록 구독하기 전에 로컬 HTTP 리스너나 TCP 포트를 설정하세요. 설정 중 다음을 참고하세요.

  • Lambda는 실행 환경 안의 대상에만 원격 측정을 보냅니다.
  • 리스너가 없거나 POST 요청이 오류를 만나면 Lambda는 (백오프와 함께) 원격 측정 전송을 재시도합니다. 원격 측정 리스너가 크래시하면 Lambda가 실행 환경을 다시 시작한 후 원격 측정 수신을 재개합니다.
  • Lambda는 포트 9001을 예약합니다. 다른 포트 번호 제한이나 권장 사항은 없습니다.

메모리 사용과 버퍼링 구성

실행 환경의 메모리 사용은 구독자 수에 따라 선형적으로 늘어나요. 각 구독은 원격 측정 데이터를 저장하는 새 메모리 버퍼를 열기 때문에 메모리 리소스를 소비해요. 버퍼 메모리 사용은 실행 환경의 전체 메모리 소비에 기여해요.

Telemetry API로 원격 측정을 받도록 구독할 때 원격 측정 데이터를 버퍼링하고 배치로 구독자에게 전달하는 옵션을 선택할 수 있어요. 메모리 사용을 최적화하려면 버퍼링 구성을 지정할 수 있어요.

{
    "buffering": {
        "maxBytes": 256*1024,
        "maxItems": 1000,
        "timeoutMs": 100
    }
}
파라미터 설명 기본값과 한도
maxBytes 메모리에 버퍼링할 최대 원격 측정량(바이트) 기본값: 262,144. 최소: 262,144. 최대: 1,048,576
maxItems 메모리에 버퍼링할 최대 이벤트 수 기본값: 10,000. 최소: 1,000. 최대: 10,000
timeoutMs 배치를 버퍼링할 최대 시간(밀리초) 기본값: 1,000. 최소: 25. 최대: 30,000

버퍼링을 설정할 때 다음 사항을 참고하세요.

  • 입력 스트림 중 하나가 닫히면 Lambda가 로그를 플러시합니다. 예를 들어 런타임이 크래시하면 이렇게 될 수 있습니다.
  • 각 구독자는 구독 요청에서 자신의 버퍼링 구성을 커스터마이즈할 수 있습니다.
  • 데이터를 읽을 버퍼 크기를 결정할 때 2 * maxBytes + metadataBytes만큼 큰 payload를 받을 수 있다고 예상하세요. 여기서 maxBytes는 버퍼링 설정의 구성 요소입니다. Lambda는 각 레코드에 다음과 유사한 메타데이터를 추가합니다.
    {
       "time": "2022-08-20T12:31:32.123Z",
       "type": "function",
       "record": "Hello World"
    }
    
  • 구독자가 들어오는 원격 측정을 충분히 빨리 처리하지 못하거나 함수 코드가 매우 높은 로그 볼륨을 생성하면 Lambda는 메모리 사용을 제한하기 위해 레코드를 버릴 수 있습니다. 이때 Lambda는 platform.logsDropped 이벤트를 보냅니다.

Telemetry API에 구독 요청 보내기

Lambda 확장은 Telemetry API에 구독 요청을 보내 원격 측정 데이터를 받도록 구독할 수 있어요. 구독 요청은 확장이 구독하려는 이벤트 유형에 대한 정보를 담아야 해요. 또한 요청은 전달 대상 정보와 버퍼링 구성을 포함할 수 있어요.

구독 요청을 보내기 전에 확장 ID(Lambda-Extension-Identifier)가 있어야 해요. Extensions API로 확장을 등록하면 API 응답에서 확장 ID를 얻어요.

구독은 확장 초기화 단계에서 발생해요. 다음 예시는 플랫폼 원격 측정, 함수 로그, 확장 로그 세 가지 원격 측정 스트림 모두를 구독하는 HTTP 요청이에요.

PUT http://${AWS_LAMBDA_RUNTIME_API}/2022-07-01/telemetry HTTP/1.1
{
   "schemaVersion": "2025-01-29",
   "types": [
        "platform",
        "function",
        "extension"
   ],
   "buffering": {
        "maxItems": 1000,
        "maxBytes": 256*1024,
        "timeoutMs": 100
   },
   "destination": {
        "protocol": "HTTP",
        "URI": "http://sandbox.localdomain:8080"
   }
}

요청이 성공하면 구독자는 HTTP 200 성공 응답을 받아요.

HTTP/1.1 200 OK
"OK"

인바운드 Telemetry API 메시지

Telemetry API로 구독한 후 확장은 POST 요청을 통해 Lambda에서 자동으로 원격 측정을 받기 시작해요. 각 POST 요청 본문에는 Event 객체의 배열이 포함돼요. 각 Event는 다음 스키마를 가져요.

{
   time: String,
   type: String,
   record: Object
}
  • time 속성은 Lambda 플랫폼이 이벤트를 생성한 시점을 정의합니다. 이는 이벤트가 실제로 발생한 시점과 다릅니다. time의 문자열 값은 ISO 8601 형식의 타임스탬프입니다.
  • type 속성은 이벤트 유형을 정의합니다.
  • record 속성은 원격 측정 데이터를 담은 JSON 객체를 정의합니다. 이 JSON 객체의 스키마는 type에 따라 달라집니다.

동시 호출의 이벤트 순서

Lambda Managed Instances의 경우 여러 함수 호출이 같은 실행 환경 안에서 동시에 실행될 수 있어요. 이 경우 서로 다른 동시 호출 사이의 platform.start와 platform.report 이벤트 순서는 보장되지 않아요. 확장은 병렬로 실행되는 여러 호출의 이벤트를 처리해야 하며 순차적 순서를 가정하면 안 돼요.

이벤트를 특정 호출에 올바르게 귀속하려면 확장이 이 플랫폼 이벤트에 있는 requestId 필드를 사용해야 해요. 각 호출에는 해당 호출의 모든 이벤트에서 일관된 고유 요청 ID가 있어, 확장이 순서가 어긋나 도착해도 이벤트를 올바르게 상호 연관시킬 수 있어요.

다음 표는 모든 Event 객체 유형을 요약하고 각 이벤트 유형의 Telemetry API Event 스키마 참조에 연결해요.

카테고리 이벤트 유형 설명
플랫폼 이벤트 platform.initStart 함수 초기화 시작
플랫폼 이벤트 platform.initRuntimeDone 함수 초기화 완료
플랫폼 이벤트 platform.initReport 함수 초기화 보고
플랫폼 이벤트 platform.start 함수 호출 시작
플랫폼 이벤트 platform.runtimeDone 런타임이 이벤트 처리를 성공 또는 실패로 완료
플랫폼 이벤트 platform.report 함수 호출 보고
플랫폼 이벤트 platform.restoreStart 런타임 복원 시작
플랫폼 이벤트 platform.restoreRuntimeDone 런타임 복원 완료
플랫폼 이벤트 platform.restoreReport 런타임 복원 보고
플랫폼 이벤트 platform.telemetrySubscription 확장이 Telemetry API 구독
플랫폼 이벤트 platform.logsDropped Lambda가 로그 항목 삭제
함수 로그 function 함수 코드의 로그 줄
확장 로그 extension 확장 코드의 로그 줄

더 알아보기 (Learn more)