redis - python
一、redis - 简介
https://www.cnblogs.com/wupeiqi/articles/5132791.html
http://www.cnblogs.com/wupeiqi/articles/5246483.html
mysql 是一个软件,帮助开发者对一台机器得硬盘进行操作;(默认端口是:3306)
redis 是一个软件,帮助开发者对一台机器得内存进行操作;(默认端口是:6379)
关键字:
缓存,优先去redis中获取,如果没有就去数据库;还可以设置超时时间。
redis 经常访问得数据,可以放到redis 读写分离 集群;
Redis快的主要原因是:
- 完全基于内存
- 数据结构简单,对数据操作也简单
- 使用多路 I/O 复用模型
第一、二点不细讲,主要围绕第三点采用多路 I/O 复用技术来展开。
多路 I/O 复用模型是利用select、poll、epoll可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),且Redis在内存中操作数据的速度非常快(内存内的操作不会成为这里的性能瓶颈),主要以上两点造就了Redis具有很高的吞吐量。
补充:
1. redis列表 - 左右 - hang住 - 通过yield构造生成器 写一个栈:写一个类实现后进先出的结构。 (题目) class FooStack(object): def push(self): pass def pop(self): pass 2. redis字典 - hscan_iter 3. 事务 4. 连接池 5. 单进程单线程 6. 持久化: - AOF - RDB
二、安装、配置文件
linux:
安装: yum install redis
启动: redis-server /etc/redis.conf
启动前:先配置
vim /etc/redis.conf
bind 0.0.0.0
port 6379
requirepass luffy1234
- redis软件 (服务端) 本质都是 socket yum install redis 启动: redis-server /etc/redis.conf 。。。 or wget http://download.redis.io/releases/redis-3.0.6.tar.gz http://download.redis.io/releases/ tar xzf redis-3.0.6.tar.gz cd redis-3.0.6 make (编译) 启动:src/redis-server redis.conf 默认端口:(6379) vim /etc/redis.conf [root@oldboyedu-01 ~]# whereis redis redis: /etc/redis.conf 配置文件: bind 0.0.0.0 port 6379 requirepass luffy1234 # requireeass foobared requirepass luffy1234
三、python - 连接redis
pip3 install redis (客户端)
1. 创建连接 发数据 取数据
# -*- coding:utf-8 -*- import redis # 内存里面帮助我们做得 大字典 # 1.创建连接 conn = redis.Redis(host='10.0.0.200',port=6379,password='luffy1234') conn.set('name',"alice",ex=10) # 设置值 ex 还可以设置超时时间 # ex s # px ms val = conn.get("name") # 获取值 # b'alice' 过了超时时间:None print(val)
2. 连接池 - 连一次,之后只要send ...
并发量大得时候,就创建多个连接
import redis # 内存里面帮助我们做得 大字典 # 2. 连接池 (需要传数据,才连,不断开,并发量大得时候,就创建多个连接,) pool = redis.ConnectionPool(host='10.0.0.200',port=6379,password='luffy1234',max_connections=1000) conn = redis.Redis(connection_pool=pool) conn.set('name',"alice")
3. 连接池 - 高效 - 单例 - 一个模块
并发量大得时候,只连一次
单例 - 否则性能就降低了
# -*- coding:utf-8 -*- import redis from redis_pool import POOL while True: key = input("请输入key:") value = input("请输入value") # 去连接池中获取连接 conn = redis.Redis(connection_pool=POOL) # 设置池 conn.set(key,value)
redis_pool.py
# -*- coding:utf-8 -*- import redis # 创建连接池 # 单例模式 不然性能就降低了 POOL = redis.ConnectionPool(host="10.0.0.200", port=6379, password="luffy1234", max_connections=1000)
四、redis 特点 - 基本操作(字典)、hscan_iter(取一部分,否则数据量大就会爆栈)、计数器 hincrby
1. 特点:
a. 持久化 AOF、RDB
b. 单进程、单线程
c. 5大数据类型
redis={
k1:'123', 字符串
k2:[1,2,3,4,4,2,1], 列表
k3:{1,2,3,4}, 集合
k4:{name:123,age:666}, 字典
k5:{('alex',60),('eva-j',80),('rt',70),},有序集合
}
注意事项:redis操作时,只有第一层value支持:list,dict
2. 使用 - 字典操作:
https://www.cnblogs.com/wupeiqi/articles/5132791.html
hset hget hgetall
hmset hmget
# -*- coding:utf-8 -*- import redis pool = redis.ConnectionPool(host="10.0.0.200", port=6379, password="luffy1234", max_connections=1000) conn = redis.Redis(connection_pool=pool) # 字典操作 """ redis = { k4:{ username:alex age:18 } } """ conn.hset('k4','username','alex') conn.hset('k4','age',18) val = conn.hget('k4','username') print(val) vals = conn.hgetall("k4") print(vals) ------------------------ conn.hmset("k4",{"username":"alex","age":20}) # val = conn.hmget("k4","username","age") val = conn.hmget("k4",["username","age"]) print(val)
3. 计数器 +1 / -1 网站浏览得次数 hincrby 增加 减少
print(conn.hget('k4','age')) conn.hincrby('k4','age',amount=-2) print(conn.hget('k4','age'))
4. 如果redis得k4 对应得字典中有1000w条数据,打印所有得数据
这样数据 太大 不行;从redis取到数据之后,服务器内存无法承受,爆栈
# res = conn.hgetall('k4') # 不能这样用 得先看他得长度 # print(res)
应该使用迭代器 conn.hsacn_iter("k4", count=100) # 每次取100条
print(conn.hlen('k4')) ret = conn.hscan_iter("k4",count=1) for item in ret: print(item)
五、redis 操作 - (列表) - list_iter(数据量大,利用生成器,自己去实现)
https://www.cnblogs.com/wupeiqi/articles/5132791.html
lpush rpush
lpop blpop
rpop brpop
左右操作,阻塞,通过yield创建生成器,
ps: 队列:先进先出 栈:后进先出
事务:一次发送多个命令
import redis """ redis = { k1:[1,2,3,43,45] } """ conn = redis.Redis(host='47.94.172.250',port=6379,password='Luffy!4321') # 左插入 # conn.lpush('k1',11) # 右插入 # conn.rpush('k1',33) # 左获取 # val = conn.lpop('k1') # val = conn.blpop('k1',timeout=10) # hang住 # 右获取 # val = conn.rpop('k1') # val = conn.brpop('k1',timeout=10) # hang住
如果redis得列表中有1000w条数据,打印所有得数据
利用生成器,需要自己手动去实现
字典,集合有scan_iter, 但是列表没有,需要自己手动去写利用生成器
# 列表100w 条数据,全部打印出来 # scan_iter 字典 集合 有,但是 列表没有 需要自己实现 # 生成器给列表 。。一点一点 设置 缓存取数据; # conn.lpush("k3",*[1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20]) # print(conn.lrange("k3",0,100)) def list_iter(key,count=100): index = 0 while True: data_list = conn.lrange(key,index,index+count-1) if not data_list: return index += count for item in data_list: yield item res = list_iter("k3",count=10) for item in res: print(item)
六、redis 操作 - 事务
pipeline
import redis """ redis = { k1:[1,2,3,43,45] } """ conn = redis.Redis(host='47.94.172.250',port=6379,password='Luffy!4321') pipe = conn.pipeline(transaction=True) pipe.multi() pipe.set('k2','123') pipe.hset('k3','n1',666) pipe.lpush('k4','laonanhai') pipe.execute()
七、redis 应用 - django
1. 自定义连接池
# urls.py from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), url(r'^order/', views.order), ] --------------------------------- # views.py from django.shortcuts import render,HttpResponse import redis from utils.redis_pool import POOL def index(request): conn = redis.Redis(connection_pool=POOL) conn.hset("kkk",'age',18) return HttpResponse("设置成功") def order(request): conn = redis.Redis(connection_pool=POOL) val = conn.hget("kkk",'age') return HttpResponse("获取成功:"+val.decode("utf-8")) --------------------------------- # utils / redis_pool.py import redis # 创建连接池 # 单例模式 不然性能就降低了 POOL = redis.ConnectionPool(host="10.0.0.200", port=6379, password="luffy1234", max_connections=1000)
2. 手动操作redis
import redis from django.shortcuts import render,HttpResponse from django_redis import get_redis_connection def index(request): conn = get_redis_connection("default") return HttpResponse('设置成功') def order(request): conn = get_redis_connection("back") return HttpResponse('获取成功')
pip3 install django-redis
CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100} # "PASSWORD": "密码", } } }
from django_redis import get_redis_connection conn = get_redis_connection("default")
setting.py
# redis 配置 CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://10.0.0.200:6379", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100}, "PASSWORD": "luffy1234", } }, "back":{ "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://10.0.0.200:6379", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100} # "PASSWORD": "密码", } } }
3. django配置 - 全站缓存 局部 ...
a. 全站使用
使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存 MIDDLEWARE = [ 'django.middleware.cache.UpdateCacheMiddleware', # 其他中间件... 'django.middleware.cache.FetchFromCacheMiddleware', ] CACHE_MIDDLEWARE_ALIAS = "" CACHE_MIDDLEWARE_SECONDS = "" CACHE_MIDDLEWARE_KEY_PREFIX = ""
b. 单独视图缓存
方式一: from django.views.decorators.cache import cache_page @cache_page(60 * 15) def my_view(request): ... 方式二: from django.views.decorators.cache import cache_page urlpatterns = [ url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)), ]
c、局部视图使用
a. 引入TemplateTag {% load cache %} b. 使用缓存 {% cache 5000 缓存key %} 缓存内容 {% endcache %}
更多:猛击这里
测试:
如果缓存生效了,那么刷新页面,时间不会发生变化,因为是从缓存中取得
from django.shortcuts import render, HttpResponse import time from django.views.decorators.cache import cache_page from django_redis import get_redis_connection conn = get_redis_connection("default") # @cache_page(60*15) # s 15min def index(request): ctime = str(time.time()) return HttpResponse(ctime) def order(request): ctime = str(time.time()) return HttpResponse(ctime)
补充:rest framework框架访问频率限制推荐放到 redis/memecached
八、redis 补充- 操作 - 增删改查
对字典,重新设计结构,增删改查。
hmset keys hget scan_iter hgetall
import redis import json conn = redis.Redis(host='140.143.227.206',port=6379,password='1234') """ -----> 第一版 { luffy_shopping_car:{ 6:{ 11:{ 'title':'21天入门到放弃', 'src':'xxx.png' }, 12:{ 'title':'21天入门到放弃', 'src':'xxx.png' } } } } -----> 第二版 { luffy_shopping_car_6_11:{ 'title':'21天入门到放弃', 'src':'xxx.png' }, luffy_shopping_car_6_12:{ 'title':'21天入门到放弃', 'src':'xxx.png' }, luffy_shopping_car_6_14:{ 'title':'21天入门到放弃', 'src':'xxx.png' } } """ # conn.flushall() # 添加课程 # redis_key = "luffy_shopping_car_%s_%s" %(7,12,) # conn.hmset(redis_key,{'title':'21天入门到放弃','src':'xxx.png'}) # 删除课程 # conn.delete('luffy_shopping_car_6_12') # print(conn.keys()) # 修改课程 # conn.hset('luffy_shopping_car_6_11','src','x1.png') # print(conn.hget('luffy_shopping_car_6_11','src')) # 查看所有课程 # print(conn.keys("luffy_shopping_car_6_*")) # for item in conn.scan_iter('luffy_shopping_car_6_*',count=10): # course = conn.hgetall(item) # print(course) # conn.set('k1',123) # print(conn.type('luffy_shopping_car_6_11')) # print(conn.type('k1')) from django.core.cache import cache # print(conn.keys()) # # for key in conn.scan_iter("luffy_shopping_car_1*"): # # title = conn.hget(key,'title') # img = conn.hget(key, 'img') # policy = conn.hget(key, 'policy') # default_policy = conn.hget(key, 'default_policy') # # # print(str(title,encoding='utf-8')) # print(str(img,encoding='utf-8')) # print(json.loads(str(policy,encoding='utf-8'))) # print(str(default_policy,encoding='utf-8')) print(conn.keys()) conn.scan_iter() print(conn.exists('luffy_sg_car_1_1'))
九、redis 补充 - 分布式、高可用、读写分离
redis http://www.cnblogs.com/wupeiqi/articles/9348938.html 1. redis是什么? 是一个由C语言编写的对内存进行存取数据的软件(NoSQL数据库;非关系型数据库); 2. redis是单进程单线程的。 3. redis基础: - 5大数据类型; - 字符串 - 列表 - 字典 - 集合 - 有序结合 - 发布和订阅 - 事务 4. 主从 = 高可用 = HA 服务器A:10.211.55.19 redis-server /etc/redis-6379.conf # 内部bind:0.0.0.0 port: 6379 服务器B: 10.211.55.20 redis-server /etc/redis-6379.conf # 内部bind:0.0.0.0 port: 6379 slaveof: 10.211.55.19 特殊情况来了:如果主宕机,应该讲从切换成主; 手动: - 登录redis将从变成主 - 修改代码,将连接字符串IP改成10.211.55.20 自动: - keepalived,监听服务器的状态做高可用;第三方组件; - sentinel(哨兵),检测redis主服务器的状态并将所有的slave获取到,一旦主挂掉,则立即将从切换成主; redis-sentinel /etc/redis-sentinel-26379.conf(主IP,失败个数) redis-sentinel /etc/redis-sentinel-26380.conf redis-sentinel /etc/redis-sentinel-26381.conf Python操作: from redis.sentinel import Sentinel # 连接哨兵服务器(主机名也可以用域名) sentinel = Sentinel([('10.211.55.20', 26379)],socket_timeout=0.5) # # 获取主服务器地址 # master = sentinel.discover_master('mymaster') # print(master) # # # # 获取从服务器地址 # slave = sentinel.discover_slaves('mymaster') # print(slave) # # # # # 获取主服务器进行写入 # master = sentinel.master_for('mymaster') # master.set('foo', 'bar') # # # # 获取从服务器进行读取(默认是round-roubin) # slave = sentinel.slave_for('mymaster', password='redis_auth_pass') # r_ret = slave.get('foo') # print(r_ret) 总结: - 高可用 - 读写分离 5. 集群=分布式 如何实现分布式集群: - codis,国产 豌豆荚 开源; - twemproxy,twitter开源 - cluster,redis官方提供 redis的cluster的原理? 16384槽位 服务器A: 0-5000 服务器B: 5001-10000 服务器B: 10001 - 16384 Python操作redis cluester: redis-py-cluster模块 6. 分布式锁 redlock算法 dlm = Redlock([{"host": "localhost", "port": 6379, "db": 0}, ]) # 如果 my_lock有值,则表示获取锁了 # 如果 my_lock无值,则表示未获取锁,别人获取走了。 my_lock = dlm.lock("my_resource_name",1000) dlm.unlock(my_lock) # 删除时调用lru脚本 redis分布式锁实现原理: 1. 配置所有要连接的服务器并计算服务器一半的个数; 2. 获取锁: - 传入参数:key,内部生成随机字符串,超时时间 - 循环所有服务器,在服务器上设置: SET key 随机字符串 NX PX 超时时间 # 如果已经存在则不设置 - 设置成功的个数 >= 一半+1 且 花费时间小于超时时间 3. 释放锁 - 删除key和value(内部调用lru脚本) - 超时释放 7. 其他: - 持久化: - AOF,记录所有命令; - RDB,指定时间间隔做快照; - 过期策略 voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰 volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰 volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰 allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰 allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰 no-enviction(驱逐):禁止驱逐数据 - 不要是直接使用: - key - all 一定要使用scan_iter
十、redis 补充 - 应用
http://www.cnblogs.com/wupeiqi/articles/5132791.html
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
一、Redis安装和基本使用
1
2
3
4
|
wget http: / / download.redis.io / releases / redis - 3.0 . 6.tar .gz tar xzf redis - 3.0 . 6.tar .gz cd redis - 3.0 . 6 make |
启动服务端
1
|
src / redis - server |
启动客户端
1
2
3
4
5
|
src / redis - cli redis> set foo bar OK redis> get foo "bar" |
二、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 |
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
6
7
8
|
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis r = 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
2
3
4
5
6
7
8
9
10
|
#!/usr/bin/env python # -*- coding:utf-8 -*- import redis pool = redis.ConnectionPool(host = '10.211.55.4' , port = 6379 ) r = redis.Redis(connection_pool = pool) r. set ( 'foo' , 'Bar' ) print r.get( 'foo' ) |
3、操作
String操作,redis中的String在在内存中按照一个name对应一个value来存储。如图:
set(name, value, ex=None, px=None, nx=False, xx=False)
123456在Redis中设置值,默认,不存在则创建,存在则修改
参数:
ex,过期时间(秒)
px,过期时间(毫秒)
nx,如果设置为True,则只有name不存在时,当前set操作才执行
xx,如果设置为True,则只有name存在时,岗前set操作才执行
setnx(name, value)
1设置值,只有name不存在时,执行设置操作(添加)
setex(name, value, time)
123# 设置值
# 参数:
# time,过期时间(数字秒 或 timedelta对象)
psetex(name, time_ms, value)
123# 设置值
# 参数:
# time_ms,过期时间(数字毫秒 或 timedelta对象)
mset(*args, **kwargs)
12345批量设置值
如:
mset(k1=
'v1'
, k2=
'v2'
)
或
mget({
'k1'
:
'v1'
,
'k2'
:
'v2'
})
get(name)
1获取值
mget(keys, *args)
12345批量获取
如:
mget(
'ylr'
,
'wupeiqi'
)
或
r.mget([
'ylr'
,
'wupeiqi'
])
getset(name, value)
1设置新值并获取原来的值
getrange(key, start, end)
123456# 获取子序列(根据字节获取,非字符)
# 参数:
# name,Redis 的 name
# start,起始位置(字节)
# end,结束位置(字节)
# 如: "武沛齐" ,0-3表示 "武"
setrange(name, offset, value)
1234# 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
# 参数:
# offset,字符串的索引,字节(一个汉字三个字节)
# value,要设置的值
setbit(name, offset, value)
123456789101112131415161718192021222324252627# 对name对应值的二进制表示的位进行操作
# 参数:
# name,redis的name
# offset,位的索引(将值变换成二进制后再进行索引)
# value,值只能是 1 或 0
# 注:如果在Redis中有一个对应: n1 = "foo",
那么字符串foo的二进制表示为:
01100110
01101111
01101111
所以,如果执行 setbit(
'n1'
,
7
,
1
),则就会将第
7
位设置为
1
,
那么最终二进制则变成
01100111
01101111
01101111
,即:
"goo"
# 扩展,转换二进制表示:
# source = "武沛齐"
source
=
"foo"
for
i
in
source:
num
=
ord
(i)
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)
12345# 获取name对应的值的二进制表示中 1 的个数
# 参数:
# key,Redis的name
# start,位起始位置
# end,位结束位置
bitop(operation, dest, *keys)
12345678910# 获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值
# 参数:
# operation,AND(并) 、 OR(或) 、 NOT(非) 、 XOR(异或)
# dest, 新的Redis的name
# *keys,要查找的Redis的name
# 如:
bitop(
"AND"
,
'new_name'
,
'n1'
,
'n2'
,
'n3'
)
# 获取Redis中n1,n2,n3对应的值,然后讲所有的值做位运算(求并集),然后将结果保存 new_name 对应的值中
strlen(name)
1# 返回name对应值的字节长度(一个汉字3个字节)
incr(self, name, amount=1)
1234567# 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
# 参数:
# name,Redis的name
# amount,自增数(必须是整数)
# 注:同incrby
incrbyfloat(self, name, amount=1.0)
12345# 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
# 参数:
# name,Redis的name
# amount,自增数(浮点型)
decr(self, name, amount=1)
12345# 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
# 参数:
# name,Redis的name
# amount,自减数(整数)
append(key, value)
12345# 在redis name对应的值后面追加内容
# 参数:
key, redis的name
value, 要追加的字符串
Hash操作,redis中Hash在内存中的存储格式如下图:
hset(name, key, value)
123456789# name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
# 参数:
# name,redis的name
# key,name对应的hash中的key
# value,name对应的hash中的value
# 注:
# hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)
hmset(name, mapping)
12345678# 在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)
1234567891011# 在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)
12345# 自增name对应的hash中的指定key的值,不存在则创建key=amount
# 参数:
# name,redis中的name
# key, hash对应的key
# amount,自增数(整数)
hincrbyfloat(name, key, amount=1.0)
12345678# 自增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)
12345678910111213# 增量式迭代获取,对于数据大的数据非常有用,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)
123456789# 利用yield封装hscan创建生成器,实现分批去redis中获取数据
# 参数:
# match,匹配指定key,默认None 表示所有的key
# count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
# 如:
# for item in r.hscan_iter('xx'):
# print item
List操作,redis中的List在在内存中按照一个name对应一个List来存储。如图:
lpush(name,values)
12345678# 在name对应的list中添加元素,每个新的元素都添加到列表的最左边
# 如:
# r.lpush('oo', 11,22,33)
# 保存顺序为: 33,22,11
# 扩展:
# rpush(name, values) 表示从右向左操作
lpushx(name,value)
1234# 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
# 更多:
# rpushx(name, value) 表示从右向左操作
llen(name)
1# name对应的list元素的个数
linsert(name, where, refvalue, value))
1234567# 在name对应的列表的某一个值前或后插入一个新值
# 参数:
# name,redis的name
# where,BEFORE或AFTER
# refvalue,标杆值,即:在它前后插入数据
# value,要插入的数据
r.lset(name, index, value)
123456# 对name对应的list中的某一个索引位置重新赋值
# 参数:
# name,redis的name
# index,list的索引位置
# value,要设置的值
r.lrem(name, value, num)
12345678# 在name对应的list中删除指定的值
# 参数:
# name,redis的name
# value,要删除的值
# num, num=0,删除列表中所有的指定值;
# num=2,从前到后,删除2个;
# num=-2,从后向前,删除2个
lpop(name)
1234# 在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
# 更多:
# rpop(name) 表示从右向左操作
lindex(name, index)
1在name对应的列表中根据索引获取列表元素
lrange(name, start, end)
12345# 在name对应的列表分片获取数据
# 参数:
# name,redis的name
# start,索引的起始位置
# end,索引结束位置
ltrim(name, start, end)
12345# 在name对应的列表中移除没有在start-end索引之间的值
# 参数:
# name,redis的name
# start,索引的起始位置
# end,索引结束位置
rpoplpush(src, dst)
1234# 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
# 参数:
# src,要取数据的列表的name
# dst,要添加数据的列表的name
blpop(keys, timeout)
12345678# 将多个列表排列,按照从左到右去pop对应列表的元素
# 参数:
# keys,redis的name的集合
# timeout,超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞
# 更多:
# r.brpop(keys, timeout),从右向左获取数据
brpoplpush(src, dst, timeout=0)
123456# 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧
# 参数:
# src,取出并要移除元素的列表对应的name
# dst,要插入元素的列表对应的name
# timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞
自定义增量迭代
123456789101112131415161718# 由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要:
# 1、获取name对应的所有列表
# 2、循环列表
# 但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能:
def
list_iter(name):
"""
自定义redis列表增量迭代
:param name: redis中的name,即:迭代name对应的列表
:return: yield 返回 列表元素
"""
list_count
=
r.llen(name)
for
index
in
xrange
(list_count):
yield
r.lindex(name, index)
# 使用
for
item
in
list_iter(
'pp'
):
item
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)
12345# 在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)
123456789101112131415161718# 按照索引范围获取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)
1234# 获取某个值在 name对应的有序集合中的排行(从 0 开始)
# 更多:
# zrevrank(name, value),从大到小排序
zrangebylex(name, min, max, start=None, num=None)
1234567891011121314151617# 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的 值 (lexicographical ordering)来进行排序,而这个命令则可以返回给定的有序集合键 key 中, 元素的值介于 min 和 max 之间的成员
# 对集合中的每个成员进行逐个字节的对比(byte-by-byte compare), 并按照从低到高的顺序, 返回排序后的集合成员。 如果两个字符串有一部分内容是相同的话, 那么命令会认为较长的字符串比较短的字符串要大
# 参数:
# name,redis的name
# min,左区间(值)。 + 表示正无限; - 表示负无限; ( 表示开区间; [ 则表示闭区间
# min,右区间(值)
# start,对结果进行分片处理,索引位置
# num,对结果进行分片处理,索引后面的num个元素
# 如:
# ZADD myzset 0 aa 0 ba 0 ca 0 da 0 ea 0 fa 0 ga
# r.zrangebylex('myzset', "-", "[ca") 结果为:['aa', 'ba', 'ca']
# 更多:
# 从大到小排序
# zrevrangebylex(name, max, min, start=None, num=None)
zrem(name, values)
123# 删除name对应的有序集合中值是values的成员
# 如:zrem('zz', ['s1', 's2'])
zremrangebyrank(name, min, max)
1# 根据排行范围删除
zremrangebyscore(name, min, max)
1# 根据分数范围删除
zremrangebylex(name, min, max)
1# 根据值返回删除
zscore(name, value)
1# 获取name对应有序集合中 value 对应的分数
zinterstore(dest, keys, aggregate=None)
12# 获取两个有序集合的交集,如果遇到相同值不同分数,则按照aggregate进行操作
# aggregate的值为: SUM MIN MAX
zunionstore(dest, keys, aggregate=None)
12# 获取两个有序集合的并集,如果遇到相同值不同分数,则按照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='*')
1234567# 根据模型获取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
4、管道
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 ) r = redis.Redis(connection_pool = pool) # pipe = r.pipeline(transaction=False) pipe = r.pipeline(transaction = True ) pipe.multi() pipe. set ( 'name' , 'alex' ) pipe. set ( 'role' , 'sb' ) pipe.execute() |
5、发布订阅
发布者:服务器
订阅者:Dashboad和数据处理
Demo如下:
订阅者:
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' ) |
6. sentinel
redis重的sentinel主要用于在redis主从复制中,如果master顾上,则自动将slave替换成master
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
28
29
30
|
#!/usr/bin/env python # -*- coding:utf-8 -*- from redis.sentinel import Sentinel # 连接哨兵服务器(主机名也可以用域名) sentinel = Sentinel([( '10.211.55.20' , 26379 ), ( '10.211.55.20' , 26380 ), ], socket_timeout = 0.5 ) # # 获取主服务器地址 # master = sentinel.discover_master('mymaster') # print(master) # # # # 获取从服务器地址 # slave = sentinel.discover_slaves('mymaster') # print(slave) # # # # # 获取主服务器进行写入 # master = sentinel.master_for('mymaster') # master.set('foo', 'bar') # # # # 获取从服务器进行读取(默认是round-roubin) # slave = sentinel.slave_for('mymaster', password='redis_auth_pass') # r_ret = slave.get('foo') # print(r_ret) |
更多参见:https://github.com/andymccurdy/redis-py/
http://doc.redisfans.com/
----------------------------
https://www.cnblogs.com/mituxiaoshutong/p/9968285.html