前言: 本来想写 redis 与 rabbitMQ 的,但写完 redis 后感觉有点多,rabbitMQ 还是留在下篇博客吧~~
关于 redis 与 rabbitMQ 的下载与安装,可参考
- 1 importredis
- 2 #建立连接
- 3 r=redis.Redis(host="127.0.0.1",port=6379)
- 4
- 5 all_keys=r.keys()#输出所有key,列表[b'age',b'name',b'occupation']
- 6 for k in all_keys:
- 7 print(k,r.get(k))
- 8
- 9 print(r.keys())
- 10
- 11 r.set("sister","yongli",ex=5) #存入缓存,5秒后清除
- 12
- 13 print(r.get("sister"))
- 14
- 15 r.set("father","jingxian",nx=True) #只有father不存在时,当前set操作才执行
- 16 print(r.get("father"))
- 17
- 18 r.set("AA","BB",xx=True) #只有AA存在时,当前set操作才执行
- 19 print(r.get("AA"))
- 20
- 21
- 22 r.mset(k1="v1",k2="v2") #批量设置值
- 23 print(r.mget("k1","k2")) #批量获取值
- 24
- 25
- 26 r.set("id","3114007487")
- 27 print(r.getrange("id",3,6)) #获取子序列(切片,0开始)
- 28
- 29 r.setrange("id",3,"AAA") #修改字符串内容,从指定字符串索引开始向后替换
- 30 print(r.getrange("id",0,-1)) #输出:b'311AAA7487'
- 31
- 32 #"3" 对应ASCII码为51, 二进制为 0011 0011
- 33 print(r.getbit("id",7))
- 34 r.setbit("id",7,0) #将第7位改为0,第0位开始算 0011 0010 : 50 对应为2
- 35 print(r.getbit("id",7))
- 36 print(r.getbit("id",1000))#读取位数超过,不爆错
- 37 print(r.get("id"))
运行结果:
View Code
- 1 b'age' b'22'
- 2 b'id' b'211AAA7487'
- 3 b'k2' b'v2'
- 4 b'k1' b'v1'
- 5 b'name' b'abc'
- 6 b'occupation' b'student'
- 7 b'father' b'BB'
- 8 [b'age', b'id', b'k2', b'k1', b'name', b'occupation', b'father']
- 9 b'yongli'
- 10 b'BB'
- 11 None
- 12 [b'v1', b'v2']
- 13 b'4007'
- 14 b'311AAA7487'
- 15 1
- 16 0
- 17 0
- 18 b'211AAA7487'
redis 基本操作 - 2(供拓展)
View Code
- getbit(name, offset)
- 1 # 获取name对应的值的二进制表示中的某位的值 (0或1)
- bitcount(key, start=None, end=None)
- 1 # 获取name对应的值的二进制表示中 1 的个数
- 2 # 参数:
- 3 # key,Redis的name
- 4 # start,位起始位置
- 5 # end,位结束位置
- strlen(name)
- 1 # 返回name对应值的字节长度(一个汉字3个字节)
- incr(self, name, amount=1)可用于计算PV
- 1 # 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
- 2
- 3 # 参数:
- 4 # name,Redis的name
- 5 # amount,自增数(必须是整数)
- 6
- strlen(name)
- 1 # 返回name对应值的字节长度(一个汉字3个字节)
- decr(self, name, amount=1)
- 1 # 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
- 2
- 3 # 参数:
- 4 # name,Redis的name
- 5 # amount,自减数(整数)
- append(key, value)返回字符的长度
- 1 # 在redis name对应的值后面追加内容
- 2
- 3 # 参数:
- 4 key, redis的name
- 5 value, 要追加的字符串
上面是 redis 的基本操作,建议一句句实验下。
redis 是一种 no-sql 缓存数据库。数据是存在缓存中的。所以你如果重启 redis-server,会发现之前存的数据都消失了! 为了解决这个问题,可在存数据后加上 save 命令, 数据便会存到磁盘,重启后数据不会消失。
1. 连接池
使用 connection pool 来管理对一个 redis server 的所有连接,避免每次建立、释放连接的开销。
- 1 import redis
- 2
- 3 pool = redis.ConnectionPool(host='10.211.55.4', port=6379)
- 4 r = redis.Redis(connection_pool=pool)
2. 计算网站 UV 实例
关于 PV,UV,IP 可以看看我下面的总结,具体也可以参考博客:
View Code
- PV(page view)即页面浏览量或点击量,是衡量一个网站或网页用户访问量。具体的说,PV值就是所有访问者在24小时(0点到24点)内看了某个网站多少个页面或某个网页多少次。PV是指页面刷新的次数,每一次页面刷新,就算做一次PV流量。
- UV(unique visitor)即独立访客数,指访问某个站点或点击某个网页的不同IP地址的人数。在同一天内,UV只记录第一次进入网站的具有独立IP的访问者,在同一天内再次访问该网站则不计数。
- IP可以理解为独立IP的访问用户,指1天内使用不同IP地址的用户访问网站的数量,同一IP无论访问了几个页面,独立IP数均为1。
setbit 巨流弊的应用场景,想想什么情况下会用到这个功能呢?超大型的应用平台,比如新浪微博,我想查看当前正在登陆的用户,如何实现?当然你会想到,用户登陆后在数据库上的用户信息上做个标记,然后 count 去统计做标记的用户一共有多少,so,当前用户查看迎刃而解;OK,好好,首先每个用户登录都要设置标记,如果当前用户几个亿,那么得存几个亿的标记位,超级占用库的开销;现在就有一个无敌高效的办法,利用二进制位统计当前在线用户,什么意思呢?看下面的代码就能明白了:
View Code
- 1 import redis
- 2 #建立连接
- 3 pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
- 4 r = redis.Redis(connection_pool=pool)
- 5
- 6 r.setbit("uv_count1", 5,1) #每来一个连接,则让字节位设为1
- 7 r.setbit("uv_count1", 8,1)
- 8 r.setbit("uv_count1", 3,1)
- 9 r.setbit("uv_count1", 3,1)#重复的不计算
- 10 print("uv_count:", r.bitcount("uv_count1"))
- 11
- 12 输出:uv_count: 3
比如: 当前第 500 位用户在线,则将第 500 个 bit 置为 1(默认为 0)。bitcount 统计二级制位中 1 的个数,setbit 和 bitcount 配合使用,轻松解决当前在线用户数的问题。1 字节 = 8 位,那么 10m=8000 万位,即一个亿的在线用户也就 10m 多的内存就可搞定,这优化不得了!!
我会直接用运行的截图来讲 hash,list,set 基本操作,不然有点无聊~~
Hash 操作,redis 中 Hash 在内存中的存储格式如下图:
1. hash 基本操作
List 操作,redis 中的 List 在在内存中按照一个 name 对应一个 List 来存储。如图:
2. list 基本操作
列表的某一个值前或后插入一个新值
r.lpush() 从左边开始放数据
r.rpush() 从右边开始放数据
3. set 基本操作
1. 16 个数据库
Redis 有默认 16 个数据库,默认在 0 库,可以切换 (eg: 切换到 15 号数据库: select 15);但在 python 中,出于安全考虑,在 python 的 API 没有切换数据库的概念,可以在连接调用时指定调用的数据库,但一连接上了就不能切换了。
- move(name, db))
- # 将redis的某个值移动到指定的db下
2. 有序集合
有序集合: 在集合的基础上,为每个元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。
有序集合的基本操作
应用场景: 一登陆QQ右上角会有广告。
发布者: 服务器
订阅者: 个人用户
发布与订阅必须在同一个频道上 (类似于收音机),不然发布方发布后,订阅方接收不到!
redis_helper.py 文件 (公共类)
- 1 import redis
- 2
- 3
- 4 class RedisHelper(object):
- 5
- 6 def __init__(self):
- 7 self.__conn=redis.Redis(host='127.0.0.1')
- 8 self.chan_sub='fm88.7' #设置两个频道,订阅频道
- 9 self.chan_pub='fm88.7' #发布频道
- 10
- 11 def public(self,msg):
- 12 self.__conn.publish(self.chan_pub,msg) #发布消息
- 13 returnTrue
- 14
- 15 def subscribe(self):
- 16 pub=self.__conn.pubsub() #生成实例打开收音机
- 17 pub.subscribe(self.chan_sub) #拧到那个台
- 18 m=pub.parse_response() #准备听,未阻塞,再调用一次就阻塞
- 19 print(m) #[b'subscribe', b'fm88.7', 1]
- 20 return pub #返回实例
redis_sub.py
- 1 from redis_helper import RedisHelper
- 2
- 3 obj=RedisHelper()
- 4 redis_sub=obj.subscribe() #返回实例
- 5
- 6 while True:7 msg=redis_sub.parse_response() #听
- 8 print(msg) #有消息则打印,无消息则阻塞
redis_pub.py
- from redis_helper importRedisHelper
- obj=RedisHelper()
- return1=obj.public('love')
- print(return1)
运行结果 (客户端): 可并发处理多个客户端。
- [b'subscribe', b'fm88.7', 1]
- [b'message', b'fm88.7', b'love']
- [b'message', b'fm88.7', b'love']
来源: