python操作redis

非關係型數據庫和關係型數據庫的差別:

非關係型數據庫的優勢:

1. 性能NOSQL是基於鍵值對的,可以想象成表中的主鍵和值的對應關係,而且不需要經過SQL層的解析,所以性能非常高。

2. 可擴展性同樣也是因爲基於鍵值對,數據之間沒有耦合性,所以非常容易水平擴展。

關係型數據庫的優勢:

1. 複雜查詢可以用SQL語句方便的在一個表以及多個表之間做非常複雜的數據查詢。

2. 事務支持使得對於安全性能很高的數據訪問要求得以實現。對於這兩類數據庫,對方的優勢就是自己的弱勢,反之亦然。但是近年來這兩種數據庫都在向着另外一個方向進化。

例如:NOSQL數據庫慢慢開始具備SQL數據庫的一些複雜查詢功能的雛形,比如Couchbase的index以及MONGO的複雜查詢。對於事務的支持也可以用一些系統級的原子操作來實現例如樂觀鎖之類的方法來曲線救國。SQL數據庫也開始慢慢進化,比如HandlerSocker技術的實現,可以在MYSQL上實現對於SQL層的穿透,用NOSQL的方式訪問數據庫,性能可以上可以達到甚至超越NOSQL數據庫。可擴展性上例如Percona Server,可以實現無中心化的集羣。雖然這兩極都因爲各自的弱勢而開始進化出另一極的一些特性,但是這些特性的增加也會消弱其本來具備的優勢,比如Couchbase上的index的增加會逐步降低數據庫的讀寫性能。所以怎樣構建系統的短期和長期存儲策略,用好他們各自的強項是架構師需要好好考慮的重要問題。

python操作redis

redis的概念:

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

Redis 是一個高性能的key-value數據庫。 redis的出現,很大程度補償了memcached這類key/value存儲的不足,在部 分場合可以對關係數據庫起到很好的補充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客戶端,使用很方便。

Redis支持主從同步。數據可以從主服務器向任意數量的從服務器上同步,從服務器可以是關聯其他從服務器的主服務器。這使得Redis可執行單層樹複製。存盤可以有意無意的對數據進行寫操作。由於完全實現了發佈/訂閱機制,使得從數據庫在任何地方同步樹時,可訂閱一個頻道並接收主服務器完整的消息發佈記錄。同步對讀取操作的可擴展性和數據冗餘很有幫助。

Redis的安裝

Redis一般都是安裝在linux系統中,具體安裝步驟如下:

#cd /usr/local/src

#wget http://download.redis.io/releases/redis-3.0.1.tar.gz 

#tar xzf redis-3.0.1.tar.gz 

#cd redis-3.0.1 

#make

#src/redis-server &

檢查redis是否正常啓動

Ps –ef |grep redis

Netstat –lnp |grep 6379

python安裝redis的模塊

Pip install redis

redis是以key-value的形式存儲的,所以我們在操作的時候。首先我們將redis所在主機的ip和發佈端口作爲參數實例化了一個對象r,然後執行set('hello','world'),這樣我們就在內存中存儲了一個key爲hello,值爲‘world’的項。我們可以理解爲{'hello':'world'},當我們要讀取的之後,keys()就是獲得多有key值。

例子:

import redis

r = redis.Redis(host="192.168.1.1", port=6379)

r.set("hello", "world")

print(r.get("hello"))

print(r.keys())

# print(dir(r))

2.連接池

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

例子:

import redis

pool = redis.ConnectionPool(host="192.168.1.1")

r = redis.Redis(connection_pool=pool)

r.set("python", "study")

print(r.get("python"))

管道

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

redis是一個cs模式的tcp server,使用和http類似的請求響應協議。一個client可以通過一個socket連接發起多個請求命令。每個請求命令發出後client通常會阻塞並等待redis服務處理,redis處理完後請求命令後會將結果通過響應報文返回給client。基本的通信過程如下:

Client: INCR X

Server: 1

Client: INCR X

Server: 2

Client: INCR X

Server: 3

Client: INCR X

Server: 4

基本上四個命令需要8個tcp報文才能完成。由於通信會有網絡延遲,假如從client和server之間的包傳輸時間需要0.125秒。那麼上面的四個命令8個報文至少會需要1秒才能完成。這樣即使redis每秒能處理100個命令,而我們的client也只能一秒鐘發出四個命令。這顯示沒有充分利用 redis的處理能力。除了可以利用mget,mset 之類的單條命令處理多個key的命令外我們還可以利用pipeline的方式從client打包多條命令一起發出,不需要等待單條命令的響應返回,而redis服務端會處理完多條命令後會將多條命令的處理結果打包到一起返回給客戶端。通信過程如下:

Client: INCR X

Client: INCR X

Client: INCR X

Client: INCR X

Server: 1

Server: 2

Server: 3

Server: 4

假設不會因爲tcp報文過長而被拆分。可能兩個tcp報文就能完成四條命令,client可以將四個命令放到一個tcp報文一起發送,server則可以將四條命令的處理結果放到一個tcp報文返回。通過pipeline方式當有大批量的操作時候。我們可以節省很多原來浪費在網絡延遲的時間。需要注意到是用 pipeline方式打包命令發送,redis必須在處理完所有命令前先緩存起所有命令的處理結果。打包的命令越多,緩存消耗內存也越多。所以並是不是打包的命令越多越好。具體多少合適需要根據具體情況測試

例子:

import datetime

import redis

def withpipe(r):

    pipe = r.pipeline(transaction=True)

    for i in xrange(1, 1000):

        key = "test1" +str(i)

        value = "test1" + str(i)

        pipe.set(key, value)

    pipe.execute()

def withoutpipe(r):

    # pipe = r.pipeline(transaction=True)

    for i in xrange(1, 1000):

        key = "test1" + str(i)

        value = "test1" + str(i)

        r.set(key, value)

if __name__ == "__main__":

    pool = redis.ConnectionPool(host="192.168.1.1", port=6379, db=0)

    r1 = redis.Redis(connection_pool=pool)

    r2 = redis.Redis(connection_pool=pool)

    start = datetime.datetime.now()

    # print(start)

    withpipe(r1)

    end = datetime.datetime.now()

    # print((end-start).microseconds)

    # print(end-start)

    t_time = (end - start).microseconds

    print("withpipe time is : {0}".format(t_time))

    start = datetime.datetime.now()

    withoutpipe(r2)

    end = datetime.datetime.now()

    t_time = (end - start).microseconds

    print("withoutpipe time is : {0}".format(t_time))

結果:

withpipe time is : 28000

withoutpipe time is : 253000


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