現在のテクノロジー時代において、データはますます貴重な商品となりつつあり、このためデータの保存とアクセスの最適化が必要となっている。
MySQLやPostgreSQLなどのリレーショナルデータベース管理システム(RDBMS)は、行と列、およびデータ内の関係を使用して構造化された形式でデータを格納します。
RDBMSとは別に、辞書のように一意のキーと値に基づいてデータを保存するキーバリューストアがある。
キーバリューデータベースは、RDBMSのリレーショナルな性質に適合しないNoSQL系列のデータベースに該当します。
この記事では、キーバリューストアとしてのRedisを調査し、プロジェクトで使用してその機能を探っていきます。
Redisとは何か、なぜ使うのか?
Redis (REmote DIctionary Server) は、データベース、キャッシュ、メッセージブローカーとして利用できるインメモリデータ構造ストアです。
データはキーバリューの形でRedisに保存され、キーはRedisインスタンスに保存されているデータの場所を特定し、抽出するために使用されます。
通常のデータベースはデータをディスクに保存するため、時間やハードウェアリソースの面で余分なコストがかかります。
Redisはすべてのデータをメモリに保存することでこれを回避し、通常のデータベースと比較してデータを容易に利用できるようにし、データアクセスや操作の速度を向上させます。
これが、Redisが卓越したハイパフォーマンス能力を持つことで知られる理由です。
Redisでは、文字列、ハッシュ、リスト、セット、ソートされたセットなど、複数の高レベルなデータ構造でデータを保存することができます。
このため、Redisデータストアに格納できる情報の種類と量に柔軟性があります。
RedisはANSI Cで書かれているため、軽量で外部依存がない。
また、Python、JavaScript、Java、C/C++、PHPなど、ほとんどの高級言語をサポートしているため、開発者にとっても非常に使い勝手が良い。
Redisはいつ使うべき?
Redisの一般的なユースケースは以下の通りです。
- キャッシュ:従来のデータベースに比べ、読み取りと書き込みの速度が速いため、Redisはデータをキャッシュに一時的に保存し、将来のデータアクセスを高速化するための理想的なソリューションとなっています。
- メッセージキューイング メッセージキューイング:Publish/Subscribeメッセージングパラダイムを実装できるため、Redisはメッセージキューイングシステムのメッセージブローカーとして機能します。
- データストレージ。データストレージ:Redisは、NoSQLデータベースとしてKey-Valueデータを保存するために使用することができます。
Twitter、Pinterest、Github、Snapchat、StackOverflowなどの企業はすべて、Redisを利用してデータを保存し、ユーザーが高度に利用できるようにします。
例えば、Twitterでは、クライアントアプリケーションへのツイートの配信を高速化するために、あるユーザーの最新の受信ツイートをRedisに保存しています。
PinterestはRedisを利用して、ユーザーがフォローしているユーザーとボードのリスト、ユーザーのフォロワーのリスト、自分のボードをフォローしている人のリストなどを保存し、プラットフォームでのエクスペリエンスを高めています。
Redisのインストール
Redis をさらに詳しく調べるには、公式ウェブページの説明に従って Redis サーバをダウンロードし、インストールする必要があります。
RedisはDocker HubでDockerイメージとして利用することもできます。
また、Redis-CLIツールも同梱されており、Redisサーバーのデータを操作するために使用することができます。
RedisはHomebrew(MacOS用)、Debian LinuxおよびUbuntuなどのその亜種のデフォルトaptリポジトリからインストールすることも可能です。
MacOSにRedisをインストールするには、以下を実行するだけです。
$ brew install redis
Debian Linuxの場合。
$ sudo apt-get install redis-server
Redisのインストールを確認するには、redis-cli
コマンドを実行し、表示されたプロンプトでping
と入力してください。
$ redis-cli -v
redis-cli 5.0.6
$ redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379>
PONG`と表示され、Redisサーバーの準備ができたことがわかります。
Redisコマンド
RedisはRedis-CLIを通じて、Redisサーバーと対話し、そこに保存されているデータを操作するために使用できる便利なコマンドをいくつか提供しています。
デフォルトでは、Redisサーバーはポート6379で実行され、これはプロンプトに表示されます。
Redis-CLIプロンプトで利用できるコマンドは以下の通りです。
- SET
: このコマンドはキーとその値を設定するために使用します。オプションでキーと値のエントリの有効期限を指定するパラメータを追加できます。ここでは、キー
helloに値として
world` を設定し、有効期限を10秒に設定してみましょう。
127.0.0.1:6379> SET hello "world" EX 10
OK
-
-
GET
: このコマンドは、キーに関連づけられた値を取得するために使用します。キーと値のエントリーが有効期限を過ぎている場合、nil
が返されます。
-
127.0.0.1:6379> GET hello
“world”
# After expiry
127.0.0.1:6379> GET hello
(nil)
-
-
DELETE
: このコマンドはキーとそれに関連する値を削除します。
-
127.0.0.1:6379> DEL hello
(integer) 1
- TTL
: TTL
: キーに有効期限が設定されている場合、このコマンドで残り時間を確認することができます。
127.0.0.1:6379> SET foo "bar" EX 100 # 100 is the number of seconds
OK
127.0.0.1:6379> TTL foo
(integer) 97 # Number of seconds remaining till expiry
127.0.0.1:6379> TTL foo
(integer) 95
127.0.0.1:6379> TTL foo
(integer) 93
- PERSIST
: PERSIST
: もし鍵の有効期限について気が変わったら、このコマンドを使って有効期限を削除することができます。
127.0.0.1:6379> PERSIST foo
(integer) 1
127.0.0.1:6379> TTL foo
(integer) -1
127.0.0.1:6379> GET foo
"bar"
- RENAME`: このコマンドはRedisサーバーの鍵の名前を変更するために使用します。
127.0.0.1:6379> RENAME foo foo2
OK
127.0.0.1:6379> GET foo
(nil)
127.0.0.1:6379> GET foo2
"bar"
- FLUSHALL`: このコマンドは、現在のセッションで設定したすべての key-value エントリをパージするために使用されます。
127.0.0.1:6379> RENAME foo foo2
OK
127.0.0.1:6379> GET foo
(nil)
127.0.0.1:6379> GET foo2
(nil)
127.0.0.1:6379> GET hello
(nil)
これらのコマンドやその他のRedisコマンドの詳細については、公式ウェブサイトを参照してください。
DjangoでRedisを使う
Redis を Web アプリケーションに統合する方法を示すために、Django と Django REST を使って、 key-value ペアを受け取り、それを Redis サーバに保存できる API を構築します。
この API は、与えられたキーの値を取得したり、保存されている全ての Key-value ペアを取得したり、Key-Value エントリを削除したりすることもできるようにします。
まず、プロジェクトを格納するためのフォルダを作成することから始めましょう。
$ mkdir redis_demo && cd $_
そして、仮想環境を作成し、それを有効にしましょう。
$ virtualenv --python=python3 env --no-site-packages
$ source env/bin/activate
そして最後に、必要なライブラリをインストールしましょう。
$ pip install django djangorestframework redis
このアプリケーションのAPIは、Redis-pyライブラリを使用してリクエストを受け取り、Redisサーバーと対話します。
それでは、アプリを作成してみましょう。
# Create the project
$ django-admin startproject django_redis_demo
$ cd django_redis_demo
# Create the app
$ django-admin startapp api
# Migrate
$ python manage.py migrate
Django のセットアップが成功したことを確認するために、サーバを起動します。
$ python manage.py runserver
http:127.0.0.1:8000` にナビゲートすると、次のように表示されます。
次のステップでは、 django_redis_demo/settings.py
にある INSTALLED_APPS
リストを更新することで、 api
アプリケーションと Django REST をプロジェクトに追加していきます。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Add these two
'rest_framework',
'api',
]
Redis-pyは、対話するために Redis の実行中のインスタンスを必要とします。
この設定はdjango_redis_demo/settings.py` に追加して行う必要があります。
REDIS_HOST = 'localhost'
REDIS_PORT = 6379
この設定により、DockerコンテナやリモートのRedisインスタンスを使用することができます。
ただし、この場合、認証情報を提供する必要があります。
ここでは、設定したローカルのRedisインスタンスを使用することにします。
次に、API にアクセスするために使用するルートを作成し、メインの Django アプリケーションにリンクします。
まず、空の api/urls.py
ファイルを作成し、次に django_redis_demo/urls.py
にパスを作成します。
# Modify this import
from django.urls import path, include
urlpatterns = [
...
# Add this entry
path('api/', include('api.urls')),
]
api/エンドポイントから入ってくる全てのリクエストは、
api` アプリケーションで処理されます。
今不足しているのは、リクエストを処理するためのビューです。
ビューはシンプルな関数ベースのビューで、Redisサーバーと対話できるようにします。
まず、api/urls.py
で対話するためのURLを作成します。
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from .views import manage_items, manage_item
urlpatterns = {
path('', manage_items, name="items"),
path('<slug:key', manage_item, name="single_item")
}
urlpatterns = format_suffix_patterns(urlpatterns)
最初のパスでは、エントリーの作成と全エントリーの表示を行い、2番目のパスでは、単一エントリーの詳細な管理を行います。
2つの関数ベースのビューを用意します。
manage_items()と
manage_item()はリクエストを処理し、Redis インスタンスと対話します。
これらはどちらもapi/views.py` ファイルに格納されます。
コードをより良く説明するために、より簡潔なチャンクに分割して説明します。
もし完全なコードを見たい場合は、この記事の最後にソースコードのあるGitHubのレポへのリンクがあります。
まずは必要なライブラリをインポートして、Redisインスタンスに接続するところから始めましょう。
import json
from django.conf import settings
import redis
from rest_framework.decorators import api_view
from rest_framework import status
from rest_framework.response import Response
# Connect to our Redis instance
redis_instance = redis.StrictRedis(host=settings.REDIS_HOST,
port=settings.REDIS_PORT, db=0)
ここでは、django_redis_demo/settings.py
で設定した Redis のホストとポートを渡して、接続オブジェクトを作成します。
それから、最初のビュー manage_items()
を作成します。
このビューは、実行中の Redis インスタンスに現在設定されている全てのアイテムを取得するために使用されます。
このビューでは、JSON オブジェクトを渡すことで Redis インスタンスに新しいエントリを作成することもできます。
@api_view(['GET', 'POST'])
def manage_items(request, *args, **kwargs):
if request.method == 'GET':
items = {}
count = 0
for key in redis_instance.keys("*"):
items[key.decode("utf-8")] = redis_instance.get(key)
count += 1
response = {
'count': count,
'msg': f"Found {count} items.",
'items': items
}
return Response(response, status=200)
elif request.method == 'POST':
item = json.loads(request.body)
key = list(item.keys())[0]
value = item[key]
redis_instance.set(key, value)
response = {
'msg': f"{key} successfully set to {value}"
}
return Response(response, 201)
次に、manage_item()
を定義します。
@api_view(['GET', 'PUT', 'DELETE'])
def manage_item(request, *args, **kwargs):
if request.method == 'GET':
if kwargs['key']:
value = redis_instance.get(kwargs['key'])
if value:
response = {
'key': kwargs['key'],
'value': value,
'msg': 'success'
}
return Response(response, status=200)
else:
response = {
'key': kwargs['key'],
'value': None,
'msg': 'Not found'
}
return Response(response, status=404)
elif request.method == 'PUT':
if kwargs['key']:
request_data = json.loads(request.body)
new_value = request_data['new_value']
value = redis_instance.get(kwargs['key'])
if value:
redis_instance.set(kwargs['key'], new_value)
response = {
'key': kwargs['key'],
'value': value,
'msg': f"Successfully updated {kwargs['key']}"
}
return Response(response, status=200)
else:
response = {
'key': kwargs['key'],
'value': None,
'msg': 'Not found'
}
return Response(response, status=404)
elif request.method == 'DELETE':
if kwargs['key']:
result = redis_instance.delete(kwargs['key'])
if result == 1:
response = {
'msg': f"{kwargs['key']} successfully deleted"
}
return Response(response, status=404)
else:
response = {
'key': kwargs['key'],
'value': None,
'msg': 'Not found'
}
return Response(response, status=404)
manage_item()` は Redis インスタンス内の個々のエントリにアクセスできるようにします。
このビューでは、呼び出し元が必要なアイテムのキーを URL で渡す必要があります。
このキーは、私たちのインスタンスに保存されている値を見つけるために使用されます。
HTTPメソッド PUT
を使用して、キーの新しい値を渡すことで、キーの値を更新することができます。
DELETE` メソッドを使用すると、Redis インスタンスからキーと値のペアを削除することができます。
このAPIを実際に使ってみるために、Postmanを使ってみましょう。
しかし、その前に redis-cli
ツールを使ってエントリを1つ2つ作成してみよう。
$ redis-cli
127.0.0.1:6379> SET HELLO "WORLD"
OK
127.0.0.1:6379> SET REDIS "DEMO"
OK
データを設定したら、localhost:8000/api/items
に GET リクエストを送信してみましょう。
このAPIは、現在のRedisインスタンスにあるすべてのKey-Valueペアを取得することができます。
次に、同じURLに以下のペイロードを持つPOSTリクエストを送信してみましょう。
{
"mighty": "mug"
}
同じエンドポイントに別の GET リクエストを送信してみましょう。
APIで作成したキーがRedisインスタンスに保存されていることがわかります。
CLIツールを使って、その存在を確認することができます。
では、http://localhost:8000/api/items/HELLO
にGETリクエストを送って、単一のキーの値を返す2番目のエンドポイントをテストしてみましょう。
うまくいきましたね。
今度は、同じエンドポイントにPUTリクエストで次のJSONを送信して、HELLO
キーに関連付けられた値を更新してみましょう。
{
"new_value": "stackabuse.com"
}
再び HELLO
キーを取得すると、次のようになります。
値は正常に更新されました。
最後に残っているのはキーの削除です。
先ほど更新したキーを削除するために、http://localhost:8000/api/items/HELLO
に対して DELETE
リクエストを送信してみましょう。
削除した後に同じアイテムにアクセスしようとすると、以下のようになります。
キーが削除されたことが通知されます。
Django API は Redis-py
ライブラリを使用して、Redis インスタンスと正常に接続されました。
結論
Redisは強力で高速なデータストレージであり、適切な状況で使用すれば、多くのメリットをもたらすことができます。
また、便利なCLIツールが付属しており、シンプルで直感的なコマンドで操作することができます。
私たちは Django API をローカルで動作する Redis インスタンスとシームレスに統合することができましたが、これは一般的な高レベルプログラミング言語での使いやすさを証明するものです。
このプロジェクトのスクリプトのソースコードは、GitHub のここで見ることができます。
を参照してください。