Redisに耐久性が加わったAmazon MemoryDB for Redisが登場
人気のインメモリデータベースRedisを使うと、読み書きをミリ秒未満で処理できるため、パフォーマンスが求められるシステムのキャッシュレイヤーで重宝されます。 一方で、AOFファイルのような永続化の仕組みは存在するものの、プライマリノードで障害が起こると、データロストが起こりうるという問題を抱えており、永続的なデータストアには向いていません。
AWSが提供する Amazon ElastiCache for Redis でも同じです。
この課題を解決するのが、今回発表された Amazon MemoryDB for Redis です。
トランザクションログは複数AZに保存され、書き込みに成功したデータのみが読み取れるため、整合性のある読み込みをサポートします。 ノード障害やフェイルオーバーが発生しても、データロストすることはありません。
Amazon MemoryDB for Redis の特徴
- Redis互換のAPI
- 書き込み時のトランザクションログは複数AZに分散。データロストなし
- レイテンシーは読み込みがミリ秒未満、書き込みが1桁ミリ秒(通常のRedisは書き込みもミリ秒未満)
- 読み込みは 470K回/秒、書き込みは 100K回/秒
- スループットは読み込みが 1GB/s、書き込みが100 MB/s
やってみた
Amazon MemoryDB For Redis を起動してみます。
非常に大事な点として、現時点では東京リージョンでは利用できず、以下のリージョンでしか提供されていません。
- 北部バージニア
- ダブリン
- ムンバイ
- サンパウロ
AWSコンソールから、「Amazon MemoryDB For Redis 」に移動します。
「Create cluster」からクラスターを作成します。
クラスターの構築方法は、ElastiCache とほぼ同じです。
MemoryDBはElastiCacheで言うところの「クラスターモード」しか存在しないため、シャード数とレプリカ数を指定します。
クラスターのステータスが"Available" になったら、 「Configuration endpoint」のエンドポイントに Redis クライアントから接続します。
今回はEC2にRedis CLIをインストールして接続しました。
$ sudo amazon-linux-extras install redis6 $ HOST=foo.xxx.clustercfg.memorydb.eu-west-1.amazonaws.com $ redis-cli -h $HOST -c 172.31.10.170:6379> ping pong 172.31.10.170:6379> set foo bar 172.31.10.170:6379> get foo bar
ElastiCacheとMemoryDBのベンチマーク
2シャードx3ノード/シャード=合計6ノードのクラスター(r6g.large)を ElastiCache/MemoryDB それぞれで構築し、EC2内(t3.large)から redis-benchmark
で簡易的にベンチマークを行いました($ redis-benchmark -q -n 100000 -h $HOST --cluster
)。
ドキュメントの通り、ElastiCacheは読み書きともに1msec未満で高速なのに対して、MemoryDBは書き込みが非常に遅いです。
すべての書き込み系コマンドが遅いわけではなく、集合系(SADD
/ZADD
等)コマンドのように高速に動作するものもあります。
リスト操作(LPUSH
/LPOP
等)が苦手だったり、 INCR
のようにインクレメントするだけのシンプルなコマンドも低速なのは興味深いですね。
ノードタイプ
現時点では、メモリ最適化のGraviton2の r6g 系だけが提供されています。
ノードタイプ | vCPU | メモリー (GiB) | ネットワークパフォーマンス (Gbps) |
---|---|---|---|
db.r6g.large | 2 | 13.07 | 〜10 |
db.r6g.xlarge | 4 | 26.32 | 〜10 |
db.r6g.2xlarge | 8 | 52.82 | 〜10 |
db.r6g.4xlarge | 16 | 105.81 | 〜10 |
db.r6g.8xlarge | 32 | 209.55 | 12 |
db.r6g.12xlarge | 48 | 317.77 | 20 |
db.r6g.16xlarge | 64 | 419.09 | 25 |
ノードタイプのプリフィックスは RDS/Aurora と同じく「db」です。 ElastiCacheの「cache」ではありません。
利用費
MemoryDB の利用費は
- インスタンス
- 書き込み量($0.20/GB) ※全リージョン固定
の2本立てです。
MemoryDB/ElastiCache/Aurora 間でバージニア北部のオンデマンド利用費を比較します。
インスタンスタイプ | サービス | $/Hour |
---|---|---|
cache.r6g.large | Elasticache | 0.206 |
db.r6g.large | Aurora | 0.260 |
db.r6g.large | MemoryDB | 0.309 |
MemoryDB はElastiCache の約1.5倍、Aurora の約1.2倍と若干高価です。
耐久性を重視するMemoryDBはElastiCacheで言うところの「クラスターモード」しか存在しないため、{シャード数} x {ノード数/シャード} x {インスタンス利用費} 分の利用費が発生する点にもご注意ください。
最後に
Redisを永続的なデータストアとしても使える Amazon MemoryDB for Redis が爆誕しました。
データ耐久性のトレードオフとして書き込み速度は低下したものの、読み取りの速さはまさにRedisです。
クライアントはRedisコマンドを投げるだけで、MemoryDBが良しなにやってくれるため、使い勝手が良さそうです。 今後はDynamodB+DAXの代替として検討したり、RDB+キャッシュRedisなシステムを MemoryDB に集約するといったケースが増えるかもしれません。
Amazon MemoryDB for Redis のネーミングから、MemoryDB シリーズはラインナップが今後増えていくと思われます。 次のデータベースエンジンが何なのか、気になるところです。
それでは。
参考
- Introducing Amazon MemoryDB for Redis – A Redis-Compatible, Durable, In-Memory Database Service | AWS News Blog
- Amazon MemoryDB for Redis – Redis-Compatible In-Memory Database – Amazon Web Services
付録
redis-benchmark
のベンチマーク結果です。
ElastiCache
$ redis-benchmark -q -n 100000 -h $EC --cluster Cluster has 2 master nodes: Master 0: 1d65e0ae87105d66acb8e619eb3f736a842a89f4 172.31.18.117:6379 ERROR: ERR unknown command `CONFIG`, with args beginning with: `GET`, `save`, ERROR: failed to fetch CONFIG from 172.31.18.117:6379 WARN: could not fetch node CONFIG 172.31.18.117:6379 Master 1: de0e23d31a3a380ce0ae462c8ee315360dedea1a 172.31.8.77:6379 ERROR: ERR unknown command `CONFIG`, with args beginning with: `GET`, `save`, ERROR: failed to fetch CONFIG from 172.31.8.77:6379 WARN: could not fetch node CONFIG 172.31.8.77:6379 PING_INLINE: 79681.27 requests per second, p50=0.271 msec PING_MBULK: 79428.12 requests per second, p50=0.455 msec SET: 79617.83 requests per second, p50=0.471 msec GET: 79681.27 requests per second, p50=0.255 msec INCR: 79808.46 requests per second, p50=0.247 msec LPUSH: 99601.60 requests per second, p50=0.255 msec RPUSH: 99700.90 requests per second, p50=0.271 msec LPOP: 99601.60 requests per second, p50=0.271 msec RPOP: 99601.60 requests per second, p50=0.255 msec SADD: 66269.05 requests per second, p50=0.455 msec HSET: 79744.82 requests per second, p50=0.255 msec SPOP: 79617.83 requests per second, p50=0.327 msec ZADD: 79681.27 requests per second, p50=0.447 msec ZPOPMIN: 79491.26 requests per second, p50=0.319 msec LPUSH (needed to benchmark LRANGE): 79681.27 requests per second, p50=0.407 msec LRANGE_100 (first 100 elements): 44247.79 requests per second, p50=0.519 msec LRANGE_300 (first 300 elements): 18921.48 requests per second, p50=1.359 msec LRANGE_500 (first 500 elements): 12383.90 requests per second, p50=1.919 msec LRANGE_600 (first 600 elements): 10441.68 requests per second, p50=2.247 msec MSET (10 keys): 79681.27 requests per second, p50=0.463 msec
MemoryDB
$ redis-benchmark -q -n 100000 -h $MDB --cluster Cluster has 2 master nodes: Master 0: ae6fc4a323b891776433048ee44fcf728a097097 172.31.10.170:6379 ERROR: ERR unknown command `CONFIG`, with args beginning with: `GET`, `save`, ERROR: failed to fetch CONFIG from 172.31.10.170:6379 WARN: could not fetch node CONFIG 172.31.10.170:6379 Master 1: c80783804e67afc9a25039fa26f77bb5773a5947 172.31.4.127:6379 ERROR: ERR unknown command `CONFIG`, with args beginning with: `GET`, `save`, ERROR: failed to fetch CONFIG from 172.31.4.127:6379 WARN: could not fetch node CONFIG 172.31.4.127:6379 PING_INLINE: 66357.00 requests per second, p50=0.559 msec PING_MBULK: 66401.06 requests per second, p50=0.543 msec SET: 15923.57 requests per second, p50=2.999 msec GET: 66445.18 requests per second, p50=0.551 msec INCR: 15931.18 requests per second, p50=2.991 msec LPUSH: 15951.51 requests per second, p50=2.999 msec RPUSH: 15943.88 requests per second, p50=2.983 msec LPOP: 15918.50 requests per second, p50=3.015 msec RPOP: 15941.34 requests per second, p50=2.991 msec SADD: 66313.00 requests per second, p50=0.551 msec HSET: 15938.79 requests per second, p50=3.007 msec SPOP: 66006.60 requests per second, p50=0.551 msec ZADD: 66401.06 requests per second, p50=0.551 msec ZPOPMIN: 66357.00 requests per second, p50=0.551 msec LPUSH (needed to benchmark LRANGE): 15948.96 requests per second, p50=2.991 msec LRANGE_100 (first 100 elements): 44228.22 requests per second, p50=0.719 msec LRANGE_300 (first 300 elements): 18018.02 requests per second, p50=1.431 msec LRANGE_500 (first 500 elements): 12402.33 requests per second, p50=2.063 msec LRANGE_600 (first 600 elements): 10734.22 requests per second, p50=2.375 msec MSET (10 keys): 14762.33 requests per second, p50=3.103 msec