1. 安裝pyredis
首先安裝pip
1
2
3
4
5
6
7
8
|
<SHELL># apt-get install python-pip
......
<SHELL># pip install --proxy=http://172.1.2.6:8080 redis
Downloading redis-2.9.1.tar.gz (62kB): 62kB downloaded
Running setup.py (path:/tmp/pip_build_root/redis/setup.py) egg_info for package redis
......
Successfully installed redis
Cleaning up...
|
也可以使用easy_install的方式來安裝:
1
|
easy_install redis
|
或者直接編譯安裝:
1
2
3
4
|
wget https://pypi.python.org/packages/source/r/redis/redis-2.9.1.tar.gz
tar xvzf redis-2.9.1.tar.gz
cd redis-2.9.1
python setup.py install
|
2 . 簡單的redis操作
redis連接實例是線程安全的,可以直接將redis連接實例設置為一個全局變量,直接使用。如果需要另一個Redis實例(or Redis數據庫)時,就需要重新創建redis連接實例來獲取一個新的連接。同理,python的redis沒有實現select命令。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
>>> import redis
>>> r = redis.Redis(host='localhost',port=6379,db=0)
>>> r.set('guo','shuai')
True
>>> r.get('guo')
'shuai'
>>> r['guo']
'shuai'
>>> r.keys()
['guo']
>>> r.dbsize() #當前數據庫包含多少條數據
1L
>>> r.delete('guo')
1
>>> r.save() #執行“檢查點”操作,將數據寫回磁盤。保存時阻塞
True
>>> r.get('guo');
>>> r.flushdb() #清空r中的所有數據
True
|
3. pipeline操作
管道(pipeline)是redis在提供單個請求中緩沖多條服務器命令的基類的子類。它通過減少服務器-客戶端之間反復的TCP數據庫包,從而大大提高了執行批量命令的功能。
1
2
3
4
5
6
7
8
|
>>> p = r.pipeline() --創建一個管道
>>> p.set('hello','redis')
>>> p.sadd('faz','baz')
>>> p.incr('num')
>>> p.execute()
[True, 1, 1]
>>> r.get('hello')
'redis'
|
管道的命令可以寫在一起,如:
1
|
>>> p.set('hello','redis').sadd('faz','baz').incr('num').execute()
|
默認的情況下,管道里執行的命令可以保證執行的原子性,執行pipe = r.pipeline(transaction=False)可以禁用這一特性。
4. 應用場景 – 頁面點擊數
《Redis Cookbook》對這個經典場景進行詳細描述。假定我們對一系列頁面需要記錄點擊次數。例如論壇的每個帖子都要記錄點擊次數,而點擊次數比回帖的次數的多得多。如果使用關系數據庫來存儲點擊,可能存在大量的行級鎖爭用。所以,點擊數的增加使用redis的INCR命令最好不過了。
當redis服務器啟動時,可以從關系數據庫讀入點擊數的初始值(1237這個頁面被訪問了34634次)
1
2
|
>>> r.set("visit:1237:totals",34634)
True
|
每當有一個頁面點擊,則使用INCR增加點擊數即可。
1
2
3
4
|
>>> r.incr("visit:1237:totals")
34635
>>> r.incr("visit:1237:totals")
34636
|
頁面載入的時候則可直接獲取這個值
1
2
|
>>> r.get ("visit:1237:totals")
'34636'
|
5. 使用hash類型保存多樣化對象
當有大量類型文檔的對象,文檔的內容都不一樣時,(即“表”沒有固定的列),可以使用hash來表達。
1
2
3
4
5
6
7
8
9
10
11
12
|
>>> r.hset('users:jdoe', 'name', "John Doe")
1L
>>> r.hset('users:jdoe', 'email', 'John@test.com')
1L
>>> r.hset('users:jdoe', 'phone', '1555313940')
1L
>>> r.hincrby('users:jdoe', 'visits', 1)
1L
>>> r.hgetall('users:jdoe')
{'phone': '1555313940', 'name': 'John Doe', 'visits': '1', 'email': 'John@test.com'}
>>> r.hkeys('users:jdoe')
['name', 'email', 'phone', 'visits']
|
6. 應用場景 – 社交圈子數據
在社交網站中,每一個圈子(circle)都有自己的用戶群。通過圈子可以找到有共同特征(比如某一體育活動、游戲、電影等愛好者)的人。當一個用戶加入一個或幾個圈子后,系統可以向這個用戶推薦圈子中的人。
我們定義這樣兩個圈子,並加入一些圈子成員。
1
2
3
4
5
6
7
8
9
10
11
12
|
>>> r.sadd('circle:game:lol','user:debugo')
1
>>> r.sadd('circle:game:lol','user:leo')
1
>>> r.sadd('circle:game:lol','user:Guo')
1
>>> r.sadd('circle:soccer:InterMilan','user:Guo')
1
>>> r.sadd('circle:soccer:InterMilan','user:Levis')
1
>>> r.sadd('circle:soccer:InterMilan','user:leo')
1
|
#獲得某一圈子的成員
1
2
3
|
>>> r.smembers('circle:game:lol')
set(['user:Guo', 'user:debugo', 'user:leo'])
redis> smembers circle:jdoe:family
|
可以使用集合運算來得到幾個圈子的共同成員:
1
2
3
4
|
>>> r.sinter('circle:game:lol', 'circle:soccer:InterMilan')
set(['user:Guo', 'user:leo'])
>>> r.sunion('circle:game:lol', 'circle:soccer:InterMilan')
set(['user:Levis', 'user:Guo', 'user:debugo', 'user:leo'])
|
7. 應用場景 – 實時用戶統計
Counting Online Users with Redis介紹了這個方法。當我們需要在頁面上顯示當前的在線用戶時,就可以使用Redis來完成了。首先獲得當前時間(以Unix timestamps方式)除以60,可以基於這個值創建一個key。然后添加用戶到這個集合中。當超過你設定的最大的超時時間,則將這個集合設為過期;而當需要查詢當前在線用戶的時候,則將最后N分鍾的集合交集在一起即可。由於redis連接對象是線程安全的,所以可以直接使用一個全局變量來表示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import time
from redis import Redis
from datetime import datetime
ONLINE_LAST_MINUTES = 5
redis = Redis()
def mark_online(user_id): #將一個用戶標記為online
now = int(time.time()) #當前的UNIX時間戳
expires = now + (app.config['ONLINE_LAST_MINUTES'] * 60) + 10 #過期的UNIX時間戳
all_users_key = 'online-users/%d' % (now // 60) #集合名,包含分鍾信息
user_key = 'user-activity/%s' % user_id
p = redis.pipeline()
p.sadd(all_users_key, user_id) #將用戶id插入到包含分鍾信息的集合中
p.set(user_key, now) #記錄用戶的標記時間
p.expireat(all_users_key, expires) #設定集合的過期時間為UNIX的時間戳
p.expireat(user_key, expires)
p.execute()
def get_user_last_activity(user_id): #獲得用戶的最后活躍時間
last_active = redis.get('user-activity/%s' % user_id) #如果獲取不到,則返回None
if last_active is None:
return None
return datetime.utcfromtimestamp(int(last_active))
def get_online_users(): #獲得當前online用戶的列表
current = int(time.time()) // 60
minutes = xrange(app.config['ONLINE_LAST_MINUTES'])
return redis.sunion(['online-users/%d' % (current - x) #取ONLINE_LAST_MINUTES分鍾對應集合的交集
for x in minutes])
|