2022.11.28 ~ 12.02 까지 라스베이거스에서 진행된 re:Invent에서 다룬 내용들 중 내가 관심 있는 것들만 정리해볼까 한다.


Lambda SnapStart

https://aws.amazon.com/ko/blogs/aws/new-accelerate-your-lambda-functions-with-lambda-snapstart/?did=ap_card&trk=ap_card 

  • 특정 Lambda 함수에 대해 Lambda SnapStart를 활성화한 후 함수의 새 버전을 게시하면 최적화 프로세스 트리거
  • 프로세스는 Init 단계에서 실행되며 메모리 및 디스크 상태의 변경할 수 없는 암호화된 스냅샷을 가져와 재사용을 위해 캐시
  • 이후 함수가 호출되면 필요에 따라 캐시에서 chunk로 상태를 검색하여 실행 환경을 채우게 됨
  • → 해당 프로세스를 통해 새로운 실행 환경을 만드는데 더이상 전용 Init 단계가 필요 없음(호출 시간이 더 빨라진다)
  • Coreoot(java11) 런타임을 사용하는 Java 기능을 지원

 

Amazon CodeCatalyst

https://aws.amazon.com/ko/codecatalyst/?did=ap_card&trk=ap_card 

https://codecatalyst.aws/explore?trk=cb9f568a-9476-40f7-92d7-71dcaa59c9fc&sc_channel=newsletter 

  • 애플리케이션을 신속하게 구축하고 제공하기 위한 통합 소프트웨어 개발 서비스
    • (이슈 관리 + 코딩 + 빌드 + 테스트/배포) - 이와 같은 과정을 연결하고 자동화
  • CodeCatalyst project blueprints: CI/CD, deployable code, issue tracking 등 자동으로 셋업
  • CodeCatalyst Dev Environments: 사전 설치된 종속성 및 언어별 패키지로 자동 생성

 

Amazon CloudWatch Internet Monitor

https://aws.amazon.com/ko/cloudwatch/features/?did=ap_card&trk=ap_card 

  • 인터넷 문제가 AWS 에서 호스팅되는 애플리케이션과 사용자 간의 성능 및 가용성에 미치는 영향에 대한 가시성을 제공, 이러한 문제를 진단하는데 걸리는 시간을 줄여줌
    • ex) 다른 AWS 서비스로 전환하거나 다른 AWS 리전을 통해 워크로드 트래픽 경로를 재지정
  • EventBridge로도 상태 이벤트 전송해 알림 설정 가능
  • AWS 네트워크 문제 발생 시 Health Dashboard 알림 수신 되는데 문제에 대해 AWS 측에서 진행 중인 단계 확인 가능

 

Amazon VPC Lattice

https://aws.amazon.com/ko/blogs/korea/introducing-vpc-lattice-simplify-networking-for-service-to-service-communication-preview/

https://aws.amazon.com/ko/vpc/lattice/?did=ap_card&trk=ap_card 

  • 서비스 간의 통신을 지속적으로 연결, 모니터링 및 보호하는 애플리케이션 계층 서비스
    • 네트워크 액세스, 트래픽 관리 및 모니터링에 대한 정책을 정의
  • 모든 AWS 컴퓨팅 유형(인스턴스, 컨테이너, 서버리스 함수)에 배포 일관성을 제공 → 서비스(소프트웨어) 연결
  • 세분화되고 자세한 트래픽 제어를 적용해 blue/green, canary 스타일 배포 지원
  • 요청 유형, 트래픽 볼륨, 오류 발생률, 응답 시간 등을 수집하는 자세한 액세스 로그와 지표로 서비스 간 통신을 모니터링하고 문제 해결 가능

 

AWS Verified Access

https://aws.amazon.com/ko/verified-access/?did=ap_card&trk=ap_card 

  • VPN을 사용할 필요가 없어 최종 사용자의 원격 접속 경험을 간소화, 관리 복잡성 감소
  • 각 액세스 요청을 실시간으로 확인하고 액세스가 허용된 애플리케이션에만 사용자를 연결

 

AWS Application Composer

https://aws.amazon.com/ko/application-composer/?did=ap_card&trk=ap_card 

  • 배포 가능 IaC로 지원되는 AWS 서비스에서 서버리스 애플리케이션을 시각적으로 작성하고 구성 가능
  • CloudFormation 또는 AWS SAM 지원

'Cloud > AWS' 카테고리의 다른 글

[AWS] AWS IoT Greengrass V2 실습  (0) 2023.01.26
[AWS] Firebase를 AWS Amplify로  (0) 2023.01.04
[AWS] Windows Server RDP 접속  (0) 2022.12.09
[AWS] Serverless Service - DynamoDB 편(4)  (0) 2022.12.08
[AWS] Serverless Service - DynamoDB 편(3)  (0) 2022.12.07

https://www.serverless.com/

Serverless Framework


나의 cloud 환경은 AWS 이며, Windows 환경에서 테스트 했다.

(현재 내 windows는 AWS CLI 설치가 완료되었고, npm도 설치되어 있음)

 

Serverless Framework 설정

# serverless framework 설치
npm install -g serverless

# 새로운 서버리스 프로젝트 생성
 serverless

 

serverless framework에 로그인하고 들어가보면,

위와 같이 생성되어 있음을 알 수 있다.

후에 deploy now의 질문에 yes로 대답하면..

이렇게 뜨는데 현재 내가 설정해둔 default region과 serverless에서 제공해주는 리전이 달라서 그러는 것 같다..

(현재는 테스트용이라 AWS 계정의 region을 us-east-1으로 변경할꺼고 나중에 프로젝트를 제대로 하려면 내가 원하는 리전으로 설정하는 방향으로 진행해야겠다.)

 

AWS 자격증명 설정

https://www.serverless.com/framework/docs/providers/aws/guide/credentials/

serverless-test user를 추가하자(IAM)

테스트니까 일단 Admin으로 박자.(프로덕션이나 중요한 프로젝트의 경우 권한을 자세히 설정하는게 좋다.)

 

 

Serverless Deploy

위와 같이 잘 실행됨을 알 수 있다..!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Test

serverless invoke -f hello

# 로그 호출 및 표시: 
serverless invoke -f hello -- log

serverless logs -f hello
 
# Tail logs
serverless logs -f hello --tail


# serverless 제거
serverless remove

 

serverless framework 기준

해당 serverless framework GUI 상에서 모니터링도 가능하다.

 

serverless remove를 사용하면 알아서 또 다 지워준다.

 


생성된 프로젝트를 까보면..

이런 느낌이고 사용자가 작성해야하는 파일의 경우 handler.js, serverless.yml 정도 인듯?

handler.js는 lambda에 들어가야할 함수고 (사용자 지정 함수 느낌)

serverless.yml의 경우 아래와 같이 생성되었다.

org: realyun99
app: test-nodejs-serverless
service: test-nodejs-serverless

frameworkVersion: '3'

provider:
  name: aws
  runtime: nodejs14.x

functions:
  hello:
    handler: handler.hello

 

 

위의 테스트 환경은 예제이고 직접 내가 템플릿을 만들어보고 사용자의 입장에서 무엇을 해야하는지 파악하려 한다.

 # 어떤 명령어 옵션이 있는지 확인
 serverless create --help
 
 serverless create --template aws-go --path "C:\Users\HP\test-go"

go언어의 템플릿으로 해당 경로에 test-go 폴더를 생성하고 넣어라의 느낌!

serverless.yml 안에 어떻게 AWS 환경 구성하고 싶은지 적는 것 같다... 아무래도...? ㅋㅋㅋㅋ

https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml


(serverless.yml)

  • AWS 인프라와 Serverless Framework로 배포할 Lambda 함수의 정보 및 설정을 담은 파일
  • CloudFormation의 문법 사용 가능
  • 다양한 Serverless Framework 플러그인 사용 가능
    • ex) 500개 리소스 제한인 CloudFormation 스택을 Nested Stack으로 만들어주는 플러그인

 

 

❗ 결론적으로 serverless.yml 파일이랑 lambda 함수에 들어갈 코드만 잘 작성하면 된다! serverless 파일이 관건일 듯! ❗

'Cloud' 카테고리의 다른 글

Cloud Service Providers  (0) 2021.05.08

Bastion Host에서 Private EC2 Windows로 접속하는 과정 정리를 해보려 한다..

https://dev.classmethod.jp/articles/access-private-ec2-windows-from-bastion-host/

 

위와 같이 구성을 먼저 해두자.

 

 EC2 Windows 의 SG를 바꿔주자.

(소스의 경우 bastion-sg로 지정)

 

MobaXterm으로 접속

Remote host의 경우엔 windows server의 private ip를 적으면 된다.

SSH gateway에는 만들어두었던 bastion host의 public ip와 key pair를 넣어주자.

 

RDP 접속 비밀번호의 경우 인스턴스 연결에서 RDP 클라이언트를 통해 key pair를 넣고 비밀 번호를 받자..

 

접속 성공!


위의 방법 말고도 Fleet Manager를 사용해 연결이 가능하다!

https://docs.aws.amazon.com/systems-manager/latest/userguide/fleet-rdp.html

  • SSM agent 설치가 필요하고 최대 세션 시간은 60분이다! (아니면 세션 종료 전에 갱신을 선택해 타이머를 다시 시작한다)
  • 기본적으로 동일한 AWS 계정 및 AWS 리전에서 최대 5개의 동시 Fleet Manager RDP 연결을 가질 수 있으며 추가 사용을 위해선 할당량 증가를 요청해야함!

'Cloud > AWS' 카테고리의 다른 글

[AWS] Firebase를 AWS Amplify로  (0) 2023.01.04
[AWS] re:Invent 2022 정리  (0) 2022.12.19
[AWS] Serverless Service - DynamoDB 편(4)  (0) 2022.12.08
[AWS] Serverless Service - DynamoDB 편(3)  (0) 2022.12.07
[AWS] Serverless Service - DynamoDB 편(2)  (0) 2022.12.05

( 참고: https://amazon-dynamodb-labs.com/hands-on-labs.html )

실습편

 

CloudFormation을 통한 환경 구성

퍼블릭 서브넷 1개 / 프라이빗 서브넷 3개 / 퍼블릭 서브넷에 배포된 AWS Cloud 9 환경

더보기
AWSTemplateFormatVersion: "2010-09-09"

# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Description: >
  This template builds a VPC with 1 public and 3 private subnets.

Parameters:
  vpccidr:
    Type: String
    MinLength: 9
    MaxLength: 18
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    ConstraintDescription: Must be a valid CIDR range in the form x.x.x.x/16
    Default: 10.20.0.0/16
  AppPublicCIDRA:
    Type: String
    MinLength: 9
    MaxLength: 18
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    ConstraintDescription: Must be a valid CIDR range in the form x.x.x.x/22
    Default: 10.20.1.0/24
  AppPrivateCIDRA:
    Type: String
    MinLength: 9
    MaxLength: 18
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    ConstraintDescription: Must be a valid CIDR range in the form x.x.x.x/22
    Default: 10.20.2.0/24
  AppPrivateCIDRB:
    Type: String
    MinLength: 9
    MaxLength: 18
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    ConstraintDescription: Must be a valid CIDR range in the form x.x.x.x/22
    Default: 10.20.3.0/24
  AppPrivateCIDRC:
    Type: String
    MinLength: 9
    MaxLength: 18
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    ConstraintDescription: Must be a valid CIDR range in the form x.x.x.x/22
    Default: 10.20.4.0/24
  IdeType:
    Type: String
    Default: "t3.medium"
  ProjectTag:
    Type: String
    Default: "dynamodb-labs"

Resources:
  VPC:
    Type: "AWS::EC2::VPC"
    Properties:
      CidrBlock: !Ref vpccidr
      EnableDnsHostnames: 'true'
      EnableDnsSupport: 'true'
      Tags:
        -
          Key: Project
          Value: !Ref ProjectTag
        -
          Key: Name
          Value: !Join ["", [!Ref ProjectTag, "-VPC"]]
  IGW:
    Type: "AWS::EC2::InternetGateway"
    Properties:
      Tags:
        -
          Key: Project
          Value: !Ref ProjectTag
        -
          Key: Name
          Value: !Join ["", [!Ref ProjectTag, "-IGW"]]
  GatewayAttach:
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties:
      InternetGatewayId: !Ref IGW
      VpcId: !Ref VPC
  SubnetPublicA:
    Type: "AWS::EC2::Subnet"
    Properties:
      AvailabilityZone: !Select [0, !GetAZs ]
      CidrBlock: !Ref AppPublicCIDRA
      MapPublicIpOnLaunch: true
      VpcId: !Ref VPC
      Tags:
        -
          Key: Project
          Value: !Ref ProjectTag
        -
          Key: Name
          Value: !Join ["", [!Ref ProjectTag, "-Subnet-PublicA"]]
  SubnetPrivateA:
    Type: "AWS::EC2::Subnet"
    Properties:
      AvailabilityZone: !Select [0, !GetAZs ]
      CidrBlock: !Ref AppPrivateCIDRA
      MapPublicIpOnLaunch: false
      VpcId: !Ref VPC
      Tags:
        -
          Key: Project
          Value: !Ref ProjectTag
        -
          Key: Name
          Value: !Join ["", [!Ref ProjectTag, "-Subnet-PrivateA"]]
  SubnetPrivateB:
    Type: "AWS::EC2::Subnet"
    Properties:
      AvailabilityZone: !Select [1, !GetAZs ]
      CidrBlock: !Ref AppPrivateCIDRB
      MapPublicIpOnLaunch: false
      VpcId: !Ref VPC
      Tags:
        -
          Key: Project
          Value: !Ref ProjectTag
        -
          Key: Name
          Value: !Join ["", [!Ref ProjectTag, "-Subnet-PrivateB"]]
  SubnetPrivateC:
    Type: "AWS::EC2::Subnet"
    Properties:
      AvailabilityZone: !Select [2, !GetAZs ]
      CidrBlock: !Ref AppPrivateCIDRC
      MapPublicIpOnLaunch: false
      VpcId: !Ref VPC
      Tags:
        -
          Key: Project
          Value: !Ref ProjectTag
        -
          Key: Name
          Value: !Join ["", [!Ref ProjectTag, "-Subnet-PrivateC"]]
  SubnetRouteTableAssociatePublicA: # Associates the subnet with a route table - passed via import
    DependsOn: SubnetPublicA
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref RouteTablePublic
      SubnetId: !Ref SubnetPublicA
  SubnetRouteTableAssociatePrivateA: # Associates the subnet with a route table - passed via parameter
    DependsOn: SubnetPrivateA
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref RouteTablePrivateA
      SubnetId: !Ref SubnetPrivateA # Associates the subnet with a route table - passed via parameter
  SubnetRouteTableAssociatePrivateB: # Associates the subnet with a route table - passed via parameter
    DependsOn: SubnetPrivateB
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref RouteTablePrivateB
      SubnetId: !Ref SubnetPrivateB # Associates the subnet with a route table - passed via parameter
  SubnetRouteTableAssociatePrivateC: # Associates the subnet with a route table - passed via parameter
    DependsOn: SubnetPrivateC
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref RouteTablePrivateC
      SubnetId: !Ref SubnetPrivateC # Associates the subnet with a route table - passed via parameter
  RouteDefaultPublic:
    Type: "AWS::EC2::Route"
    DependsOn: GatewayAttach
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref IGW
      RouteTableId: !Ref RouteTablePublic
  RouteTablePublic:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
  RouteDefaultPrivateA:
    Type: "AWS::EC2::Route"
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGatewayA
      RouteTableId: !Ref RouteTablePrivateA
  RouteDefaultPrivateB:
    Type: "AWS::EC2::Route"
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGatewayA
      RouteTableId: !Ref RouteTablePrivateB
  RouteDefaultPrivateC:
    Type: "AWS::EC2::Route"
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGatewayA
      RouteTableId: !Ref RouteTablePrivateC
  RouteTablePrivateA:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
  RouteTablePrivateB:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
  RouteTablePrivateC:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC
  EIPNatGWA:
    DependsOn: GatewayAttach
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: vpc
  NatGatewayA:
    Type: "AWS::EC2::NatGateway"
    Properties:
      AllocationId: !GetAtt EIPNatGWA.AllocationId
      SubnetId: !Ref SubnetPublicA
      Tags:
        -
          Key: Project
          Value: !Ref ProjectTag
        -
          Key: Name
          Value: !Join ["", [!Ref ProjectTag, "-NatGWA"]]

  DynamoDBLabsIDE:
    Type: AWS::Cloud9::EnvironmentEC2
    Properties:
      Description: "Cloud 9 IDE"
      InstanceType: !Ref IdeType
      SubnetId: !Ref SubnetPublicA
      Tags:
        -
          Key: Project
          Value: !Ref ProjectTag
        -
          Key: ProjectName
          Value: !Join ["", [!Ref ProjectTag, "-Ide"]]

Outputs:
  VpcId:
    Description: VPC ID
    Value: !Ref VPC
  SubnetIdPublicA:
    Description: Subnet ID for first public subnet
    Value: !Ref SubnetPublicA
  SubnetIdPrivateA:
    Description: Subnet ID for first private subnet
    Value: !Ref SubnetPrivateA
  SubnetIdPrivateB:
    Description: Subnet ID for second private subnet
    Value: !Ref SubnetPrivateB
  SubnetIdPrivateC:
    Description: Subnet ID for third private subnet
    Value: !Ref SubnetPrivateC
  RouteTableIdPrivateC:
    Value: !Ref RouteTablePrivateC
  RouteTableIdPrivateB:
    Value: !Ref RouteTablePrivateB
  RouteTableIdPrivateA:
    Value: !Ref RouteTablePrivateA

 

Cloud9 콘솔

aws sts get-caller-identity

위의 명령어로 AWS 자격 증명이 올바르게 구성되었는지 확인

 

aws dynamodb create-table \
    --table-name ProductCatalog \
    --attribute-definitions \
        AttributeName=Id,AttributeType=N \
    --key-schema \
        AttributeName=Id,KeyType=HASH \
    --provisioned-throughput \
        ReadCapacityUnits=10,WriteCapacityUnits=5

aws dynamodb create-table \
    --table-name Forum \
    --attribute-definitions \
        AttributeName=Name,AttributeType=S \
    --key-schema \
        AttributeName=Name,KeyType=HASH \
    --provisioned-throughput \
        ReadCapacityUnits=10,WriteCapacityUnits=5

aws dynamodb create-table \
    --table-name Thread \
    --attribute-definitions \
        AttributeName=ForumName,AttributeType=S \
        AttributeName=Subject,AttributeType=S \
    --key-schema \
        AttributeName=ForumName,KeyType=HASH \
        AttributeName=Subject,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=10,WriteCapacityUnits=5

aws dynamodb create-table \
    --table-name Reply \
    --attribute-definitions \
        AttributeName=Id,AttributeType=S \
        AttributeName=ReplyDateTime,AttributeType=S \
    --key-schema \
        AttributeName=Id,KeyType=HASH \
        AttributeName=ReplyDateTime,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=10,WriteCapacityUnits=5

aws dynamodb wait table-exists --table-name ProductCatalog && \
aws dynamodb wait table-exists --table-name Reply && \
aws dynamodb wait table-exists --table-name Forum && \
aws dynamodb wait table-exists --table-name Thread

create-table 명령어를 통해 테이블을 생성하고 wait 명령어를 활용해 테이블을 하나씩 생성하도록...

https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SampleData.html

 

wget https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/samples/sampledata.zip

unzip sampledata.zip

샘플 데이터를 다운로드하고 압축을 푼다.

 

aws dynamodb batch-write-item --request-items file://ProductCatalog.json

aws dynamodb batch-write-item --request-items file://Forum.json

aws dynamodb batch-write-item --request-items file://Thread.json

aws dynamodb batch-write-item --request-items file://Reply.json

batch-write-item CLI를 사용해 샘플 데이터 로드

 

CLI로 DynamoDB 탐색

aws dynamodb scan --table-name ProductCatalog

scan api 를 사용해 테이블을 스캔할 수 있다. 하지만 DynamoDB에서 데이터를 가져올 때 가장 느리고 비싼 방법!

현재는 아이템이 몇 개 없으니까 테스트 가능하다.

(CLI의 데이터 입력 및 출력은 JSON 형식을 활용한다.)

 

aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"101"}}'

하나의 아이템을 가져오기 위해선 GetItem api 활용! DynamoDB에서 데이터를 가져오는 가장 빠르고 저렴한 방법이다.

 

aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"101"}}' \
    --consistent-read \
    --projection-expression "ProductCategory, Price, Title" \
    --return-consumed-capacity TOTAL

읽기 일관성에 관한 옵션에는 

--consistent-read: 강력한 일관된 읽기를 원함(쓰기 작업 결과가 다 반영이 된 후에 읽음)

--projection-expression: 요청에서 특정 속성만 반환되도록 지정

--return-consume-capacity: 요청에 의해 소비된 용량 알려줌

위의 결과는 --consistent-read 옵션을 사용했을 때, 1.0 RCU를 사용(항목이 4KB 미만)

해당 옵션을 제거하면 최종적으로 일관된 읽기가 절반의 용량을 사용함!!(0.5 RCU)


이제부턴 쿼리를 사용해 아이템을 읽어올 것!

 

Item Collections은 partition key를 공유하는 collection group.

DynamoDB에서 "query"는 Item collection의 전체 또는 일부를 읽는 특정 의미이다.(RDBMS와 다름)

aws dynamodb scan --table-name Reply

 

Replay 테이블에 데이터에는 Thread 테이블의 항목을 참조하는 Id Attribute가 있음

쿼리 CLI를 통해 Thread 1의 아이템만 가져오자.

aws dynamodb query \
    --table-name Reply \
    --key-condition-expression 'Id = :Id' \
    --expression-attribute-values '{
        ":Id" : {"S": "Amazon DynamoDB#DynamoDB Thread 1"}
    }' \
    --return-consumed-capacity TOTAL

 

Replay 테이블의 정렬 키는 타임스탬프다. 정렬 키 조건을 추가해 특정 시간 이후에 게시된 스레드의 응답만 가져오자.

aws dynamodb query \
    --table-name Reply \
    --key-condition-expression 'Id = :Id and ReplyDateTime > :ts' \
    --expression-attribute-values '{
        ":Id" : {"S": "Amazon DynamoDB#DynamoDB Thread 1"},
        ":ts" : {"S": "2015-09-21"}
    }' \
    --return-consumed-capacity TOTAL

 

키가 아닌 attribute의 기반으로 결과를 제한하기 위한 필터 표현식을 사용하자.

aws dynamodb query \
    --table-name Reply \
    --key-condition-expression 'Id = :Id' \
    --filter-expression 'PostedBy = :user' \
    --expression-attribute-values '{
        ":Id" : {"S": "Amazon DynamoDB#DynamoDB Thread 1"},
        ":user" : {"S": "User B"}
    }' \
    --return-consumed-capacity TOTAL

위와 같은 결과를 얻게 되는데 키 조건 표현식이 2개 아이템(ScannedCount)과 일치하고 필터 표현식이 1개 아이템으로 줄였다는 것을 볼 수 있음..

 

이 밖에도 여러 옵션으로 쿼리 작성 가능하다!


이제는 테이블 스캔 관련 작업을 해보자.

 

scan api는 단일 아이템 컬렉션이 아닌 전체 테이블을 스캔하려고 하기 때문에 스캔에 대한 필터 표현식을 걸어주는게 좋다.

예) User A가 게시한 답장에서 모든 답글 찾기

aws dynamodb scan \
    --table-name Reply \
    --filter-expression 'PostedBy = :user' \
    --expression-attribute-values '{
        ":user" : {"S": "User A"}
    }' \
    --return-consumed-capacity TOTAL

 

데이터를 스캔할 때 서버 측의 1MB 제한에 도달하거나 지정된 --max-items 매개변수 보다 더 많은 아이템이 남아 있는 경우가 있을 수 있다. 이 경우엔 스캔 응답에 NextToken이 포함되며 이를 후속 스캔 호출에 넣어 중단한 위치에서 선택이 가능하다.

예) 위의 예시에서 --max-items를 2로 걸어보자(위의 응답은 3개 였음..)

aws dynamodb scan \
    --table-name Reply \
    --filter-expression 'PostedBy = :user' \
    --expression-attribute-values '{
        ":user" : {"S": "User A"}
    }' \
    --max-items 2 \
    --return-consumed-capacity TOTAL

위의 NextToken을 --starting-token 옵션에 포함해 명령하자.

aws dynamodb scan \
    --table-name Reply \
    --filter-expression 'PostedBy = :user' \
    --expression-attribute-values '{
        ":user" : {"S": "User A"}
    }' \
    --max-items 2 \
    --starting-token eyJFeGNsdXNpdmVTdGFydEtleSI6IG51bGwsICJib3RvX3RydW5jYXRlX2Ftb3VudCI6IDJ9 \
    --return-consumed-capacity TOTAL

데이터 삽입 관련 (put-item)

aws dynamodb put-item \
    --table-name Reply \
    --item '{
        "Id" : {"S": "Amazon DynamoDB#DynamoDB Thread 2"},
        "ReplyDateTime" : {"S": "2021-04-27T17:47:30Z"},
        "Message" : {"S": "DynamoDB Thread 2 Reply 3 text"},
        "PostedBy" : {"S": "User C"}
    }' \
    --return-consumed-capacity TOTAL

 

데이터 업데이트 (update-item)

--condition-expression이 충족되는 경우에만 업데이트 가능!

aws dynamodb update-item \
    --table-name Forum \
    --key '{
        "Name" : {"S": "Amazon DynamoDB"}
    }' \
    --update-expression "SET Messages = :newMessages" \
    --condition-expression "Messages = :oldMessages" \
    --expression-attribute-values '{
        ":oldMessages" : {"N": "4"},
        ":newMessages" : {"N": "5"}
    }' \
    --return-consumed-capacity TOTAL

 

데이터 삭제 (delete-item)

aws dynamodb delete-item \
    --table-name Reply \
    --key '{
        "Id" : {"S": "Amazon DynamoDB#DynamoDB Thread 2"},
        "ReplyDateTime" : {"S": "2021-04-27T17:47:30Z"}
    }'

 

Replay 테이블에서 항목을 제거했으니 Forum 관련 메시지 개수 줄여야함!

aws dynamodb update-item \
    --table-name Forum \
    --key '{
        "Name" : {"S": "Amazon DynamoDB"}
    }' \
    --update-expression "SET Messages = :newMessages" \
    --condition-expression "Messages = :oldMessages" \
    --expression-attribute-values '{
        ":oldMessages" : {"N": "5"},
        ":newMessages" : {"N": "4"}
    }' \
    --return-consumed-capacity TOTAL

이번엔 GSI를 다뤄보자.

 

GSI는 테이블에 이미 데이터가 있더라도 언제든 만들고 제거가 가능하다.

예) PostedBy 속성을 파티션(HASH) 키로 사용, ReplyDateTime으로 정렬된 메시지를 정렬(RANGE) 키로 유지하는 PostedBy-ReplyDateTime-gsi 라는 이름의 GSI 생성

aws dynamodb update-table \
    --table-name Reply \
    --attribute-definitions AttributeName=PostedBy,AttributeType=S AttributeName=ReplyDateTime,AttributeType=S \
    --global-secondary-index-updates '[{
        "Create":{
            "IndexName": "PostedBy-ReplyDateTime-gsi",
            "KeySchema": [
                {
                    "AttributeName" : "PostedBy",
                    "KeyType": "HASH"
                },
                {
                    "AttributeName" : "ReplyDateTime",
                    "KeyType" : "RANGE"
                }
            ],
            "ProvisionedThroughput": {
                "ReadCapacityUnits": 5, "WriteCapacityUnits": 5
            },
            "Projection": {
                "ProjectionType": "ALL"
            }
        }
    }
]'

 

DynamoDB가 GSI를 생성하고 테이블의 데이터를 인덱스로 채우는 데 시간이 걸릴 수 있음.

IndexStatus가 Active가 되어야 함!!

aws dynamodb describe-table --table-name Reply | grep IndexStatus

 

어떤 식으로 사용하게 되냐면...

--index-name query 옵션과 사용하게 됨!

aws dynamodb query \
    --table-name Reply \
    --key-condition-expression 'PostedBy = :pb' \
    --expression-attribute-values '{
        ":pb" : {"S": "User A"}
    }' \
    --index-name PostedBy-ReplyDateTime-gsi \
    --return-consumed-capacity TOTAL

현재는 아이템 수가 적어서 괜찮지만 예를 들어 십만개 이상의 아이템이 있더라도 반환하려는 정확한 아이템을 읽는데만 비용이 든다!

 

GSI 삭제

aws dynamodb update-table \
    --table-name Reply \
    --global-secondary-index-updates '[{
        "Delete":{
            "IndexName": "PostedBy-ReplyDateTime-gsi"
        }
    }
]'

DynamoDB 콘솔 살펴보기

테이블로 들어가 표 항목 탐색을 클릭하면 아이템들을 확인할 수 있다.

아이템들 중 101을 클릭해보면 편집기를 확인할 수 있고, 모든 속성을 보고 수정할 수 있다!


쿼리를 사용해 아이템 컬렉션을 읽어보자.

 

위와 같이 쿼리를 간단하게 사용 가능하다.

필터 또한 추가 가능하다!

 

위와 같이 스캔도 가능!


이번엔 GSI 생성 해보자.

인덱스 생성을 클릭하면,

위와 같이 생성해주면 된다.

생성이 끝나고 다시 해당 테이블에 대해 쿼리를 해주려 들어가면..

Table / index 선택 항목이 생겨 있다!

 

 

 

❗ 여까지 간단하게 DynamoDB 다루는 방법에 대해 알아봤고..

다음엔 백업 + RDBMS에서 마이그레이션 해오는 방법을 알아보도록 하자!! ❗

'Cloud > AWS' 카테고리의 다른 글

[AWS] Windows Server RDP 접속  (0) 2022.12.09
[AWS] Serverless Service - DynamoDB 편(4)  (0) 2022.12.08
[AWS] Serverless Service - DynamoDB 편(2)  (0) 2022.12.05
[AWS] Serverless Service - DynamoDB 편(1)  (0) 2022.12.02
[AWS] AppStream 2.0  (0) 2022.11.26

+ Recent posts