redis緩存數據庫

本節內容

緩存數據庫介紹

redis操作

 

 

緩存數據庫介紹

 NoSQL(NoSQL = Not Only SQL ),意即“不僅僅是SQL”,泛指非關係型的數據庫,隨着互聯網web2.0網站的興起,傳統的關係數據庫在應付web2.0網站,特別是超大規模和高併發的SNS類型的web2.0純動態網站已經顯得力不從心,暴露了很多難以克服的問題,而非關係型的數據庫則由於其本身的特點得到了非常迅速的發展。NoSQL數據庫的產生就是爲了解決大規模數據集合多重數據種類帶來的挑戰,尤其是大數據應用難題。

NoSQL數據庫的四大分類

鍵值(Key-Value)存儲數據庫

這一類數據庫主要會使用到一個哈希表,這個表中有一個特定的鍵和一個指針指向特定的數據。Key/value模型對於IT系統來說的優勢在於簡單、易部署。但是如果DBA只對部分值進行查詢或更新的時候,Key/value就顯得效率低下了。[3]  舉例如:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB.
 
列存儲數據庫。
這部分數據庫通常是用來應對分佈式存儲的海量數據。鍵仍然存在,但是它們的特點是指向了多個列。這些列是由列家族來安排的。如:Cassandra, HBase, Riak.
 
文檔型數據庫
文檔型數據庫的靈感是來自於Lotus Notes辦公軟件的,而且它同第一種鍵值存儲相類似。該類型的數據模型是版本化的文檔,半結構化的文檔以特定的格式存儲,比如JSON。文檔型數據庫可 以看作是鍵值數據庫的升級版,允許之間嵌套鍵值。而且文檔型數據庫比鍵值數據庫的查詢效率更高。如:CouchDB, MongoDb. 國內也有文檔型數據庫SequoiaDB,已經開源。
 
圖形(Graph)數據庫
圖形結構的數據庫同其他行列以及剛性結構的SQL數據庫不同,它是使用靈活的圖形模型,並且能夠擴展到多個服務器上。NoSQL數據庫沒有標準的查詢語言(SQL),因此進行數據庫查詢需要制定數據模型。許多NoSQL數據庫都有REST式的數據接口或者查詢API。[2]  如:Neo4J, InfoGrid, Infinite Graph.
因此,我們總結NoSQL數據庫在以下的這幾種情況下比較適用:1、數據模型比較簡單;2、需要靈活性更強的IT系統;3、對數據庫性能要求較高;4、不需要高度的數據一致性;5、對於給定key,比較容易映射覆雜值的環境。
 

NoSQL數據庫的四大分類表格分析

分類Examples舉例典型應用場景數據模型優點缺點
鍵值(key-value)[3]  Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB 內容緩存,主要用於處理大量數據的高訪問負載,也用於一些日誌系統等等。[3]  Key 指向 Value 的鍵值對,通常用hash table來實現[3]  查找速度快 數據無結構化,通常只被當作字符串或者二進制數據[3] 
列存儲數據庫[3]  Cassandra, HBase, Riak 分佈式的文件系統 以列簇式存儲,將同一列數據存在一起 查找速度快,可擴展性強,更容易進行分佈式擴展 功能相對侷限
文檔型數據庫[3]  CouchDB, MongoDb Web應用(與Key-Value類似,Value是結構化的,不同的是數據庫能夠了解Value的內容) Key-Value對應的鍵值對,Value爲結構化數據 數據結構要求不嚴格,表結構可變,不需要像關係型數據庫一樣需要預先定義表結構 查詢性能不高,而且缺乏統一的查詢語法。
圖形(Graph)數據庫[3]  Neo4J, InfoGrid, Infinite Graph 社交網絡,推薦系統等。專注於構建關係圖譜 圖結構 利用圖結構相關算法。比如最短路徑尋址,N度關係查找等 很多時候需要對整個圖做計算才能得出需要的信息,而且這種結構不太好做分佈式的集羣方案。[3] 

 

 

 

redis

介紹

redis是業界主流的key-value nosql 數據庫之一。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支持各種不同方式的排序。與memcached一樣,爲了保證效率,數據都是緩存在內存中。區別的是redis會週期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,並且在此基礎上實現了master-slave(主從)同步。

Redis優點

  • 異常快速 : Redis是非常快的,每秒可以執行大約110000設置操作,81000個/每秒的讀取操作。

  • 支持豐富的數據類型 : Redis支持最大多數開發人員已經知道如列表,集合,可排序集合,哈希等數據類型。

    這使得在應用中很容易解決的各種問題,因爲我們知道哪些問題處理使用哪種數據類型更好解決。
  • 操作都是原子的 : 所有 Redis 的操作都是原子,從而確保當兩個客戶同時訪問 Redis 服務器得到的是更新後的值(最新值)。

  • MultiUtility工具:Redis是一個多功能實用工具,可以在很多如:緩存,消息傳遞隊列中使用(Redis原生支持發佈/訂閱),在應用程序中,如:Web應用程序會話,網站頁面點擊數等任何短暫的數據;

安裝Redis環境

要在 Ubuntu 上安裝 Redis,打開終端,然後輸入以下命令:
$sudo apt-get update
$sudo apt-get install redis-server
這將在您的計算機上安裝Redis

啓動 Redis

$redis-server

查看 redis 是否還在運行

$redis-cli
這將打開一個 Redis 提示符,如下圖所示:
redis 127.0.0.1:6379>
在上面的提示信息中:127.0.0.1 是本機的IP地址,6379是 Redis 服務器運行的端口。現在輸入 PING 命令,如下圖所示:
redis 127.0.0.1:6379> ping
PONG
這說明現在你已經成功地在計算機上安裝了 Redis。
 

Python操作Redis

1
2
3
4
5
6
7
sudo pip install redis
or
sudo easy_install redis
or
源碼安裝
  
詳見:https://github.com/WoLpH/redis-py

  

在Ubuntu上安裝Redis桌面管理器

要在Ubuntu 上安裝 Redis桌面管理,可以從 http://redisdesktop.com/download 下載包並安裝它。

Redis 桌面管理器會給你用戶界面來管理 Redis 鍵和數據。
 
 

Redis API使用

redis-py 的API的使用可以分類爲:

  • 連接方式
  • 連接池
  • 操作
    • String 操作
    • Hash 操作
    • List 操作
    • Set 操作
    • Sort Set 操作
  • 管道
  • 發佈訂閱

 

連接方式

1、操作模式

redis-py提供兩個類Redis和StrictRedis用於實現Redis的命令,StrictRedis用於實現大部分官方的命令,並使用官方的語法和命令,Redis是StrictRedis的子類,用於向後兼容舊版本的redis-py。

1
2
3
4
5
import redis
  
= redis.Redis(host='10.211.55.4', port=6379)
r.set('foo''Bar')
print r.get('foo')

 

2、連接池

redis-py使用connection pool來管理對一個redis server的所有連接,避免每次建立、釋放連接的開銷。默認,每個Redis實例都會維護一個自己的連接池。可以直接建立一個連接池,然後作爲參數Redis,這樣就可以實現多個Redis實例共享一個連接池。

 

操作

 

1. String操作

redis中的String在在內存中按照一個name對應一個value來存儲。如圖:

set(name, value, ex=None, px=None, nx=False, xx=False)

1
2
3
4
5
6
在Redis中設置值,默認,不存在則創建,存在則修改
參數:
     ex,過期時間(秒)
     px,過期時間(毫秒)
     nx,如果設置爲True,則只有name不存在時,當前set操作才執行
     xx,如果設置爲True,則只有name存在時,崗前set操作才執行

setnx(name, value)

1
設置值,只有name不存在時,執行設置操作(添加)

setex(name, value, time)

1
2
3
# 設置值
# 參數:
    # time,過期時間(數字秒 或 timedelta對象)

 

 

psetex(name, time_ms, value)

1
2
3
# 設置值
# 參數:
    # time_ms,過期時間(數字毫秒 或 timedelta對象)

mset(*args, **kwargs)

1
2
3
4
5
批量設置值
如:
    mset(k1='v1', k2='v2')
    
    mget({'k1''v1''k2''v2'})

get(name)

1
獲取值

mget(keys, *args)

1
2
3
4
5
批量獲取
如:
    mget('ylr''wupeiqi')
    
    r.mget(['ylr''wupeiqi'])

getset(name, value)

1
設置新值並獲取原來的值

getrange(key, start, end)

1
2
3
4
5
6
# 獲取子序列(根據字節獲取,非字符)
# 參數:
    # name,Redis 的 name
    # start,起始位置(字節)
    # end,結束位置(字節)
# 如: "武沛齊" ,0-3表示 "武"

setrange(name, offset, value)

1
2
3
4
# 修改字符串內容,從指定字符串索引開始向後替換(新值太長時,則向後添加)
# 參數:
    # offset,字符串的索引,字節(一個漢字三個字節)
    # value,要設置的值

setbit(name, offset, value)

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
# 對name對應值的二進制表示的位進行操作
 
# 參數:
    # name,redis的name
    # offset,位的索引(將值變換成二進制後再進行索引)
    # value,值只能是 1 或 0
 
# 注:如果在Redis中有一個對應: n1 = "foo",
        那麼字符串foo的二進制表示爲:01100110 01101111 01101111
    所以,如果執行 setbit('n1'71),則就會將第7位設置爲1
        那麼最終二進制則變成 01100111 01101111 01101111,即:"goo"
 
# 擴展,轉換二進制表示:
 
    # source = "武沛齊"
    source = "foo"
 
    for in source:
        num = ord(i)
        print bin(num).replace('b','')
 
    特別的,如果source是漢字 "武沛齊"怎麼辦?
    答:對於utf-8,每一個漢字佔 3 個字節,那麼 "武沛齊" 則有 9個字節
       對於漢字,for循環時候會按照 字節 迭代,那麼在迭代時,將每一個字節轉換 十進制數,然後再將十進制數轉換成二進制
        11100110 10101101 10100110 11100110 10110010 10011011 11101001 10111101 10010000
        -------------------------- ----------------------------- -----------------------------
                    武                         沛                           齊

*用途舉例,用最省空間的方式,存儲在線用戶數及分別是哪些用戶在線

 

getbit(name, offset)

1
# 獲取name對應的值的二進制表示中的某位的值 (0或1)

bitcount(key, start=None, end=None)

1
2
3
4
5
# 獲取name對應的值的二進制表示中 1 的個數
# 參數:
    # key,Redis的name
    # start,位起始位置
    # end,位結束位置

strlen(name)

1
# 返回name對應值的字節長度(一個漢字3個字節)

incr(self, name, amount=1)

1
2
3
4
5
6
7
# 自增 name對應的值,當name不存在時,則創建name=amount,否則,則自增。
 
# 參數:
    # name,Redis的name
    # amount,自增數(必須是整數)
 
# 注:同incrby

incrbyfloat(self, name, amount=1.0)

1
2
3
4
5
# 自增 name對應的值,當name不存在時,則創建name=amount,否則,則自增。
 
# 參數:
    # name,Redis的name
    # amount,自增數(浮點型)

decr(self, name, amount=1)

1
2
3
4
5
# 自減 name對應的值,當name不存在時,則創建name=amount,否則,則自減。
 
# 參數:
    # name,Redis的name
    # amount,自減數(整數)

append(key, value)

1
2
3
4
5
# 在redis name對應的值後面追加內容
 
# 參數:
    key, redis的name
    value, 要追加的字符串

  

2. Hash操作

hash表現形式上有些像pyhton中的dict,可以存儲一組關聯性較強的數據 , redis中Hash在內存中的存儲格式如下圖:  

 

hset(name, key, value)

1
2
3
4
5
6
7
8
9
# name對應的hash中設置一個鍵值對(不存在,則創建;否則,修改)
 
# 參數:
    # name,redis的name
    # key,name對應的hash中的key
    # value,name對應的hash中的value
 
# 注:
    # hsetnx(name, key, value),當name對應的hash中不存在當前key時則創建(相當於添加)

hmset(name, mapping)

1
2
3
4
5
6
7
8
# 在name對應的hash中批量設置鍵值對
 
# 參數:
    # name,redis的name
    # mapping,字典,如:{'k1':'v1', 'k2': 'v2'}
 
# 如:
    # r.hmset('xx', {'k1':'v1', 'k2': 'v2'})

hget(name,key)

1
# 在name對應的hash中獲取根據key獲取value

hmget(name, keys, *args)

1
2
3
4
5
6
7
8
9
10
11
# 在name對應的hash中獲取多個key的值
 
# 參數:
    # name,reids對應的name
    # keys,要獲取key集合,如:['k1', 'k2', 'k3']
    # *args,要獲取的key,如:k1,k2,k3
 
# 如:
    # r.mget('xx', ['k1', 'k2'])
    # 或
    # print r.hmget('xx', 'k1', 'k2')

hgetall(name)

1
獲取name對應hash的所有鍵值

hlen(name)

1
# 獲取name對應的hash中鍵值對的個數

hkeys(name)

1
# 獲取name對應的hash中所有的key的值

hvals(name)

1
# 獲取name對應的hash中所有的value的值

hexists(name, key)

1
# 檢查name對應的hash是否存在當前傳入的key

hdel(name,*keys)

1
# 將name對應的hash中指定key的鍵值對刪除

hincrby(name, key, amount=1)

1
2
3
4
5
# 自增name對應的hash中的指定key的值,不存在則創建key=amount
# 參數:
    # name,redis中的name
    # key, hash對應的key
    # amount,自增數(整數)

hincrbyfloat(name, key, amount=1.0)

1
2
3
4
5
6
7
8
# 自增name對應的hash中的指定key的值,不存在則創建key=amount
 
# 參數:
    # name,redis中的name
    # key, hash對應的key
    # amount,自增數(浮點數)
 
# 自增name對應的hash中的指定key的值,不存在則創建key=amount

hscan(name, cursor=0, match=None, count=None)

Start a full hash scan with:

HSCAN myhash 0

Start a hash scan with fields matching a pattern with:

HSCAN myhash 0 MATCH order_*

Start a hash scan with fields matching a pattern and forcing the scan command to do more scanning with:

HSCAN myhash 0 MATCH order_* COUNT 1000

 

1
2
3
4
5
6
7
8
9
10
11
12
13
# 增量式迭代獲取,對於數據大的數據非常有用,hscan可以實現分片的獲取數據,並非一次性將數據全部獲取完,從而放置內存被撐爆
 
# 參數:
    # name,redis的name
    # cursor,遊標(基於遊標分批取獲取數據)
    # match,匹配指定key,默認None 表示所有的key
    # count,每次分片最少獲取個數,默認None表示採用Redis的默認分片個數
 
# 如:
    # 第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None)
    # 第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None)
    # ...
    # 直到返回值cursor的值爲0時,表示數據已經通過分片獲取完畢

 

hscan_iter(name, match=None, count=None)

1
2
3
4
5
6
7
8
9
# 利用yield封裝hscan創建生成器,實現分批去redis中獲取數據
  
# 參數:
    # match,匹配指定key,默認None 表示所有的key
    # count,每次分片最少獲取個數,默認None表示採用Redis的默認分片個數
  
# 如:
    # for item in r.hscan_iter('xx'):
    #     print item

 

3. list

List操作,redis中的List在在內存中按照一個name對應一個List來存儲。如圖:  

lpush(name,values)

1
2
3
4
5
6
7
8
# 在name對應的list中添加元素,每個新的元素都添加到列表的最左邊
 
# 如:
    # r.lpush('oo', 11,22,33)
    # 保存順序爲: 33,22,11
 
# 擴展:
    # rpush(name, values) 表示從右向左操作

lpushx(name,value)

1
2
3
4
# 在name對應的list中添加元素,只有name已經存在時,值添加到列表的最左邊
 
# 更多:
    # rpushx(name, value) 表示從右向左操作

llen(name)

1
# name對應的list元素的個數

linsert(name, where, refvalue, value))

1
2
3
4
5
6
7
# 在name對應的列表的某一個值前或後插入一個新值
 
# 參數:
    # name,redis的name
    # where,BEFORE或AFTER
    # refvalue,標杆值,即:在它前後插入數據
    # value,要插入的數據

r.lset(name, index, value)

1
2
3
4
5
6
# 對name對應的list中的某一個索引位置重新賦值
 
# 參數:
    # name,redis的name
    # index,list的索引位置
    # value,要設置的值

r.lrem(name, value, num)

1
2
3
4
5
6
7
8
# 在name對應的list中刪除指定的值
 
# 參數:
    # name,redis的name
    # value,要刪除的值
    # num,  num=0,刪除列表中所有的指定值;
           # num=2,從前到後,刪除2個;
           # num=-2,從後向前,刪除2個

lpop(name)

1
2
3
4
# 在name對應的列表的左側獲取第一個元素並在列表中移除,返回值則是第一個元素
 
# 更多:
    # rpop(name) 表示從右向左操作

lindex(name, index)

1
在name對應的列表中根據索引獲取列表元素

lrange(name, start, end)

1
2
3
4
5
# 在name對應的列表分片獲取數據
# 參數:
    # name,redis的name
    # start,索引的起始位置
    # end,索引結束位置

ltrim(name, start, end)

1
2
3
4
5
# 在name對應的列表中移除沒有在start-end索引之間的值
# 參數:
    # name,redis的name
    # start,索引的起始位置
    # end,索引結束位置

rpoplpush(src, dst)

1
2
3
4
# 從一個列表取出最右邊的元素,同時將其添加至另一個列表的最左邊
# 參數:
    # src,要取數據的列表的name
    # dst,要添加數據的列表的name

blpop(keys, timeout)

1
2
3
4
5
6
7
8
# 將多個列表排列,按照從左到右去pop對應列表的元素
 
# 參數:
    # keys,redis的name的集合
    # timeout,超時時間,當元素所有列表的元素獲取完之後,阻塞等待列表內有數據的時間(秒), 0 表示永遠阻塞
 
# 更多:
    # r.brpop(keys, timeout),從右向左獲取數據

brpoplpush(src, dst, timeout=0)

1
2
3
4
5
6
# 從一個列表的右側移除一個元素並將其添加到另一個列表的左側
 
# 參數:
    # src,取出並要移除元素的列表對應的name
    # dst,要插入元素的列表對應的name
    # timeout,當src對應的列表中沒有數據時,阻塞等待其有數據的超時時間(秒),0 表示永遠阻塞

 

4.set集合操作

Set操作,Set集合就是不允許重複的列表

sadd(name,values)

1
# name對應的集合中添加元素

scard(name)

1
獲取name對應的集合中元素個數

sdiff(keys, *args)

1
在第一個name對應的集合中且不在其他name對應的集合的元素集合

sdiffstore(dest, keys, *args)

1
# 獲取第一個name對應的集合中且不在其他name對應的集合,再將其新加入到dest對應的集合中

sinter(keys, *args)

1
# 獲取多一個name對應集合的並集

sinterstore(dest, keys, *args)

1
# 獲取多一個name對應集合的並集,再講其加入到dest對應的集合中

sismember(name, value)

1
# 檢查value是否是name對應的集合的成員

smembers(name)

1
# 獲取name對應的集合的所有成員

smove(src, dst, value)

1
# 將某個成員從一個集合中移動到另外一個集合

spop(name)

1
# 從集合的右側(尾部)移除一個成員,並將其返回

srandmember(name, numbers)

1
# 從name對應的集合中隨機獲取 numbers 個元素

srem(name, values)

1
# 在name對應的集合中刪除某些值

sunion(keys, *args)

1
# 獲取多一個name對應的集合的並集

sunionstore(dest,keys, *args)

1
# 獲取多一個name對應的集合的並集,並將結果保存到dest對應的集合中

sscan(name, cursor=0, match=None, count=None)
sscan_iter(name, match=None, count=None)

1
# 同字符串的操作,用於增量迭代分批獲取元素,避免內存消耗太大

 

有序集合,在集合的基礎上,爲每元素排序;元素的排序需要根據另外一個值來進行比較,所以,對於有序集合,每一個元素有兩個值,即:值和分數,分數專門用來做排序。

zadd(name, *args, **kwargs)

1
2
3
4
5
# 在name對應的有序集合中添加元素
# 如:
     # zadd('zz', 'n1', 1, 'n2', 2)
     # 或
     # zadd('zz', n1=11, n2=22)

zcard(name)

1
# 獲取name對應的有序集合元素的數量

zcount(name, min, max)

1
# 獲取name對應的有序集合中分數 在 [min,max] 之間的個數

zincrby(name, value, amount)

1
# 自增name對應的有序集合的 name 對應的分數

r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 按照索引範圍獲取name對應的有序集合的元素
 
# 參數:
    # name,redis的name
    # start,有序集合索引起始位置(非分數)
    # end,有序集合索引結束位置(非分數)
    # desc,排序規則,默認按照分數從小到大排序
    # withscores,是否獲取元素的分數,默認只獲取元素的值
    # score_cast_func,對分數進行數據轉換的函數
 
# 更多:
    # 從大到小排序
    # zrevrange(name, start, end, withscores=False, score_cast_func=float)
 
    # 按照分數範圍獲取name對應的有序集合的元素
    # zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float)
    # 從大到小排序
    # zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=float)

zrank(name, value)

1
2
3
4
# 獲取某個值在 name對應的有序集合中的排行(從 0 開始)
 
# 更多:
    # zrevrank(name, value),從大到小排序

 

zrem(name, values)

1
2
3
# 刪除name對應的有序集合中值是values的成員
 
# 如:zrem('zz', ['s1', 's2'])

zremrangebyrank(name, min, max)

1
# 根據排行範圍刪除

zremrangebyscore(name, min, max)

1
# 根據分數範圍刪除

 

zscore(name, value)

1
# 獲取name對應有序集合中 value 對應的分數

zinterstore(dest, keys, aggregate=None)

1
2
# 獲取兩個有序集合的交集,如果遇到相同值不同分數,則按照aggregate進行操作
# aggregate的值爲:  SUM  MIN  MAX

zunionstore(dest, keys, aggregate=None)

1
2
# 獲取兩個有序集合的並集,如果遇到相同值不同分數,則按照aggregate進行操作
# aggregate的值爲:  SUM  MIN  MAX

zscan(name, cursor=0, match=None, count=None, score_cast_func=float)
zscan_iter(name, match=None, count=None,score_cast_func=float)

1
# 同字符串相似,相較於字符串新增score_cast_func,用來對分數進行操作

 

 

其他常用操作

delete(*names)

1
# 根據刪除redis中的任意數據類型

exists(name)

1
# 檢測redis的name是否存在

keys(pattern='*')

1
2
3
4
5
6
7
# 根據模型獲取redis的name
 
# 更多:
    # KEYS * 匹配數據庫中所有 key 。
    # KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
    # KEYS h*llo 匹配 hllo 和 heeeeello 等。
    # KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo

expire(name ,time)

1
# 爲某個redis的某個name設置超時時間

rename(src, dst)

1
# 對redis的name重命名爲

move(name, db))

1
# 將redis的某個值移動到指定的db下

randomkey()

1
# 隨機獲取一個redis的name(不刪除)

type(name)

1
# 獲取name對應值的類型

scan(cursor=0, match=None, count=None)
scan_iter(match=None, count=None)

1
# 同字符串操作,用於增量迭代獲取key

 

 

管道

redis-py默認在執行每次請求都會創建(連接池申請連接)和斷開(歸還連接池)一次連接操作,如果想要在一次請求中指定多個命令,則可以使用pipline實現一次請求指定多個命令,並且默認情況下一次pipline 是原子性操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
import redis
 
pool = redis.ConnectionPool(host='10.211.55.4', port=6379)
 
= redis.Redis(connection_pool=pool)
 
# pipe = r.pipeline(transaction=False)
pipe = r.pipeline(transaction=True)
 
pipe.set('name''alex')
pipe.set('role''sb')
 
pipe.execute()

 

 

發佈訂閱

發佈者:服務器

訂閱者:Dashboad和數據處理

Demo如下:

import redis


class RedisHelper:

    def __init__(self):
        self.__conn = redis.Redis(host='10.211.55.4')
        self.chan_sub = 'fm104.5'
        self.chan_pub = 'fm104.5'

    def public(self, msg):
        self.__conn.publish(self.chan_pub, msg)
        return True

    def subscribe(self):
        pub = self.__conn.pubsub()
        pub.subscribe(self.chan_sub)
        pub.parse_response()
        return pub
redis helper

 

訂閱者:

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
from monitor.RedisHelper import RedisHelper
 
obj = RedisHelper()
redis_sub = obj.subscribe()
 
while True:
    msg= redis_sub.parse_response()
    print msg

發佈者:

1
2
3
4
5
6
7
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
from monitor.RedisHelper import RedisHelper
 
obj = RedisHelper()
obj.public('hello')

 

 

更多參見:https://github.com/andymccurdy/redis-py/

http://doc.redisfans.com/

 

什麼時候用關係型數據庫,什麼時候 用NoSQL?

 


Go for legacy relational databases (RDBMS) when:

  1. The data is well structured, and lends itself to a tabular arrangement (rows and columns) in a relational database. Typical examples: bank account info, customer order info, customer info, employee info, department info etc etc.
  2. Another aspect of the above point is : schema oriented data model. When you design a data model (tables, relationships etc) for a potential use of RDBMS, you need to come up with a well defined schema: there will be these many tables, each table having a known set of columns that store data in known typed format (CHAR, NUMBER, BLOB etc).
  3. Very Important: Consider whether the data is transactional in nature. In other words, whether the data will be stored, accessed and updated in the context of transactions providing the ACID semantics or is it okay to compromise some/all of these properties.
  4. Correctness is also important and any compromise is _unacceptable_. This stems from the fact that in most NoSQL databases, consistency is traded off in favor of performance and scalability (points on NoSQL databases are elaborated below).
  5. There is no strong/compelling need for a scale out architecture ; a database that linearly scales out (horizontal scaling) to multiple nodes in a cluster.
  6. The use case is not for “high speed data ingestion”.
  7. If the client applications are expecting to quickly stream large amounts of data in/out of the database then relational database may not be a good choice since they are not really designed for scaling write heavy workloads.
  8. In order to achieve ACID properties, lots of additional background work is done especially in writer (INSERT, UPDATE, DELETE) code paths. This definitely affects performance.
  9. The use case is not for “storing enormous amounts of data in the range of petabytes”.

 

Go for NoSQL databases when:

  1. There is no fixed (and predetermined) schema that data fits in:
  2. Scalability, Performance (high throughput and low operation latency), Continuous Availability are very important requirements to be met by the underlying architecture of database.
  3. Good choice for “High Speed Data Ingestion”. Such applications (for example IoT style) which generate millions of data points in a second and need a database capable of providing extreme write scalability.
  4. The inherent ability to horizontally scale allows to store large amounts of data across commodity servers in the cluster. They usually use low cost resources, and are able to linearly add compute and storage power as the demand grows.

source page https://www.quora.com/When-should-you-use-NoSQL-vs-regular-RDBMS 

 

 

附贈redis性能測試

  準備環境:

  因爲找不到可用的1000M網絡機器,使用一根直通線將兩臺筆記本連起來組成1000M Ethernet網。沒錯,是直通線現在網卡都能自適應交叉線、直通線,速度不受影響,用了一段時間機器也沒出問題。

  服務端:T420 i5-2520M(2.5G)/8G ubuntu 11.10

  客戶端:Acer i5-2430M(2.4G)/4G mint 11

  redis版本:2.6.9

  測試腳本:./redis-benchmark -h xx -p xx -t set -q -r 1000 -l -d 20

  

長度 速度/sec 帶寬(MByte/s) 發送+接收 CPU CPU Detail
20Byte 17w 24M+12M 98.00% Cpu0 : 21.0%us, 40.7%sy, 0.0%ni, 4.3%id, 0.0%wa, 0.0%hi, 34.0%si, 0.0%st
100Byte 17w 37M+12M 97.00% Cpu0 : 20.3%us, 37.9%sy, 0.0%ni, 7.0%id, 0.0%wa, 0.0%hi, 34.9%si, 0.0%st
512Byte 12w 76M+9M 87.00% Cpu0 : 20.9%us, 33.2%sy, 0.0%ni, 25.6%id, 0.0%wa, 0.0%hi, 20.3%si, 0.0%st
1K 9w 94M+8M 81.00% Cpu0 : 19.9%us, 30.2%sy, 0.0%ni, 34.2%id, 0.0%wa, 0.0%hi, 15.6%si, 0.0%st
2K 5w 105M+6M 77.00% Cpu0 : 18.0%us, 32.0%sy, 0.0%ni, 34.7%id, 0.0%wa, 0.0%hi, 15.3%si, 0.0%st
5K 2.2w 119M+3.2M 77.00% Cpu0 : 22.5%us, 32.8%sy, 0.0%ni, 32.8%id, 0.0%wa, 0.0%hi, 11.9%si, 0.0%st
10K 1.1w 119M+1.7M 70.00% Cpu0 : 18.2%us, 29.8%sy, 0.0%ni, 42.7%id, 0.0%wa, 0.0%hi, 9.3%si, 0.0%st
20K 0.57w 120M+1M 58.00% Cpu0 : 17.8%us, 26.4%sy, 0.0%ni, 46.2%id, 0.0%wa, 0.0%hi, 9.6%si, 0.0%st

  value 在1K以上時,1000M網卡輕鬆的被跑慢,而且redis-server cpu連一個核心都沒佔用到,可見redis高效,redis的服務也不需要太高配置,瓶頸在網卡速度。

  整理看redis的us都在20%左右,用戶層代碼資源佔用比例都很小。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章