NoSQL泛指非關系型的數據庫
非關系型數據庫和關系型數據庫的差別:
- 性能NOSQL是基於鍵值對的,可以想象成表中的主鍵和值的對應關系,而且不需要經過SQL層的解析,所以性能非常高
- 可擴展性同樣也是因為基於鍵值對,數據之間沒有耦合性,所以非常容易水平擴展
- 關系型數據庫的優勢:復雜查詢可以用SQL語句方便的在一個表以及多個表之間做非常復雜的數據查詢;事務支持使得對於安全性能很高的數據訪問要求得以實現
- 對於這兩類數據庫,對方的優勢就是自己的弱勢,所以如何利用好這兩種數據庫的強項,使其相互補充,是一個很重要的需要好好設計的問題
redis簡介
redis是一個key-value存儲系統。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)
這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支持各種不同方式的排序
與memcached一樣,為了保證效率,數據都是緩存在內存中。區別的是redis會周期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,並且在此基礎上實現了主從同步
redis官網:
https://redis.io/
redis中文網:
http://www.redis.net.cn/
redis服務端安裝
[root@web ~]# cd /usr/local/src/ [root@web src]# wget http://download.redis.io/releases/redis-3.2.5.tar.gz [root@web src]# tar -zxf redis-3.2.5.tar.gz [root@web src]# cd redis-3.2.5 [root@web redis-3.2.5]# make [root@web redis-3.2.5]# vim /usr/local/src/redis-3.2.5/redis.conf //默認配置文件,把daemonize no 改為daemonize yes,允許后台啟動 [root@web redis-3.2.5]# cd src [root@web src]# pwd /usr/local/src/redis-3.2.5/src [root@web src]# ls -rwxr-xr-x 1 root root 5580311 11月 25 11:18 redis-benchmark //基准測試 -rwxr-xr-x 1 root root 22185 11月 25 11:18 redis-check-aof //aof持久化 -rwxr-xr-x 1 root root 7826902 11月 25 11:18 redis-check-rdb //rdb持久化 -rwxr-xr-x 1 root root 5709036 11月 25 11:18 redis-cli //linux上的redis客戶端 -rwxr-xr-x 1 root root 7826902 11月 25 11:18 redis-sentinel //哨兵,用於redis集群選舉 -rwxr-xr-x 1 root root 7826902 11月 25 11:18 redis-server //redis服務端程序 [root@web src]# ./redis-server /usr/local/src/redis-3.2.5/redis.conf //啟動redis [root@web src]# netstat -lnp //監聽127.0.0.1:6379 Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 4443/./redis-server
redis客戶端安裝
[root@web ~]# pip install redis [root@web ~]# ipython In [1]: import redis
注意:默認配置文件定義監聽localhost
如果客戶端和服務端不在同一台服務器上,服務端的配置文件監聽地址需要改為bind 0.0.0.0
redis客戶端的使用
[root@web redis_py]# cat demon1.py #!/usr/bin/env python import redis r = redis.Redis(host='localhost', port=6379, db=0, password=None) //實例化Redis這個類獲得一個對象r,對象的方法就是redis的所有命令 r.set('name', 'aaa') //set()方法往服務端存入兩個鍵值對 r.set('age', 30) print r.get('name') //get(key)方法獲取key對應的value print r.keys() //keys()方法打印所有的key [root@web redis_py]# python demon1.py aaa ['age', 'name']
redis連接池
redis客戶端使用連接池管理所有請求服務端的連接,避免每次建立、釋放連接造成多余的開銷
默認情況下,每個redis實例都會維護自己的連接池
可以直接建立一個連接池,實例化對象的時候使用連接池作為參數,這樣可以實現多個redis實例共享連接池
[root@web redis_py]# cat demon2.py #!/usr/bin/env python import redis def getConnection(): config = { 'host': 'localhost', 'port': 6379, 'db': 0, 'password': None } pool = redis.ConnectionPool(**config) r = redis.Redis(connection_pool=pool) return r if __name__ == '__main__': r = getConnection() r.set('gender', 'M') print r.get('gender') [root@web redis_py]# python demon2.py M
管道:
redis客戶端執行每次請求都會向連接池申請創建連接,請求完畢斷開連接
redis是c/s模式的tcp server,使用和http類型的請求響應協議。一個client可以通過socket連接向服務端發起多個請求,每發送一個請求后,client會阻塞並等待redis服務端響應,服務端處理完請求后悔將結果通過響應報文返回給client,也就是說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的處理能力
客戶端要想一次發送多個請求,需要使用mset、mget等命令,或者使用管道
client可以將四個命令放到一個tcp報文一起發送,server則可以將四條命令的處理結果放到一個tcp報文返回
需要注意的是,用pipeline方式打包命令發送,redis在處理完所有請求后會緩存請求結果到內存中。打包的命令越多,緩存消耗內存也越多。所以並是不是打包的命令越多越好。具體多少合適需要根據具體情況測試
client: INCR X
client: INCR X
client: INCR X
client: INCR X
server: 1
server: 2
server: 3
server: 4
管道的用法:
In [6]: help(r.pipeline) Help on method pipeline in module redis.client: pipeline(self, transaction=True, shard_hint=None) method of redis.client.Redis instance //獲取一個連接對象,通過連接對象創建一個管道 Return a new pipeline object that can queue multiple commands for //返回一個管道對象 later execution. ``transaction`` indicates whether all commands //自動執行多條命令(把多個請求發送到服務端) should be executed atomically. Apart from making a group of operations atomic, pipelines are useful for reducing the back-and-forth overhead //提高處理能力 between the client and server
使用管道和不使用管道的效率對比:
[root@web redis_py]# cat demon3.py #!/usr/bin/env python import redis import datetime from demon2 import getConnection def withpipeline(r): p = r.pipeline(transaction=True) for i in xrange(1000): key = 'test1' + str(i) value = i+1 p.set(key, value) p.execute() def withoutpipeline(r): for i in xrange(1000): key = 'test2' + str(i) value = i+1 r.set(key, value) if __name__ == '__main__': r = getConnection() start = datetime.datetime.now() withpipeline(r) end = datetime.datetime.now() offset = (end-start).microseconds print 'With pipeline time: {0}'.format(offset) start = datetime.datetime.now() withoutpipeline(r) end = datetime.datetime.now() offset = (end-start).microseconds print 'Without pipeline time: {0}'.format(offset) [root@web redis_py]# python demon3.py With pipeline time: 16403 Without pipeline time: 43398