AWS ElastiCache for Redis オンラインアプリケーション用の高速セッションストアを構築するチュートリアルをやってみた

# 初めに

以下のチュートリアルをやってみました。ElastiCache はセッションデータの保持や、DB 処理の高速化など資格勉強でよく見かけますので、実際に使ってみたいとずっと思っていました。ElastiCache の起動、キャッシュの追加・削除、TTL の設定を学ぶことができました。

https://aws.amazon.com/jp/getting-started/hands-on/building-fast-session-caching-with-amazon-elasticache-for-redis/

# 1. Redis クラスターを作成する

クラスターエンジンには「Redis」を選択し、ロケーションには「Amazon クラウド」を選択します。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/5f413090-2adc-fda7-bb29-6376688ec5ea.png)

以下のように設定します。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/a1a5f1c5-5bcc-069d-f2db-87b97fa241eb.png)

サブネットグループでは「新規作成」を選択します。VPC はデフォルトを選択しました。サブネットを2つ選択します。アベイラビリティゾーンの配置では「指定なし」にチェックを入れます。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/8bf29d7c-b0e1-9203-12ab-0b0640c8bc69.png)

なお、ゾーンの選択にチェックを入れると、プライマリとレプリカをどのアベイラビリティゾーンに配置するか選択することができます。今回は「指定なし」にチェックを入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/f8cc4cf1-6e4d-dca7-d462-9d1d18ce7247.png)

今回は動作検証が目的であるため、「自動バックアップの有効化」のチェックを外します。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/85336949-84ba-0a24-ce17-1f20b421f244.png)

「作成」をクリックします。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/756b0750-ec19-5768-e2ba-b679846866d3.png)

作成にしばらく時間がかかるので、この間に EC2 （Linux2、t2.micro）を起動します。

# EC2 から Redis を利用する

以下のコマンドを実行し、アプリケーションを構築します。`REDIS_URL` は以下のプライマリエンドポイントをコピーします。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/1fdfd24f-3f6f-6f25-52c4-444e5c6021cf.png)


```
sudo yum -y update
sudo yum -y install git
sudo pip3 install virtualenv
git clone https://github.com/aws-samples/amazon-elasticache-samples/
cd amazon-elasticache-samples/
virtualenv venv
source ./venv/bin/activate
cd session-store/
pip3 install -r requirements.txt
export FLASK_APP=example-1.py
export SECRET_KEY=test
export REDIS_URL="redis://elc-tutorial.mdb3zt.ng.0001.apne1.cache.amazonaws.com:6379"
```

Redis に接続できるか確認します。python の対話モードを開き、以下を実行します。True が返ってくれば接続できています。

```
>>> import redis
>>> client = redis.Redis.from_url('redis://elc-tutorial.mdb3zt.ng.0001.apne1.cache.amazonaws.com:6379')
>>> client.ping()
True
```

## サンプル 1

アプリケーションを開始します。

```
flask run -h 0.0.0.0 -p 5000 --reload
```

ブラウザを開き、`http://public-dns:5000` または `http://public-ip:5000` にアクセスします。

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/4835429a-0fe7-f4e3-cf4b-efa32f0a2834.png)

続いて `http://public-dns:5000/login` にアクセスします。

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/5c97a57d-3eb2-0bc4-803c-4b43a91750ba.png)

test-user-1 というユーザーでログインしました。

![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/4c3e749f-1ddf-f0bf-c067-ef5ba7d09505.png)

`http://public-dns:5000/logout` にアクセスしてログアウトします。以下のページにリダイレクトされ、ログアウトできたことが確認できました。

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/4835429a-0fe7-f4e3-cf4b-efa32f0a2834.png)

## サンプル 2

`Ctrl` + `C` でアプリケーションを停止し、2 つ目のサンプルを試してみます。以下のように環境変数を設定し直します。

```
export FLASK_APP=example-2.py
```

再度アプリケーションを開始します。

```
flask run -h 0.0.0.0 -p 5000 --reload
```

`http://public-dns:5000/login` にアクセスしログインすると、カウンターが表示されます。

![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/5b362b07-9d08-6e2a-fe36-72b45b23ff71.png)

ページを更新するたびに Visits が増加していくのが確認できます。これは以下の visits を `hincrby()` メソッドでインクリメントしているためです。

```example-2.py
# Connect to Redis with the REDIS_URL environment variable.
store = redis.Redis.from_url(os.environ.get('REDIS_URL'))

@app.route('/')
def index():
    if 'username' in session:
        username = escape(session['username'])
        # インクリメント
        visits = store.hincrby(username, 'visits', 1)

        return '''
            Logged in as {0}.<br>
            Visits: {1}
        '''.format(username, visits)

    return 'You are not logged in'
```

## サンプル 3

次に 3 つ目のサンプルを試してみます。

```
export FLASK_APP=example-3.py
flask run -h 0.0.0.0 -p 5000 --reload
```

TTL を 10 秒に設定することで、10 秒以上経過した後で更新すると Visits が 1 に戻ることが確認できます。該当ソースは以下の通りです。

```example-3.py
# Connect to Redis with the REDIS_URL environment variable.
store = redis.Redis.from_url(os.environ.get('REDIS_URL'))

@app.route('/')
def index():
    if 'username' in session:
        username = escape(session['username'])

        visits = store.hincrby(username, 'visits', 1)
        # TTL を 10 秒に設定
        store.expire(username, 10)

        return '''
            Logged in as {0}.<br>
            Visits: {1}
        '''.format(username, visits)

    return 'You are not logged in'
```

- 何回かページを更新する

![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/ceeff992-985f-65ec-4653-194bcaab7947.png)


- 10 秒以上待ってから再度更新する

![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/1fd75428-c714-4d92-1cf5-e46ab2a4818b.png)

# 参考記事

https://aws.amazon.com/jp/getting-started/hands-on/building-fast-session-caching-with-amazon-elasticache-for-redis/

https://flask.palletsprojects.com/en/1.0.x/