Category: 한국 기술 문서


AWS Well-Architected Framework 기반 AWS GameDay 구성하기

GameDay는 몇 년 전부터 AWS Summits와 re:Invent에서 개최해 온 몰입형 팀 기반이벤트입니다. 도전적이고 재미있는 시나리오에 따라 진행되는 이 이벤트에서 각 참가 팀은 널리 기대되는 제품의 출시를 목전에 둔 인기 스타트업, Unicorn.Rentals를 DevOps의 입장에서 이끌어 갑니다. 자세한 내용은 GameDay 웹 사이트를 참조하십시오.

물론, GameDay를 효과적으로 만들기 위해 무대 뒤에서 많은 일을 진행하고 있습니다. 모든 열광적인 연기와 재미있는 소품 뒤에는 라이브 점수 추적 엔진, 게임하는 동안 로드를 실시간으로 변경할 수 있는 단일 인스턴스의 Load Generator, 다양한 명령과 제어 기능이 포함된 복잡한 AWS 인프라가 있습니다. 전체 인프라는 단순하게 설계되었지만 운영하기는 복잡하며, 게임 과정 중 플레이어에게 추천하는 똑같은 모범 사례를 통합하여 개선할 수 있는 여지가 있습니다.

AWS 파트너 솔루션스 아키텍트 팀에서는 오늘 플레이어 환경과 운영 방식을 개선하기 위해 표준 벤치마크인 AWS Well-Architected 프레임워크를 기준으로 GameDay 아키텍처를 검토했습니다. 검토 팀은 아키텍처를 상세히 이해하고, 설계와 의도에 대해 세부적인 질문을 한 다음, 우선 순위에 따라 결과를 정리한 문서를 제공할 것입니다.

1부

이 게시물에서는 초기 아키텍처 검토 결과 및 검토 팀에서 알아낸 정보를 살펴보겠습니다. 이번 개선 과정에 대한 소개와 앞으로 지속적인 개선 및 AWS 솔루션스 아키텍트와의 공동 작업을 통해 아키텍처를 향상하기 위한 계획은 향후 게시물을 통해 알려 드릴 예정입니다.

아키텍처 개요

먼저, 적절한 위치에서 다이어그램과 기타 부대 자료를 사용하여 다양한 구성 요소 및 관계를 강조하면서 GameDay의 아키텍처 개요를 검토 팀에게 제공하는 것으로 검토 세션을 시작했습니다. 독자의 이해를 돕기 위해 GameDay 아키텍처에 대해 검토 팀에게 제공한 고급 세부 정보를 요약하면 다음과 같습니다.

GameDay 인프라는 마스터 AWS 계정에서 실행되며, 각 팀에는 고유의 플레이어 AWS 계정이 있습니다(그림 1). 마스터 계정의 다양한 구성 요소는 플레이어 계정에 로드를 제공하고 점수표 및 비용 계산기와 같은 기타 서비스를 호스팅합니다. 마스터 계정은 각 플레이어 계정에서 일상적인 관리 작업을 수행하기 위한 필수 권한을 제공하는 IAM 교차 계정 역할을 이용합니다.

그림 1: 마스터 – 플레이어 계정 관계

마스터 계정에는 다음과 같은 구성 요소가 있습니다.

  1. 점수표 – 이 항목은 Amazon Simple Storage Service(Amazon S3) 버킷에서 호스팅하는 정적 사이트이며 JavaScript와 HTML로 작성됩니다.
  2. 비용 계산기 – 플레이어가 비용 최적화를 생각해 보도록 유도하기 위해 Amazon Elastic Computer Cloud(Amazon EC2) 이용 요금을 실제 세계와 같은 방식으로 부과합니다. 비용 계산기에는 소비에 비례하여 포인트를 차감하는 AWS Lambda 함수가 포함되어 있습니다.
  3. Amazon DynamoDBAmazon DynamoDB 테이블 여러 개에 팀 정보, 점수 정보, 일반 게임 구성 값 및 마스터 계정 구성 요소에서 사용하는 기타 지원 정보를 저장합니다.
  4. Load Generator – 이 구성 요소는 게임 구현의 핵심입니다. EC2 인스턴스 하나로 이루어진 이 Load Generator는 게임을 제어하고 관리 작업을 시작합니다.
    1. 플레이어 계정이 동적으로 생성되면 계정 생성 알림과 함께 마스터 계정의 Amazon Simple Notification Service(Amazon SNS) 주제에 메시지가 게시됩니다. Load Generator에서는 SNS 메시지를 기반으로 계정 등록/프로비저닝을 수행하기 위해 PHP 스크립트가 실행됩니다.
    2. Load Generator는 팀당 하나의 프로세스를 실행하여 각 플레이어의 계정에서 실행 중인 인프라에 연결을 시작합니다.
    3. 플레이어 계정에 제공되는 메시지 수는 이 Load Generator 인스턴스 내에서 팀별 추가 프로세스 생성에 따라 조정됩니다.

그림 2는 마스터 계정 아키텍처의 고급 개요를 보여 줍니다.

그림 2: 초기 아키텍처

심층 분석

검토 팀은 아키텍처를 이해한 후 심층 분석을 시작하여 Well-Architected Framework 백서의 부록에 있는 질문을 기반으로 다양한 구성 요소에 대해 심도 있는 질문을 했습니다. 특히 수작업(예: Load Generator의 작업), 재해 복구(예: 이벤트 전 손실된 자산의 복구 시간) 및 전체적인 애플리케이션 보안(예: 고객 데이터 및 자격 증명의 보안)에 높은 관심을 보였습니다. 전체 검토는 포괄적으로 이루어졌으며 완료하는 데 약 3시간 걸렸습니다.

검토 결과

검토 팀은 데이터를 통합하여 다양한 결과가 요약된 서면 보고서를 제공했습니다. 또한 검토 팀은 수정 계획을 개발하기 위한 시작점으로 삼을 수 있도록 각 결과에 대한 메모와 우선 순위에 따른 권장 사항도 제공했습니다.

Well-Architected Framework의 관점으로 GameDay를 살펴보면 많은 개선 기회가 있다는 점이 분명했습니다. AWS 검토 팀은 심각 및 권장이라는 두 가지 세트로 결과에 우선 순위를 지정했습니다. 대부분의 결과는 권장으로 분류되었으며, 이러한 결과는 즉각적인 위험이 없고 기존 로드맵에 통합됩니다. 하지만 심각으로 식별된 세 가지 요소는 즉시 처리해야 했습니다.

검토 팀이 제공한 결과 텍스트는 다음과 같습니다.

보안 11. 키를 어떻게 관리하고 있습니까?

  • 심각한 결과: GameDay용 레거시 관리 스크립트는 AWS 액세스 키와 보안 액세스 키를 사용하며 Amazon DynamoDB 테이블에 일반 텍스트로 저장됩니다.
  • 참고: 레거시 관리 스크립트는 플레이어 계정의 AWS API와 상호 작용하기 위해 AWS 액세스 키와 보안 액세스 키를 사용해야 하며, 교차 계정 역할을 지원하지 않습니다. 현재 이러한 키는 Amazon DynamoDB 테이블에 일반 텍스트로 저장되고 있으며, 스크립트는 이 테이블에 쿼리하여 키를 가져옵니다. AWS 액세스 키와 보안 액세스 키는 명시적으로 취소될 때까지 만료되지 않는 수명이 긴 자격 증명입니다. 이러한 키를 일반 텍스트로 저장하면 키가 손상될 가능성이 증가하며, 현재 설계에서는 DynamoDB 테이블에 읽기 액세스 권한이 있는 모든 사람이(애플리케이션 또는 애플리케이션 관리 인터페이스를 통해, 백업 또는 로그를 통해 간접적으로, 또는 AWS DynamoDB API를 통해 직접적으로) 키를 읽고 도용할 수 있습니다.
  • 권장: 교차 계정 역할을 지원하도록 레거시 관리 스크립트를 수정합니다. 그러면 AWS 액세스 키와 보안 액세스 키를 저장하여 사용할 필요가 없습니다.

안정성 7. 재해 복구를 어떻게 계획하고 있습니까?

  • 심각한 결과: 명확하게 정의된 재해 복구 계획, 복구 시점 목표(RPO) 또는 복구 시간 목표(RTO)가 없습니다. 또한 계획이 없기 때문에 RPO 및 RTO 목표를 기준으로 정기적으로 테스트할 수 없습니다.
  • 참고: GameDay는 원래 최소한으로 구성된 계정에서 플레이어가 반복적으로 실행하는 명령 세트로 계획되었습니다. 시간이 지나면서 도구 구성 및 부가 기능이 추가됨에 따라, 이전 단계로 돌아가서 전체 스택을 점검하고 우발적, 악의적 또는 환경적 결함으로부터 보호하는 방법을 고려할 수 없게 되었습니다. 단순한 게임일 뿐이지만, GameDay 고객은 하루 전체를 투자하여 참가하며 최대한 좋은 환경을 제공받을 자격이 있습니다. 이벤트 준비 중에 또는 라이브 게임 중에 허둥지둥 복구 프로세스를 만들어 내야 한다면 관련된 모든 사람에게 나쁜 경험이 될 것입니다.
  • 권장:
    1. RPO 및 RTO를 포함하여 재해 복구 계획을 정의합니다.
    2. 정의된 목표를 기준으로 계획을 정기적으로 테스트합니다.

안정성 2. 구성 요소 장애 시 시스템에서 어떻게 대처합니까?

  • 심각한 결과: 현재 Load Generator는 단일 가용 영역의 단일 인스턴스이며, 복구 옵션이 구성되지 않았습니다.
  • 참고: 하드웨어 결함 또는 가용 영역 장애(가능성은 낮음)가 발생할 경우 Load Generator 인스턴스가 장애를 일으키거나 사용 불가능하게 되면 장애 노드를 복구하기 위한 자동 프로세스가 없기 때문에 게임을 더 이상 계속할 수 없습니다. Load Generator는 현재 Auto Scaling 그룹에 속하지 않으며, EC2 인스턴스 복구도 구성되어 있지 않습니다. 또한 인스턴스가 수동으로 구성되었으며 필요한 모든 설정과 스크립트가 인스턴스에 포함되어 있지 않습니다. 마지막으로, 모든 상태가 인스턴스에 로컬로 저장되며 다중 인스턴스 아키텍처를 구현할 때 모든 상태를 세분화해야 합니다. 상태를 외부에 저장하면 인스턴스 장애로 인해 상태가 손실되는 문제도 완화할 수 있습니다.
  • 권장:
    1. 필요한 모든 구성 요소가 자체 완비된 Amazon 머신 이미지(AMI)를 생성하여 시작 구성이 포함된 EC2 Auto Scaling 그룹을 구현합니다. 선택 사항으로 사용자 데이터를 이용하여 필요한 모든 구성 요소를 준비할 수 있습니다.
    2. 여러 가용 영역에 걸쳐 Auto Scaling 그룹을 구성하여 아키텍처의 복원성과 내결함성을 향상합니다.
    3. 인스턴스를 상태 비저장으로 전환하여 장애가 발생할 경우 정보가 손실될 가능성을 낮춥니다.

다음 단계

검토 팀이 이 피드백과 해결해야 할 심각한 항목을 제공했으므로, 이제 이러한 결점을 해결하기 위한 수정 계획을 구성해야 합니다. 다음 블로그 게시물에서는 이 수정 계획을 살펴보고 이러한 항목을 해결하여 보안과 안정성을 향상하기 위한 계획 방법을 심층적으로 설명합니다.

2부

AWS Well-Architected 프레임워크 원칙을 활용하여 GameDay의 문제를 수정하는 프로젝트를 다룬 시리즈 중 두 번째 게시물을 시작해 보겠습니다. 이 프로세스의 개요, 초기 검토, 검토 팀에서 확인한 중요 결과 목록에 대해서는 본 게시물의 1부를 참조하십시오.

본 게시물에서는 검토 팀에서 확인한 중요 사항을 수정하기 위해 취한 조치를 다룹니다. 향후 게시물에서 지속적인 개선과 AWS 솔루션스 아키텍트와의 협업을 통해 아키텍처를 구체화하는 계획을 발표합니다.

결과 검토

검토 팀은 즉시 우선 순위를 정하여 수정하는 데 필요한 중요 사항 목록뿐 아니라 GameDay 아키텍처 로드맵에서 처리하도록 권장되는 일반 아이디어 목록의 우선 순위를 지정하고 수정하는 데 필요한 중요 결과 목록을 제공했습니다.

다음은 중요 항목입니다.

  • GameDay용 레거시 관리 스크립트는 Amazon DynamoDB 테이블의 일반 텍스트에 저장된 AWS 액세스 키와 보안 액세스 키를 사용합니다.
  • Load Generator는 복구 옵션을 전혀 구성하지 않은 단일 가용 영역의 단일 인스턴스입니다.
  • 재해 복구(DR) 계획이 명확하게 정의되지 않고, 복구 시점 목표(RPO)와 복구 시간 목표(RTO)가 설정되어 있지 않습니다.  또한, 재해 복구 계획이 RPO 및 RTO 목표를 기준으로 정기적으로 테스트되지 않았습니다.

검토 팀은 구현 전에 수정 계획을 기꺼이 검토할 것이라고 언급했으므로, 저희는 결함을 분석하고, 계획을 기록하고, 변경 전에 수정 사항을 실행하는 데 필요한 작업량을 대략적으로 추정할 것입니다.

다음은 필수 결과를 처리하기 위해 제안한 고급 수정 계획으로, 우선 순위 순서로 나열한 것입니다.

  • 교차 계정 역할을 사용하여 보안 키와 액세스를 사용하지 않습니다. 
    신속한 코드 검토의 경우 교차 계정 액세스를 개발하고 테스트하는 데 하루를 할애하고 지침을 업데이트하고 새 기능을 직원에게 교육시키는 데 추가 하루를 더 할애해야 한다고 제안했습니다. 이 수정 사항은 비교적 간단해 보이고 보안과 운영상의 이점을 모두 갖추고 있기 때문에 새 설계에 통합하기 위해 이 수정 사항을 최우선 순위에 놓기로 결정했습니다.
  • Load Generator의 경우 단일 인스턴스에서 클러스터링된 배포를 허용하는 컨테이너 모델로 전환합니다. 
    이 변경은 이전 액세스 키 수정 사항보다 약간 더 복잡했습니다. 로컬로 작성하지 않고 DynamoDB에 상태를 저장하도록 애플리케이션을 수정해야 했으며 다양한 애플리케이션과 바이너리를 Docker 컨테이너에 패키징해야 했습니다.  이 구성 요소별로 Amazon EC2 Container Service(Amazon ECS) 작업 정의와 서비스를 만들 계획을 세웠고, 이것은 예약과 작업 배치를 자동으로 관리할 것입니다. DynamoDB와 컨테이너로 전환하면 하드 코딩된 구성을 Auto Scaling 그룹 시작 구성으로 이동하고, 실행 시 변수 세트에 유리하게 하드 코딩된 모든 값을 제거하고, AWS CloudFormation 템플릿을 배포 메커니즘에 사용할 수 있게 됩니다.  정적 구성 파일이 아닌 DynamoDB와 Auto Scaling 그룹을 사용하기 위해 로드 관리 도구 및 게임 설정 스크립트를 업데이트해야 했다는 점을 감안하더라도 이러한 변경은 상당한 개선을 가져다 주고 전체 게임 흐름에 거의 영향을 미치지 않습니다. 새로운 기능을 개발하고 테스트하는 데 2주, 새로운 작업에서 문서를 업데이트하고 직원을 교육하는 데 일주일을 할애했습니다.
  • 재해 복구 계획을 세우고 이 계획을 검증합니다. Amazon ECS 및 Auto Scaling 그룹을 사용한 인프라 배포 자동화를 통해 재해 복구 계획을 간소화했지만 이는 완벽한 솔루션이 되지 못했습니다.  복구 프로세스에는 여전히 여러 문제점이 있었기 때문에 솔루션이 있지만 테스트하지 않았거나 최소한 여러 시나리오를 실행하면 계획을 이행할 때 프로세스의 문제점이 쉽게 드러날 것입니다.  계획을 세우는 데 추가로 1주일을 할애하고, 모든 비상 사태가 포함되어 예행 연습이 실시되었는지 확인하는 데 추가로 하루를 더 할애했습니다.

이 작업을 시작하기 전에 검토 팀에 계획을 전달하여 모든 요구 사항에 부합하도록 올바른 방향으로 진행했는지 확인했습니다.  검토 팀이 저희 작업에 동의하여 계획을 이행하기 시작했습니다.

최초 분석 및 아키텍처의 재구성

보기에는 목록이 간단해 보였지만 이들 항목에 공통적으로 근본적인 문제가 있음을 바로 깨닫게 되었습니다. 즉, 아키텍처가 상당히 단순하고 오래된 것은 물론, AWS 플랫폼의 최신 기능을 제대로 활용하지 못했습니다.  처음 GameDay를 빌드하던 당시에는 기능에 초점을 두고 이전 환경을 토대로 빌드했습니다.  따라서 이 아키텍처는 사실상 장애에 대비한 빌드, 재해 복구 기능 개선 필요성 등 최신 도구나 기법을 수용하지 못했습니다.

이러한 문제를 염두에 두고, 이 핵심 아키텍처 문제에 대처해야 한다는 사실을 깨달았으므로 중요한 사항 대다수를 해결하는 것은 물론 많은 일반 권장사항을 적용할 것입니다.  이 조치를 이행하기 위해 단일 인스턴스 Load Generator에서 Amazon ECS 클러스터에서 실행되는 Docker 컨테이터로 전환했습니다. 그 즉시 Multi-AZ 아키텍처의 이점을 활용하면서도 인프라를 확장하고 구성 요소 손실을 처리할 수 있게 되었습니다.  또한 AWS Lambda 함수로 실행되도록 Load Generator의 추가 서비스를 수정하자, 확장과 인프라 관리가 자동으로 처리되었습니다.

업데이트된 Amazon ECS 아키텍처

이 새로운 아키텍처를 실행하면서 이전 배포 프로세스에 수동 리소스 및 구성 생성이 포함되어 있다는 사실을 알게 되었습니다.  저희는 처음부터 인프라를 코드로 처리하고 AWS CloudFormation을 사용하여 환경을 정의하려는 확고한 입장을 취했습니다.  그 덕분에 수정 단계를 진행하고 새로운 재해 복구 계획을 세우는 데 중요한 역할을 담당하면서 인프라 버전을 쉽게 관리할 수 있었습니다.

문제 해결

문제 1: AWS 액세스 키

놀랍게도 이 항목은 가장 쉽게 해결할 수 있는 것으로 드러났습니다. AWS에는 계정 간 역할 기반 액세스를 지원하는 기능이 있습니다. AWS CloudFormation으로 관리자 계정과 플레이어 계정 구성을 이미 자동화했기 때문에 플레이어 계정에서 액세스/비밀 키 페어가 아닌 역할을 만들기 위한 템플릿 업데이트가 간단해 보였습니다.

처음에는 이 작업이 전체 코드 기반을 수정하여 sts:AssumeRole을 사용하는 방대한 작업이라고 생각했지만, 곧 간단한 작업임이 드러났습니다.  AWS SDK를 사용했고, 액세스 키와 IAM 역할이 기본 자격 증명 공급자 체인의 일부이고 SDK를 통해 완벽하게 지원되기 때문에 유일한 필수 변경은 액세스 키를 제거하고 맡을 역할 ARN을 전달하는 것이었습니다.

문제 2: Load Generator

이 문제를 해결하기 위해 단일 EC2 인스턴스에서 Amazon ECS 클러스터로 전환했습니다.  이 작업을 위해 팀 및 플레이어 데이터를 외부에 저장하도록 애플리케이션을 수정해야 했습니다.  이미 다른 메타데이터에서 Amazon DynamoDB를 사용하고 있었기 때문에 이 용도로도 이것을 선택했습니다.  Load Generator 컨테이너가 이제 임시로 사용되었고 새 서비스를 만들어 구성원을 추적하는 것이 아닌 업데이트를 푸시하려고 했기 때문에 DynamoDB로의 상태 전환 및 구성 폴링 작업은 필수적이었습니다.

Amazon ECS를 사용하면 Load Generator를 Amazon ECS 내부의 서비스로 작동할 수 있으므로 복잡한 분산 구성 관리 도구를 관리하지 않고도 게임 전체에서 애플리케이션을 확장할 수 있었습니다.  또한 내결함성을 강화하기 위해 세 가지 가용 영역에서 작업을 예약 및 배치하고 오류나 장애가 발생할 경우 컨테이너를 교체했습니다.

문제 3: 재해 복구

재해 복구는 시도한 수정 조치 중에서도 가장 난해한 작업이었습니다. 문제는 애플리케이션을 빠르고 안정적으로 배포해 주는 도구와 기법 활용에 대한 확장 계획을 이미 세웠기 때문에 기술적인 문제로만 국한되지 않았습니다. 그렇다면, 정의(재해를 어떻게 정의할 것인가?), 예상(합리적인 복구 시간 목표는?), 규정 준수(DR 테스트를 실행하는 주기는? 자동화할 수 있는 기능은? 테스트 프레임워크는 새 릴리스 이후에도 DR 계획의 유효성을 보장하는가?), 소유권(재해 선언 책임자는? 시간이 흐르면서 프로세스가 적절히 유지되도록 보장할 책임자는?)과 같은 과제는 해결이 더 어려운 과제입니까?

결국 이 모든 문제를 한꺼번에 해결하기 보다는 점증적이고 단계적인 접근 방식을 취하기로 결정했습니다. 시뮬레이션된 이벤트 손실(프로덕션 계정 제어력 상실)에 초점을 둔 시뮬레이션된 재난에 대한 대응 전략을 세우는 데 하루를 할애하고, 다른 결과를 작성하는 데 하루를 더 할애했습니다.

시뮬레이션된 테스트에는 시나리오 발표를 담당하는 중재자와 함께 팀원이 방 안에 앉아서 참여했으며 현재 보유한 모든 자료를 사용하여 복구 프로세스를 시뮬레이션했습니다. 중재자는 솔직한 태도로 응답하려고 노력하고, 시나리오가 진행되면서 세부 사항의 부연 설명을 할 것입니다. 복구 팀은 주의 사항을 기록하고, 허점, 행운 및 개선할 부분을 확인한 후 가장 중요한 유효 RTO 및 RPO를 기록합니다.

시나리오(프로덕션 계정 제어력을 완전히 상실)를 고려해 볼 때 우리가 취할 수 있는 유일하고도 안전한 대응은 이 계정을 포기하고 완전히 새로운 계정으로 복구를 시뮬레이션하는 것이었습니다. 이 목적으로 사용할 수 있도록 대부분 구성되지 않은 미사용 계정이 있어야 했고, RTO에서 계정 생성과 초기 설정을 고려해야 한다는 사실은 분명했습니다. 새 계정에서 게임 자산 배포는 새 CloudFormation 템플릿을 사용하면서 상당히 수월해졌고, 다행히 이 템플릿은 위반에 따른 영향을 받지 않는 다른 AWS 계정이 소유한 S3 버킷에 저장되어 있었습니다.

훨씬 더 큰 문제는 DynamoDB에 저장된 게임 데이터를 복구하는 일이었습니다. 현재 백업 계획은 수동으로 실행되었고, 소스 데이터와 동일한 계정 및 AWS 리전에 있는 S3 버킷에 푸시되었습니다. 확실히 기본 계정을 제어했던 공격자는 유일한 백업도 제어할 수 있을 것입니다. 계정 제어력을 상실한 이벤트에서 백업은 자동화되지 않고 액세스할 수 없기 때문에 RPO를 명확하게 정의할 수 없었습니다.  간단히 말해 이 시나리오에서는 복구 성공을 보장할 수 없었습니다.

이런 과제가 있더라도 DR 시뮬레이션은 꽤 성공적일 것이라고 생각했습니다. 복구를 테스트하고 실행 중인 작업(데이터 결합 해제, AWS CloudFormation을 통한 배포 자동화), 필요한 작업(자동화된 DynamoDB 백업 및 다른 계정의 S3 버킷에 감사 로깅), 현재 달성 가능한 RTO 및 RPO를 확인했습니다.

결국 직접적인 로드맵에 복구 및 감사 작업을 추가했고, 변경이 이뤄지고 새로운 재해가 예상되면 실제 대응 역량을 계속 조사할 수 있는 분기별 DR 시뮬레이션의 향후 케이던스에 동의했습니다.

결론

지금 시점에서 뒤돌아 보면 매우 취약한 아키텍처로 이 프로세스를 시작한 탓에 보안과 재해 복구 보안 및 재해 복구 관점에서 취약할 수 밖에 없었습니다.  우리의 단점을 확인하는 일은 내키지 않는 일이었지만, 유능한 AWS 솔루션 아키텍트들이 아키텍처를 단계별로 실행하면서 개선할 영역을 알려준 덕분에 변경 사항을 기록하고 우선 순위를 지정할 수 있었습니다.  이로써 한 걸음 물러나 잠재 문제를 계속 완화하면서 고객 환경 개선 작업에 주력하는 데 필요한 사항을 점검할 수 있었습니다.  이제 아키텍처에 대한 신뢰도가 훨씬 높아져 장애에 잘 대비할 수 있게 되었습니다.

그러나 재해 복구 시뮬레이션에서도 알 수 있듯이 GameDay 애플리케이션은 완벽하지 않습니다.  물론, 초기 검토에서 로드맵에 대한 권장 사항이 아직도 있습니다.  AWS에 새 기능이 추가되고 모범 사례가 업데이트되면서 다른 솔루션 아키텍트와 계속 협력하여 이러한 기능과 모범 사례를 아키텍처에 계속 통합하고 있습니다.

다음 게시물에서는 그 사이 AWS가 새로운 기능을 출시했다는 점을 고려하여 이 게시물에서 다룬 변경 사항을 적용한지 6개월이 되었을 때 어떤 일이 일어났는지 살펴보겠습니다.  이 새로운 기능에 대한 평가 과정을 거친 후 통합 가능한 부분을 살펴볼 것입니다.  그 외에도, 일반 항목에 대해서도 검토 팀과 어떤 방식으로 계속 협력했는지에 대해 다루겠습니다.

이 글은 AWS Partner 블로그에서 Ian Scofield, Juan Villa, and Mike Ruiz 가 작성한 Testing AWS GameDay with the AWS Well-Architected Framework  1부, 2부 등의 연재를 한국어로 번역하였습니다.

EC2 스팟 인스턴스로 Amazon ECS 콘테이너 클러스터 운영하기

Amazon EC2 컨테이너 서비스 (Amazon ECS)가 ECS 콘솔에서 Amazon EC2 스팟 인스턴스에 직접 ECS 클러스터를 시작하는 기능을 지원한다는 것을 알리게 되어 매우 기쁩니다.

스팟 인스턴스는 예비 Amazon EC2 컴퓨팅 용량에 입찰 할 수 있게 합니다. 스팟 인스턴스는 일반적으로 온 디맨드 인스턴스보다 50-90 % 저렴합니다. 스팟 인스턴스로 ECS 클러스터를 운영하면 기존의 컨테이너화 된 워크로드를 실행하는 비용을 줄이거나 동일한 예산을 유지하면서 컴퓨팅 용량을 2 ~ 10 배까지 증가시킬 수 있습니다. 혹은 둘 다 조합 할 수 있습니다!

스팟 인스턴스를 사용하면 인스턴스 시간당 지불 할 가격을 지정합니다. 스팟 인스턴스는 언제든지 당신의 입찰가가 현재 스팟 가격을 초과 할 경우 실행됩니다. 더 높은 스팟 가격으로 인해 인스턴스가 회수 된 경우 인스턴스가 실행된 부분 시간에 대해서는 비용이 청구되지 않습니다.

ECS 콘솔은 스팟 집합을 사용하여 스팟 인스턴스를 배포합니다. 스팟 집합은 최적의 가격으로 컨테이너 어플리케이션에 대해 요청한 목표 용량 (인스턴스 또는 vCPU 개수로 표현)을 배포하려고 시도합니다. 현재 입찰 가격 또는 사용 가능한 용량의 변경으로 인해 스팟 인스턴스가 회수 된 경우에도 스팟 집합은 목표 용량을 유지하려고 시도합니다.

컨테이너는 다수의 스팟 집합이 배포되는 여러 종류의 자원 풀과 잘 들어 맞습니다. 스팟 집합을 사용하면 여러 스팟 인스턴스풀 (인스턴스 유형 및 가용 영역 조합)에 용량을 프로비저닝 할 수 있어 애플리케이션 가용성을 향상시키고 시간이 지남에 따라 집합의 운영 비용을 절감할 수 있습니다.  스팟 집합과 함께 ECS가 제공하는 확장 가능하고 유연한 컨테이너 배치 시스템을 결합하면 컨테이너 작업 부하를 효율적으로 배치하고 비용의 일부만으로 규모에 관계없이 쉽게 클러스터를 관리 할 수 있습니다.

이전에는 스팟 인스턴스에 ECS 클러스터를 배포하는 것이 수동 프로세스였습니다. 이 글에서는 ECS 콘솔에서 새로운 스팟 집합 통합을 사용하여 컨테이너 작업 부하에 대한 고 가용성, 확장성 및 비용 절감 방법을 제시합니다. 또한 AWS CloudFormation을 사용하여 스팟 인스턴스에 자신의 ECS 클러스터를 구축하는 방법을 보여줍니다.

스팟 인스턴스에서 실행되는 ECS 클러스터 만들기
AWS 관리 콘솔을 사용하여 ECS 클러스터를 만들 수 있습니다.

  1. https://console.aws.amazon.com/ecs/에서 Amazon ECS 콘솔을 엽니다.
  2. 탐색 창에서 클러스터를 선택하십시오.
  3. 클러스터 페이지에서 클러스터 생성을 선택하십시오.
  4. 클러스터 이름에 이름을 입력하십시오.
  5. 인스턴스 구성에서 프로비저닝 모델에 대해 스팟을 선택하십시오.

스팟 인스턴스 할당 전략 선택하기
두 가지 가능한 스팟 인스턴스 할당 전략은 다각화와 최저 가격입니다.

스팟 집합에 대해 선택한 할당 전략에 따라 가능한 스팟 인스턴스 풀에서 스팟 집합 요청이 어떻게 수행되는지가 결정됩니다. 다양한 전략을 사용하면 스팟 인스턴스가 모든 풀에 분산됩니다. 가장 낮은 가격 전략을 사용하면 스팟 인스턴스는 요청에 지정된 최저 가격의 풀에서 가져옵니다.

모든 리전의 각 가용 영역 안에 있는 각 인스턴스 유형 (각 인스턴스 패밀리 내의 인스턴스 크기, 예 : c4.4xlarge)은 별도의 용량 풀이므로 별도의 스팟 마켓입니다. 가능한 많은 인스턴스 유형과 가용 영역을 다양화함으로써 스팟 집합의 가용성을 향상시킬 수 있습니다. 또한 시간이 지남에 따라 하나의 풀에서 스팟 가격 상승에 집합이 덜 민감해지도록 됩니다.

https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2017/06/05/06.06-Spot-3.png

스팟 집합에 사용할 최대 6 개의 EC2 인스턴스 유형을 선택할 수 있습니다. 이 예에서는 크기가 xlarge 인 m3, m4, c3, c4, r3 및 r4 인스턴스 유형을 선택했습니다.

https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2017/06/05/06.06-Spot-4.png

인스턴스에 대한 입찰가를 입력해야 합니다. 일반적으로 온 디맨드 인스턴스 가격 또는 그 근처에서의 입찰은 좋은 출발점입니다. 입찰가는 해당 스팟 풀에서 인스턴스 유형에 대해 지불할 최대 가격입니다. 스팟 가격이 입찰가 또는 그 이하인 경우 스팟 가격을 지불합니다. 낮은 입찰가는 낮은 비용을 보장, 높은 입찰가는 중단 가능성을 낮춥니다.

클러스터에 포함할 인스턴스 수를 구성하십시오. 스팟 집합은 요청에 지정된 목표 용량을 충족시키는 데 필요한 스팟 인스턴스 수를 배포하려고 시도합니다. 또한 스팟 집합은 스팟 가격이나 사용 가능한 용량이 변경되어 스팟 인스턴스가 회수되는 경우 대상 용량을 유지하려고 시도합니다.

ECS–optimized AMI가 인스턴스가 배포될 때 사용됩니다.

저장소 및 네트워크 설정을 구성하십시오. 다양화 및 고 가용성을 활성화하려면 여러 가용 영역에서 서브넷을 선택해야합니다. 단일 Spot Fleet에서 동일한 가용 영역에서 여러 서브넷을 선택할 수 없습니다.

ECS 컨테이너 에이전트는 사용자를 대신하여 ECS API 작업을 호출합니다. 에이전트를 실행하는 컨테이너 인스턴스에는 에이전트가 사용자에게 속한 것을 알 수 있도록 서비스에 대한 ecsInstanceRole IAM 정책 및 롤이 필요합니다. ecsInstanceRole이 없는 경우 ECS 콘솔을 사용하여 ecsInstanceRole을 만들 수 있습니다.

스팟 집합을 사용하는 관리형 컴퓨트 환경을 만드는 경우, 스팟 집합에 인스턴스에 대한 입찰, 실행 및 종료 권한을 부여하는 롤을 만들어야 합니다. ECS 콘솔을 사용하여 롤을 만들 수도 있습니다.

여기까지입니다! ECS 콘솔에서 생성을 선택하여 스팟 인스턴스에서 실행되는 새 ECS 클러스터를 시작하십시오.

AWS CloudFormation 사용하여 스팟 인스턴스에 ECS 클러스터 배포
이제 CloudFormation 스택을 쉽게 시작하고 스팟 인스턴스에 ECS 클러스터를 배포하는 방법을 보여주는 참조 아키텍처 AWS CloudFormation 템플릿을 게시했습니다.

CloudFormation 템플릿에는 앞서 언급한 스팟 인스턴스 종료 알림 스크립트뿐만 아니라 신속한 시작을 위한 몇 가지 추가 로깅 및 기타 예제 기능이 포함되어 있습니다. Amazon EC2 스팟 인스턴스 GitHub 레포에서 CloudFormation 템플릿을 찾을 수 있습니다.

시험해보고 당신의 환경에 필요에 맞게 사용자 정의하십시오.

 

Spot Fleet Architecture 종료 처리
스팟 인스턴스를 사용하면 지정한 가격 이상을 절대 지불하지 않습니다. 스팟 가격이 주어진 인스턴스의 입찰 가격을 초과하면 자동으로 종료됩니다.

스팟 인스턴스 중단을 방지하는 가장 좋은 방법은 컨테이너 애플리케이션을 내결함성으로 설계하는 것입니다. 또한 스팟 인스턴스 종료 통지라는 기능을 활용할 수 있습니다. EC2가 스팟 인스턴스를 종료하기 2 분전에 경고를 제공합니다.

이 경고는 인스턴스 메타 데이터의 항목을 사용하여 스팟 인스턴스의 어플리케이션에서 사용할 수 있습니다. 콘솔을 사용하여 스팟 인스턴스에 ECS 클러스터를 배포하면 AWS는 5 초마다 스팟 인스턴스 종료 알림을 확인하는 스크립트를 설치합니다. 통지가 감지되면 스크립트는 컨테이너 인스턴스 상태를 드레이닝으로 즉시 업데이트합니다.

스팟 인스턴스 종료 통지 스크립트의 단순화 된 버전은 다음과 같습니다.

Bash
#!/bin/bash

while sleep 5; do
  if [ -z $(curl -Isf http://169.254.169.254/latest/meta-data/spot/termination-time) ]; then
    /bin/false
  else
    ECS_CLUSTER=$(curl -s http://localhost:51678/v1/metadata | jq .Cluster | tr -d \") CONTAINER_INSTANCE=$(curl -s http://localhost:51678/v1/metadata \ | jq .ContainerInstanceArn | tr -d \")
    aws ecs update-container-instances-state --cluster $ECS_CLUSTER \
      --container-instances $CONTAINER_INSTANCE --status DRAINING
  fi
done

컨테이너 인스턴스를 드레이닝으로 설정하면 ECS는 새 작업이 컨테이너 인스턴스에 배치되지 않도록 합니다. 리소스가 가용한 경우, 교체 서비스 작업이 클러스터의 다른 컨테이너 인스턴스에서 시작됩니다. 컨테이너 인스턴스 드레이닝을 사용하면 클러스터의 작업에 영향을 미치지 않고 클러스터에서 컨테이너 인스턴스를 제거 할 수 있습니다. PENDING 상태에 있는 컨테이너 인스턴스의 서비스 작업은 즉시 중지됩니다.

RUNNING 상태에 있는 컨테이너 인스턴스의 서비스 작업은 서비스의 배치 구성 매개 변수 minimumHealthyPercent 및 maximumPercent에 따라 중지 및 교체됩니다.

스팟 인스턴스에 ECS 실제 작동
고객들이 어떻게 이미 스팟 인스턴스 위에 ECS 클러스터를 운영하고 있는지 알고 싶습니까? Mapbox에 있는 우리 친구들이 그 일을 하고 있습니다.

Mapbox는 맞춤 지도를 디자인하고 게시하기 위한 플랫폼입니다. 이 회사는 ECS를 사용하여 전체 일괄 처리 아키텍처에 전력을 공급하여 일일 1 억 마일이 넘는 센서 데이터를 수집하고 처리하여 지도에 사용합니다. 또한 스팟 인스턴스를 사용하여 ECS에서 일괄 처리 아키텍처를 최적화합니다.

Mapbox 플랫폼은 매달 5,000 개가 넘는 앱과 2 억 명 이상의 사용자에게 서비스를 제공합니다. 백엔드는 ECS에서 실행되므로 하루 13 억 건의 요청을 처리 할 수 있습니다. 그들의 ECS 로의 최근 이전에 대한 자세한 내용을 보려면 최근 블로그 게시물, We Switched to Amazon ECS, and You Won’t Believe What Happened Next를 읽으시기 바랍니다. 그리고 후속 블로그 게시물인 Caches to Cash에서 어떻게 그들의 전체 플랫폼을 스팟 인스턴스에서 운영하면서 EC2 비용을 50-90%이상 절약할 수 있었는지 배워보세요.

결론
스팟 인스턴스를 사용하여 규모가 크고 비용 효율적으로 컨테이너 응용 프로그램을 운영하는 것에 대해 우리만큼 흥분을 느끼시길 바랍니다. 자세한 내용은 다음 페이지를 참조하십시오.

의견이나 제안이 있으시면, 의견 부탁드립니다.

Chad Schmutzer, Solutions Architect Shawn O'Conner, Enterprise Solutions Architect
Chad Schmutzer
Solutions Architect
Shawn O’Connor
Solutions Architect

원문: Powering your Amazon ECS Cluster with Amazon EC2 Spot Instances

본 글은 아마존웹서비스 코리아의 솔루션즈 아키텍트가 국내 고객을 위해 전해 드리는 AWS 활용 기술 팁을 보내드리는 코너로서, 이번 글은 이창수 솔루션즈 아키텍트께서 번역해주셨습니다.

[기술백서] AWS 에서의 멀티 플레이어 게임 서버 성능 최적화

AWS 클라우드에서 멀티 플레이어 게임 서버들을 구동하는 사용 사례와 최고 수준의 성능을 달성하기 위한 최적화에 대해 기술 백서를 소개합니다. 이 백서는 AWS 상에서 구동되는 Linux 기반의 멀티 플레이어 게임 서버를 성공적으로 구동하는 데에 필요한 성능을 얻기 위하여 Amazon EC2에서 활용해야 하는 정보들을 제공하고 있습니다.

기술 백서 다운로드 (PDF)

예를 들어,  C4 인스턴스 제품군에서 Linux 상에서 게임서버들을 구동할 경우에 대한 네트워크, CPU 및 메모리의 성능 최적화에 중점을 두고 있습니다.

  • 네트워킹: 멀티 플레이어 클라이언트/서버 게임들은 지연시간과 패킷 손실에 매우 민감합니다. 다양한 네트워크 성능 권장 사항, 플레이어 위치 기반 서버 배치, 향상된 네트워크 기능, UDP 활용 및 대기열 활용 기법 등으로 지연 시간 감소, 패킷 손실 방지 및 게임 서버를 위한 최적의 네트워킹 성능을 얻는 방법을 알려드립니다.
  • CPU: CPU 는 네트워킹과 함께 게임 서버에서 가장 중요한 두 가지 성능 조정 영역 중 하나입니다. 클럭 소스, 프로세서 상태 제어(C-States 및 P-States), Irqbalance, 하이퍼스레딩, CPU 고정, Linux 스케줄러 등을 통한 성능 향상 방법을 소개합니다.
  • 메모리: EC2에서 특히 NUMA 정보에 주의해야 합니다. 자동 NUMA 밸런싱, Numad 데몬 활용, 가상 메모리 스와핑 방식 등의 활용 방법을 알려드립니다.

그 외에도 디스크와 벤치마킹 및 테스트를 통한, CPU 성능 분석, 시각적 CPU 프로파일링 등을 확인하는 방법을 상세히 설명하고 있습니다.

본 백서를 통해 AWS  기반 게임 서버를 빠르게 준비하고 운영하기 위한 핵심 정보, 성능 권장 사항 및 주의 사항을 미리 알아둠으로서 더 효율적으로 빠른 게임 서버 운영을 하시는데 도움이 되시기 바랍니다.

본 글은 아마존웹서비스 코리아의 솔루션즈 아키텍트가 국내 고객을 위해 전해 드리는 AWS 활용 기술 팁을 보내드리는 코너로서, 본 백서 번역은 김병수 솔루션즈 아키텍트께서 작성해주셨습니다.

Elastic Network Adapter를 활용한 고성능 네트워크 구성하기

많은 고객 분들은 네트워크 성능을 최대한 활용하기를 원합니다. Amazon EC2는 다양하고 새로운 인스턴스 타입을 지속적으로 추가하고 있습니다. AWS는 CC1 instance를 시작으로 10Gbps 네트워크를 채택하고 Enhanced Networking 기능을 소개했습니다. Enhanced Networking은 Intel 82599 VF Interface와 SR-IOV 기술을 활용합니다. I/O 성능은 높이고, CPU자원 소모는 줄일 수 있습니다. 더 넓은 네트워크 대역폭을 지원하며, PPS(Packet per second) 성능이 뛰어나고 인스턴스간의 통신 시 Latency도 낮습니다.

최근 고객 분들의 여러 의견을 듣고 새로운 기술을 활용해 Elastic Network Adapter(ENA)를 채택한 새로운 인스턴스 타입들을 추가했습니다. vCPU가 점점 많아지면서 vCPU의 리소스를 보다 효과적으로 분산하여 사용하여 성능을 높일 수 있는 기술입니다. ENA를 활용하기 위해서는 몇가지 설정이 필요합니다. 쉽게 설정 하실 수 있도록 구성하는 방법을 소개해 드립니다.

Elastic Network Adapter(ENA)를 지원하는 EC2 인스턴스
2016년 12월 현재 ENA는 최대 20Gbps 네트워크 성능을 지원하며, P2, R4, X1, 그리고 m4.16xlarge에서 ENA를 지원하고 있습니다. 또한 최신 Amazon Linux HVM AMI(Amazon Machine Image)는 기본적으로 ENA를 사용할 수 있도록 구성되어 있습니다.

Elastic Network Adapter(ENA) 활성화 하기
Amazon Linux의 이전 버젼 또는 다른 Linux 배포판의 경우 ENA를 사용하기 위해서는 아래와 같이 설정이 필요합니다. 이 블로그에서는 RedHat Enterprise Linux Server 7.3 AMI를 를 사용해 x1.16xlarge 인스턴스를 구동했습니다. Public IP와 Key file을 이용하여 인스턴스에 SSH 접속합니다.

$ ssh -i {$key_file} ec2-user@54.161.110.6
[ec2-user@ip-10-10-10-10 ~]$
[ec2-user@ip-10-10-10-10 ~]$ uname -na
Linux ip-10-10-10-10.localdomain 3.10.0-514.el7.x86_64 #1 SMP Wed Oct 19 11:24:13 EDT 2016 x86_64 x86_64 x86_64 GNU/Linux
[ec2-user@ip-10-10-10-10 ~]$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.3 (Maipo)
launching_x1_instance

X1 인스턴스 구동

1. ENA 드라이버 확인하기
아래 명령으로 현재 ENA 드라이버가 설정되어 있는지 확인합니다. Vif라고 이름이 나온다면 현재는 기본 Driver로 ENA를 사용할 수 없는 상태입니다.

[ec2-user@ip-10-10-10-10 ~]$ ethtool -i eth0
driver: vif
version:
firmware-version:
expansion-rom-version:
bus-info: vif-0
supports-statistics: yes
supports-test: no
supports-eeprom-access: no
supports-register-dump: no
supports-priv-flags: no

2. Linux 최신 업데이트 하기
아래 명령으로 Linux의 설치된 패키지들을 최신으로 업데이트합니다. 업데이트 완료 후 intstance를 reboot 합니다.

[ec2-user@ip-10-10-10-10 ~]$ sudo yum update -y
Loaded plugins: amazon-id, rhui-lb, search-disabled-repos
Resolving Dependencies
--> Running transaction check
---> Package NetworkManager.x86_64 1:1.4.0-12.el7 will be updated
---> Package NetworkManager.x86_64 1:1.4.0-13.el7_3 will be an update
---> Package NetworkManager-config-server.x86_64 1:1.4.0-12.el7 will be updated
---> Package NetworkManager-config-server.x86_64 1:1.4.0-13.el7_3 will be an update
---> Package NetworkManager-libnm.x86_64 1:1.4.0-12.el7 will be updated
---> Package NetworkManager-libnm.x86_64 1:1.4.0-13.el7_3 will be an update
---> Package NetworkManager-team.x86_64 1:1.4.0-12.el7 will be updated
---> Package NetworkManager-team.x86_64 1:1.4.0-13.el7_3 will be an update
---> Package NetworkManager-tui.x86_64 1:1.4.0-12.el7 will be updated
---> Package NetworkManager-tui.x86_64 1:1.4.0-13.el7_3 will be an update
………

3. 드라이버 다운로드
Github 에 공개되어 있는 ENA Linux driver 를 git 툴을 통해 가져옵니다. 그리고 컴파일을 위해서 gcc와 kernel-devel 패키지를 설치합니다.

[ec2-user@ip-10-10-10-10 ~]$ git clone https://github.com/amzn/amzn-drivers
Cloning into 'amzn-drivers'...
remote: Counting objects: 57, done.
remote: Total 57 (delta 0), reused 0 (delta 0), pack-reused 57
Unpacking objects: 100% (57/57), done.

드라이버를 컴파일 하기 위해 gcc 컴파일러와 Kernel-devel 패키지를 먼저 설치합니다.

[ec2-user@ip-10-10-10-10 ena]$ sudo yum install gcc -y
Loaded plugins: amazon-id, rhui-lb, search-disabled-repos
Resolving Dependencies
--> Running transaction check
---> Package gcc.x86_64 0:4.8.5-11.el7 will be installed
--> Processing Dependency: cpp = 4.8.5-11.el7 for package: gcc-4.8.5-11.el7.x86_64
--> Processing Dependency: glibc-devel >= 2.2.90-12 for package: gcc-4.8.5-11.el7.x86_64
--> Processing Dependency: libmpc.so.3()(64bit) for package: gcc-4.8.5-11.el7.x86_64
--> Processing Dependency: libmpfr.so.4()(64bit) for package: gcc-4.8.5-11.el7.x86_64
….
[ec2-user@ip-10-10-10-10 ena]$ sudo yum install kernel-devel -y
Loaded plugins: amazon-id, rhui-lb, search-disabled-repos
Resolving Dependencies
--> Running transaction check
---> Package kernel-devel.x86_64 0:3.10.0-514.2.2.el7 will be installed
--> Finished Dependency Resolution

4. 드라이버 컴파일
드라이버 소스 코드가 있는 디렉토리로 이동합니다. 그리고 make명령을 통해서 driver를 compile합니다.

[ec2-user@ip-10-10-10-10 ena]$ make
make -C /lib/modules/3.10.0-514.2.2.el7.x86_64/build M=/home/ec2-user/amzn-drivers/kernel/linux/ena modules
make[1]: Entering directory `/usr/src/kernels/3.10.0-514.2.2.el7.x86_64'
CC [M]  /home/ec2-user/amzn-drivers/kernel/linux/ena/ena_netdev.o
CC [M]  /home/ec2-user/amzn-drivers/kernel/linux/ena/ena_ethtool.o
CC [M]  /home/ec2-user/amzn-drivers/kernel/linux/ena/../common/ena_com//ena_com.o
CC [M]  /home/ec2-user/amzn-drivers/kernel/linux/ena/../common/ena_com//ena_eth_com.o
CC [M]  /home/ec2-user/amzn-drivers/kernel/linux/ena/ena_sysfs.o
LD [M]  /home/ec2-user/amzn-drivers/kernel/linux/ena/ena.o
Building modules, stage 2.
MODPOST 1 modules
CC      /home/ec2-user/amzn-drivers/kernel/linux/ena/ena.mod.o
LD [M]  /home/ec2-user/amzn-drivers/kernel/linux/ena/ena.ko
make[1]: Leaving directory `/usr/src/kernels/3.10.0-514.2.2.el7.x86_64'

컴파일이 완료되면 ena.ko 드라이버 파일이 생성됩니다. Modinfo 명령으로 드라이버를 확인합니다.

[ec2-user@ip-10-10-10-10 ena]$ modinfo ena.ko
filename:       /home/ec2-user/amzn-drivers/kernel/linux/ena/ena.ko
version:        1.1.2
license:        GPL
description:    Elastic Network Adapter (ENA)
author:         Amazon.com, Inc. or its affiliates
rhelversion:    7.3
srcversion:     25093B15753CC7D0357E01C
alias:          pci:v00001D0Fd0000EC21sv*sd*bc*sc*i*
alias:          pci:v00001D0Fd0000EC20sv*sd*bc*sc*i*
alias:          pci:v00001D0Fd00001EC2sv*sd*bc*sc*i*
alias:          pci:v00001D0Fd00000EC2sv*sd*bc*sc*i*
depends:
vermagic:       3.10.0-514.2.2.el7.x86_64 SMP mod_unload modversions
parm:           debug:Debug level (0=none,...,16=all) (int)

5. 드라이버 설치 및 로드 설정
현재 makefile에서는 make install은 구성되어 있지 않습니다. README파일을 참조하여 아래와 같이 부팅 시 드라이버가 로드될 수 있도록 설정하고 드라이버를 리눅스의 드라이버 모듈 디렉토리 밑으로 복사합니다.

      1. sudo vi /etc/modules-load.d/ena.conf 로 ena.conf생성
      2. ena.conf 파일에 ena 입력 후 저장
      3. sudo cp ena.ko /lib/modules/`uname -r`/ 로 드라이버 복사
      4. sudo depmod 드라이버 디펜던시 체크
      5. reboot OS

6. 인스턴스 enaSupport 설정 활성화
인스턴스의 enaSupport 설정값을 변경하기 위해서는 먼저 인스턴스를 Stop합니다. Stop이 완료 된 후에, 아래와 같은 명령으로 enaSupport를 활성화합니다.

$ aws ec2 modify-instance-attribute --instance-id instance_id --ena-support

7. 인스턴스 Start
이제 인스턴스를 다시 시작하면 ENA가 활성화되어 사용할 수 있습니다. 아래 명령으로 직접 확인할 수 있습니다.

[ec2-user@ip-10-10-10-10 ~]$ ethtool -i eth0 
driver: ena 
version: 1.1.2 
firmware-version: 
expansion-rom-version: 
bus-info: 0000:00:03.0 
supports-statistics: yes 
supports-test: no 
supports-eeprom-access: no 
supports-register-dump: no 
supports-priv-flags: no

본 글은 아마존웹서비스 코리아의 솔루션즈 아키텍트가 국내 고객을 위해 전해 드리는 AWS 활용 기술 팁을 보내드리는 코너로서, 이번 글은 김일호 솔루션즈 아키텍트께서 작성해주셨습니다.
andy_kim_photo

Amazon Athena 초간단 사용기

지난 2016년 11월 28일부터 12월 2일에 걸쳐 개최된 글로벌 컨퍼런스 AWS re:Invent 2016에서는 20여개가 넘는 신규 기능 및 서비스가 발표되었습니다. 크게 나눠 보았을때 기존 서비스에 추가된 기능(새로운 EC2 타입 등)을 제외한다면 가장 많은 주목을 받은 부분은 딥러닝에 기반한 인공 지능 서비스(Amazon Rekognition, Polly, Lex 등)들과 데이터에 기반한 분석 서비스였습니다.

이 중 기존에 인프라나 비즈니스 운영을 관리하시는 분들이 가장 많이 관심을 가진 서비스가 바로 Amazon Athena 발표입니다. Athena는 Amazon S3 스토리지에 저장된 다양한 포맷의 기초 데이터, 예를 들어 csv, tsv, txt, CRC, Parquet 등에 대해 바로 표준 SQL 문을 사용해 데이터를 검색 및 분석할 수 있는 서비스입니다.

Amazon Athena의 기반 기술 및 장점
Amazon Athena는 페타바이트 규모의 데이터에 대해 표준 SQL 문에 기반한 질의를 수행할 수 있습니다. S3 를 스토리지로 사용하기 때문에 99.999999999%에 달하는 S3의 내구성이 그대로 데이터에 적용됩니다. 또한 데이터 소스에 대응하는 테이블 메타 정보만 생성하면 바로 쿼리를 수행할 수 있으며, 쿼리 수행 속도 또한 매우 빠릅니다.

가격 또한 매우 큰 이점으로 작용합니다. 매번 쿼리를 수행할 때 스캔하는 데이터의 양에 따라 과금되며, 미리 서버를 준비할 필요가 없어 고정 비용이 발생하지 않습니다. 비용은 S3에서 스캔하는 데이터 1TB당 5 달러입니다.

또한, Athena는 여러 가용영역에 걸친 컴퓨팅 자원을 준비해 두고 여러분의 쿼리를 처리합니다. 아래와 같이 크게 두 가지의 오픈소스 기술이 Athena에 적용되어 있습니다.

athena_underlying_technologies

[그림 1] Athena의 적용 기반 기술


Presto는 인 메모리 분석 쿼리 엔진으로 ANSI-SQL이 호환됩니다. 또한 Hive는 DDL 관련 기능을 처리하는 것을 담당합니다. 복잡한 데이터 타입, 여러 포맷, 데이터 파티셔닝, 테이블 생성 등과 관련된 부분을 담당합니다.

Athena가 유용한 부분을 살펴보기 위해서는 다른 서비스, 예를 들어 유사한  AWS의 다른 빅 데이터 분석 서비스인 EMR, Redshift 와 어떤 차이점이 있는지 살펴보는 것이 좋겠습니다.

Athena EMR Redshift
SQL 지원의 쿼리 서비스
S3에 데이터 존재
바로 실행
서버리스
쿼리 수행에 따른 과금
단순 SQL 만이 아니라, 여러 배치 잡을 수행 가능 (딥 러닝 트레이닝, 파일 변환/복사 등)
다양한 플랫폼을 사용해서 워크로드에 따라서 다양하게 구성 할 수 있음
데이터가 반드시 S3 에 있을 필요는 없음.
서버 클러스터 존재
클러스터 시간당 과금
여러 데이터 소스에 대해 구조화된 데이터를 집적. 전형적인 D/W 워크로드에 적합.
서버 클러스터 존재
시간당 과금

Athena를 적용할 수 있는 대표적인 분야는 각종 로그 분석입니다. 과거 대량 로그 분석에는 EMR 혹은 Redshift를 사용해야 했는데, EMR은 다양한 프레임워크 선택에서, Redshift는 비용에서 상대적으로 사용자가 부담을 가질 수 있었습니다. 이제는 Athena를 통해 손쉽고 저렴하게 분석을 할 수 있습니다.

물론 로그 분석 이외에도 ETL 적용이 부담스럽거나 어려운 워크로드, 기존에 Hive, Spark를 사용했던 워크로드들도 Athena가 대체할 수 있는 대상입니다.

Athena 바로 사용해 보기
서울 리전에 여러분의 데이터가 존재한다고 합시다. 현재 Athena는 2개 리전(버지니아, 오레곤)에서 사용할 수 있습니다.  따라서 서울 리전의 버킷을 버지니아 리전으로 리전간 복제(CRR, Cross Region Replication)합니다. 이것은 버킷의 프로퍼티에서 지정할 수 있습니다. CRR을 하기 위해서는 먼저 버킷의 버저닝을 활성해야 합니다. 활성 버튼을 누르고 나면 그림 2와 같이 설정을 할 수 있습니다.

athena_crossregionreplication

그림2. CRR 설정

버킷 내 데이터의 양에 따라 다르지만 리전 간 복제 설정 시점 이후로 만들어진 신규 로그 파일에 대해서 버지니아의 대상 버킷으로 복제가 완료됩니다. 이렇게 복제가 완료된 후 Athena에서 데이터베이스와 테이블을 생성하면 됩니다.

예를 들어 로우 데이터가 csv파일이라고 합시다. 여러 파일이 버킷의 특정 폴더에 존재한다면, 데이터 소스를 다음과 같이 지정하면 해당 폴더 안의 파일 전체를 지정하게 됩니다.

S3:\\<버킷이름>\< 폴더이름>\

그림 3은 테이블을 새롭게 생성하는 화면입니다. 데이터베이스 이름은 새롭게 생성할 수도 있고 기존의 데이터베이스 이름을 사용할 수도 있습니다.

athena_creating_table

그림 3. 테이블의 생성

이렇게 테이블을 생성하고 나면, 각 칼럼들을 지정하게 됩니다. 그림 4는 소스 타입을 지정하는 부분입니다.

athena_defining_source_type

그림 4. 소스 타입 지정

그림 5.는 칼럼을 지정하는 과정입니다. 여기까지만 하면 기본적으로 쿼리를 수행할 수 있습니다.

05

그림 5. 칼럼 지정

이렇게 만들고 나면 바로 쿼리를 수행할 수 있습니다. 수행의 한 예제가 그림 6입니다.

06

그림 6. 기본 쿼리의 수행

지금까지 Athena의 특성과 다른 서비스와의 비교를 살펴보았습니다. 이제  여러분의 S3 에 존재하는 데이터를 대상으로 바로 쿼리를 사용할 수 있으므로, 보다 손쉽게 데이터 분석과 관리가 가능합니다. 다음 포스팅에서는 Athena 활용에 도움이 되도록 보다 고급 예제, 파티셔닝, CRC, Parquet으로의 전환, 최적화 방법 등에 대해 살펴보도록 하겠습니다.

본 글은 아마존웹서비스 코리아의 솔루션즈 아키텍트가 국내 고객을 위해 전해 드리는 AWS 활용 기술 팁으로, 이번 포스팅은 박선용 솔루션즈 아키텍트께서 작성해주셨습니다.
seonyong_park

Amazon Redshift 쿼리 캐싱을 위해 pgpool 및 Amazon ElastiCache 사용

최근 국내의 많은 고객 분들이 Amazon Redshift 도입을 고려하고 계시거나, 또는 이미 도입하여 사용하고 계십니다. OLTP 뿐만 아니라 데이터 웨어하우스 시스템에서도 쿼리 캐싱은 전체적인 사용자 체감 속도를 개선할 수 있는 아주 좋은 방법입니다. 쿼리 캐싱을 위한 다양한 방법이 있겠지만, pgpool 및 Amazon ElastiCache  사용에 대한 좋은 블로그 글이 있어 소개하도록 하겠습니다.

원문은 Using pgpool and Amazon ElastiCache for Query Caching with Amazon Redshift (https://aws.amazon.com/blogs/big-data/using-pgpool-and-amazon-elasticache-for-query-caching-with-amazon-redshift/)입니다.

이 글에서는 실제 고객 시나리오를 사용하여 pgpool 및 Amazon ElastiCache를 사용하여 Amazon Redshift 앞에 캐시 레이어를 만드는 방법을 보여줍니다.

거의 모든 애플리케이션은 아무리 간단한 것이든 어떤 종류의 데이터베이스를 사용합니다. SQL 쿼리를 자주 사용하게 되면 때때로 중복 실행이 발생할 수 있습니다. 이러한 중복성은 다른 작업에 할당 될 수 있는 자원을 낭비합니다.

예를 들어 Amazon Redshift에 위치한 데이터를 사용하는 BI 도구 및 애플리케이션은 일반적인 쿼리를 실행할 가능성이 높습니다. 최종 사용자 환경을 개선하고 데이터베이스의 경합을 줄이기 위해 그중 일부를 캐시 할 수 있습니다. 사실 좋은 데이터 모델링 및 분류 정책을 사용하여 클러스터 크기를 줄임으로써 비용을 절약 할 수 있습니다.

캐싱이란 무엇입니까?
컴퓨팅에서 캐시는 데이터를 저장하는 하드웨어 또는 소프트웨어 구성 요소이므로 향후 해당 데이터에 대한 요청을 더 빨리 처리 할 수 있습니다. 캐시에 저장된 데이터는 이전 계산의 결과이거나 다른 곳에 저장된 데이터의 복제 일 수 있습니다. 요청 된 데이터가 캐시에서 발견되면 캐시 히트가 발생합니다. 그렇지 않은 경우 캐시 미스가 발생합니다. 캐시 히트는 캐시에서 데이터를 읽어 제공하기 때문에 결과를 다시 계산하거나 느린 데이터 저장소에서 읽는 것보다 빠릅니다. 캐시가 더 많은 요청을 처리 할수록 시스템은 더 빠르게 운영될 수 있습니다.

고객 사례 : 실험실 분석
임상 분석 실험실에서, 6-10 명의 과학자 (유전 학자, 의사 및 생물 학자)로 이루어진 특정 팀이 특정 유전자 변형을 찾는 약 200 만 줄의 유전자 코드를 검색합니다. 변형된 유전자 옆의 유전자는 질병이나 장애를 확인할 수 있기 때문에 매우 흥미롭습니다.

과학자들은 동시에 하나의 DNA 샘플을 분석 한 다음, 회의를 통해 서로의 의견을 공유하여 결론을 내립니다.

Node.js 웹 애플리케이션에는 Amazon Redshift 에 대해 쿼리를 실행하는 로직이 포함되어 있습니다. Amazon Redshift에 연결된 웹 애플리케이션을 사용함에 있어서 과학자 팀은 약 10 초의 대기 시간을 경험했습니다. pgpool을 사용하도록 아키텍처를 수정한 후, 이 과학자들은 동일한 쿼리를 1 초 미만 (즉, 10 배 더 빨리)에 실행할 수 있었습니다.

o_PgPool_1

pgpool 소개
Pgpool은 데이터베이스 클라이언트와 데이터베이스 서버 사이에 위치하는 소프트웨어입니다. 역방향 프록시(reverse proxy) 역할을 하며 클라이언트로부터 연결을 수신하여 데이터베이스 서버로 전달합니다. 원래 PostgreSQL 용으로 작성된 pgpool은 캐싱 외에도 연결 풀링(pooling), 복제(replication), 로드 밸런싱 및 초과 연결 큐와 같은 다른 흥미로운 기능을 가지고 있습니다. 이러한 기능을 자세히 찾아보지 않았지만 PostgreSQL과 Amazon Redshift 간의 호환성으로 인해 Amazon Redshift와 함께 사용할 수 있다고 생각됩니다.

Pgpool은 Amazon EC2 인스턴스 또는 사내 구축 환경에서 실행할 수 있습니다. 예를 들어, 개발 및 테스트를 위해 한개의 EC2 인스턴스가 있고 프로덕션 환경에 Elastic Load Balancing 및 Auto Scaling을 사용하는 EC2 인스턴스 그룹이 있을 수 있습니다.
임상 분석 실험실이라는 우리의 사용 예제에서는 psql (command line) 및 Node.js 애플리케이션을 사용하여 Amazon Redshift에 대한 쿼리를 실행했으며 예상대로 동작했습니다. 그러나 아키텍처를 변경하기 전에 PostgreSQL 클라이언트에서 pgpool을 테스트 할 것을 강력하게 권장합니다.

pgpool 캐싱 기능 살펴보기
pgpool 캐싱 기능은 기본적으로 비활성화 되어 있습니다. 다음 두 가지 방법으로 구성 할 수 있습니다.

  • On-memory (shmem)
    • 캐시를 활성화 하고, 설정을 전혀 변경하지 않았을 때 기본적으로 제공하는 방법입니다. Memcached 보다 약간 빠르며 구성 및 유지 관리가 더 쉽습니다. 반면에 고 가용성 시나리오에서는, 서버 당 쿼리를 캐싱하고 각 서버에 대해 적어도 한 번 캐싱할 쿼리를 처리하기 때문에 메모리와 일부 데이터베이스 처리를 낭비하는 경향이 있습니다. 예를 들어 4대로 구성된 pgpool 클러스터에서 20GB 캐시가 필요할 경우, 4대의xlarge 인스턴스를 준비하고 각 서버당 20GB메모리를 캐시를 위해 사용해야 합니다. 데이터베이스에 의해 처리되는 각 쿼리는 각 서버에 캐싱이 되어야 하기 때문에 최소한 4 번 캐싱 되어야 합니다.
  • Memcached (memcached)
    • 이 방법에서 캐시는 서버의 외부에서 유지 관리됩니다. 장점은 캐시 저장 영역 (Memcached)이 캐시 처리 영역(pgpool)에서 분리된다는 것입니다. 이는 쿼리가 Memcached에서만 처리되고 외부에서 캐싱되기 때문에 서버 메모리 및 데이터베이스 처리 시간을 낭비하지 않는다는 것을 의미합니다.
    • Memcached를 구성할 수 있는 방법은 많지만, Amazon ElastiCache에서 제공하는Memcached를 함께 사용하는 것이 좋습니다. Amazon ElastiCache는 실패한 노드를 자동으로 감지하고 교체하는 기능을 제공하므로 직접 인프라를 관리하는 오버헤드가 줄어듭니다. 웹 사이트 및 애플리케이션 실행 시간을 지연시키는 데이터베이스의 과부화 위험을 완화시켜 안정적인 서비스를 가능하게 합니다.

pgpool을 이용한 쿼리 캐싱
다음의 흐름도는 쿼리 캐싱이 pgpool과 함께 작동하는 방법을 보여줍니다.

다음 다이어그램은 개발/테스트 환경을 위해 pgpool을 설치하고 구성하는 데 필요한 최소 아키텍처를 보여줍니다.

o_PgPool_3

다음 다이어그램은 프로덕션 환경에 권장되는 최소 아키텍처를 보여줍니다.

o_PgPool_4

선결 요건
이 단계는 AWS CLI (Command Line Interface)를 사용할 것입니다. Mac, Linux 또는 Microsoft Windows 시스템을 이용하여 구성해 보시려면AWS CLI가 설치되어 있어야합니다. 설치 방법은 AWS Command Line Interface 설치를 참조하십시오.

pgpool 설치 및 구성 단계
1. 변수 설정 :

IMAGEID=ami-c481fad3
KEYNAME=<set your key name here>

IMAGEID 변수는 미국 동부 (버지니아) 지역의 Amazon Linux AMI를 사용하도록 설정합니다.
KEYNAME 변수를 여러분이 사용할 EC2 Key pair 이름으로 설정하십시오. 이 Key pair는 미국 동부 (버지니아) 지역에서 생성 된 것이어야 합니다.

미국 동부 (버지니아) 이외의 지역을 사용하는 경우 IMAGEID 및 KEYNAME을 적절하게 수정하시기 바랍니다.
2. EC2 인스턴스 만들기 :

aws ec2 create-security-group --group-name PgPoolSecurityGroup --description "Security group to allow access to pgpool"

MYIP=$(curl eth0.me -s | awk '{print $1"/32"}')

aws ec2 authorize-security-group-ingress --group-name PgPoolSecurityGroup --protocol tcp --port 5432 --cidr $MYIP

aws ec2 authorize-security-group-ingress --group-name PgPoolSecurityGroup --protocol tcp --port 22 --cidr $MYIP

INSTANCEID=$(aws ec2 run-instances \
	--image-id $IMAGEID \
	--security-groups PgPoolSecurityGroup \
	--key-name $KEYNAME \
	--instance-type m3.medium \
	--query 'Instances[0].InstanceId' \
	| sed "s/\"//g")

aws ec2 wait instance-status-ok --instance-ids $INSTANCEID

INSTANCEIP=$(aws ec2 describe-instances \
	--filters "Name=instance-id,Values=$INSTANCEID" \
	--query "Reservations[0].Instances[0].PublicIpAddress" \
	| sed "s/\"//g")

3. Amazon ElastiCache 클러스터 생성 :

aws ec2 create-security-group --group-name MemcachedSecurityGroup --description "Security group to allow access to Memcached"

aws ec2 authorize-security-group-ingress --group-name MemcachedSecurityGroup --protocol tcp --port 11211 --source-group PgPoolSecurityGroup

MEMCACHEDSECURITYGROUPID=$(aws ec2 describe-security-groups \
	--group-names MemcachedSecurityGroup \
	--query 'SecurityGroups[0].GroupId' | \
	sed "s/\"//g")

aws elasticache create-cache-cluster \
	--cache-cluster-id PgPoolCache \
	--cache-node-type cache.m3.medium \
	--num-cache-nodes 1 \
	--engine memcached \
	--engine-version 1.4.5 \
	--security-group-ids $MEMCACHEDSECURITYGROUPID

aws elasticache wait cache-cluster-available --cache-cluster-id PgPoolCache

4. SSH를 통해 EC2 인스턴스 접근 후 필요한 패키지 설치 :

ssh -i <your pem file goes here> ec2-user@$INSTANCEIP

sudo yum update -y

sudo yum group install "Development Tools" -y

sudo yum install postgresql-devel libmemcached libmemcached-devel -y

5. pgpool 소스코드 tarball 을 다운로드 :

curl -L -o pgpool-II-3.5.3.tar.gz http://www.pgpool.net/download.php?f=pgpool-II-3.5.3.tar.gz

6. 소스 추출 및 컴파일 :

tar xvzf pgpool-II-3.5.3.tar.gz

cd pgpool-II-3.5.3

./configure --with-memcached=/usr/include/libmemcached-1.0

make

sudo make install

7.  pgpool과 함께 제공되는 샘플 conf를 통해 pgpool.conf 생성

sudo cp /usr/local/etc/pgpool.conf.sample /usr/local/etc/pgpool.conf

8. pgpool.conf 편집 :
사용하기 편한 편집기(vi editor 등)를 사용하여 /usr/local/etc/pgpool.conf를 열고 다음 매개변수를 찾아서 설정하십시오 :

  • Setlisten_addresses 를 *로 변경
  • Setport 를 5432로 변경
  • Setbackend_hostname0 을 여러분의 Amazon Redshift 클러스터 endpoint로 변경
  • Setbackend_port0를 5439로 변경.
  • Setmemory_cache_enabled를 on으로 변경
  • Setmemqcache_method를 memcached로 변경
  • Setmemqcache_memcached_host를  ElastiCache endpoint 주소로 변경
  • Setmemqcache_memcached_port를  ElastiCache endpoint 포트로 변경
  • Setlog_connections를 on으로 변경
  • Setlog_per_node_statement를 on으로 변경
  • Setpool_passwd를 “으로 변경

여러분의 설정 파일에서 수정된 매개변수는 아래와 같을 것입니다:

listen_addresses = '*'

port = 5432

backend_hostname0 = '<your redshift endpoint goes here>'

backend_port0 = 5439

memory_cache_enabled = on

memqcache_method = 'memcached'

memqcache_memcached_host = '<your memcached endpoint goes here>'

memqcache_memcached_port = 11211

log_connections = on

log_per_node_statement = on

9. 사용권한 설정 :

sudo mkdir /var/run/pgpool

sudo chmod u+rw,g+rw,o+rw /var/run/pgpool

sudo mkdir /var/log/pgpool

sudo chmod u+rw,g+rw,o+rw /var/log/pgpool

10. pgpool 시작 :

pgpool -n

pgpool은 이미 포트 5432에서 수신 대기 중입니다.

2016-06-21 16:04:15: pid 18689: LOG: Setting up socket for 0.0.0.0:5432
2016-06-21 16:04:15: pid 18689: LOG: Setting up socket for :::5432
2016-06-21 16:04:15: pid 18689: LOG: pgpool-II successfully started. version 3.5.3 (ekieboshi)

11. 구성 테스트 :
이제 pgpool이 실행 중이므로 Amazon Redshift 클라이언트가 Amazon Redshift 클러스터 엔드포인트 대신 pgpool 엔드포인트를 가리키도록 구성합니다. 엔드포인트 주소를 얻으려면 콘솔이나 CLI를 사용하여 EC2 인스턴스의 공개 IP 주소를 확인하거나 $INSTANCEIP 변수에 저장된 값을 인쇄하여 확인 할 수 있습니다.

#psql –h <pgpool endpoint address> -p 5432 –U <redshift username>

쿼리를 처음 실행하면 pgpool 로그에 다음 정보가 표시됩니다 :

2016-06-21 17:36:33: pid 18689: LOG: DB node id: 0 backend pid: 25936 statement: select
      s_acctbal,
      s_name,
      p_partkey,
      p_mfgr,
      s_address,
      s_phone,
      s_comment
  from
      part,
      supplier,
      partsupp,
      nation,
      region
  where
      p_partkey = ps_partkey
      and s_suppkey = ps_suppkey
      and p_size = 5
      and p_type like '%TIN'
      and s_nationkey = n_nationkey
      and n_regionkey = r_regionkey
      and r_name = 'AFRICA'
      and ps_supplycost = (
          select 
              min(ps_supplycost)
          from
              partsupp,
              supplier,
              nation,
              region
          where
              p_partkey = ps_partkey,
              and s_suppkey = ps_suppkey,
              and s_nationkey = n_nationkey,
              and n_regionkey = r_regionkey,
              and r_name = 'AFRICA'
      )
  order by
      s_acctbal desc,
      n_name,
      s_name,
      p_partkey
  limit 100;

로그의 첫 번째 줄은 쿼리가 Amazon Redshift 클러스터에서 직접 실행되는 것을 보여줍니다. 이는 캐시 미스입니다. 데이터베이스에 대해 쿼리를 실행하면 결과를 반환하는데 6814.595ms 가 걸렸습니다.

동일한 조건을 사용하여 이 쿼리를 다시 실행하면 로그에 다른 결과가 표시됩니다 :

2016-06-21 17:40:19: pid 18689: LOG: fetch from memory cache
2016-06-21 17:40:19: pid 18689: DETAIL: query result fetched from cache. statement: 
select
      s_acctbal,
      s_name,
      p_partkey,
      p_mfgr,
      s_address,
      s_phone,
      s_comment
  from
      part,
      supplier,
      partsupp,
      nation,
      region
  where
      p_partkey = ps_partkey
      and s_suppkey = ps_suppkey
      and p_size = 5
      and p_type like '%TIN'
      and s_nationkey = n_nationkey
      and n_regionkey = r_regionkey
      and r_name = 'AFRICA'
      and ps_supplycost = (
          select 
              min(ps_supplycost)
          from
              partsupp,
              supplier,
              nation,
              region
          where
              p_partkey = ps_partkey,
              and s_suppkey = ps_suppkey,
              and s_nationkey = n_nationkey,
              and n_regionkey = r_regionkey,
              and r_name = 'AFRICA'
      )
  order by
      s_acctbal desc,
      n_name,
      s_name,
      p_partkey
  limit 100;

로그의 처음 두 줄을 통해 원하는 결과가 캐시를 통해 검색되는 것을 알 수 있습니다. 이는 캐시 히트입니다. 차이점은 엄청납니다. 쿼리를 실행하는데 247.719ms 밖에 걸리지 않았습니다. 즉, 이전 시나리오보다 30 배 빠르게 실행됩니다.

pgpool 캐싱 동작 이해
Pgpool은 여러분의 SELECT 쿼리를 가져온 결과의 키로 사용합니다.
캐싱 동작과 무효화는 몇 가지 방법으로 구성 할 수 있습니다.

  • 자동 무효화
    • 기본적으로 memqcache_auto_cache_invalidation은 on으로 설정됩니다. Amazon Redshift의 테이블을 업데이트하면 pgpool의 캐시가 무효화됩니다.
  • 만료
    • memqcache_expire는 결과가 캐시에 남아 있어야하는 시간을 초로 정의합니다. 기본값은 0이며 무한대를 의미합니다.
  • 블랙리스트와 화이트리스트
    • white_memqcache_table_list
      • 캐시되어야 하는 테이블의 목록을 쉼표로 구분하여 정의. 정규 표현식이 허용됩니다.
    • black_memqcache_table_list
      • 캐시해서는 안되는 테이블의 목록을 쉼표로 구분하여 정의. 정규 표현식이 허용됩니다.
    • 캐시 무시
      • / * NO QUERY CACHE * /

쿼리에 * / NO QUERY CACHE * / 주석을 지정하면 쿼리는 pgpool 캐시를 무시하고 데이터베이스에서 결과를 가져옵니다.

예를 들어, 만약 pgpool이 DNS 이름 확인 또는 라우팅 문제로 인해 캐시에 연결하지 못하면, 데이터베이스 엔드포인트로 직접 연결하고 캐시를 전혀 사용하지 않습니다.

결론
Amazon Redshift 및 Amazon ElastiCache와 함께 pgpool을 사용하여 캐싱 솔루션을 쉽게 구현할 수 있습니다. 이 솔루션은 최종 사용자 경험을 크게 향상시키고 클러스터의 부하를 크게 줄일 수 있습니다.

이 글은 pgpool과 이 캐싱 아키텍처가 여러분에게 어떤 도움이 되는지 보여주는 한 가지 간단한 예제 입니다. pgpool 캐싱 기능에 대한 자세한 내용은 pgpool 설명서의 이곳이곳 을 참조하시기 바랍니다. 해피 쿼리 (물론 캐싱). 질문이나 제안이 있으시면 아래에 의견을 남겨주십시오.

본 글은 아마존웹서비스 코리아의 솔루션즈 아키텍트가 국내 고객을 위해 전해 드리는 AWS 활용 기술 팁을 보내드리는 코너로서, 이번 글은 양승도 솔루션즈 아키텍트께서 번역해주셨습니다.
sd-yang-photo

Amazon Redshift 를 위한 10가지 성능 튜닝 기법

최근 국내의 많은 고객 분들이 Amazon Redshift 도입을 고려하고 계시거나, 또는 이미 도입하여 사용하고 계십니다. 도입 전, PoC(Proof of Concept) 등의 과정을 통해서 기존 업무와의 호환성 또는 원하는 성능에 대한 평가 등을 하신 후에 사용하고 계시겠지만, 제목과 같이 Redshift 의 성능 튜닝에 도움이 될 수 있는 내용을 다시 한번 살펴보시라는 의미에서, 좋은 블로그 포스트를 번역하여 제공하고자 합니다.

원문은 Top 10 Performance Tuning Techniques for Amazon Redshfit(Ian Meyers is a Solutions Architecture Senior Manager with AWS, Zach Christopherson, an Amazon Redshift Database Engineer, contributed to this post)

Amazon Redshift는 완벽하게 관리되는 페타 바이트 규모의 대규모 병렬 데이터 웨어하우스로서 간단한 조작을 통한 높은 성능을 제공합니다. 확장에 어려움을 겪고있는 기존 데이터베이스 환경 가속화에서부터 빅데이터 분석을 위한 웹 로그 처리에 이르기까지 많은 고객들이 Amazon Redshift를 사용합니다. Amazon Redshift는 업계 표준 JDBC/ODBC 드라이버 인터페이스를 제공하므로 고객은 기존 비즈니스 인텔리전스 도구를 연결하고, 분석을 위해 사용하던 기존 쿼리를 재사용 할 수 있습니다.

Amazon Redshift는 프로덕션 트랜잭션 시스템 제 3 정규형 모델(3NF)에서 스타 및 스노플레이크 스키마 또는 간단한 플랫 테이블에 이르기까지 모든 유형의 데이터 모델을 실행할 수 있습니다. 고객이 Amazon Redshift를 채택하면 데이터 모델이 데이터베이스에 올바르게 배치되고 유지 관리되도록 아키텍처를 고려해야합니다. 이 게시물을 통해 고객은 Amazon Redshift를 채택 할 때 가장 많이 발견되는 문제를 해결할 수 있으며 각 문제를 해결하는 방법에 대한 구체적인 지침을 제공합니다. 여기에서 언급하는 각 항목을 처리하면 최적의 쿼리 성능을 달성하고 고객 요구 사항을 충족시키기 위해 효과적으로 확장 할 수 있을 것입니다.

이슈 #1 : 잘못된 컬럼 인코딩

Amazon Redshift는 열(Column) 기반 데이터베이스로, 행(Row)별로 디스크에 데이터를 구성하는 대신 데이터를 열 별로 저장하고, 런타임에 행들은 열 기반 스토리지에서 추출됩니다. 이 아키텍처는 대부분의 쿼리가 가능한 모든 차원과 측정의 특정 하위 집합 만을 액세스 하는, 많은 수의 열이 있는 테이블에 대한 분석 쿼리에 특히 적합합니다. Amazon Redshift는 SELECT 또는 WHERE 절에 포함 된 열의 디스크 블록에만 액세스 할 수 있으며, 쿼리를 평가하기 위해 모든 테이블 데이터를 읽을 필요가 없습니다. 열에 저장된 데이터도 인코딩 됩니다. (Amazon Redshift 데이터베이스 개발자 가이드에서 열 압축 유형 선택 참조), 이는 높은 읽기 성능을 제공하기 위해 많이 압축되어 있음을 의미합니다. 또한 Amazon Redshift는 색인(Index)을 생성하고 관리할 필요가 없다는 것을 의미합니다. 즉, 모든 열은 저장되는 데이터에 적합한 구조와 함께 자체 색인과 거의 같습니다.

열 인코딩을 사용하지 않고 Amazon Redshift 클러스터를 실행하는 것은 좋지 않은 방법이며, 열 인코딩이 최적으로 적용될 때 고객이 큰 성능을 얻을 수 있습니다. 이 모범 사례에서 벗어나는 경우 다음 쿼리를 실행하여 열 인코딩이 적용되지 않은 테이블이 있는지 확인하십시오.

SQL
SELECT database, schema || '.' || "table" AS "table", encoded, size 
FROM svv_table_info 
WHERE encoded='N' 
ORDER BY 2;

그렇게 난 후, 다음 쿼리를 실행하여 인코딩되지 않은 테이블과 열을 검토하십시오.

SQL
SELECT trim(n.nspname || '.' || c.relname) AS "table",trim(a.attname) AS "column",format_type(a.atttypid, a.atttypmod) AS "type", 
format_encoding(a.attencodingtype::integer) AS "encoding", a.attsortkeyord AS "sortkey" 
FROM pg_namespace n, pg_class c, pg_attribute a 
WHERE n.oid = c.relnamespace AND c.oid = a.attrelid AND a.attnum > 0 AND NOT a.attisdropped and n.nspname NOT IN ('information_schema','pg_catalog','pg_toast') AND format_encoding(a.attencodingtype::integer) = 'none' AND c.relkind='r' AND a.attsortkeyord != 1 ORDER BY n.nspname, c.relname, a.attnum;

최적으로 열 인코딩을 하지 않은 테이블이 있으면 AWS Labs GitHub의 Amazon Redshift Column Encoding 유틸리티를 사용하여 인코딩을 적용하십시오. 이 명령 행 유틸리티는 각 테이블에서 ANALYZE COMPRESSION 명령을 사용합니다. 만약 인코딩이 필요한 경우, 올바른 인코딩으로 새 테이블을 만들고 모든 데이터를 새 테이블에 복사 한 다음 원래 데이터를 유지하면서 새 테이블의 이름을 이전 이름으로 트랜잭션 방식으로 변경하는 SQL 스크립트를 생성합니다. (복합 정렬 키(compound sort key)의 첫 번째 열은 인코딩 하면 안되며, 이 유틸리티로 인코딩 되지 않습니다.)

이슈 #2 : 왜곡된 테이블 데이터

Amazon Redshift는 클러스터의 각 노드가 전체 데이터의 일부를 저장하는 분산된 비 공유 데이터베이스 아키텍처입니다. 테이블을 만들 때 노드 간에 데이터를 고르게 분산(기본값) 할지 또는 열 중 하나를 기준으로 노드에 데이터를 분산할지 결정해야 합니다. 일반적으로 함께 조인되는 열을 분산의 기준으로 선택하면, 조인 중에 네트워크를 통해 전송되는 데이터의 양을 최소화 할 수 있습니다. 이렇게 하면 여러가지 유형의 쿼리에서 성능이 크게 향상 될 수 있습니다.
좋은 분산 키(Distribution Key)를 선택하는 것은 “가장 적합한 분산 스타일 선택“을 포함한 많은 AWS 관련 글들의 주제입니다. Amazon Redshift 에서 스타 스키마 최적화 및 인터리빙된 정렬 블로그 게시물을 통해 스타 스키마의 분산과 정렬에 대한 확실한 안내를 받으시기 바랍니다. 일반적으로 좋은 분산 키는 다음과 같은 속성을 가지고 있습니다.

  • 높은 카디널리티 – 클러스터의 노드 수에 비례하여 열에 많은 수의 고유 한 데이터 값이 있어야 합니다.
  • 균일 분산 / 저 왜곡 – 분산 키의 각 고유 값은 테이블에서 짝수 번 발생해야 합니다. 이렇게 하면 Amazon Redshift가 클러스터의 각 노드에 동일한 수의 레코드를 넣을 수 있습니다.
  • 일반적으로 조인 – 분산 키의 열은 일반적으로 다른 테이블에 조인하는 열 이어야 합니다. 이 기준에 맞는 여러 개의 가능한 열이 있는 경우 가장 큰 테이블에 조인하는 열을 선택할 수 있습니다.

왜곡된 분산 키는 쿼리 실행 시 각 노드들이 똑같이 힘들지 않고, CPU 또는 메모리의 불균형이 발생하며 그리고 궁극적으로 가장 느린 노드의 속도만큼 실행됩니다.

왜곡 문제가 있는 경우 일반적으로 노드들의 성능이 클러스터에서 고르지 않은 것으로 나타납니다. Amazon Redshift Utils GitHub 저장소의 관리 스크립트 중 하나(예 : table_inspector.sql)를 사용하여 분산 키의 데이터 블록을 클러스터의 슬라이스 및 노드에 매핑하는 방법을 확인하십시오.

왜곡된 분산 키가 있는 테이블이 있는 경우, 배포 키를 높은 카디널리티와 균일 한 분포를 나타내는 열로 변경하십시오. CTAS를 사용하여 새 테이블을 작성하여 후보 열을 분산 키로 평가하십시오.

SQL
CREATE TABLE MY_TEST_TABLE DISTKEY (<COLUMN NAME>) AS SELECT * FROM <TABLE NAME>;

테이블에 대해 table_inspector.sql 스크립트를 다시 실행하여 데이터 왜곡을 분석하십시오.

레코드에 좋은 분산 키가 없으면 단일 노드를 핫스폿으로 만들지 않기 위해 EVEN 방식으로 분산하는 것이 효과적이라는 것을 알 수 있습니다. 작은 테이블의 경우 DISTSTYLE ALL을 사용하여 테이블 데이터를 클러스터 내의 모든 노드에 저장 할 수 있습니다.

이슈 #3 : 정렬 키를 사용하지 않는 쿼리

Amazon Redshift 테이블에는 다른 데이터베이스의 인덱스처럼 작동하지만 다른 플랫폼과는 달리 저장소 비용이 발생하지 않는 정렬 키 열을 설정할 수 있습니다. 자세한 내용은 정렬 키 선택을 참조하십시오. 정렬 키는 WHERE 절에서 가장 일반적으로 사용되는 열에 작성되어야 합니다. 알려진 쿼리 패턴이 있는 경우 COMPOUND 정렬 키가 최상의 성능을 제공합니다. 최종 사용자가 다른 열을 똑같이 쿼리하면 INTERLEAVED 정렬 키를 사용하십시오.

정렬 키가 없는 테이블을 찾고, 얼마나 자주 쿼리가 되었는지 확인하려면 다음 쿼리를 실행합니다.

SQL
SELECT database, table_id, schema || '.' || "table" AS "table", size, nvl(s.num_qs,0) num_qs
FROM svv_table_info t
LEFT JOIN (SELECT tbl, COUNT(distinct query) num_qs
FROM stl_scan s
WHERE s.userid > 1
  AND s.perm_table_name NOT IN ('Internal Worktable','S3')
GROUP BY tbl) s ON s.tbl = t.table_id
WHERE t.sortkey1 IS NULL
ORDER BY 5 desc;

Amazon Redshift Developer Guide에서 정렬되지 않은 테이블을 처리하는 방법론을 참고하실 수 있습니다. 또한 쿼리 활동을 기반으로 정렬 키 권장 이라는 GitHub 의 관리 스크립트를 활용할 수도 있습니다. 정렬 키 열에 대해 평가 된 조회는 정렬 키에 SQL 함수를 적용해서는 안됩니다. 대신 비교 값에 함수를 적용하여 정렬 키가 사용되는지 확인하십시오. 이것은 일반적으로 정렬 키로 사용되는 TIMESTAMP 컬럼에서 발견됩니다.

이슈 #4 : 통계가 없거나 버큠(vacuum)이 필요한 테이블

Amazon Redshift는 다른 데이터베이스와 마찬가지로 쿼리를 계획 할 때 올바른 결정을 내리기 위해 테이블 및 저장될 테이터 블록의 구성에 대한 통계정보가 필요합니다(자세한 내용은 테이블 분석 참조). 좋은 통계가 없으면 옵티마이저는 테이블에 액세스하는 순서나 데이터 세트를 조인하는 방법에 대해 최선이 아니거나 잘못된 선택을 할 수 있습니다.

Amazon Redshift Developer GuideANALYZE Command History 항목은 누락되거나 부실한 통계를 해결하는 데 도움이 되는 쿼리를 제공하며, missing_table_stats.sql 관리 스크립트를 실행하여 통계가 누락 된 테이블을 확인하거나 아래 구문을 사용하여 오래된 통계정보를 가지고 있는 테이블을 확인할 수 있습니다.

SQL
SELECT database, schema || '.' || "table" AS "table", stats_off 
FROM svv_table_info 
WHERE stats_off > 5 
ORDER BY 2;

Amazon Redshift에서 데이터 블록은 변경 불가능합니다. 행이 삭제되거나 업데이트되면 단순히 논리적으로 삭제되고 (삭제 플래그가 있음) 디스크에서 물리적으로 제거되지는 않습니다. 업데이트로 인해 새로운 블록이 작성되고 새로운 데이터가 추가됩니다. 이 두 가지 조작으로 인해 행의 이전 버전이 계속해서 디스크 스페이스를 소비하고 특정 쿼리가 테이블을 스캔할 때 논리적으로 삭제된 행이 계속 읽히게 됩니다. 결과적으로, 테이블의 저장 공간이 증가하고, 스캔 중에 디스크 I/O를 피할 수 없으므로 성능이 저하됩니다. VACUUM 명령은 삭제 된 행에서 공간을 복구하고 정렬 순서를 복원합니다.

누락되거나 오래된 통계가 있거나 버큠이 필요한 테이블 문제를 해결하려면 AWS Labs 유틸리티인 Analyze & Vacuum Schema 를 실행하십시오. 이렇게 하면 항상 최신 통계를 유지하고 실제로 재구성이 필요한 테이블들만 버큠을 할 수 있습니다.

이슈 # 5 – 매우 큰 VARCHAR 열을 가진 테이블

복잡한 쿼리를 처리하는 동안 중간 쿼리 결과를 임시 블록에 저장해야 할 수 있습니다. 이러한 임시 테이블은 압축되지 않으므로 불필요하게 넓은 열은 과도한 메모리 및 임시 디스크 공간을 소비하므로 쿼리 성능에 영향을 줄 수 있습니다. 자세한 내용은 가능한 가장 작은 열 크기 사용을 참조하십시오.
다음 쿼리를 사용하여 최대 열 너비를 포함하는 테이블 목록을 검토할 수 있습니다.

다음 쿼리를 사용하여 최대 열 너비를 포함하는 테이블 목록을 검토할 수 있습니다.

SQL
SELECT database, schema || '.' || "table" AS "table", max_varchar 
FROM svv_table_info 
WHERE max_varchar > 150 
ORDER BY 2;

테이블 목록을 얻은 후에는, 다음 쿼리를 사용하여 넓은 varchar 열을 가진 테이블 열을 식별 한 다음 각 열에 대한 실제 최대 너비를 결정하십시오.

SQL
SELECT max(len(rtrim(column_name))) 
FROM table_name;

경우에 따라 JSON 함수를 사용하여 쿼리하는 JSON 조각을 테이블에 저장하기 때문에 큰 VARCHAR 유형 열이 있을 수 있습니다. top_queries.sql 관리 스크립트를 사용하여 데이터베이스에 대해 가장 많이 실행되는 쿼리를 찾는 경우, JSON 조각 열을 포함하는 SELECT * 쿼리에 특히 주의하십시오. 최종 사용자가 이러한 큰 열을 쿼리하지만 실제로 JSON 함수를 사용하지 않으면, 원래 테이블의 기본 키 열과 JSON 열만 포함하는 다른 테이블로 데이터를 이동하는 것이 좋습니다.

필요한 것보다 넓은 열이 테이블에 있는 경우 deep copy 를 수행하여 적절한 너비의 열로 구성되는 새로운 버전의 테이블을 만들어야 합니다.

이슈# 6 – 큐(Queue) 슬롯에서 대기중인 쿼리

Amazon Redshift는 작업 부하 관리(WLM)라는 큐 시스템을 사용하여 쿼리를 실행합니다. 서로 다른 작업 부하를 분리하기 위해 최대 8 개의 큐를 정의 할 수 있으며 전체 처리량 요구 사항을 충족하도록 개별 큐의 동시성을 설정할 수 있습니다.

어떤 경우에는 사용자 또는 쿼리가 할당 된 큐가 완전히 사용 중이어서 추가 쿼리는 슬롯이 열릴 때까지 대기 해야합니다. 이 시간 동안 시스템은 추가 쿼리를 전혀 실행하지 못하기 때문에 이는 동시성을 높여야 한다는 신호입니다.

먼저 queuing_queries.sql 관리 스크립트를 사용하여 쿼리가 대기 중인지 여부를 확인해야합니다. 그리고 난 후 wlm_apex.sql을 사용하여 과거에 클러스터가 필요로 했던 최대 동시성을 검토하고 wlm_apex_hourly.sql을 사용하여 시간별 히스토리 분석을 진행하십시오. 동시성을 높이면, 동시에 더 많은 쿼리를 실행할 수 있지만 동일한 양의 메모리(증가시키지 않는 한)를 공유한다는 점을 유의하십시오. 동시성을 높이면 일부 쿼리는 실행 중에 임시 디스크 저장소를 사용하여야 하며, 다음 문제에서 볼 수 있듯이 최적의 방안은 아닙니다.

이슈 # 7 – 디스크 기반 쿼리

쿼리가 메모리에서 완전히 실행될 수 없는 경우, Explain 플랜의 일부에 대해 디스크 기반의 임시 저장 영역을 사용해야 할 수도 있습니다. 추가적인 디스크 I/O는 쿼리 속도를 늦추게 되는데, 이는 세션에 할당 된 메모리 양을 늘림으로써 해결할 수 있습니다(자세한 내용은 WLM 동적 메모리 할당 참조).

디스크에 사용하는 쿼리가 있는지 확인하려면 다음 쿼리를 사용하십시오.

SQL
SELECT
q.query, trim(q.cat_text)
FROM (SELECT query, replace( listagg(text,' ') WITHIN GROUP (ORDER BY sequence), '\n', ' ') AS cat_text FROM stl_querytext WHERE userid>1 GROUP BY query) q
JOIN
(SELECT distinct query FROM svl_query_summary WHERE is_diskbased='t' AND (LABEL LIKE 'hash%' OR LABEL LIKE 'sort%' OR LABEL LIKE 'aggr%') AND userid > 1) qs ON qs.query = q.query;

사용자 또는 큐 할당 규칙에 따라 선택한 큐에 지정된 메모리 양을 늘려서 완료해야하는 쿼리가 디스크를 사용하지 않도록 할 수 있습니다. 세션의 WLM_QUERY_SLOT_COUNT 를 기본값인 1에서 큐의 최대 동시성으로 늘릴 수도 있습니다. 문제# 6에서 설명한 것처럼 쿼리 대기열이 생길 수 있으므로 주의해서 사용해야 합니다.

이슈 # 8 – 커밋 큐 대기

Amazon Redshift는 트랜잭션 처리가 아닌 분석 쿼리를 위해 설계 되었습니다. COMMIT 비용이 상대적으로 높기 때문에 COMMIT를 과도하게 사용하면 쿼리가 커밋 큐를 액세스하기 위해 기다릴 수 있습니다.

데이터베이스에 너무 자주 커밋하는 경우commit_stats.sql 관리 스크립트로 커밋 큐에서 대기하는 쿼리가 증가하는 것을 볼 수 있습니다. 이 스크립트는 지난 2 일 동안 실행 된 쿼리의 최대 큐 길이 및 큐 시간을 보여줍니다. 만약 커밋 큐에서 대기중인 쿼리가 있는 경우, 진행상황을 로깅하거나 비효율적인 데이터 로드를 구행하는 ETL 작업과 같이, 세션 당 다수의 커밋을 수행하는 세션을 찾아야 합니다.

이슈 # 9 – 비효율적인 데이터 로드

Amazon Redshift 모범 사례는 COPY 명령을 사용하여 데이터로드를 수행 할 것을 제안합니다. 이 API 작업은 클러스터의 모든 컴퓨트 노드를 사용하여 Amazon S3, Amazon DynamoDB, Amazon EMR HDFS 파일 시스템 또는 SSH 연결과 같은 원본에서 데이터를 병렬로 로드 합니다.

데이터 로드를 수행 할 때 가능하다면 로드 할 파일을 압축해야 합니다. Amazon Redshift는 GZIP 및 LZO 압축을 모두 지원합니다. 하나의 큰 파일보다 많은 수의 작은 파일을 로드하는 것이 더 효율적이며 이상적인 파일 수는 슬라이스 수의 배수입니다. 노드 당 슬라이스 수는 클러스터의 노드 크기에 따라 다릅니다. 예를 들어, 각 DS1.XL 컴퓨트 노드에는 두 개의 슬라이스가 있고 각 DS1.8XL 컴퓨트 노드에는 16 개의 슬라이스가 있습니다. 슬라이스 당 짝수 개의 파일을 사용함으로써 COPY 실행이 클러스터 리소스를 고르게 사용하고 최대한 빨리 완료됨을 알 수 있습니다.

안티 패턴은 단일 레코드를 INSERT 하거나 또는 한 번에 최대 16MB 데이터를 INSERT 할 수 있는 다중 값 INSERT 문의 사용으로 Amazon Redshift에 직접 데이터를 INSERT하는 것입니다. 이는 리더 노드 기반 작업이며 리더 노드의 CPU 또는 메모리 사용을 극대화하여 성능 병목 현상을 유발할 수 있습니다.

이슈 # 10 – 비효율적인 임시 테이블 사용

Amazon Redshift는 임시 테이블을 제공합니다. 이 테이블은 단일 세션 내에서만 볼 수 있다는 것을 제외하면 일반 테이블과 같습니다. 사용자가 세션의 연결을 끊으면 테이블은 자동으로 삭제됩니다. 임시 테이블은 CREATE TEMPORARY TABLE 구문을 사용하거나 SELECT … INTO #TEMP_TABLE 쿼리를 실행하여 만들 수 있습니다. SELECT … INTO 및 C(T)TAS 명령은 입력 데이터를 사용하여 열 이름, 크기 및 데이터 유형을 결정하고 기본 저장소 특성을 사용하는 반면 CREATE TABLE 문은 임시 테이블의 정의를 완벽하게 제어합니다.

이러한 기본 저장소 속성은 신중하게 고려하지 않으면 문제가 발생할 수 있습니다. Amazon Redshift의 기본 테이블 구조는 열 인코딩이 없는 EVEN 분산 방법을 사용하는 것입니다. 이것은 많은 유형의 쿼리에 대해 차선의 데이터 구조이며, select/into 구문을 사용하는 경우 열 인코딩이나 분산 및 정렬 키를 설정할 수 없습니다.

CREATE 문을 사용하려면 모든 select/into 구문을 변환하실 것을 권장합니다. 이렇게 하면 임시 테이블에 열 인코딩이 적용되고 워크플로의 일부인 다른 엔터티에 동정적인 방식으로 분산됩니다. 사용하는 명령문을 변환하려면 다음을 수행하십시오.

SQL
select column_a, column_b into #my_temp_table from my_table;

최적의 열 인코딩을 위해 임시 테이블을 분석합니다.

그런 다음 select/into 문을 다음으로 변환합니다.

SQL
BEGIN;
create temporary table my_temp_table(
column_a varchar(128) encode lzo,
column_b char(4) encode bytedict)
distkey (column_a) -- Assuming you intend to join this table on column_a
sortkey (column_b); -- Assuming you are sorting or grouping by column_b

insert into my_temp_table select column_a, column_b from my_table;
COMMIT;

임시 테이블이 후속 쿼리의 조인 테이블로 사용되는 경우 임시 테이블의 통계를 분석 할 수도 있습니다.

SQL
analyze my_temp_table;

이렇게 하면, 분산 키를 지정하고 열 인코딩을 사용하여 Amazon Redshift의 열 기반 특성의 장점을 취함으로써, 임시 테이블을 사용하는 기능은 그대로 유지되지만 클러스터에 데이터 위치를 제어 할 수 있습니다.

Tip: Explain plan 경고 사용

마지막 팁은 쿼리 실행 중에 클러스터의 진단 정보를 사용하는 것입니다. 이것은 STL_ALERT_EVENT_LOG라는 매우 유용한 뷰(view)에 저장됩니다. perf_alert.sql 관리 스크립트를 사용하여 지난 7 일 동안 클러스터에서 발생한 문제를 진단할 수 있습니다. 이는 시간이 지남에 따라 클러스터가 어떻게 발전 하는지를 이해하는 데 매우 귀중한 자료입니다.

요약

Amazon Redshift는 클라우드 기반에서 성능을 크게 향상시키고 비용을 절감 할 수 있는 완벽하게 관리되는 강력한 데이터 웨어하우스 입니다. Amazon Redshift는 모든 유형의 데이터 모델을 실행할 수 있지만 데이터를 저장하고 관리하는 방법을 알고 있으면 성능이 저하되거나 비용이 증가 할 수 있는 오류를 피할 수 있습니다. 일반적인 문제에 대한 간단한 진단 쿼리들을 실행하고 최상의 성능을 얻을 수 있도록 하십시오.

데이터 로딩 성능을 높이려면, Amazon Redshift에서 빠르게 데이터 로딩하기 글을 참고하시기 바랍니다.

본 글은 아마존웹서비스 코리아의 솔루션즈 아키텍트가 국내 고객을 위해 전해 드리는 AWS 활용 기술 팁을 보내드리는 코너로서, 이번 글은 양승도 솔루션즈 아키텍트께서 번역해주셨습니다.
sd-yang-photo

Amazon GameLift 시작하기

올해 초에 처음 발표된 Amazon GameLift는 세션 기반의 멀티 플레이어 게임 서비스를 손쉽게 구축하고 운영하기 쉽도록 도와주는 관리형 서비스입니다.  지난 2월 블로그 글을 통해서 Amazon Lumberyard에 기본적으로 포함된 멀티플레이어 게임 샘플을 GameLift상에서 돌려보는 방법에 대한 소개를 드린 바 있습니다.

또한 지난 9월 Gaming On AWS 행사를 통해서 Amazon GameLift Deep-dive 강연에서 GameLift에 대해 자세한 내용을 다루었습니다. 이번 글에서는 좀 더 구체적으로 여러분이 만든 게임 서버를 직접 GameLift에 올려서 사용하는 방법과 게임 클라이언트가 GameLift의 Fleet에 접근하는 방법에 대해 다루어 보도록 하겠습니다.

Amazon GameLift 복습하기
GameLift 연동 방법 설명에 앞서, GameLift의 전체적인 개념을 기술적인 관점에서 다시 한 번 정리하고 넘어가도록 하겠습니다.  온라인 게임을 서비스하기 위해서는 크게 3가지 측면에서의 준비가 필요합니다.

첫번째는 플레이어들이 직접 실행하여 게임을 즐길 수 있도록 하는 게임 클라이언트고, 두번째는 다수의 게임 클라이언트들의 접속을 받아서 멀티플레이를 중계해주는 게임 서버입니다. 세번째는 게임 클라이언트들의 인증처리뿐만 아니라 게임 서버들을 제어하고 모니터링 할 수 있도록 운영을 도와주는 게임 서비스 플랫폼입니다. 바로 이 게임 서비스 플랫폼 역할에 더하여 게임 서버들의 확장/축소(scaling)를 도와주는 것이 GameLift입니다.  (여러분들의 게임 서버를 AWS가 만들어 주는 것이 아닙니다.)

게임 서버를 호스팅 하기 위해서는 직접 개발한 게임 서버 빌드로부터 플릿을 생성하면 됩니다.  플릿을 생성하면 처음에는 초기 설정한 대수만큼의 EC2 인스턴스가 게임 서버를 호스팅하게 됩니다. (물론, 이후에는 GameLift의 Auto-scaling 기능을 통해 인스턴스 수를 자동으로 확장/축소할 수 있습니다.)

gamelift1

플릿 생성시에 하나의 EC2 인스턴스가 몇 개의 게임 서버 프로세스를 호스팅할지 정할 수 있습니다. 기본적으로 하나의 게임 서버 프로세스는 하나의 게임 세션을 맡아서 처리 합니다. 즉, 게임 서버 작성시에 하나의 게임 세션을 처리할 수 있도록 구현하면 됩니다. (참고: 현재 하나의 게임 세션당 받을 수 있는 최대 플레이어 세션 제한은 250명 입니다.) 게임 서버의 워크로드와 인스턴스 성능에 따라 다르지만 하나의 인스턴스는 적게는 수십개, 많게는 수백개의 게임 세션을 호스팅 하도록 설정하는 것이 일반적입니다.

GameLift 플릿이 게임 세션을 생성 가능한 상태인 Active상태가 되면 게임 클라이언트는 플릿에 직접 요청(게임 세션 생성, 게임 세션 내 플레이어 슬롯 예약, 게임 세션에 참여 등)할 수 있습니다. 당연히, 게임 클라이언트는 EC2인스턴스의 상태를 전혀 몰라도 됩니다. 단지, 어느 플릿에 접근하면 되는지에 대한 정보만 알면 되기 때문입니다.

Amazon GameLift SDK 사용하기
GameLift를 사용하기 위해서는 2가지 종류의 SDK를 사용하여야 합니다. 게임 서버는 GameLift 전용 Server SDK를 사용하여 통합작업을 하면 되지만 게임 클라이언트의 경우는 GameLift 전용 SDK가 따로 존재하는 것이 아니라 기본적으로 프로그래밍 언어별로 제공되는 AWS SDK를 사용하면 됩니다.

지난 블로그 글을 통해 AWS C++ SDK 사용하는 법을 소개 드린 적이 있습니다만, C++언어 뿐만 아니라 AWS SDK가 제공하는 타 언어별 SDK를 사용하셔도 됩니다. 즉, 게임 클라이언트 프레임워크의 상황에 맞게 적합한 AWS SDK를 사용하시면 됩니다.

게임 클라이언트와 게임 서버간의 통신에는 TCP 및 UDP 프로토콜을 사용하실 수 있으며, 메시지 전달을 위한 패킷은 직접 구현하시거나 기존의 유명한 데이터 직렬화 및 패킷 생성 도구인 Google Protocol BuffersMessagePack를 활용하셔도 좋습니다.

게임 클라이언트와 게임 서버, GameLift 서비스간의 API 레벨에서의 전체적인 상호 작용은 다음 그림을 참고하시기 바랍니다.

gamelift2

GameLift Server SDK통해서 게임 서버 연동하기
그럼 이제 본격적으로 여러분들의 게임 서버에 GameLift Server SDK를 연동하는 방법에 대해 알아보겠습니다. GameLift Server SDK는 C++로 작성된 게임 서버와 통합할 수 있습니다. (향후 C# 프로그래밍 언어도 지원할 예정입니다.)

지원하는 운영체제는 Windows Server 및 Amazon Linux이며, 사용하고자 하는 운영체제에 맞춰 빌드해야 합니다. Windows Server의 경우에는 Visual Studio 2013 이상, Linux의 경우에는 GCC 4.9 이상의 버전이 필요합니다. 추가로 CMAKE가 필요하며 자세한 빌드 방법에 대해서는GameLift Server SDK내에 포함된 README.md 파일을 참고하시기 바랍니다.

GameLift Server SDK 빌드가 완료되면 생성되는 라이브러리 파일(Windows의 경우 *.dll 및 *.lib, Linux의 경우에는 *.a 또는 *.so)과 GameLift Server SDK의 include 디렉토리에 포함된 헤더파일들을 게임 서버가 위치한 프로젝트로 복사하시기 바랍니다. Visual Studio의 경우에는 프로젝트 설정에서 해당 파일들의 위치를 지정해주시고, GCC를 사용하는 경우에는 Makefile 또는 CMakeLists.txt 파일을 통해 해당 라이브러리와 헤더 파일의 위치를 게임 서버 프로젝트에서 참조할 수 있게 지정해주시기 바랍니다. GameLift Server SDK가 연동된 게임 서버 프로젝트 예제를 참고하시기 바랍니다.

GameLift Server SDK에서 제공하는 게임 서버전용 API는 다음과 같으며, 여러분들이 제작하는 게임 서버에서 이 API를 호출하는 부분과 GameLift서비스가 게임 서버에게 요청하는 콜백 함수에 대한 구현을 하시면 됩니다.

  • 게임 서버가 GameLift 서비스에 요청하는 API
    • ProcessReady() – 게임 서버가 준비 되었음을 GameLift 서비스에게 알림. 이 호출이 성공적으로 완료되면 플릿 상태가 Active로 됨.
    • ActivateGameSession() – 게임 세션이 준비완료 되었음을 GameLift 서비스에게 알림. 이후에 플레이어의 접속을 받아 게임 세션에 참여 시키면 됨.
    • AcceptPlayerSession() – 접속한 게임 클라이언트가 정상적인 플레이어라면 이 API 호출을 통해 GameLift 서비스에게 알림. 이를 통해 GameLift 서비스는 플레이어가 게임 세션에 참여했음을 알게됨.
    • RemovePlayerSession() – 게임 클라이언트가 게임 세션에서 나갔을 때, 게임 서버가 GameLift 서비스에게 통보하는 API.
    • TerminateGameSession() – 게임 세션이 종료되었을 때 GameLift 서비스에게 알려서 게임 세션을 종료하도록 하는 API.
    • ProcessEnding() – 게임 서버 프로세스가 종료되었음을 알리는 API. 이 경우 GameLift 서비스가 해당 게임 서버를 종료시키고 새로운 게임 서버 프로세스를 생성하여 추후의 게임 세션 요청에 대해 준비하도록 함.
  • GameLift 서비스가 게임 서버에게 요청하는 콜백함수
    • onHealthCheck() – 주기적으로 GameLift 서비스가 게임 서버가 살아있는지 호출하는 함수로 게임 서버가 정상이라면 true를 리턴해주면 됨.
    • onStartGameSession() – 게임클라이언트가 GameLift 서비스에 게임 세션 생성을 요청하게 되면, GameLift 서비스가 게임 서버에게 이 콜백 함수를 통해 통지함. 게임 서버는 게임 세션 준비가 완료되면 ActivateGameSession() API 호출을 통해 게임 세션 준비가 완료되었음을 알리면 됨.

구체적인 사용 샘플 코드 구현을 참고하시기 바랍니다.  이런 방식으로 GameLift Server SDK를 활용한 게임 서버의 빌드가 준비되었다면 AWS CLI를 통하여 GameLift에 빌드를 올려야 합니다. 기본적으로 생성된 게임 서버 실행파일 이외에도 의존성 있는 파일들(DLL 등)이 있다면 함께 하나의 폴더 내에 모아주시기 바랍니다. 준비가 완료 되면 다음과 같은 명령어를 통해 GameLift상에 빌드를 올릴 수 있고, 업로드가 완료되면 AWS 콘솔 상에서 확인이 가능합니다.

$ aws gamelift upload-build --name “빌드 이름” --build-version “빌드 버전” --build-root “빌드가 있는 폴더” --operating-system <운영체제:  WINDOWS_2012 또는 AMAZON_LINUX>   --region <리전>

업로드된 게임 서버 빌드를 보실 수 있습니다.

gamelift3

이제 해당 빌드로부터 플릿을 생성할 수 있습니다. 빌드를 선택하고 플릿 생성하기를 진행하게 되면 몇 가지 설정을 하여야 합니다. 대표적으로 EC2 인스턴스 타입 설정, 실행파일 이름, 게임 서버 프로세스 수, 열어둘 포트 번호 및 프로토콜 등을 설정하게 됩니다. 또한 Auto-scaling 정책을 설정하게 되는데 이 정책은 플릿 생성후에 수정할 수도 있습니다. 모든 설정을 마쳤다면, 플릿을 생성하시기 바랍니다.

기본적으로 게임 클라이언트는 플릿 ID를 통해 플릿에 접근하게 됩니다. 하지만, ALIAS기능을 활용하기를 추천드립니다. ALIAS는 플릿의 ID를 바라보게 할 수 있고 이를 사용하게 되면, 게임 클라이언트는 ALIAS ID를 통해서 지정된 플릿에 접근할 수 있습니다. 만일 게임 클라이언트 수정 없이 새로운 플릿으로 접속을 유도하고 싶다면, ALIAS가 바라보는 플릿의 ID만 바꾸면 되기 때문에, 중단 없이 새로운 플릿으로 접속을 유도할 수 있습니다. (즉, ALIAS 기능을 통한 무중단 배포가 가능함을 의미합니다.)

gamelift4

AWS SDK통해서 게임 클라이언트 연동하기
게임 서버가 플릿에 올라가 있는 상황이라면, 게임 클라이언트가 플릿에 접속해서 게임 세션에 참여할 수 있습니다. GameLift 연동 가능한 게임 클라이언트 준비는 앞서 설명 드린 게임 서버 연동에 비해서는 쉬운 편입니다.  또한, 프로그래밍 언어나 프레임워크 선택도 자유로운 편입니다. 그 이유는 AWS SDK를 쓸 수 있는 환경이기만 하면 되기 때문입니다.

즉, 각 프로그래밍 언어별로 존재하는 AWS SDK를 여러분들의 게임 클라이언트에서 사용하도록 설정하면 됩니다. 게임 클라이언트 제작시 가장 많이 사용되는 프로그래밍 언어인 C++의 경우에는 얼마전 정식 버전이 발표된 AWS C++ SDK를 사용하면 되며, 자세한 사용 방법에 대해서는 지난 블로그 포스팅에서 다룬 바 있습니다. 예를 들어, 유명한 오픈소스 게임 엔진인 Cocos2d-x에 AWS C++ SDK를 연동하여 GameLift를 사용하는 샘플 프로젝트를 참고하시기 바랍니다.

GameLift 연동을 위해서 게임 클라이언트를 구현시 사용하게 되는 API는 다음과 같습니다.

  • CreateGameSession() – GameLift서비스에 게임 세션 생성을 요청하는 API. 대상 플릿ID 또는 ALIAS ID 설정하고 해당 게임 세션이 최대로 수용할 수 있는 플레이어 세션 수를 지정. 요청에 대한 응답으로 게임 세션 ID및 해당 게임 세션을 호스팅하는 게임 서버의 IP주소와 포트 번호를 받게 됨.
  • SearchGameSessions() – 이미 만들어진 게임 세션이 있다면, 조건식으로 해당 게임 세션을 찾는 API. 여러가지 조건으로 게임 세션 검색이 가능하며, 자세한 조건식 작성 방법은 API 문서에서 확인 가능. 요청에 대한 응답은 위의 CreateGameSession()과 같음.
  • CreatePlayerSession() – 참여하고자 하는 적합한 게임 세션을 찾거나 만든 후에, 플레이어 참여를 시킬 수 있도록 플레이어 세션을 생성하는 API. 요청에 대한 응답으로 플레이어 세션 ID를 발급 받게 되며, 이후에 실제 게임 서버에 접속을 요청하면 됨.

이외에도 게임 클라이언트가 사용할 수 있는 API가 있지만 대부분의 경우에는 위의 3종류 API만 사용하게 됩니다. 전체적인 API 상호 작용 과정은 아래 그림을 참고하시기 바랍니다.

gamelift5

게임 클라이언트가 요청하는 GameLift API는 그에 맞는 권한이 IAM을 통하여 부여 되어야 합니다. IAM 권한을 모든 사용자에게 부여하기 힘든 환경이라면 제3자 인증 주체(Amazon, Google, Facebook 등)와의 연방화(Federation)을 통해서 권한을 부여할 수 있습니다. 제 3자를 통한 인증이 힘든 상황이라면 Amazon Cognito UserPool을 활용(https://aws.amazon.com/ko/blogs/korea/how-to-own-user-auth-service-using-amazon-cognito/)하여 직접 인증 서비스를 구축하실 수도 있습니다.

이렇게 여러분의 게임 서버 및 게임 클라이언트를 GameLift에 연동함으로써, 게임 클라이언트는 플릿에 게임 세션을 요청하고 적합한 게임 세션을 찾은 후에 플레이어 세션 생성을 통해 게임에 참여할 수 있게 됩니다. 이제 직접 GameLift의 웹 콘솔을 통하여 서비스 상태 모니터링 및 플릿의 설정을 원하는대로 제어해 보시기 바랍니다.

필요에 따라 수동으로도 게임 서버를 호스팅하는 인스턴스의 수를 조정할 수 있으며, 게임 세션 및 플레이어 세션들의 세부 상태에 대한 확인과 제어가 가능 합니다. 이렇게 GameLift를 통하여 세션형 멀티 플레이어 게임의 서버 관리 부담을 덜어낼 수 있을 뿐만 아니라, 사용자의 상황에 맞게 플릿의 인스턴스 수가 자동으로 확장/축소 되는 기능을 통해 손쉽게 게임 서비스를 운영할 수 있습니다.

본 글은 아마존웹서비스 코리아의 솔루션즈 아키텍트가 국내 고객을 위해 전해 드리는 AWS 활용 기술 팁을 보내드리는 코너로서, 이번 글은 구승모 솔루션즈 아키텍트께서 작성해주셨습니다.

AWS로 딥 러닝을 위한 프레임워크 MxNet 활용하기

머신 러닝에 대한 관심이 폭발적으로 증가했습니다. 특히, 국내에서는 올해 알파고로 인해 딥러닝(Deep Learning)에 대한 관심이 크게 증가하였습니다. 인공 신경망을 이용한 딥 러닝 기법은 하드웨어 성능의 비약적인 개선과 신경망 알고리즘의 개선으로 인해 실제 활용 가능한 수준으로 빠르게 변화하였습니다.

이러한 관심으로 인해 분산 딥 러닝 프레임워크(distributed deep-learning framework)가 많이 개발되어 오픈소스 형식으로 공개되고 있는 상황입니다. 게임 서비스 영역에서도 차츰 딥 러닝을 활용한 서비스들이 지속적으로 나타나고 있습니다. 인공 지능 연구 및 서비스 개발자의 요구 사항, 지원 언어 및 하드웨어 따라 여러 종류의 딥 러닝 프레임워크가 개발되어 공개되었습니다. 대표적인 것이 MXNet,   Caffe , Theano , TensorFlow™, Torch  등이 있습니다.

딥러닝 프레임워크 소개
DeepLearning 4J에서 비교한 딥러닝 프레임워크 비교 기사를 보면 아래와 같은 장단점을 나열할 수 있습니다. (본 자료는 AWS의 공식적인 자료가 아니며, DeepLearning 4J의 의견입니다.)

프레임워크 장점 단점
Theano
  • Python 지원
  • Wrapper 를 통한 높은 추상화로 사용성 편리
  • 여러 에코시스템이 존재
  •  연구용으로 많이 사용됨
  • Theano자체는 로우레벨 라이브러리
  • 큰 규모 모델에 많은 컴파일 시간
  • torch에 비해 매우 큰 라이브러리
  • 에러메시지가 부정확
Torch
  • 모듈화된 라이브러리로 상호 연계가 쉬움
  • GPU지원, 본인 레이어 타입 작성이 편리
  • 선훈련된 모델들이 많음
  • Lua 기반
  • 회귀 뉴럴 네트워크에 적합하지 않음
  • 문서화 부실
TensorFlow
  • Python + Numpy
  • 컴퓨팅 그래프 추상화
  • Theano보다 빠른 컴파일
  • 시각화를 위한 TensorBoard
  • 데이터와 모델의 병렬화
  • 다른 프레임워크보다 느림
  • Torch보다 훨씬 큰 라이브러리
  • 선 훈련된 모델이 적음
  • 계산 그래프가 Python으로 되어 있어서 느림
  • 도구로서의 기능이 약함
Caffe
  • 이미지 프로세싱에 적합
  • 잘 튜닝된 네트워크
  • 코드 작성없이 모델 트레이닝 가능
  • Python인터페이스가 유용
  • GPU를 위해서는 C++/CUDA작성 필요
  • 회귀 네트워크에는 부적합
  • 큰 네트워크에는 부적절
  • 확장성이 떨어짐
MxNet
  • 혼합 패러다임 지원(symbolic/imperative)
  • 자동 미분화
  • GPU, mobile에서도 동작
  • 여러 언어 지원(C++, Python, R, Scala, Julia, Matlab and Javascript)
  • 최적화된 C++ 엔진으로 좋은 성능
  • 로우 레벨 텐서 연산자가 적음
  • 흐름 제어 연산자 지원하지 않음
  • 컴파일 세팅에 따라 결과가 달라짐.
  • 자신의 커스컴 레이어 생성을 위해서는 어느정도 백엔드 텐서 라이브러리 이해가 필요

아마존의 CTO인 Werner Vogels 박사께서는 최근 MXNet – Deep Learning Framework of Choice at AWS라는 글에서 확장 능력, 개발 속도, 이동성 등의 다양한 요인을 비추어 볼 때, MXNet이 가장 좋은 딥러닝 프레임웍이라고 판단하고, 이를 기반한 딥러닝 서비스 개발 지원 및 오픈 소스 지원에 대한 의지를 피력한 바 있습니다.

MxNet은 오픈소스로 여러 언어를 지원하고 모바일부터 서버까지 다양한 디바이스를 지원하는 딥 러닝 프레임워크 입니다. CPU와 GPU 연산을 지원하고, 심볼릭과 명령적(imperative) 프로그래밍의 혼합 방식 까지 지원하며 최적화된 엔진을 사용해서 성능이 뛰어납니다.

또한 실무적으로 많이 사용하는 Python, C++, R, Scala, Julia, Matlab, and JavaScript을 지원하는 등 산업계에서 응용하기에 매우 적합한 딥 러닝 프레임워크입니다.

아래 그림에서 보시다시피, Inception v3 (MXNet 및 P2 인스턴스 사용)를 통해 GPU 숫자를 증가시켰을 때, 다른 라이브러리 보다 빠른 처리량을 가짐과 동시에 GPU 숫자가 증가하는 확장 상황에서도 처리량의 효율이 85%에 달할 정도로 뛰어난 성능을 보여 주고 있습니다.

컴퓨팅 처리량 및 효율 뿐만 아니라 메모리 사용량도 중요합니다. MXNet은 1,000개의 신경망 레이어를 사용할 때 4GB 이하의 메모리를 사용하고, 이식성 면에서도 다양한 플랫폼을 지원합니다. 안드로이드나 iOS에서도 활용 가능하고, 심지어 자바스크립트 확장 기능으로 웹 브라우저에서도 실행 할 수 있습니다.

DeepLearning AMI를 통해 MXNet 실행하기
이 글에서는 Amazon EC2의 신규 GPU 기반 P2 인스턴스 및 G2 인스턴스를 통해 딥러닝 API를 기반으로 MXNet을 간단히 실행해 보겠습니다. (P2 및 G2 인스턴스는 시간당 가격이 다른 인스턴스에 비해 높으므로, 짧은 시간 테스트를 위해서는 스팟 인스턴스를 이용해 보는 것도 권장합니다.)

2016-11-mxnet-1

먼저 AWS 마켓 플레이스에서 제공하는 Amazon Deep Learning AMI을 기반으로 인스턴스를 실행합니다. 본 AMI에 설치된 딥 러닝 프레임워크는 Caffe, MxNet, TensorFlow, Theano, Torch 입니다. 우리는 여기서 MxNet을 사용해 보겠습니다. SSH로 접속해서 인스턴스의 src 디렉토리에 있습니다.

2016-11-mxnet-2

인스턴스의 src/mxnet/example 디렉토리를 보면 많은 예제들이 존재합니다. 이와 관련된 튜토리얼은 http://mxnet.io/tutorials/index.html 링크를 참조하면 됩니다.

우리가 실행을 해볼 것은 숫자 이미지를 트레이닝 해서 특정 이미지 내 숫자 데이터가 어떤 것인지 찾아내는 예제입니다. 간단한 Python 코드를 통해 해 볼 수 있습니다. (http://mxnet.io/tutorials/python/mnist.html.)

다만 여기서 플롯팅의 경우 현재 실행 중인 인스턴스에서 구동이 되지 않기 때문에 플롯(plot)을 이미지로 출력하는 부분은 제외하고 실행을 해야 합니다. 문서에는 단계별로 수행을 하게 되어 있습니다만 소스 부분을 고쳐서 한번에 실행하게 수정을 한 것이 다음 Python 소스 입니다.

import mxnet as mx

def to4d(img):
    return img.reshape(img.shape[0], 1, 28, 28).astype(np.float32)/255

batch_size = 100
train_iter = mx.io.NDArrayIter(to4d(train_img), train_lbl, batch_size, shuffle=True)
val_iter = mx.io.NDArrayIter(to4d(val_img), val_lbl, batch_size)


# Create a place holder variable for the input data
data = mx.sym.Variable('data')
# Flatten the data from 4-D shape (batch_size, num_channel, width, height) 
# into 2-D (batch_size, num_channel*width*height)
data = mx.sym.Flatten(data=data)

# The first fully-connected layer
fc1  = mx.sym.FullyConnected(data=data, name='fc1', num_hidden=128)
# Apply relu to the output of the first fully-connnected layer
act1 = mx.sym.Activation(data=fc1, name='relu1', act_type="relu")

# The second fully-connected layer and the according activation function
fc2  = mx.sym.FullyConnected(data=act1, name='fc2', num_hidden = 64)
act2 = mx.sym.Activation(data=fc2, name='relu2', act_type="relu")

# The thrid fully-connected layer, note that the hidden size should be 10, which is the number of unique digits
fc3  = mx.sym.FullyConnected(data=act2, name='fc3', num_hidden=10)
# The softmax and loss layer
mlp  = mx.sym.SoftmaxOutput(data=fc3, name='softmax')

# We visualize the network structure with output size (the batch_size is ignored.)
shape = {"data" : (batch_size, 1, 28, 28)}
mx.viz.plot_network(symbol=mlp, shape=shape)


import logging
logging.getLogger().setLevel(logging.DEBUG)

model = mx.model.FeedForward(
    symbol = mlp,       # network structure
    num_epoch = 10,     # number of data passes for training 
    learning_rate = 0.1 # learning rate of SGD 
)
model.fit(
    X=train_iter,       # training data
    eval_data=val_iter, # validation data
    batch_end_callback = mx.callback.Speedometer(batch_size, 200) # output progress for each 200 data batches
)

prob = model.predict(val_img[0:1].astype(np.float32)/255)[0]
print 'Classified as %d with probability %f' % (prob.argmax(), max(prob))

위의 코드를 실행하면 다음과 같이 모델을 훈련하게 되고, 그 다음에 숫자 7 이미지를 판단해서 결과를 출력합니다.

2016-11-mxnet-3

MxNet 의 Github 레포지터리의 example을 보면 이 외에도 아주 다양한 샘플 코드가 존재합니다.

딥 러닝은 이제 많은 분야에서 빠르게 응용되고 있습니다. 게임 개발자 분들도 이러한 딥 러닝 기법을 활용한 다양한 게임 AI를 만드셔서 활용하시기 바랍니다. 만약 실제 서비스를 위해 클러스터를 구성해야 한다면, AWS CloudFormation를 통해 AWS 자원을 손쉽게 만들고 운영할 수 있는 방식을 통해 딥러닝 클러스터를 만들 수 있는 MXNet의 CF 템플릿을 소개합니다.

이 템플릿을 이용하여 Amazon Deep Learning AMIAmazon EC2의 신규 GPU P2 인스턴스에 구성하여, 자동 스케일링을 지원하는 분산 딥러닝 클러스터를 만들어 운영할 수 있게 됩니다. (자세한 것은 AWS를 통한 분산 딥러닝(Deep Learning) 구성하기를 참고하세요.)

본 글은 아마존웹서비스 코리아의 솔루션즈 아키텍트가 국내 고객을 위해 전해 드리는 AWS 활용 기술 팁을 보내드리는 코너로서, 이번 글은 박선용 솔루션즈 아키텍트께서 작성해주셨습니다.

AWS 하이브리드 렌더팜 아키텍처를 위한 스토리지 캐시 설계

클라우드 컴퓨팅은 새로운 기준(New Norma)이 되었습니다.  컴퓨팅 리소스가 필요한 산업군 어디에서나 이제는 클라우드를 먼저 생각합니다. 미디어 및 엔터테인먼트 시장도 예외는 아닙니다. 특히 컴퓨팅 자원이 많이 필요한 렌더링 분야에서 빠르게 성장하고 있습니다.

사용자들은 점점 4K 영상과 같은 더 높은 해상도를 원하고 있으며 이에 따라 데이터와   콘텐트 셋의 크기도 더 커지고 있습니다.  이런 데이터를 렌더링하기 위해서는 더 높은 성능과 더 많은 컴퓨팅 자원이 필요합니다. 하지만, 자체 렌더팜에 대한 TCO는 매우 높습니다. 프로듀서나 렌더팜 운영 담당자는 일반적으로 프로젝트를 진행한 후 얼마 지나지 않아 곧 보유한 용량보다 더 많은 컴퓨팅 자원이 필요한 것을 깨닫게 됩니다. 그리고 이런 일들은 새로운 프로젝트가 진행될 때마다 반복됩니다. 반면에 컴퓨팅 자원을 탄력적으로 확보하고 확장하는 것은 매우 어렵고 비용도 많이 듭니다.

클라우드를 통한 동영상 렌더링 요구 사항
이런 요구에 대한 해결 방법으로 제3의 공급자 솔루션을 찾거나 렌더팜 대여 업체를 통하면 해결 가능할 것으로 생각하기도 합니다. 하지만 이런 방법을 통해서는 정확하게 고객의 요구사항을 맞추는 것은 어려우며, 필요한 시점에 원하는 용량을 확보해서 사용하는 것도 어렵습니다. 무엇보다 콘텐트에 대한 보안이 가장 높은 우려 사항입니다.

그래서 클라우드를 활용하는 것이 큰 대안으로 고려되고 있습니다. 클라우드를 사용하여 얻는 장점들이 많이 있지만, 필요할 때 원하는 만큼의 컴퓨팅 용량을 바로 사용할 수 있는 탄력성을 손꼽을 수 있습니다. 이 특징은 렌더링 시장에서 클라우드를 사용할 수 밖에 없는 가장 중요한 이유이기도 합니다.

렌더링을 주로 하는 분야는 비주얼 이펙트(VFX)와 애니메이션 스튜디오입니다.  컴퓨팅 자원 소비에 따라 스튜디오를 분류해보면 아래 그림처럼 티어-1, 티어-2 그리고 티어-3으로 시장을 세분화할 수 있습니다.

2016-11-hybrid-renderfarm-1

티어-1은  월트 디즈니 애니메이션 스튜디오처럼  전세계적으로 몇 안 되는 대형 스튜디오들이 해당 됩니다. 이런 스튜디오는 주로 리눅스로 구성되어 있고 1,000노드에서 10,000노드 규모의 렌더팜을 자체적으로 운영하고 있습니다. 티어-2 규모의 스튜디오는 중형 스튜디오나 부띠크 포스트들로 100노드에서 500노드 규모의 렌더팜을 운영합니다. 전세계적으로 250개 정도의 스튜디오가 있으며, 기호에 따라 리눅스나 윈도우를 구성해 운영합니다. 티어-3 는 전세계적으로 10,000개 이상의 소형 스튜디오부터 개별 사용자와 프로수머로 구성되어 있습니다. 이들은 주로 윈도우 환경에서 렌더링 작업을 수행합니다.

렌더링 작업을 위해 클라우드를 고려할 때, 대형 및 중형 스튜디오들은 렌더링에 최적화된 자체 렌더팜과 클라우드 렌더팜을 함께 활용하는 하이브리드 파이프라인 아키텍처를 일반적으로 고려합니다. 반면에 중소형 스튜디오는 렌더링 작업을 온전히 클라우드에서 수행하는 올-인 파이프라인 아키텍처를 고려합니다.  각각의 아키텍처는 2015년 re:invent에서 발표한 월트 디즈니 애니메이션 스튜디오에서의 클라우드 렌더링 세션을 통해서 확인할 수 있습니다.

2016-11-hybrid-renderfarm-2

중소형 스튜디오의 일반적인 클라우드 렌더링 아키텍처가 올-인 파이프라인 아키텍처이지만 하이브리드 아키텍처에 대한 요구도 적지 않습니다. 이렇게 하이브리드로 구성하게 되면, 컴퓨팅 자원을 필요한 만큼 탄력적으로 확보해서 그래픽 아티스트들에게 환경 변화 없이 아주 매끄럽게 렌더링할 수 있도록 구성 가능합니다.  즉, 렌더링하기 위해 클라우드로 씬파일이나 스크립트, 텍스처 이미지 등을 별도로 전송할 필요 없이 아티스트들이 기존과 동일하고 투명하게 렌더링 작업이 가능한 환경을 제공할 수 있습니다.  또한 보유하고 있는 온-프레미스 렌더팜과 클라우드 렌더팜을 연동할 수 있기 때문에 기투자에 대한 보호도 할 수 있습니다.

하이브리드 아키텍처에서의 핵심 구성요소는 클라우드 내에 스토리지 캐시를 구성하는 것입니다. 스토리지 캐시를 위해 중대형 스튜디오에서 활발하게 사용하는 제품은 AWS 파트너 생태계 솔루션인 Avere vFXT 엣지 파일러입니다. Avere vFXT 엣지 파일러는 아주 작은 워크로드에서부터 매우 큰 워크로드까지 상당히 안정적으로 그 역할을 수행합니다. 다만 예산과 비용에 제약을 많이 받는 작은 스튜디오는 이런 솔루션을 사용하는 것이 적잖은 부담으로 작용합니다.

그래서 이번 블로그에서는 윈도우를 주로 사용하는 소형 스튜디오에서 안정적이면서 비용 최적화할 수 있는 스토리지 캐시 솔루션을 도입해 하이브리드 아키텍처를 구축할 수 있는 방법을 소개하려고 합니다.

소형 스튜디오를 위한 하이브리드 아키텍처 소개
AWS에서는 마이크로소프트 윈도우 서버 AMI를 제공하고 있습니다. 이를 통해서 윈도우 서버 인스턴스를 클라우드에서 쉽게 생성하고, 윈도우 기반 렌더팜을 간단히 구축하여 렌더링 작업을 수행할 수 있습니다.  그리고 스토리지 캐시 솔루션은 윈도우 서버에 기본적으로 탑재된 MS BranchCache 기능을 활용하여 해결할 수 있습니다.

윈도우 BranchCache는 기본적으로 WAN 대역폭을 최적화하는 기술입니다. 이 기술을 활용하여 온-프레미스 데이터 센터 내에 있는 데이터를 AWS 클라우드에서 지연시간을 줄여서 빠르게 접근할 수 있도록 할 수 있습니다.  BranchCache는 클라우드에서 온-프레미스에 있는 스토리지 콘텐츠를 접근할 때, WAN 대역폭을 최적화하기 위해 온-프레미스 데이터센터 콘텐츠를 복사해서 클라우드에 캐시하고, 클라우드에 있는 클라이언트들이 WAN이 아닌 로컬 내에서 콘텐츠를 바로 접근할 수 있도록 해줍니다.

BranchCache를 이용하여 클라우드에서 콘텐츠를 캐시하는 방법은 두 가지가 있습니다. 캐시 전용 호스트에 저장하거나 클라우드내에 있는 클라이언트 컴퓨터들 간에 분산 저장하는 방법입니다. 전자를 호스트 캐시 모드라고 하고, 후자를 분산 캐시모드라고 합니다.  분산 캐시모드는 호스트 캐시 서버로 사용할 수 있는 로컬 서버가 없는 소규모 환경에서 간단하게 구성하는 방법입니다.  분산 캐시 모드를 사용하는 경우 클라이언트가 오프라인 상태가 되면 캐시 효율이 떨어질 수 있습니다. 그래서 캐시 효율성을 안정적으로 높이고, 다중 서브넷의 모든 클라이언트에서도 콘텐츠를 접근할 수 있는 호스트 캐시 모드 사용을 권장합니다.

Microsoft BranchCache 구성
BranchCache 구성은 아래 그림처럼 3가지로 구성되어 있습니다.  온-프레미스 데이터 센터에 있는 콘텐츠 스토리지, 그리고 AWS 클라우드에 있는 호스트 캐시 서버와 캐시된 데이터를 접근하는 클라이언트입니다.

2016-11-hybrid-renderfarm-4

원본 데이터와 콘텐츠가 저장된 온-프레미스의 콘텐츠 스토리지는 BranchCache 기능이 탑재되어 있어야 합니다. 만일 컨텐츠 스토리지를 윈도우 서버 2008 R2 또는 그 이상의 윈도우 서버로 구성했다면 설정은 상대적으로 간단합니다. 공유 스토리지로 많이 사용되는 EMC VNX 스토리지와 NetApp 스토리지에도 이 기능이 탑재되어 있습니다. 따라서 사용하는 볼륨에 대해서 이 기능을 활성화할 수 있습니다.

클라우드 내에 구성되는 호스트 캐시 서버는 윈도우 서버 2008 R2나 윈도우 서버 2012를 사용합니다. 호스트 캐시 서버는 콘텐츠 스토리지와 클라이언트인 렌더팜 노드들 사이에서 동작하며, 이를 통해서 렌더팜 노드들이 온-프레미스에 있는 컨텐츠 스토리에 대한 접근을 최소화시켜 데이터를 빠르게 접근하고 효과적으로 처리할 수 있도록 도와줍니다.

렌더팜 노드인 클라이언트가 온-프레미스 공유 콘텐츠 스토리지를 접속할 때, 데이터가 호스트 캐시 서버에 저장되어 있으면 바로 접근하여 지연시간을 극적으로 줄여 줍니다. 이를 통해 네트워크 성능을 개선하고, 대역폭 사용량도 줄이게 됩니다.  따라서 렌더팜 노드들이 클라우드에 배포된 캐시 서버를 통해 온-프레미스 데이터 센터와 클라우드간의 속도와 생산성을 높일 수 있습니다.

AWS 클라우드 온-프레미스
렌더팜노드(클라이언트) 호스트 캐시 서버 콘텐츠 스토리지
윈도우 7,8, 및 10 또는 윈도우 서버 2008 R2 또는 그 이상 윈도우 서버 2008 R2 또는 그 이상 윈도우서버 2008R2 또는 그 이상
EMC VNX 스토리지
NetApp 스토리지
BranchCache 기능이 있는 기타 스토리지

BranchCache를 사용할 때의 추가적인 장점은 네트워크 토폴로리를 특별하게 변경하지 않고도 호스트 캐시 서버를 추가하고 간단한 구성과 설정만으로 온-프레미스와 클라우드 간의 데이터 교환 성능을 향상시킬 수 있도록 해줍니다.

MS BranchCache 설정하기
이 기능을 사용하기 위해서는 온-프레미스 콘텐츠 저장 스토리지상에서 공유 볼륨에 대해 BranchCache 기능을 활성화합니다. 설정 방법은 아래에 있는 스토리지 공급사에서 제공하는 절차를 따릅니다.

호스트 캐시 서버의 경우는 윈도우 서버 2008 R2보다는 그 이상의 서버로 구성하기를 권장합니다. 윈도우 2008 R2를 사용할 경우 호스트 캐시 서버와 클라이언트에 인증서를 등록하는 절차를 수행해야 하기 때문에 구성 방법이 다소 복잡합니다. 반면 윈도우 서버 2012의 경우는 인증서를 등록하지 않고도 쉽게 구성할 수 있으며, 다중의 호스트 캐시 서버도 구성할 수 있는 장점을 제공합니다. 또한 캐시될 데이터를 호스트 캐시 서버에 미리 적재할 수 있는 기능도 제공합니다. 윈도우 서버 2012를 이용한 호스트 캐시 서버 설정 방법은 Microsoft 기술 문서를 참조합니다.

AWS 에서 렌더팜으로 사용되는 BranchCache 클라이언트의 경우 AWS에서 기본으로 제공하는 윈도우 서버 AMI로 구성하거나, EC2 가져오기 기능을 활용해서 윈도우 7, 8 및 10과 같은 클라이언트 운영체제를 AWS내로 가져와서 구성할 수 있습니다. 후자의 경우 Microsoft로부터 별도의 라이선스를 구매(BYOL)해야 하고 EC2 전용 인프라에서 구성해야합니다. 따라서 특별한 요구 사항이 없다면 AWS에서 기본으로 제공하는 윈도우 서버 AMI를 활용해서 구성합니다.  다만 BranchCache 클라이언트는 파일 및 폴더의 SMB 캐싱을 위해 오프라인 파일 기능을 활용한다는 것을 유념해야 합니다. 이 기능은 윈도우 클라이언트 운영체제에는 기본적으로 설치되어 있지만, 윈도우 서버에는 설치되어 있지 않습니다. 따라서 윈도우 서버 AMI를 활용하는 경우 아래 작업이 선행되어야 합니다:

  1. 작업표시줄에서 서버 관리자를 클릭합니다
  2. 역할과 기능추가를 클릭하고 다음을 클릭합니다
  3. 역할기반 또는 기능기반 설치를 선택하고 다음을 클릭합니다
  4. 서버 선택의 기본 설정을 그대로 두고 다음을 클릭합니다
  5. 서버 역할의 기본 설정을 그대로 두고 다음을 클릭합니다
  6. BranchCache 기능을 선택합니다
  7. User Interfaces and Infrastructure 밑에 있는 Desktop Experience를 선택합니다
  8. 팝업 창에서 요구하는 추가 기능에 대해서 Add Features를 선택한 후 다음을 클릭합니다
  9. Install을 클릭합니다
  10. 설치가 종료될 때까지 대기하고, 끝나면 닫기를 클릭합니다
  11. 재시작을 수행합니다
  12. 윈도우에 원격 접속합니다
  13. 마우스를 시작 메뉴에 올려놓고 우측 마우스를 클릭합니다
  14. 제어판을 클릭합니다
  15. Sync Center를 선택합니다
  16. Manage offline files를 선택합니다
  17. Enable offline files를 선택합니다

이 절차가 끝난 이후에는 Microsoft 기술 문서를 참고하여 클라이언트 설정을 마무리하고 테스트를 해봅니다.

맺으면서
BranchCache를 활용한 스토리지 캐시 솔루션은 소형 스튜디오의 하이브리드 렌더팜 아키텍처 설계에 많은 장점을 제공합니다. 스토리지 캐시를 위한 별도의 전용 어플라이언스 구매없이 윈도우 서버 인스턴스만으로 간단히 구성할 수 있기 때문에 비용 부담을 덜어줍니다. 또한 구성 방법도 간단하고 기존의 네트워크 환경 및 전체 아키텍처에 대한 변경 없이 가능합니다. 복잡한 구성 변경 없이 단순히 호스트 캐시 서버를 추가하면 되고, 각 구성요소들간에 BranchCache 기능만 활성화하고 설정만 하면 됩니다.  이를 통해서 온-프레미스와 AWS 클라우드간의 데이터 이동을 최소화해서 지연시간과 대역폭 문제를 해결 할 수 있습니다.

또한, AWS 클라우드 내에 있는 렌더팜 노드들이 동일한 공간에 있는 스토리지 캐시 노드에서 데이터를 빠르게 읽을 수 있고, 이를 통해 렌더링 처리를 하므로 보다 빠른 결과물을 얻을 수 있습니다. 렌더링 작업이 끝나면 AWS 클라우드 내에 있던 모든 렌더팜 노드들과 더불어 스토리지 캐시를 제거함으로써 사용한 인스턴스 비용만을 지불할 수 있어서 비용도 최적화 할 수 있습니다. 이번 블로그를 통해서 여러분들의 온-프레미스 렌더팜 확장 용도로AWS클라우드가 활용될 수 있다는 아이디어를 얻으셨기를 기대해봅니다.

본 글은 아마존웹서비스 코리아의 솔루션즈 아키텍트가 국내 고객을 위해 전해 드리는 AWS 활용 기술 팁을 보내드리는 코너로서, 이번 글은 박철수 솔루션즈 아키텍트께서 작성해주셨습니다.