この記事は約2分で読めます。
この記事は1年以上前に書かれたものです。
内容が古い可能性がありますのでご注意ください。
はじめに
こんにちは、荒堀です。
ElastiCacheの公式のハンズオンがあります。今回はこれをAmazon ElastiCache Serverlessでやってみます。
このハンズオンは、RDSのデータをキャッシュするというシナリオになっています。 しかし少し試したいだけでRDSを作るのは大仰なので、今回はCloud9の中にSQLiteでデータベースを作ってそれを使います。
概要
- 利用するサービスは以下です
- Amazon ElastiCache Serverless
- AWS Cloud9
- この中にSQLiteでデータベースを作ります
- VPCは、デフォルトVPCを使います
- ElastiCacheにデフォルトのセキュリティグループを宛がうので、インバウンドルールを追加します
参考
やってみた
環境作成
以前の記事と同じ環境を作ります。
- Cloud9の起動
- ElastiCache Serverlessを作成
- セキュリティグループにインバウンドルールを追加
Cloud9にデータベース作成
ハンズオンでRDSに作成しているデータベースを、Cloud9上のSQLiteで作成します。
ディレクトリを作成し、seed.sql
で空のSQLファイルを作成します。
mkdir demo-elasticacheserverless && cd demo-elasticacheserverless touch seed.sql
seed.sql
に、テーブルを作成・データを登録するSQLを記述します。
CREATE TABLE planet (id integer primary key autoincrement,name VARCHAR(30));INSERT INTO planet (name) VALUES ("Mercury");INSERT INTO planet (name) VALUES ("Venus");INSERT INTO planet (name) VALUES ("Earth");INSERT INTO planet (name) VALUES ("Mars");INSERT INTO planet (name) VALUES ("Jupiter");INSERT INTO planet (name) VALUES ("Saturn");INSERT INTO planet (name) VALUES ("Uranus");INSERT INTO planet (name) VALUES ("Neptune");
SQLiteを実行し、SQLファイルを実行します。
sqlite3 tutorial.sqlite sqlite> .read seed.sql sqlite> SELECT * FROM planet;
Python実行
以下のサンプルコードを参考にしました。
redisをインストールして、Pythonを実行します。
pip install redis python
まずは必要なパッケージをインポートします。
import jsonimport redisimport sqlite3
データベースクラスを作ります。dict_factory
は、SQLiteの戻り値を辞書型にする関数です。指定しないとtuple型になり、Redisの.hmset
で扱えなくなります。
# 戻り値を辞書型にする関数def dict_factory(cursor, row):d = {}for idx,col in enumerate(cursor.description):d[col[0]] = row[idx]return d# SQLiteを扱うクラスclass DB:def __init__(self, dbname):self.sqlite = sqlite3.connect(dbname)self.sqlite.row_factory = dict_factorydef query(self, sql):cursor = self.sqlite.cursor()try:cursor.execute(sql)return cursor.fetchall()finally:cursor.close()def record(self, sql, values):cursor = self.sqlite.cursor()try:cursor.execute(sql, values)return cursor.fetchone()finally:cursor.close()
次に、SQLiteとElasticacheに接続します。
# Time to live for cached dataTTL = 10# Initialize the databaseDatabase = DB('tutorial.sqlite')# Initialize the cacheCache = redis.RedisCluster(host='xxx.cache.amazonaws.com'(ElastiCacheのエンドポイント), ssl=True, decode_responses=True)
redis.RedisCluster
にdecode_responses=True
は、.hgetall
の戻り値をバイト型にしないため指定します。
fetch関数を定義して試してみます。
def fetch(sql):"""Retrieve records from the cache, or else from the database."""res = Cache.get(sql)if res:print("キャッシュあり")return json.loads(res)print("キャッシュなし")res = Database.query(sql)Cache.setex(sql, TTL, json.dumps(res))return res
何回か実行してみます。
>>> print(fetch("SELECT * FROM planet")) キャッシュなし [{'id': 1, 'name': 'Mercury'}, {'id': 2, 'name': 'Venus'}, {'id': 3, 'name': 'Earth'}, {'id': 4, 'name': 'Mars'}, {'id': 5, 'name': 'Jupiter'}, {'id': 6, 'name': 'Saturn'}, {'id': 7, 'name': 'Uranus'}, {'id': 8, 'name': 'Neptune'}] >>> print(fetch("SELECT * FROM planet")) キャッシュあり [{'id': 1, 'name': 'Mercury'}, {'id': 2, 'name': 'Venus'}, {'id': 3, 'name': 'Earth'}, {'id': 4, 'name': 'Mars'}, {'id': 5, 'name': 'Jupiter'}, {'id': 6, 'name': 'Saturn'}, {'id': 7, 'name': 'Uranus'}, {'id': 8, 'name': 'Neptune'}] >>> print(fetch("SELECT * FROM planet")) キャッシュあり [{'id': 1, 'name': 'Mercury'}, {'id': 2, 'name': 'Venus'}, {'id': 3, 'name': 'Earth'}, {'id': 4, 'name': 'Mars'}, {'id': 5, 'name': 'Jupiter'}, {'id': 6, 'name': 'Saturn'}, {'id': 7, 'name': 'Uranus'}, {'id': 8, 'name': 'Neptune'}]
次はplanet関数を定義します。
def planet(id):"""Retrieve a record from the cache, or else from the database."""key = f"planet:{id}"res = Cache.hgetall(key)if res:print("キャッシュあり")return resprint("キャッシュなし")sql = "SELECT `id`, `name` FROM `planet` WHERE `id`=?"res = Database.record(sql, (id,))if res:Cache.hmset(key, res)Cache.expire(key, TTL)return res
何回か実行してみます。idが文字列型になってしまっているのは残念ですが、キャッシュに入っていることが確認できます。
>>> print(planet(3)) キャッシュなし {'id': 3, 'name': 'Earth'} >>> print(planet(3)) キャッシュあり {'name': 'Earth', 'id': '3'} >>> print(planet(3)) キャッシュあり {'name': 'Earth', 'id': '3'}
おわりに
実装されたAmazon ElastiCache Serverlessを、ハンズオンで使ってみました。 サーバレスでも元のElastiCacheでも、使用感は変わらないと感じました。すぐに起動する分、サーバレスの方がいいかもしれません。
この記事がどなたかのお役に立てれば幸いです。