Redisの5つのデータ型と利用シナリオ
1. Redisの5つのデータ型
1.文字列型
a. 目的
- テキスト、数値などを含む文字列型データを保存します。
b. 共通コマンド
- SET キー値: キーと値のペアを設定します。
- GET key: 指定したキーの値を取得します。
- INCRキー:キーに対応する値に1を加算します。
- DECR キー: キーに対応する値を 1 減算します。
サンプルコード:
import redis
# 连接redis
r = redis.Redis(host='localhost', port=6379, db=0)
# 设置键值对
r.set('name', 'Lucy')
# 获取键对应的值
print(r.get('name'))
# 值加1
r.incr('age')
# 值减1
r.decr('age')
2. ハッシュの種類
a. 目的
- ユーザー情報など、対応関係のあるデータを保存します。
b. 共通コマンド
- HSETキーフィールド値: ハッシュ型データのフィールドの値を設定します
- HGETキーフィールド:ハッシュ型データのフィールドの値を取得します
- HGETALLキー:ハッシュ型データのすべてのフィールドと値を取得
サンプルコード:
import redis
# 连接redis
r = redis.Redis(host='localhost', port=6379, db=0)
# 设置哈希类型数据
r.hset('user', 'name', 'Lucy')
r.hset('user', 'age', 18)
# 获取哈希类型数据中某个域的值
print(r.hget('user', 'name'))
# 获取哈希类型数据中所有域和值
print(r.hgetall('user'))
3. リスト型
a. 目的
- メッセージ キューやタスク リストなどのシナリオを実装するために使用できる、順序付けされた文字列型データのセットを格納します。
b. 共通コマンド
- LPUSH キー値: リストの左側から値を挿入します。
- RPUSH キーの値: リストの右側から値を挿入します。
- LPOP キー: リストの左側から値をポップします。
- RPOP キー: リストの右側から値をポップします。
サンプルコード:
import redis
# 连接redis
r = redis.Redis(host='localhost', port=6379, db=0)
# 向列表左侧插入两个值
r.lpush('task', 'task1')
r.lpush('task', 'task2')
# 向列表右侧插入一个值
r.rpush('task', 'task3')
# 从列表左侧弹出一个值
print(r.lpop('task'))
# 从列表右侧弹出一个值
print(r.rpop('task'))
4. コレクションの種類
a. 目的
- 順序付けされていない文字列型データのセットを保存します。これは、重複を排除し、セット内に要素が存在するかどうかを迅速に判断するためによく使用されます。
b. 共通コマンド
- SADD キー メンバー: コレクションに要素を追加します。
- SMEMBERS キー: コレクション内のすべての要素を取得します
- SISMEMBER キー メンバー: 要素がコレクション内に存在するかどうかを判断します。
サンプルコード:
import redis
# 连接redis
r = redis.Redis(host='localhost', port=6379, db=0)
# 向集合中添加两个元素
r.sadd('students', 'Lucy', 'Jack')
# 获取集合中所有元素
print(r.smembers('students'))
# 判断某元素是否存在集合中
print(r.sismember('students', 'Lucy'))
5. 順序付きコレクション型
a. 目的
- 順序付けされた文字列データのセットを保存します。各要素には対応するスコアがあり、リーダーボードなどのシナリオで使用できます。
b. 共通コマンド
- ZADD キー スコア メンバー: 要素とスコアを順序付きセットに追加します。
- ZRANGEBYSCORE key min max: スコアが指定された間隔内にあるソートされたセット内のすべての要素を返します。
- ZREVRANGE キー start stop [WITHSCORES]: スコアの大きいものから小さいものまでソートされたソート セット内の要素の一部を返します。同時にスコアを返すことも選択できます
サンプルコード:
import redis
# 连接redis
r = redis.Redis(host='localhost', port=6379, db=0)
# 向有序集合中添加三个元素和分数
r.zadd('score', {
'Lucy': 90, 'Jack': 85, 'Mike': 92})
# 返回有序集合中分数在给定区间内的所有元素
print(r.zrangebyscore('score', min=85, max=92))
# 返回有序集合中按照分数从大到小排序的一部分元素,并返回分数
print(r.zrevrange('score', start=0, stop=1, withscores=True))
2. Redis の使用シナリオ
Redis は効率的なキーと値のペアのデータベースであり、その高速性、豊富なデータ型のサポート、および柔軟な構成により、次の 5 つのシナリオで広く使用されています。
1. キャッシュシステム
Redisはよく使うデータをメモリ上に保存し、有効期限を設定することでキャッシュ機能を実現します。アプリケーションがデータを必要とする場合、Redis から直接データを取得できるため、ディスクからデータを読み取る IO 操作が回避され、システムの応答時間とスループットが向上します。
# 以字符串类型为例,在 Python 中使用 Redis 实现缓存功能的示例代码
import redis
# 创建 Redis 客户端
redis_client = redis.Redis(host='localhost', port=6379, db=0)
def get_data_from_cache(key):
"""
从 Redis 的缓存中获取数据
"""
data = redis_client.get(key)
if data is not None:
# 如果缓存中存在对应 key 的数据,则直接返回
return data
# 如果缓存中不存在对应 key 的数据,则去数据库中查询并写入缓存
data = fetch_data_from_database(key)
redis_client.set(key, data, ex=3600) # 设置过期时间为 1 小时
return data
2. カウンター
Redis の incr/decr コマンドは、キーに対してアトミックな増分/減分操作を実行できるため、カウンターとしてよく使用されます。たとえば、Web サイトの訪問数、商品の売上、コメントの「いいね!」の数などを数えます。
# 在 Python 中使用 Redis 的 incr/decr 实现计数器功能的示例代码
def increase_counter(key):
"""
自增一个计数器,返回自增后的值
"""
return redis_client.incr(key)
def decrease_counter(key):
"""
自减一个计数器,返回自减后的值
"""
return redis_client.decr(key)
3. メッセージキュー
Redis は、軽量のメッセージ ミドルウェアとして使用できるメッセージ キュー機能を提供し、複数のプロデューサーとコンシューマーをサポートします。プロデューサは lpush または rpush を使用してメッセージをリストに挿入できますが、コンシューマは blpop または brpop を使用してリストからメッセージをポップして処理します。
# 在 Python 中使用 Redis 实现消息队列功能的示例代码
import threading
import time
def produce_message(queue_name: str):
"""
生产者向队列中插入消息
"""
for i in range(10):
message = f"Message {i}"
redis_client.lpush(queue_name, message) # 左边插入消息
print(f"Produce Message: {message}")
time.sleep(0.5)
def consume_message(queue_name: str):
"""
消费者从队列中弹出消息并进行处理
"""
while True:
message = redis_client.brpop(queue_name, timeout=3) # 从右边弹出消息
if message is not None:
print(f"Consume Message: {message[1].decode()}")
# 创建生产者和消费者线程
t1 = threading.Thread(target=produce_message, args=('my_queue',))
t2 = threading.Thread(target=consume_message, args=('my_queue',))
# 启动线程
t1.start()
t2.start()
# 等待线程结束
t1.join()
t2.join()
4. リーダーボードシステム
Redis は、特定のフィールドに応じたメンバーの並べ替えをサポートする順序付きセット (SortedSet) 構造を提供するため、リーダーボード システムの実装に使用できます。たとえば、音楽の再生回数、ニュースの閲覧量、ユーザーのランキングなどをカウントします。
# 在 Python 中使用 Redis 实现排行榜系统的示例代码
def update_ranking(username: str, score: float):
"""
更新排行榜,以 username 为成员、score 为排序指标
"""
redis_client.zadd('ranking', {
username: score})
def get_top_n(n: int):
"""
获取排行榜前 n 名
"""
return redis_client.zrevrangebyscore('ranking', '+inf', '-inf', start=0, num=n, withscores=True)
5. 分散ロック
Redis の setnx コマンドは、キーが存在しない場合にキーの値を設定できるため、これをベースに分散ロックを実装できます。プロセスがロック操作を実行するとき、最初に setnx を使用してロックのキーを占有しようとします。戻り値が 1 の場合は、ロックが取得されたことを意味します。それ以外の場合は、ロックが他のキーによって占有されていることを意味します。しばらく待ってから再試行してください。ロック操作とロック解除操作を成功させるには、同じキーと値を使用する必要があります。
# 在 Python 中使用 Redis 实现分布式锁的示例代码
def acquire_lock_with_timeout(lockname: str, acquire_timeout: int=10):
"""
获取分布式锁,等待 acquire_timeout 秒后仍未获得锁则放弃
"""
identifier = str(uuid.uuid4())
end = time.time() + acquire_timeout
while time.time() < end:
if redis_client.setnx(lockname, identifier):
# 成功获取到锁
return identifier
elif not redis_client.ttl(lockname):
# 如果锁没有设置过期时间,则设置一个过期时间,避免死锁
redis_client.expire(lockname, 10)
# 等待一段时间后进行重试
time.sleep(0.1)
return False
def release_lock(lockname: str, identifier: str):
"""
释放分布式锁,需要传入获取锁时返回的 identifier
"""
pipline = redis_client.pipeline(True)
while True:
try:
# 监视锁,保证在执行事务期间锁没有被其他进程修改
pipline.watch(lockname)
if pipline.get(lockname).decode() == identifier:
# 删除锁
pipline.multi()
pipline.delete(lockname)
pipline.execute()
return True
# 锁已被其他进程修改,放弃执行事务
pipline.unwatch()
except redis.exceptions.WatchError:
# 如果在执行pipline.watch()和pipline.multi()之间,锁的值被其他进程改变,会抛出 WatchError 异常
continue
finally:
pipline.reset()
return False