Redis除了用作缓存存储之外的用途

该标题并不准确,并且以下的用途实际上也是利用了Redis的一部分特性。Redis主要被用作内存数据库来加快WEB应用程序的会话、令牌和RDB查询的缓存,然而通过使用数据类型和附属功能,还可以应用于生成排名和锁管理器等方面。

リアルタイムランキング

SortedSetの機能を使うことで、リアルタイムランキングを作ることができる。
スコア(点数)を伴ったレコードを挿入するだけで、バッチ等の集計処理を挟まなくとも自動的にソートされたランキングデータが生成される。

例えば以下のようなランキングを作りたいとすると

順位名前 (value)点数 (score)1smith50.02paul20.03john10.0

可以利用SortedSet的功能来创建以下这样的排名。

import redis

client = redis.Redis()

RANKING_NAME = 'TEST_RANK'

# ランキングデータを挿入
# zadd(key, value, score)
client.zadd(RANKING_NAME, 'john', 10.0)
client.zadd(RANKING_NAME, 'smith', 50.0)
client.zadd(RANKING_NAME, 'paul', 20.0)

# ランキングを降順で取得
# zrevrange(key, start, end)
client.zrevrange(RANKING_NAME, 0, -1)  # ['smith', 'paul', 'john']

# 新しいデータを挿入後も自動でソートされる
client.zadd(RANKING_NAME, 'george', 100.0)
client.zadd(RANKING_NAME, 'dave', 5.0)
client.zrevrange(RANKING_NAME, 0, -1)  # ['george', 'smith', 'paul', 'john', 'dave']

# 順位を取得
# zrevrank(key, value)
# 0スタートのインデックスが返るので、順位を表示するときは +1をする等
# 昇順はzrank(key, value)
client.zrevrank(RANKING_NAME, 'george')  # 0
client.zrevrank(RANKING_NAME, 'paul')  # 2

# 点数を取得
client.zscore(RANKING_NAME, 'paul')  # 20.0
client.zscore(RANKING_NAME, 'john')  # 10.0


※zrank/zrevrankで取得できる順位は昇降順に並び替えたリストの添字で、同点の順位を考慮出来ないので、アプリケーション側で適宜調整する必要があります。

分散ロック

setnxの機能を使ってリソースの排他制御を行える。
データベース内であればトランザクションが、アプリケーションサーバ内のプロセスであればmutexが排他制御に利用できるものの、サーバを跨いだプロセス間で制御を行うのは難しい。
Redisのsetnxには同じキーを登録できないという特性があり、登録に成功した場合は1を、失敗した場合は0を返すので、これをロックの獲得状態と見なしてリソースの排他制御に利用できる。

import redis

client = redis.Redis()

# 'LOCK_NAME'をキーに登録
client.setnx('LOCK_NAME', 'hoge')  # True
# 確認
client.get('LOCK_NAME')  # 'hoge'

# 同じキーで登録を試みると失敗する
client.setnx('LOCK_NAME', 'fuga')  # False

# 解放する場合はdelete
client.delete('LOCK_NAME')

如果不明确删除,锁将一直保持下去,所以如果成功注册,可以同时设置过期时间或在值中设置锁定时间,在下次引用时超过时间则删除。

发布订阅

可以通过Redis实现在1:n和n:n的客户端之间进行实时消息的发送和接收。
通过通道作为单位,在发布者(publisher)和订阅者(subscriber)之间进行消息交流。
订阅者可以兼作发布者,只要他们订阅了目标通道,发布者就可以向多个订阅者发送消息。
可用于简易聊天应用等。

发布者

import redis

client = redis.Redis()
# "test"チャネル に "hoge"メッセージ他を送信
client.publish('test', 'hoge')
client.publish('test', 'fuga')
client.publish('test', 'exit')

订阅者

client = redis.Redis()
pubsub = client.pubsub()
# "test"チャネルを購読
pubsub.subscribe('test')

for message in pubsub.listen():
    print message.get('data')
    if message.get('data') == 'exit':
        # 終了メッセージなら購読終了
        pubsub.unsubscribe()
广告
将在 10 秒后关闭
bannerAds