Amazon Web Services 한국 블로그

Amazon CloudFront KeyValueStore 출시 – CloudFront Functions를 위한 지연 시간이 짧은 데이터 스토어

Amazon CloudFront를 사용하면 짧은 지연 시간과 빠른 전송 속도로 정적 및 동적 콘텐츠를 안전하게 전송할 수 있습니다. CloudFront Functions를 사용하면 초당 수백만 건의 요청에 대해 지연 민감도 사용자 설정을 수행할 수 있습니다. 예를 들어 CloudFront Functions를 사용하여 헤더를 수정하거나, 캐시 키를 정규화하거나, URL을 재작성하거나, 요청을 승인할 수 있습니다.

오늘 소개해 드리는 CloudFront KeyValueStore는 CloudFront 엣지 로케이션에서 고급 사용자 지정 로직을 활성화하여 CloudFront Functions 내에서 읽기 액세스를 허용하는 안전한 글로벌 저지연 키 값 데이터 스토어입니다.

이전에는 함수 코드 내에 구성 데이터를 임베드해야 했습니다. 예를 들어, URL을 리디렉션해야 하는지 여부와 시청자를 리디렉션할 URL을 결정하는 데 사용되는 데이터가 이에 해당합니다. 함수 코드로 구성 데이터를 임베드하면 구성을 조금 변경할 때마다 코드를 변경하고 함수 코드를 재배포해야 합니다. 새로 조회를 추가할 때마다 코드를 업데이트하고 배포하면 실수로 코드가 변경될 위험이 있습니다. 또한 최대 함수 크기가 10KB이므로, 많은 사용 사례에서 코드 내의 모든 데이터가 꼭 맞기 어렵습니다.

CloudFront KeyValueStore를 사용하면 이제 함수 관련 데이터와 함수 코드를 서로 독립적으로 업데이트할 수 있습니다. 이렇게 하면 함수 코드가 간소화되고 코드 변경 내용을 배포할 필요 없이 데이터를 쉽게 업데이트할 수 있습니다.

이제 실제로 어떻게 작동하는지 알아보겠습니다.

CloudFront 키 값 스토어 생성
CloudFront 콘솔의 탐색 창에서 Functions(함수)를 선택합니다. KeyValueStores 탭에서 Create KeyValueStore(KeyValueStore 생성)를 선택합니다.

여기서는 Amazon Simple Storage Service(Amazon S3) 버킷의 JSON 파일에서 키 값 페어를 가져올 수 있는 옵션이 있습니다. 키가 없는 상태에서 시작하려 하기 때문에 지금은 그렇게 하지 않습니다. 이름과 설명을 입력하고 키 값 스토어 생성을 완료합니다.

콘솔 스크린샷.

키 값 스토어가 생성되면 Key value pairs(키 값 페어) 섹션에서 Edit(편집)을 선택한 다음 Add pair(페어 추가)를 선택합니다. 키에는 hello를 입력하고 값에는 Hello World를 입력하고 변경 사항을 저장합니다. 키와 값을 더 추가할 수 있지만 지금은 키 하나면 충분합니다.

콘솔 스크린샷.

키 값 스토어를 업데이트하면 변경 사항이 몇 초 내에 모든 CloudFront 엣지 로케이션에 전파되므로 키 값 스토어와 연결된 함수에서 짧은 지연 시간으로 사용할 수 있습니다. 이제 작동 방식을 살펴보겠습니다.

CloudFront Functions에서 CloudFront KeyValueStore 사용
CloudFront 콘솔의 탐색 창에서 Functions(함수)를 선택한 다음 Create function(함수 생성)을 선택합니다. 함수 이름을 입력하고 cloudfront-js-2.0 런타임을 선택한 다음 함수 생성을 완료합니다. 그런 다음 새 옵션을 사용하여 키 값 스토어를 이 함수와 연결합니다.

콘솔 스크린샷.

콘솔에서 키 값 스토어 ID를 복사하여 다음 함수 코드에서 사용합니다.

import cf from 'cloudfront';

const kvsId = '<KEY_VALUE_STORE_ID>';

//키 값 스토어가 함수와 연결되어 있지 않으면 실패합니다
const kvsHandle = cf.kvs(kvsId);

async function handler(event) {
    //경로 이름의 첫 부분을 키로 사용합니다. 예: http(s)://domain/<key>/something/else
    const key = event.request.uri.split('/')[1]
    let value = "Not found" // Default value
    try {
        value = await kvsHandle.get(key);
    } catch (err) {
        console.log(`Kvs key lookup failed for ${key}: ${err}`);
    }
    var response = {
        statusCode: 200,
        statusDescription: 'OK',
        body: {
            encoding: 'text',
            data: `Key: ${key} Value: ${value}\n`
        }
    };
    return response;
}

이 함수는 요청 경로의 첫 부분을 키로 사용하고 키 이름과 값으로 응답합니다.

변경 사항을 저장하고 함수를 게시합니다. 함수의 Publish(게시) 탭에서 함수를 이전에 생성한 CloudFront 배포와 연결합니다. Viewer Request(시청자 요청) 이벤트 유형과 Default (*)(기본) 캐시 동작을 사용하여 배포에 대한 모든 요청을 가로챕니다.

콘솔에서 함수 목록으로 돌아가서 함수가 배포될 때까지 기다립니다. 그런 다음 명령줄에서 curl을 사용하여 배포에서 콘텐츠를 다운로드하고 함수의 결과를 테스트합니다.

먼저 함수를 간접적으로 호출하고 이전에 만든 키를 조회하는 몇 가지 경로를 사용해 봅니다(hello).

curl https://distribution-domain.cloudfront.net/hello
Key: hello Value: Hello World

curl https://distribution-domain.cloudfront.net/hello/world
Key: hello Value: Hello World

제대로 작동합니다! 그런 다음 다른 경로로 시도하여 키를 찾지 못할 때 코드에 사용한 기본 값이 반환되는지 확인합니다.

curl https://distribution-domain.cloudfront.net/hi
Key: hi Value: Not found

이제 이 첫 번째 예제가 제대로 작동하므로 좀 더 유용한 고급 설정을 시도해 보겠습니다.

CloudFront KeyValueStore의 구성 데이터를 사용하여 URL을 다시 작성
HTTP 요청의 URL 콘텐츠를 사용하여 CloudFront가 실제 요청을 할 때 사용해야 하는 사용자 지정 경로를 키 값 스토어에서 조회하는 함수를 구축해 보겠습니다. 이 함수는 웹 사이트의 일부인 여러 서비스를 관리하는 데 도움이 될 수 있습니다.

예를 들어, 제 웹사이트에 사용하는 블로그 플랫폼을 업데이트하고 싶습니다. 이전 블로그에는 오리진 경로 /blog-v1이 있고 새 블로그에는 오리진 경로 /blog-v2가 있습니다.

아키텍처 다이어그램.

처음에는 예전 블로그를 계속 사용하고 있습니다. CloudFormation 콘솔에서 blog-v1 값이 포함된 키 값 스토어에 blog 키를 추가합니다.

그런 다음, 다음 함수를 만들고 Viewer Request(시청자 요청) 이벤트 및 Default (*)(기본) 캐시 동작을 사용하여 배포에 대한 모든 요청을 가로채는 배포에 연결합니다.

import cf from 'cloudfront';

const kvsId = "<KEY_VALUE_STORE_ID>";

//키 값 스토어가 함수와 연결되어 있지 않으면 실패합니다
const kvsHandle = cf.kvs(kvsId);

async function handler(event) {
    const request = event.request;
    // 경로 이름의 첫 번째 세그먼트를 키로 사용합니다
    // 예: http(s)://domain/<key>/something/else
    const pathSegments = request.uri.split('/')
    const key = pathSegments[1]
    try {
        // 경로 이름의 첫 번째 경로를 키 값으로 바꿉니다
        // 예: http(s)://domain/<value>/something/else
        pathSegments[1] = await kvsHandle.get(key);
        const newUri = pathSegments.join('/');
        console.log(`${request.uri} -> ${newUri}`)
        request.uri = newUri;
    } catch (err) {
        // 키를 찾을 수 없는 경우 경로 이름이 변경되지 않습니다
        console.log(`${request.uri} | ${err}`);
    }
    return request;
}

이제 URL 경로의 시작 부분에 blog를 입력하면 요청이 실제로 blog-v1 경로로 이동합니다. blog-v1은 이전 블로그에서 사용한 오리진 경로이므로 CloudFront는 이전 블로그에 HTTP 요청을 보냅니다.

예를 들어 브라우저에 https://distribution-domain.cloudfront.net/blog/index.html을 입력하면 이전 블로그(V1)가 표시됩니다.

블로그 V1을 보여주는 브라우저 스크린샷.

콘솔에서 blog 키를 blog-v2 값으로 업데이트합니다. 몇 초 후 동일한 URL에 액세스하면 이제 새 블로그(V2)에 도달합니다.

블로그 V2를 보여주는 브라우저 스크린샷.

보시다시피 공개 URL은 동일하지만 내용이 변경되었습니다. 보다 일반적으로 이 함수는 두 블로그 버전 간에 URL이 변경되지 않는다고 가정합니다.

이제 웹사이트에 포함된 다양한 서비스(블로그, 지원, 도움말, 상거래 등)에 대해 키를 더 추가하고 각 서비스에 대해 올바른 URL 경로를 사용하도록 값을 설정할 수 있습니다. 그 중 하나에 새 버전을 추가할 때(예: 새 상거래 플랫폼으로 마이그레이션하는 경우) 새 오리진을 구성하고 새 오리진 경로를 사용하도록 해당 키를 업데이트할 수 있습니다.

이는 구성 데이터를 코드에서 분리할 때 얻을 수 있는 유연성의 한 예시일 뿐입니다. 이미 CloudFront Functions를 사용하고 있다면 CloudFront KeyValueStore를 사용하여 코드를 간소화할 수 있습니다.

알아야 할 사항
CloudFront KeyValueStore는 현재 전 세계 모든 엣지 로케이션에서 사용할 수 있습니다. CloudFront KeyValueStore를 사용하면 퍼블릭 API의 읽기/쓰기 작업과 CloudFront Functions 내에서의 읽기 작업을 기반으로 사용한 만큼만 비용을 지불합니다. 자세한 내용은 CloudFront 요금을 참조하십시오.

AWS Management Console, AWS Command Line Interface(AWS CLI), AWS SDK를 사용하여 키 값 스토어를 관리할 수 있습니다. AWS CloudFormation 지원도 곧 제공 예정입니다. 키 값 스토어의 최대 크기는 5MB이며 단일 키 값 스토어를 각 함수에 연결할 수 있습니다. 키의 최대 크기는 512바이트입니다. 값은 최대 1KB까지 가능합니다. 키 값 스토어를 생성할 때 다음 JSON 구조의 Amazon S3에 있는 소스 파일을 사용하여 생성 중에 키/값 데이터를 가져올 수 있습니다.

{
  "data":[
    {
      "key":"key1",
      "value":"val1"
    },
    {
      "key":"key2",
      "value":"val2"
    }
  ]
}

생성 시 키/값 데이터를 가져오면 새 환경(예: 테스트 또는 개발) 설정을 자동화하고, 한 환경에서 다른 환경으로 구성을 쉽게 복제할 수 있습니다(예: 사전 프로덕션 환경에서 프로덕션 환경으로).

CloudFront KeyValueStore를 사용하여 엣지에 사용자 지정 로직을 추가하는 방식을 간소화합니다.

Danilo