728x90

READ Sample DATA

  • Scan API
    • 전체 테이블 스캔
    • 1MB 청크로 항목 리턴
    • DynamoDB JSON 형식 사용
aws dynamodb scan --table-name ProductCatalog

 

  • GetItem API
    • 단일 항목만 읽기
    • 전체 기본키를 지정해야함

 

  • Dynamo DB의 읽기 : 최종 일관성 사용
    • 💡 Read Consistency - 읽기 일관성(읽기 정합성)
    • 읽기를 진행하는 데이터 : 테이블 / LSI / GSI / 스트림 데이터
    • 테이블, LSI 모두 eventual consistency(최종 일관성), strongly consistent(강한 일관성) 지원

 

  • 다양한 옵션
    • -consistent-read : Specifying that you want a strongly consistent read
    • -projection-expression : Specifying that you only want certain attributes returned in the request
    • -return-consume-capacity : Tell us how much capacity was consumed by the request

 

  • eventual consistencystrongly consistent 의 절반 가격




READING ITEM COLLECTIONS USING QUERY

  • Query의 의미
    • 일반적으로 쿼리는 컬렉션 전체 또는 일부를 읽는다는 의미를 갖는다.
    • 🔥 일반적인 DB 에서의 “reading data from a database”만을 의미하는 내용이 아니다.
      → 구어체적(as the word)으로 “쿼리를 날린다~” 뭐 이런 간단한 개념이 아니라
      정식적으로
      “Query(쿼리)”라는 개념이 있는 것으로 이해하라는 뜻으로 보인다.

 

  • 구체적인 조건 표현식을 포함해야한다.
    • DB의 WHERE 절과 비슷한 역할을 수행한다고 보면 된다.

 

  • 필터 표현식 사용시, 실제 소비되는 총 용량에는 유의미한 결과를 미치지 않지만 최종적으로 리턴되는 응답의 개수는 줄어들기때문에 영향을 미친다.

 

✏️ e.g. query filter expression

  • Request
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

 

  • Response
{
    "Items": [ // 실제 리턴된 아이템 정보
        {
            "ReplyDateTime": {
                "S": "2015-09-22T19:58:22.947Z"
            },
            "Message": {
                "S": "DynamoDB Thread 1 Reply 2 text"
            },
            "PostedBy": {
                "S": "User B"
            },
            "Id": {
                "S": "Amazon DynamoDB#DynamoDB Thread 1"
            }
        }
    ],
    "Count": 1, // 최종 반환된 아이템 개수
    "ScannedCount": 2, // 전체 스캔을 수행한 전체 아이템 개수
    "ConsumedCapacity": {
        "TableName": "Reply",
        "CapacityUnits": 0.5
    }
}

 

Exercise

Read the documentation for –max-items and write two queries:

  • return only the first reply to a thread
aws dynamodb query \
    --table-name Reply \
    --key-condition-expression 'Id = :Id' \
    --expression-attribute-values '{
        ":Id" : {"S": "Amazon DynamoDB#DynamoDB Thread 1"}
    }' \
    --max-items 1 \ // 최대 1개까지만 응답
    --scan-index-forward  \ // 인덱스 정렬 순서대로
    --return-consumed-capacity TOTAL
  • ScanIndexForward
    • Specifies the order for index traversal: If true (default), the traversal is performed in ascending order; if false, the traversal is performed in descending order.

 

  • return only the most recent reply for a thread
aws dynamodb query \
    --table-name Reply \
    --key-condition-expression 'Id = :Id' \
    --expression-attribute-values '{
        ":Id" : {"S": "Amazon DynamoDB#DynamoDB Thread 1"}
    }' \
    --max-items 1 \
    --no-scan-index-forward  \ // 인덱스 정렬 순서대로 적용 x
    --return-consumed-capacity TOTAL




Working with table Scans

  • Scan API : 전체 아이템 스캔 후 리턴 (1MB)
    • 단일 항목 뿐만 아니라, 전체 테이블 스캔 ⇒ 키 조건 표현식 ❌
    • 최대 용량 제한은 1MB이지만, --max-items 보다 더 많은 항목이 있는 경우 스캔 응답으로 NextToken이 포함되고 이를 후속 스캔 호출에 발행 → 중단 지점부터 다시 시작

 

✏️ e.g. --max-items 2 지정

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

 

  • Response
{
    "Items": [
        {
            "ReplyDateTime": {
                "S": "2015-09-15T19:58:22.947Z"
            },
            "Message": {
                "S": "DynamoDB Thread 1 Reply 1 text"
            },
            "PostedBy": {
                "S": "User A"
            },
            "Id": {
                "S": "Amazon DynamoDB#DynamoDB Thread 1"
            }
        },
        {
            "ReplyDateTime": {
                "S": "2015-09-29T19:58:22.947Z"
            },
            "Message": {
                "S": "DynamoDB Thread 2 Reply 1 text"
            },
            "PostedBy": {
                "S": "User A"
            },
            "Id": {
                "S": "Amazon DynamoDB#DynamoDB Thread 2"
            }
        }
    ],
    "Count": 3,
    "ScannedCount": 4,
    "ConsumedCapacity": {
        "TableName": "Reply",
        "CapacityUnits": 0.5
    },
    "NextToken": "eyJFeGNsdXNpdmVTdGFydEtleSI6IG51bGwsICJib3RvX3RydW5jYXRlX2Ftb3VudCI6IDJ9"
}
  • NextToken 값으로 미처 다 받지 못한 부분에 대해 Hash Key가 함께 온다.

 

  • Request
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
  • 다음과 같이 --starting-token 으로 같이 토큰 값을 보내서 요청에 대한 응답을 다시 호출할 수 있다.

 

Exercise

Explore the data in the Forum table and write a scan command to return only the Forums that have more than 1 thread and more than 50 views.

  • Request
aws dynamodb scan \\
    --table-name Forum \\
    --filter-expression 'Threads >= :threads AND Views >= :views' \\
    --expression-attribute-values '{
        ":threads" : {"N": "1"},
        ":views" : {"N": "50"}
    }' \\
    --return-consumed-capacity TOTAL

 

  • Response
An error occurred (ValidationException) when calling the Scan operation: Invalid FilterExpression: Attribute name is a reserved keyword; reserved keyword: Views
  • Views 가 DynamoDB의 예약어이기 때문에, 별도의 값임을 명시해줘야한다.

 

aws dynamodb scan \\
    --table-name Forum \\
    --filter-expression 'Threads >= :threads AND **#Views** >= :views' \\
    --expression-attribute-values '{
        ":threads" : {"N": "1"},
        ":views" : {"N": "50"}
    }' \\
    --expression-attribute-names '{"#Views" : "Views"}' \\
    --return-consumed-capacity TOTAL
  • Views 가 예약어가 아님을 명시하기 위해, 다음과 같이 표현을 써준다. --expression-attribute-names '{"#Views" : "Views"}'

 

 


Inserting/Updating Data

  • Insert
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
    • update-item API : ConditionExpression 적용해서 요청
    • ConditionExpression가 만족할 때의 요청만 수행

 

  • oldMessage → newMessage
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

 

  • 동일 명령 재 실행시, 오류 발생
An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed

 

Exercise

aws dynamodb update-item \\
    --table-name ProductCatalog \\
    --key '{
        "Id" : {"N": "201"}
    }' \\
    --update-expression "SET #Color = list_append(#Color, :values)" \\
    --expression-attribute-names '{"#Color": "Color"}' \\
    --expression-attribute-values '{
        ":values" : {"L": [{"S" : "Blue"}, {"S" : "Yellow"}]}
    }' \\
    --return-consumed-capacity TOTAL
aws dynamodb update-item \\
    --table-name ProductCatalog \\
    --key '{
        "Id" : {"N": "201"}
    }' \\
    --update-expression "SET Messages = :newMessages" \\
    --condition-expression "Messages = :oldMessages" \\
    --expression-attribute-values '{
        ":oldMessages" : {"N": "4"},
        ":newMessages" : {"N": "5"}
    }' \\
    --return-consumed-capacity TOTAL



Deleting Data

  • delete-item
aws dynamodb delete-item \\
    --table-name Reply \\
    --key '{
        "Id" : {"S": "Amazon DynamoDB#DynamoDB Thread 2"},
        "ReplyDateTime" : {"S": "2021-04-27T17:47:30Z"}
    }'
  • delete-item 수행 시, 동일한 쿼리를 두번 날리면 아무런 일 발생 ❌

 

Transactions

  • DynamoDB : 최대 100개의 작업 요청 → 동기식 쓰기 작업
    • 트랜잭션 4mb 크기 제한
  • 작업 모두 성공 or 모두 실패하도록 원자적 완료
    • 멱등성 : 동일한 트랜잭션 두 번 이상 보낼 수 있음, But 해당 트랜잭션은 한번만 실행
    • 자체적으로 멱등성이 없는 API 사용시 유용



Global Secondary Indexes

  • 타 DB 서비스의 인덱스 개념
    • GSI : 다양한 파티션 & 정렬 키 중심으로 데이터 자동 로테이션
    • Query & Scan API 를 통해 더 많은 액세스 패턴 제공을 위한 데이터 그룹화 및 정렬

 

  • 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"
            }
        }
    }
]'    

 

  1. scan 명령 대신에, query 명령을 통해 정렬된 사용자가 작성한 모든 Reply 탐색
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 키 속성을 사용해야함

 

  1. 인덱스에서 get-item 명령어가 안되는 이유
    1. get-item 요청은 최대 항목과 일치하는 지 의미하는 행을 추가
    2. GSI의 키가 단일 항목에 대해 고유하게 식별한다는 보장 존재 ❌

 

🙋🏻‍♀️ Questions

  1. eventual consistency 🆚 strongly consistent 가 가격 차이가 나는 이유?

결과적 일관성 / 최종적 일관성

  • eventual consistency?
    • 분산 컴퓨팅 환경과 크게 밀접한 관련이 있다.
    • 단기적으로 일관성을 잃더라도 결국에는 일관성을 유지하는 모델
Eventual consistency는 항목이 새롭게 업데이트되지 않는다는 전제하에 항목의 모든 읽기 작업이 최종적으로는 마지막으로 업데이트된 값을 반환한다는 것을 이론적으로 보장한다.

e.g. DNS

 

  • strongly consistency?
    • 전통적인 RDB에서의 데이터 정합성 문제가 이에 해당한다.
    • 조회된 데이터가 해당 항목을 보는 모든 사용자에게 일관적으로 표시된다.
    • But, 애플리케이션의 확장성과 성능을 어느 정도는 포기해야할 수도 있다.

  • 데이터의 정합성을 엄격하게 유지해야하기 때문에, 데이터 접근에 따른 Lock 설정을 통해 데이터를 긴밀하게 관리해야한다.

적합한 예시의 한 형태

strong consistency를 필요로 하지 않는 사용 사례
e.g 1) '친구 목록에서 특정 시간에 온라인 상태인 사용자 확인하기'
e.g 2) '게시물에서 몇 명의 사용자가 +1을 눌렀는지 확인하기'

strong consistency를 필요로 하는 경우
e.g 3) '사용자가 결제 프로세스를 완료했는지'
e.g 4) '게임 플레이어가 한 전투 세션 동안 획득한 포인트'

  1. DynamoDB 의 인덱싱 알고리즘?
    1. How does DynamoDB internal architecture look like?
  • DynamoDB 내부 동작
    • 추가는 맨 끝에 하면 되지만 스캐닝은 어려움
  • key-value 쌍을 리스트로 파일에서 관리한다.

  • Hashmap을 이용한 저장방법
    • 인덱스 활용 → 포인터 오프셋을 이용한 데이터 탐색
    • 원본 테이블 보다 더 적은 사이즈로 데이터 읽기가 가능



🔗 Reference

728x90