ablog

不器用で落着きのない技術者のメモ

Python で DynamoDB で負荷をかける

  • DDBGetItem.py
import boto3
import json
import datetime
import threading

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('ycsb8')

def getItem():
    i = 0
    last = datetime.datetime.now()
    while True:
        response = table.get_item(
    	        Key={
	        	    'firstname': 'user1000385178204227360'
        	    }
        )
        i += 1
        mod = i % 1000
        if mod == 0:
            prev = last
            last = datetime.datetime.now()
            delta = last - prev
            print i, ':', delta.total_seconds()

if __name__ == "__main__":
	for n in range(4):
            p = threading.Thread(target=getItem)
	    p.start()
$ sudo pip install boto3
  • 実行する
$ export AWS_DEFAULT_REGION=ap-northeast-1
$ python DDBGetItem.py >> DDBGetItem.log &

pgbench で PostgreSQL に半永久的に負荷をかけ続ける

pgbench で PostgreSQL に半永久的に負荷をかけ続ける手順をメモ。

スクリプト

  • pgbench_infinite_loop.sh
#!/bin/bash
export LANG=C
export PGPASSWORD=<パスワード>
ENDPOINT=<ホスト名>

BASE_NAME=$(basename $0)
STEM="${BASE_NAME%.*}"
DATE=`date '+%Y-%m-%d-%H%M%S'`

while :
do
	pgbench -n -r -c 8 -j 8 -t 100000 -U awsuser -h ${ENDPOINT} -d mydb >> ${STEM}-${DATE}.log 2>/dev/null
done
  • pgbench をインストール
$ sudo yum -y install postgresql
$ sudo yum -y install postgresql-contrib
  • データを登録する
$ pgbench -i -s 1000 -U awsuser -h ******.******.ap-northeast-1.rds.amazonaws.com -d mydb

実行

  • 実行する
$ nohup ./pgbench_infinite_loop.sh &

モニタリング

  • ログをモニタリングする。
$ tail -f pgbench_infinite_loop-2019-03-03-175614.log
pghost: aurora-posgres10-r5l.cluster-*****.ap-northeast-1.rds.amazonaws.com pgport:  nclients: 8 nxacts: 100000 dbName: mydb
transaction type: TPC-B (sort of)
scaling factor: 1000
query mode: simple
number of clients: 8
number of threads: 8
number of transactions per client: 100000
number of transactions actually processed: 800000/800000
tps = 359.656559 (including connections establishing)
tps = 359.660528 (excluding connections establishing)
statement latencies in milliseconds:
	0.034531	\set nbranches 1 * :scale
	0.029953	\set ntellers 10 * :scale
	0.030349	\set naccounts 100000 * :scale
	0.024340	\setrandom aid 1 :naccounts
	0.022874	\setrandom bid 1 :nbranches
	0.020391	\setrandom tid 1 :ntellers
	0.018264	\setrandom delta -5000 5000
	2.382775	BEGIN;
	3.217786	UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
	2.441472	SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
	2.465225	UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
	2.486259	UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
	2.445141	INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
	6.599387	END;
  • Performance Insights でモニタリングする(今回は Aurora PostgreSQL互換で実行したため)。

f:id:yohei-a:20190304030248p:plain

補足

pgbench でパスワードの自動入力は PGPASSWORD 環境変数などでできる。

You have four choices regarding the password prompt:

1. set the PGPASSWORD environment variable. For details see the manual:
http://www.postgresql.org/docs/current/static/libpq-envars.html
2. use a .pgpass file to store the password. For details see the manual:
http://www.postgresql.org/docs/current/static/libpq-pgpass.html
3. use "trust authentication" for that specific user:
http://www.postgresql.org/docs/current/static/auth-methods.html#AUTH-TRUST
4. use a connection URI that contains everything:
http://www.postgresql.org/docs/current/static/libpq-connect.html#AEN42532

postgresql - How to use psql with no password prompt? - Database Administrators Stack Exchange

JAWS DAYS 2019 に参加してきた

JAWS DAYS 2019 に参加してきた。

RDBリファクタリングと異種間DB移行の戦い – Amazon DMSを使った止めずにリファクタリングする手法
  • 曽根 壮大さん 所属:株式会社 オミカレ (副社長/CTO)
実践!CloudFormation Best Practice ~CloudFormationで始める組織改革~
Kinesis→Redshift連携を、KCLからFirehoseに切り替えたお話-
Sansanという会社がどのようにAWSと向き合っているのか
  • 間瀬 哲也さん 所属:Sansan株式会社 Eight事業部
AI/MLシステムにおけるビッグデータとの付き合い方
  • 鈴木 翔太さん 所属:株式会社DeNAシステム本部AIシステム部MLエンジニアリンググループ
自社基盤で運用していた事業用サービスをAWS Fargate/Lambda等を活用しAWS上で再構築!苦労話もあるよ。
  • 平山 智史さん 、東川 寿充さん 所属:ソニーネットワークコミュニケーションズ(株)法人サービス事業部 CNS開発運用部 クラウドビジネス開発課

Aurora MySQLとS3間でデータをロード&アンロードする

Aurora MySQLとS3間でデータをロード(LOAD DATA FROM S3)&アンロード(SELECT INTO OUTFILE S3)したメモ。

環境

手順

  • IAMロールを作成する
    • ロール名: rds-s3-role
    • アクセス権限-Permissions policies: AmazonS3FullAccess
    • 信頼されたエンティティ-IDプロバイダー: rds.amazonaws.com
  • パラメータグループを作成する
    • グループ名: aurora-mysql57-cluster-custom
    • パラメータグループファミリー: aurora-mysql5.7
    • タイプ: DB Cluster Parameter Group
  • 作成したパラメータグループ "aurora-mysql57-cluster-custom" のパラメータ "aws_default_s3_role" に作成したIAMロールの ARN "arn:aws:iam::AWSアカウントid:role/rds-s3-role" を指定する。
  • Aurora MySQL クラスターを作成する。
  • Aurora MySQL クラスターのIAMロール管理で "rds-s3-role" を指定する。
  • mysql と sysbench をインストールする
$ curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash
$ sudo yum -y install sysbench mysql
  • sysbench で1億件のデータをロードする。
$ sysbench /usr/share/sysbench/oltp_read_write.lua \
 --db-driver=mysql \
 --table-size=10000000 \
 --mysql-host=aurora-mysql57-r4-8xl.cluster-********.ap-northeast-1.rds.amazonaws.com \
 --mysql-user=awsuser \
 --mysql-password=******** \
 --mysql-db=mydb \
 --db-ps-mode=disable \
 prepare
  • Aurora MySQL にログインする。
$ mysql -h aurora-mysql57-r4-8xl.cluster-********.ap-northeast-1.rds.amazonaws.com -u awsuser -p
  • データを増幅する。
> create table sbtest100m (select a.* from sbtest1 a, sbtest1 b limit 100000000);
  • S3 にアンロードする。
> select count(*) from sbtest100m;
5.7.12 awsuser: [mydb] 16:36> SELECT * FROM sbtest100m INTO OUTFILE S3 's3-ap-northeast-1://az-cp-dst/sbtest100m'
    ->      FIELDS TERMINATED BY ','
    ->      LINES TERMINATED BY '\n'
    ->      MANIFEST ON
    ->      OVERWRITE OFF;
Query OK, 100000000 rows affected (8 min 55.83 sec)
  • S3 にアンロードしたオブジェクトのサイズを確認する。
$ aws s3 ls --human-readable s3://aurora-data-bucket/100m
2019-02-19 15:19:13  377 Bytes sbtest100m.manifest
2019-02-19 15:10:09    6.0 GiB sbtest100m.part_00000
2019-02-19 15:13:05    6.0 GiB sbtest100m.part_00001
2019-02-19 15:16:08    6.0 GiB sbtest100m.part_00002
2019-02-19 15:19:05  249.4 MiB sbtest100m.part_00003
$ aws s3 cp s3://az-cp-dst/sbtest100m.part_00000  ./
$ head -1 sbtest100m.part_00000 > 1line
$ ls -l 1line
-rw-rw-r-- 1 ec2-user ec2-user 190 Feb 19 16:24 1line
  • テーブルを truncate する。
5.7.12 awsuser: [mydb] 15:22> truncate table sbtest100m;
Query OK, 0 rows affected (1.28 sec)
  • S3からデータをロードする。
5.7.12 awsuser: [mydb] 15:23> LOAD DATA FROM S3 MANIFEST 's3-ap-northeast-1://aurora-data-bucket/100m.manifest'
    ->   INTO TABLE sbtest100m
    ->   FIELDS TERMINATED BY ','
    ->   LINES TERMINATED BY '\n' (id, k, c, pad);
Query OK, 100000000 rows affected (22 min 11.60 sec)
Records: 100000000  Deleted: 0  Skipped: 0  Warnings: 0

追記(2019/02/22)

1.8GB(1千万件)
  • UNLOAD
> create table sbtest10m (select * from sbtest1);
> select count(*) from sbtest10m;
5.7.12 awsuser: [mydb] 16:03> SELECT * FROM sbtest10m INTO OUTFILE S3 's3-ap-northeast-1://az-cp-dst/sbtest10m'
    ->      FIELDS TERMINATED BY ','
    ->      LINES TERMINATED BY '\n'
    ->      MANIFEST ON
    ->      OVERWRITE OFF;
Query OK, 10000000 rows affected (55.03 sec)
  • LOAD
5.7.12 awsuser: [mydb] 15:15> LOAD DATA FROM S3 MANIFEST 's3-ap-northeast-1://az-cp-dst/sbtest10m.manifest'
    ->     INTO TABLE sbtest10m
    ->        FIELDS TERMINATED BY ','
    ->        LINES TERMINATED BY '\n' (id, k, c, pad);
Query OK, 10000000 rows affected (2 min 16.17 sec)
Records: 10000000  Deleted: 0  Skipped: 0  Warnings: 0
9GB(5千万件)
  • UNLOAD
> create table sbtest50m (select a.* from sbtest1 a, sbtest1 b limit 50000000);
> select count(*) from sbtest50m;
5.7.12 awsuser: [mydb] 14:55> SELECT * FROM sbtest50m INTO OUTFILE S3 's3-ap-northeast-1://az-cp-dst/sbtest50m'
    ->      FIELDS TERMINATED BY ','
    ->      LINES TERMINATED BY '\n'
    ->      MANIFEST ON
    ->      OVERWRITE OFF;
Query OK, 50000000 rows affected (4 min 18.54 sec)
  • LOAD
5.7.12 awsuser: [mydb] 15:26> LOAD DATA FROM S3 MANIFEST 's3-ap-northeast-1://az-cp-dst/sbtest50m.manifest'
    ->     INTO TABLE sbtest50m
    ->        FIELDS TERMINATED BY ','
    ->        LINES TERMINATED BY '\n' (id, k, c, pad);
Query OK, 50000000 rows affected (11 min 9.39 sec)
Records: 50000000  Deleted: 0  Skipped: 0  Warnings: 0

YCSB で DynamoDB On-Demand に負荷をかける

YCSB(Yahoo Cloud Serving Benchmark)で DynamoDB On-Demand に負荷をかける手順。

準備

DynamoDBにテーブルを作成する
  • テーブル名: ycsb1、ycsb2、ycsb3、ycsb10、ycsb100、ycsb1000、ycsb10000
  • プライマリパーティションキー:firstname(文字列)
  • 読み込み/書き込みキャパシティーモード: オンデマンド
Maven のインストール
  • OpenJDK をインストールする。
$ sudo yum -y install java-1.8.0-openjdk-devel.x86_64
  • Maven をインストールする。
$ curl -OL https://archive.apache.org/dist/maven/maven-3/3.5.2/binaries/apache-maven-3.5.2-bin.tar.gz
$ tar xzvf apache-maven-3.5.2-bin.tar.gz
$ sudo mv apache-maven-3.5.2 /opt/
$ sudo ln -s /opt/apache-maven-3.5.2 /opt/apache-maven
  • .bash_profile に追記して Maven へのパスを通す。
$ vi .bash_profile
PATH=$PATH:$HOME/.local/bin:$HOME/bin:/opt/apache-maven/bin
JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.amzn2.x86_64
export JAVA_HOME
$ source .bash_profile
  • Maven のバージョンを確認する。
$ mvn --version
Apache Maven 3.5.2 (138edd61fd100ec658bfa2d307c43b76940a5d7d; 2017-10-18T07:58:13Z)
Maven home: /opt/apache-maven
Java version: 1.7.0_201, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.201.x86_64/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "4.14.77-70.59.amzn1.x86_64", arch: "amd64", family: "unix"
YCSBのインストールと設定
  • YCSBのダウンロードとビルド
$ sudo yum -y install git
$ git clone https://github.com/brianfrankcooper/YCSB.git
$ cd YCSB/
$ mvn clean package
  • DynamoDBの接続設定
$ vi ~/YCSB/dynamodb/conf/dynamodb.properties
dynamodb.awsCredentialsFile = dynamodb/conf/AWSCredentials.properties
dynamodb.primaryKey = firstname
dynamodb.endpoint = http://dynamodb.ap-northeast-1.amazonaws.com
  • クレデンシャルを設定する。
$ vi ~/YCSB/dynamodb/conf/AWSCredentials.properties
accessKey = <記述する>
secretKey = <記述する>
  • YCSB/workloads/workload1 を作成する。
$ cp workloada workload1
$ vi workload1
recordcount=1
table=ycsb1
operationcount=10000000
workload=com.yahoo.ycsb.workloads.CoreWorkload
readallfields=true
readproportion=1
updateproportion=0
scanproportion=0
insertproportion=0

ベンチマークをかける

  • データをロードする。
$ cd ~/YCSB
$ ./bin/ycsb load dynamodb -P workloads/workload1 -P dynamodb/conf/dynamodb.properties
$ ./bin/ycsb load dynamodb -P workloads/workload2 -P dynamodb/conf/dynamodb.properties
$ ./bin/ycsb load dynamodb -P workloads/workload3 -P dynamodb/conf/dynamodb.properties
$ ./bin/ycsb load dynamodb -P workloads/workload10 -P dynamodb/conf/dynamodb.properties
$ ./bin/ycsb load dynamodb -P workloads/workload100 -P dynamodb/conf/dynamodb.properties
$ ./bin/ycsb load dynamodb -P workloads/workload1000 -P dynamodb/conf/dynamodb.properties
$ ./bin/ycsb load dynamodb -P workloads/workload10000 -P dynamodb/conf/dynamodb.properties
$ ./bin/ycsb load dynamodb -P workloads/workload100hotspot -P dynamodb/conf/dynamodb.properties
  • 負荷をかける。
$ ./bin/ycsb run dynamodb -P workloads/workload1 -P dynamodb/conf/dynamodb.properties -threads 50
$ ./bin/ycsb run dynamodb -P workloads/workload2 -P dynamodb/conf/dynamodb.properties -threads 100
$ ./bin/ycsb run dynamodb -P workloads/workload3 -P dynamodb/conf/dynamodb.properties -threads 150
$ ./bin/ycsb run dynamodb -P workloads/workload10 -P dynamodb/conf/dynamodb.properties -threads 200
$ ./bin/ycsb run dynamodb -P workloads/workload100 -P dynamodb/conf/dynamodb.properties -threads 300
$ ./bin/ycsb run dynamodb -P workloads/workload1000 -P dynamodb/conf/dynamodb.properties -threads 400
$ ./bin/ycsb run dynamodb -P workloads/workload10000 -P dynamodb/conf/dynamodb.properties -threads 500
$ ./bin/ycsb run dynamodb -P workloads/workload100hotspot -P dynamodb/conf/dynamodb.properties -threads 200

確認ポイント

補足

  • YCSB/dynamodb/conf/dynamodb.properties
dynamodb.consistentReads = true
dynamodb.awsCredentialsFile = dynamodb/conf/AWSCredentials.properties
dynamodb.primaryKey = firstname
dynamodb.endpoint = http://dynamodb.ap-northeast-1.amazonaws.com
  • YCSB/workloads/workload1
recordcount=1
table=ycsb1
operationcount=10000000
workload=com.yahoo.ycsb.workloads.CoreWorkload
readallfields=true
readproportion=1
updateproportion=0
scanproportion=0
insertproportion=0
  • YCSB/workloads/workload2
recordcount=2
table=ycsb2
以降、workload1 と同じ
  • YCSB/workloads/workload3
recordcount=3
table=ycsb3
以降、workload1 と同じ
  • YCSB/workloads/workload10
recordcount=10
table=ycsb10
以降、workload1 と同じ
  • YCSB/workloads/workload100
recordcount=100
table=ycsb100
以降、workload1 と同じ
  • YCSB/workloads/workload100hotspot
recordcount=100
table=ycsb100
requestdistribution=hotspot
以降、workload1 と同じ
  • YCSB/workloads/workload1000
recordcount=1000
table=ycsb1000
以降、workload1 と同じ

S3 Object Lock について

たぶんこんな感じ。

S3 Object Lock とは

バージョニングされた過去バージョンを消せなくする機能。オブジェクトの上書きはできるが過去バージョンを消せない。従って、バージョニングを有効化しないと S3 Object Lock を有効化できない。

期間保持と法的保有

バケット*1に対して設定する一定期間オブジェクトバージョンを削除できない「期間保持」とオブジェクトに対して設定する解除するまで永久にオブジェクトバージョンを削除できない「法的保有」がある。
保持期間(Retention period)では過去バージョンを削除できない期間を設定できる。長くは変更できるが、短くはできない。法的保有(Legal hold)はオブジェクトレベルのみの設定でバケットレベルでは設定できず、有効化しているとそのオブジェクトの全過去バージョンを削除できない。s3:PutObjectLegalHold 権限を持つIAMユーザー/ロールで無効化するまでオブジェクトバージョンを削除できない。保持期間(Retention period)と法的保有(Legal hold)の両方を有効化できるが、全過去バージョンを削除できなくなるので法的保有(Legal hold)のみ有効化しているのと同じ動作になる。

期間保持のガバナンスモードとコンプライアンスモード

期間保持には「ガバナンスモード」と「コンプライアンスモード」があり両方共バケットレベルでは設定後に無効化できるが、オブジェクトに対しては「コンプライアンスモード」で作成されたオブジェクトは保持期間を過ぎるまで二度とバージョンを消せなくなる。「コンプライアンスモード」にしたバケットを削除するにはアカウントを解約するしかない。「ガバナンスモード」は明示的に s3:BypassGovernanceRetention 権限*2を付与されたIAMユーザー/ロールでは無効化して削除できる。

利用例

バケットのプロパティで保持期間90日に設定し、Organizations の Service Control Policy(SCP) で子アカウントの s3:PutBucketObjectLockConfiguration と s3:PutObjectRetention を Deny すると、そのバケットに作成されたオブジェクトは90日間削除できない。「コンプライアンスモード」の場合はこの期間はどうやっても削除できない。「ガバナンスモード」の場合は、親アカウントでSCPをデタッチしてs3:BypassGovernanceRetention 権限を持ったIAMユーザー/ロールでオブジェクトの保持期限を無効化して削除することができる。

*1:オブジェクト毎にも設定できる

*2: s3:PutObjectRetention 権限も必要