13
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

DynamoDBの基礎まとめ ― 読み込み(RCU)検証

Last updated at Posted at 2018-07-03

DynamoDBの基礎まとめ ― 書き込み(WCU)検証
ではWCUの挙動を検証してから大分時間が経ちましたが、今回はRCUについてやってみました。

##テーブル作成
前回のSampleTableを利用
image.png

##読み込み(RCU)
DynamoDBはデータ読み取りのために基本三つのアクションを提供しています。
テーブルからデータを読み込む を参考

アクション 説明
GetItem テーブルから単一の項目を取り出します。
Query 特定のパーティションキーがあるすべての項目を取り出します。
Scan 指定されたテーブルで、すべての項目を取り出します。

それぞれ実行してみます。

##PythonでLambda関数

###パターン1:GetItemで1レコード読み取り
RCUの課金境界線は4KBなので、それぞれデータサイズ4KB以下と4KB超えの2回実施

回数 userid updatedatetime itemid itemstatus データ
1回目 U00001 2018-04-09 09:02:00 IT007 good レコード全体4KB未満
2回目 U00001 2018-04-09 09:01:00 IT006 4,938バイトの長い文字列 レコード全体4KB超え
import boto3
import logging

dynamoDB = boto3.resource("dynamodb")
table = dynamoDB.Table("SampleTable")

def lambda_handler(event, context):
    
    try:
        itemdata = table.get_item(
            Key={
                "userid" : "U00001",
                "updatedatetime" : "2018-04-08 09:01:00"
            },
            ConsistentRead=True
        )
    except Exception as e:
        logging.error("type : %s", type(e))
        logging.error(e)

RCU計算しやすいように、ConsistentReadをTrueにし、DynamoDB はオペレーション時に強い整合性のある読み込みを使用します。

GetItemは1行ずつの読み込みが基本ですので、Keyの条件から「"updatedatetime" : "2018-04-08 09:01:00"」を抜くとThe provided key element does not match the schemaエラーが出ます。

[ERROR]	2018-05-02T06:53:18.565Z	caf6a9b7-66fa-11e8-a314-1579052166ad	type : <class 'botocore.exceptions.ClientError'>
[ERROR]	2018-05-02T06:53:18.586Z	caf6a9b7-66fa-11e8-a314-1579052166ad	An error occurred (ValidationException) when calling the GetItem operation: The provided key element does not match the schema

###パターン1:CloudWatch結果
1-1は4KB未満で4KB(1RCU)に切り上げ、1-2は4KB超えで8KB(2RCU)に切り上げられました。
image11.png

###パターン2:Queryで1パーティションすべてのレコードを読み取り

回数 userid データ
1回目 U00003 1レコード、データサイズ4KB未満
2回目 U00002 合計3レコード、データサイズ4KB未満
3回目 U00001 7レコード、データサイズ4KB超え
import boto3
import logging
from boto3.dynamodb.conditions import Key

dynamoDB = boto3.resource("dynamodb")
table = dynamoDB.Table("SampleTable")

def lambda_handler(event, context):
    
    try:
        itemdata = table.query(
            KeyConditionExpression=Key("userid").eq("U00003"),
            ConsistentRead=True
        )
    except Exception as e:
        logging.error("type : %s", type(e))
        logging.error(e)

###パターン2:CloudWatch結果
読み取りレコード数に関係なく、あくまで合計サイズが4KBまたはその倍数かで切り上げられています。
image12.png

###パターン3:Queryで1パーティションの一部レコード(or 一部項目)取得

回数 userid 条件 データ
1回目 U00001 itemid=IT004 1レコード、データサイズ4KB未満、パーティションデータサイズ4KB超え
2回目 U00001 Select itemid 合計7レコード、取得項目データサイズ4KB未満、パーティションデータサイズ4KB超え
パターン3-1回目
import boto3
import logging
from boto3.dynamodb.conditions import Key, Attr

dynamoDB = boto3.resource("dynamodb")
table = dynamoDB.Table("SampleTable")

def lambda_handler(event, context):
    
    try:
        itemdata = table.query(
            KeyConditionExpression=Key("userid").eq("U00001"),
            FilterExpression=Attr("itemid").eq("IT004"),
            ConsistentRead=True
        )
    except Exception as e:
        logging.error("type : %s", type(e))
        logging.error(e)
パターン3-2回目
import boto3
import logging
from boto3.dynamodb.conditions import Key, Attr

dynamoDB = boto3.resource("dynamodb")
table = dynamoDB.Table("SampleTable")

def lambda_handler(event, context):
    
    try:
        itemdata = table.query(
            ProjectionExpression="itemid",
            KeyConditionExpression=Key("userid").eq("U00001"),
            ConsistentRead=True
        )
    except Exception as e:
        logging.error("type : %s", type(e))
        logging.error(e)

###パターン3:CloudWatch結果
3-1でたとえ結果はIT004という1レコードのみがヒットしたとしても、検索範囲(パーティションのサイズ)でRCUが計上されました。3-2も同様、結果が1カラムのみほしいにもかかわらず、RCUは検索範囲(パーティションのサイズ)で計上されます。
image13.png

###パターン4:Scanでテーブル全レコードを読み取り

回数 userid データ
1回目 すべて 16レコード、15.33 KB
image14.png

import boto3
import logging

dynamoDB = boto3.resource("dynamodb")
table = dynamoDB.Table("SampleTable")

def lambda_handler(event, context):
    
    try:
        itemdata = table.scan(
            ConsistentRead=True
        )
    except Exception as e:
        logging.error("type : %s", type(e))
        logging.error(e)

###パターン4:CloudWatch結果
スキャンの場合、テーブルの合計サイズでRCUが計上されます。
image141.png

##考察
WCU時と同様、1レコードのデータサイズを4KB未満(あるいはKBに比例する)に抑えるのがよく、プロビジョニングする際にも読み取りレコード数/秒で算出するので良いです。
すこし勘違いしました。WCUは1レコードずつ(挿入、更新、削除は1レコード単位のため)のサイズを1KB未満(あるいはKBに比例する)に抑えるとよいです。
RCUは基本パーティション単位の読み取りとなるので、
1パーティション=1レコードの場合、4KBを意識すればよいですが、
1パーティションが複数レコードの場合、レコード数も変動となるはずで、4KBという境界線を気にすることがなく、あくまで全体的にデータサイズ(Key、Value)を抑えたテーブル設計を念頭に置けばよいかと思います。
また、テーブルサイズが肥大化すると、Scan時のRCUが膨大になるため、基本Scanは使用しないようにアプリケーション設計が必要です。

13
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?