和不少大牛談過,玩python的web框架有一點瓶頸,那就是高併發,可是redis給咱們提供解決高併發,高可用,高性能的弊端。 redis是業界主流的key-value nosql 數據庫。和Memcached相似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操做,並且這些操做都是原子性的。在此基礎上,redis支持各類不一樣方式的排序。與memcached同樣,爲了保證效率,數據都是緩存在內存中。區別的是redis會週期性的把更新的數據寫入磁盤或者把修改操做寫入追加的記錄文件,而且在此基礎上實現了master-slave(主從)同步。node
異常快速 : Redis是很是快的,每秒能夠執行大約110000設置操做,81000個/每秒的讀取操做。python
支持豐富的數據類型 : Redis支持最大多數開發人員已經知道如列表,集合,可排序集合,哈希等數據類型。git
這使得在應用中很容易解決的各類問題,由於咱們知道哪些問題處理使用哪一種數據類型更好解決。github
操做都是原子的 : 全部 Redis 的操做都是原子,從而確保當兩個客戶同時訪問 Redis 服務器獲得的是更新後的值(最新值)。web
MultiUtility工具:Redis是一個多功能實用工具,能夠在不少如:緩存,消息傳遞隊列中使用(Redis原生支持發佈/訂閱),在應用程序中,如:Web應用程序會話,網站頁面點擊數等任何短暫的數據;redis
要在 Ubuntu 上安裝 Redis,打開終端,而後輸入如下命令:sql
$sudo apt-get update $sudo apt-get install redis-server
這將在您的計算機上安裝Redis數據庫
啓動 Redisubuntu
$redis-server
查看 redis 是否還在運行promise
$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。
1 2 3 4 5 6 7 |
|
要在Ubuntu 上安裝 Redis桌面管理,能夠從 http://redisdesktop.com/download 下載包並安裝它。
Redis 桌面管理器會給你用戶界面來管理 Redis 鍵和數據。
redis-py 的API的使用能夠分類爲:
鏈接方式
鏈接池
操做
String 操做
Hash 操做
List 操做
Set 操做
Sort Set 操做
管道
發佈訂閱
一、操做模式
redis-py提供兩個類Redis和StrictRedis用於實現Redis的命令,StrictRedis用於實現大部分官方的命令,並使用官方的語法和命令,Redis是StrictRedis的子類,用於向後兼容舊版本的redis-py。
1 2 3 4 5 |
|
二、鏈接池
redis-py使用connection pool來管理對一個redis server的全部鏈接,避免每次創建、釋放鏈接的開銷。默認,每一個Redis實例都會維護一個本身的鏈接池。能夠直接創建一個鏈接池,而後做爲參數Redis,這樣就能夠實現多個Redis實例共享一個鏈接池。
redis中的String在在內存中按照一個name對應一個value來存儲。如圖:
set(name, value, ex=None, px=None, nx=False, xx=False)
1 2 3 4 5 6 |
|
setnx(name, value)
1 |
|
setex(name, value, time)
1 2 3 |
|
psetex(name, time_ms, value)
1 2 3 |
|
mset(*args, **kwargs)
1 2 3 4 5 |
|
get(name)
1 |
|
mget(keys, *args)
1 2 3 4 5 |
|
getset(name, value)
1 |
|
getrange(key, start, end)
1 2 3 4 5 6 |
|
setrange(name, offset, value)
1 2 3 4 |
|
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 |
|
*用途舉例,用最省空間的方式,存儲在線用戶數及分別是哪些用戶在線
getbit(name, offset)
1 |
|
bitcount(key, start=None, end=None)
1 2 3 4 5 |
|
strlen(name)
1 |
|
incr(self, name, amount=1)
1 2 3 4 5 6 7 |
|
incrbyfloat(self, name, amount=1.0)
1 2 3 4 5 |
|
decr(self, name, amount=1)
1 2 3 4 5 |
|
append(key, value)
1 2 3 4 5 |
|
hash表現形式上有些像pyhton中的dict,能夠存儲一組關聯性較強的數據 , redis中Hash在內存中的存儲格式以下圖:
hset(name, key, value)
1 2 3 4 5 6 7 8 9 |
|
hmset(name, mapping)
1 2 3 4 5 6 7 8 |
|
hget(name,key)
1 |
|
hmget(name, keys, *args)
1 2 3 4 5 6 7 8 9 10 11 |
|
hgetall(name)
1 |
|
hlen(name)
1 |
|
hkeys(name)
1 |
|
hvals(name)
1 |
|
hexists(name, key)
1 |
|
hdel(name,*keys)
1 |
|
hincrby(name, key, amount=1)
1 2 3 4 5 |
|
hincrbyfloat(name, key, amount=1.0)
1 2 3 4 5 6 7 8 |
|
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_iter(name, match=None, count=None)
1 2 3 4 5 6 7 8 9 |
|
List操做,redis中的List在在內存中按照一個name對應一個List來存儲。如圖:
lpush(name,values)
1 2 3 4 5 6 7 8 |
|
lpushx(name,value)
1 2 3 4 |
|
llen(name)
1 |
|
linsert(name, where, refvalue, value))
1 2 3 4 5 6 7 |
|
r.lset(name, index, value)
1 2 3 4 5 6 |
|
r.lrem(name, value, num)
1 2 3 4 5 6 7 8 |
|
lpop(name)
1 2 3 4 |
|
lindex(name, index)
1 |
|
lrange(name, start, end)
1 2 3 4 5 |
|
ltrim(name, start, end)
1 2 3 4 5 |
|
rpoplpush(src, dst)
1 2 3 4 |
|
blpop(keys, timeout)
1 2 3 4 5 6 7 8 |
|
brpoplpush(src, dst, timeout=0)
1 2 3 4 5 6 |
|
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 |
|
zremrangebyrank(name, min, max)
1 |
|
zremrangebyscore(name, min, max)
1 |
|
zscore(name, value)
1 |
|
zinterstore(dest, keys, aggregate=None)
1 2 |
|
zunionstore(dest, keys, aggregate=None)
1 2 |
|
zscan(name, cursor=0, match=None, count=None, score_cast_func=float)
zscan_iter(name, match=None, count=None,score_cast_func=float)
1 |
|
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 |
|
發佈者:服務器
訂閱者:Dashboad和數據處理
Demo以下:
訂閱者:
1 2 3 4 5 6 7 8 9 10 11 |
|
發佈者:
1 2 3 4 5 6 7 |
|
更多參見:https://github.com/andymccurdy/redis-py/
http://doc.redisfans.com/
Go for legacy relational databases (RDBMS) when:
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.
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).
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.
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).
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.
The use case is not for 「high speed data ingestion」.
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.
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.
The use case is not for 「storing enormous amounts of data in the range of petabytes」.
Go for NoSQL databases when:
There is no fixed (and predetermined) schema that data fits in:
Scalability, Performance (high throughput and low operation latency), Continuous Availability are very important requirements to be met by the underlying architecture of database.
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.
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
準備環境:
由於找不到可用的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%左右,用戶層代碼資源佔用比例都很小。
redis pool = redis.ConnectionPool(=, =,=,=) r = redis.Redis(=pool) pipe = r.pipeline(=) pipe.set(, ) pipe.set(, ) pipe.execute() (r.get())