MySQLからAmazon Timestreamへの移行の検証

 ·  ☕ 4 

MySQLに格納している時系列データをTimestreamにインポートして検証を行ったときの情報です。

おことわり

先に書いておくと、Timestreamは結局使用していません。
スナップショットが取れず、PITR (Point In Time Recovery) 機能もない事が発覚したため。
折角使ってみたので参考として記しておきます。まぁそのうち機能追加されるかも知れないし?

Amazon Timestreamとは

時系列データに特化したデータベースです。
クラスメソッドさんの記事を読めば何となく分かるかと。

ちょっと補足すると、データの書き込みはAPIで行いますが
クエリはSQLで書く事ができます。なのでRDBライクに集計を行う事ができます。

仕様

インポートのコード

GitHubのサンプルコード を元に実装しました。

ちなみに ドキュメントにもサンプル がありますが、部分的にしか書かれて無く、この通り書いても動きません(いやいや…)

作ったコードはGitHubに上げました。(かなりテキトウですが…)
https://github.com/sakojun/Timestream-from-MySQL

抜粋してちょっと補足

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
sql = "select count(*) from {}".format(mysql_table)
cur.execute(sql)
rows = cur.fetchall()
for row in rows:
    rows_count = row[0]

print(rows_count)

# Timestreamが100レコードずつしか書き込めないため、
# 100レコードずつ読み込んで、配列を作って書き込んでる。
for i in range(0, rows_count + 100, 100):

    sql = "select * from {0} where id > {1} limit 100".format(mysql_table, i)
    cur.execute(sql)
    rows = cur.fetchall()

    tmp_records = []

    # MySQLから読み込んだデータを1行ずつrowに格納
    for row in rows:
        print(row)


        current_time = row[6].timestamp()

        # 全レコードで共通の設定
        tmp_common_attributes = {
            'MeasureValueType': 'BIGINT',
            'TimeUnit': 'SECONDS'
        }

        # 各レコードのデータ
        tmp_records.append(
            {
                'Dimensions': [
                    {
                        'Name': 'uuid',
                        'Value': row[2],
                        'DimensionValueType': 'VARCHAR'
                    },
                ],
                'MeasureName': 'status',
                'MeasureValue': str(row[3]),
                'Time': str(int(current_time))
            }
        )

    ts.write_records_with_common_attributes(Constant.TABLE_NAME, tmp_common_attributes, tmp_records)

cur.close
conn.close

クエリの検証

こんな感じのクエリがMySQLで遅かったので検証しました。

1
2
3
4
5
SELECT uuid, avg(value) as avg
 FROM table
 WHERE 先週 <= timestamp
  AND timestamp <= 今週
GROUP BY uuid;

MySQLで14秒掛かっていたのが、4秒程度になりました。
ただこれは後に、MySQLのインデックスの貼り方が悪かった事が判明し、適切にインデックスを貼った場合はMySQLの方が高速でした。

まぁ、インデックスを気にしなくていいというのは利点でしょうかね。

残念仕様の発覚

上の検証は全データがメモリストアに格納されている場合であったので
マグネティックストアの場合も検証しよう、その前にスナップショットを取ろう、とした所で前述の仕様が発覚しました。

複製して検証したい場合はどうしたら良いのでしょうか?
サポートに確認してみましたが、同様のデータをロードするしかないとの事。
これにはいくつかの問題があります。

  1. RDBとは違い、読み込みはSQLで書き込みはAPIであるため、単純にコピーできない。
  2. 一度に100件しか書き込めないので何時間も掛かってしまう。(分散処理するコードを書けば改善はできるが…)
  3. これらを乗り越えたとしても、1年以上前はそもそも書き込む事ができない。
    Amazon Timestream であらゆる規模の時系列データを保存してアクセス – 一般提供が開始されました

    Timestream にデータを書き込む場合、メモリストアの保持期間よりも古いデータを挿入することはできません。

またPITRもないので、リストアができません。
delete_recordsがない のでデータは消せないのでしょうが、もし誤って古いタイムスタンプのデータが書き込まれてしまったら、元に戻せないじゃないですか?

一応新しいデータをTimestreamに格納する方針にして、S3にも同時に書き込んどくという使い方はできそうです。(複製やリストアに時間がかかる問題は解消しないけど)
が、データのライフサイクル管理をデータベース側でやってくれる利点はどこ行ったとなりますね。。

どういう使い方を想定したサービスなのか、良く分からなくなりました。
いつかスナップショット機能が追加されないと使わなそうです。