의외로 단순한 Lambda Runtime API를 구성하는 프로토콜과 SST가 로컬에서 이를 에뮬레이션하는 방법을 살펴봅니다.
의외로 단순한 Lambda Runtime API 상세 분석
Oct 06, 2021
3 min read
지난 몇 주 동안, 로컬에서 Lambda 함수가 실행되는 방식에 큰 변화를 포함한 Serverless Stack (SST) 업데이트를 작업해 왔습니다.
저는 개발 중에는 가능한 한 실제 AWS 서비스를 최대한 사용하는 것을 일반적으로 권장하지만, SST는 전체를 AWS로 업로드할 때까지 기다리지 않고도 코드 변경 사항이 즉시 반영되도록 함수를 로컬에서 실행할 수 있게 해줍니다.
이를 프로덕션에서 동작하는 방식과 일치시키기 위해, 우리는 AWS가 여러분의 코드를 호출하는 방식을 매우 가깝게 미러링합니다. 이는 많은 작업처럼 보일 수 있지만, 실제로는 이 글에서 알아볼 꽤 단순한 프로토콜입니다.
여러분의 코드가 AWS에서 실행될 때는 Lambda Runtime API.에 접근할 수 있습니다. 이는 다음 엔드포인트를 노출하는 꽤 단순한 API입니다:
GET /runtime/invocation/next
POST /runtime/invocation/<aws-request-id>/response
POST /runtime/invocation/<aws-request-id>/error
함수가 부팅되면, 사용 중인 언어에 특화된 API 클라이언트를 실행합니다. 이 클라이언트는 자신의 프로세스에 여러분의 핸들러를 로드한 다음, /runtime/invocation/next 엔드포인트로 요청을 보냅니다.

이 엔드포인트는 여러분의 Lambda가 처리해야 할 요청이 들어올 때까지 블로킹됩니다. 요청이 발생하면, 여러분의 lambda로 전달해야 하는 페이로드를 반환합니다.

이제 API 클라이언트가 페이로드를 갖고 있으므로, 페이로드를 인자로 넘겨 여러분의 핸들러를 호출합니다.
핸들러가 성공하면, 결과를 /runtime/invocation/<aws-request-id>로 POST합니다.
핸들러가 실패하면, 에러를 /runtime/invocation/<aws-request-id>로 POST합니다.

Lambda Runtime API는 결과를 필요한 곳으로 전달하는 일을 처리합니다. 이제 API 클라이언트는 /runtime/invocation/next로 요청을 보내며 사이클을 다시 시작합니다. 참고로 이번에는 핸들러를 다시 import할 필요가 없는데, 이것이 매 호출마다 콜드 스타트가 발생하지 않는 이유입니다.
그리고 이게 전부입니다! 프로토콜은 그만큼 단순하며, 이를 재현하는 것은 이 3개의 엔드포인트를 구현하는 것만 의미합니다.
SST에서는 함수가 로컬에서 실행되기 때문에 로컬 Lambda Runtime API가 필요합니다. 우리는 동일한 세 엔드포인트를 에뮬레이션하고 websocket을 통해 여러분의 AWS 계정에 연결되는 가짜 버전을 제공합니다.
함수를 호출하기 위한 요청이 들어오면, 그것은 websocket으로 전달되고 /runtime/invocation/next 엔드포인트를 통해 여러분의 로컬 코드로 전달됩니다. 이후 응답은 다시 AWS로 전송됩니다.
이것이 변경마다 코드를 업로드하지 않고도 프로덕션 환경을 미러링하는 방법입니다. 여러분의 코드는, 찾고 있던 Lambda Runtime API를 발견할 수 있기 때문에, 자신이 AWS에서 실행되고 있지 않다는 것을 알아차릴 수 없습니다.
SST는 여러 언어를 지원하므로, 여러분은 우리가 언어마다 API 클라이언트를 다시 만들어야 했다고 생각할 수도 있습니다. 하지만 AWS는 실제로 네이티브로 지원하는 다양한 언어용 클라이언트를 오픈 소스로 공개하고 있습니다. 몇 가지 예: NodeJS, Go, 그리고 .NET
이 클라이언트들은 AWS_LAMBDA_RUNTIME_API 환경 변수를 받아들이는 표준까지 따르므로, 우리가 이들을 로컬 인스턴스로 향하게 할 수 있습니다. 마치 AWS가 우리가 이렇게 하길 원했던 것 같습니다.
새 언어에 대한 지원을 추가하고 싶다면, 이 3개의 엔드포인트와 통신할 수 있고 여러분의 코드를 실행할 수 있는 API 클라이언트를 작성하기만 하면 됩니다. 원한다면 bash로도 작성할 수 있는데, 이 Deno 구현이 바로 그렇게 하고 있습니다
이 모든 것이 어떻게 동작하는지, 그리고 얼마나 단순한지 이해하고 나서도 우리가 SST에서 하고 있는 작업이 너무 시시하게 느껴지지 않기를 바랍니다.
우리는 로컬에서 실행할 때 SST가 가능한 한 최소한만 더하도록 의도적으로 보장해, 모든 것이 프로덕션과 동일하게 계속 동작하도록 합니다. 클라우드 우선 개발이 정답이며, 이는 그 경험을 더 매끄럽게 만들기 위한 작은 예외일 뿐입니다.