day25-python操做redis一

1.     Python操做nosql數據庫

   

NoSQL,泛指非關係型的數據庫。隨着互聯網web2.0網站的興起,傳統的關係數據庫在應付web2.0網站,特別是超大規模和高併發的SNS類型的web2.0純動態網站已經顯得力不從心,暴露了不少難以克服的問題,而非關係型的數據庫則因爲其自己的特色獲得了很是迅速的發展。NoSQL數據庫的產生就是爲了解決大規模數據集合多重數據種類帶來的挑戰,尤爲是大數據應用難題。python

雖然NoSQL的流行與火起來才短短几年的時間,可是不能否認,如今已經開始了第二代運動。儘管早期的堆棧代碼只能算是一種實驗,然而如今的系統已經更加的成熟、穩定。不過如今也面臨着一個嚴酷的事實:技術愈來愈成熟——以致於原來很好的NoSQL數據存儲不得不進行重寫,也有少數人認爲這就是所謂的2.0版本。該工具能夠爲大數據創建快速、可擴展的存儲庫。linux

 

非關係型數據庫和關係型數據庫的差異:web

 

非關係型數據庫的優點:1. 性能NOSQL是基於鍵值對的,能夠想象成表中的主鍵和值的對應關係,並且不須要通過SQL層的解析,因此性能很是高。2. 可擴展性一樣也是由於基於鍵值對,數據之間沒有耦合性,因此很是容易水平擴展。關係型數據庫的優點:1. 複雜查詢能夠用SQL語句方便的在一個表以及多個表之間作很是複雜的數據查詢。2. 事務支持使得對於安全性能很高的數據訪問要求得以實現。對於這兩類數據庫,對方的優點就是本身的弱勢,反之亦然。可是近年來這兩種數據庫都在向着另一個方向進化。例如:NOSQL數據庫慢慢開始具有SQL數據庫的一些複雜查詢功能的雛形,好比Couchbase的index以及MONGO的複雜查詢。對於事務的支持也能夠用一些系統級的原子操做來實現例如樂觀鎖之類的方法來曲線救國。SQL數據庫也開始慢慢進化,好比HandlerSocker技術的實現,能夠在MYSQL上實現對於SQL層的穿透,用NOSQL的方式訪問數據庫,性能能夠上能夠達到甚至超越NOSQL數據庫。可擴展性上例如Percona Server,能夠實現無中心化的集羣。雖然這兩極都由於各自的弱勢而開始進化出另外一極的一些特性,可是這些特性的增長也會消弱其原本具有的優點,好比Couchbase上的index的增長會逐步下降數據庫的讀寫性能。因此怎樣構建系統的短時間和長期存儲策略,用好他們各自的強項是架構師須要好好考慮的重要問題。redis

2.     python操做redis

redis的概念:sql

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

 

安裝redis的客戶端

pip install redis
python操做redis
例子
import redis

r = redis.Redis(host='192.168.1.5', port=6379)
r.set("wxp","I love you")
print(r.get("wxp"))
print(r.keys())
#print(dir(r))

輸出結果

I love you
['wxp']

3.鏈接池

redis-py使用connection pool來管理對一個redis server的全部鏈接,避免每次創建、釋放鏈接的開銷。默認,每一個Redis實例都會維護一個本身的鏈接池。能夠直接創建一個鏈接池,而後做爲參數Redis,這樣就能夠實現多個Redis實例共享一個鏈接池服務器

import redis

pool = redis.ConnectionPool(host="192.168.1.5")
r = redis.Redis(connection_pool=pool)
r.set("name","wxp")
print(r.get("name"))

結果:
wxp

4.管道

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 = "wxp" + str(i)
        value = "wxp1" +str(i)
        pipe.set(key,value)
    pipe.execute()
def withoutpipe(r):
    for i in xrange(1,1000):
        key = "wxp" + str(i)
        value = "wxp1" +str(i)
        r.set(key,value)

if __name__ == "__main__":
    pool = redis.ConnectionPool(host="192.168.1.5",port = 6379,db=0)
    r1 = redis.Redis(connection_pool=pool)
    r2 = redis.Redis(connection_pool=pool)
    start = datetime.datetime.now()
    withpipe(r1)
    end = datetime.datetime.now()
    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:34000
withoutpipe time is : 969000
相關文章
相關標籤/搜索