赞
踩
import redis
# decode_responses=True将二进制转换成字符串存储;decode_responses=False就是二进制储存
redis_pool = redis.ConnectionPool(
host='127.0.0.1',
port=6379,
db=0,
decode_responses=True)
r0 = redis.Redis(connection_pool=redis_pool)
print(r0)
1、字符串
直接存的键值对,根据key来获取value,在存键值对的时候加上过期时间,就不会将数据永久保存,加强的利用率
a = r0.set('string1', 's1', ex=60) print(a) b = r0.get('string1') print(b) # nx:nx为True,则只有key不存在时,操作才会执行 # xx:xx为True,则只有key存在时,操作才会执行 a = r0.set('string1', 's1', xx=True) print(a) a = r0.set('string1', 's11', nx=True) print(a) # setrange(key, start, end) 修改字符串内容,从指定字符串索引开始向后替换 # getrange(key, start, end) 获取子序列(根据字节获取,非字符) r0.setrange('key6', 2, '222') print(r0.get('key6')) print(r0.getrange('key6', 1, 3)) # strlen(key) 返回key对应值的字节长度 # 删除键 r0.delete('key6') print(r0.get('key6')) # 清空数据库 # r0.flushdb()
2、hash
以表,键,值的方式储存,存或者取的时候需要知道表和键,才能获取到存的值。
r0.hset('table1', 'k1', 'v1')
r0.hset('table1', 'k2', 'v2')
r0.hset('table1', 'k3', 'v3')
a = r0.hget('table1', 'k1')
print(a)
a = r0.hmget('table1', 'k1', 'k2', 'k3')
print(a)
# hgetall(name) 取出所有的键值对
r0.hdel('table1', 'k1', 'v1')
print(r0.hgetall('table1'))
# r0.flushdb()
3、list
以列表的方式储存。
# 从左边插入 r0.lpush('list2', 1111111, 222222, 33333333) 从右边插入 r0.rpush('list1', 11, 22, 33) a = r0.lrange('list1', 0, -1) print(a) # linsert(name, where, refvalue, value)) 新增(固定索引号位置插入元素) # 参数:where - BEFORE或AFTER; refvalue - 标杆值,即:在它前后插入数据; value - 要插入的数据 r0.linsert('list1', 'before', '1', '666') r0.linsert('list1', 'after', '2', '777') a = r0.lrange('list1', 0, -1) print(a) # r.lset(name, index, value) 修改(指定索引号进行修改) r0.lset('list1', 1, '0000') a = r0.lrange('list1', 0, -1) print(a) # r.lrem(name, count, value) 删除(指定值进行删除) # 参数:value - 要删除的值; count=0,删除列表中所有的指定值; count=2 - 从前到后,删除2个, count=1,从前到后,删除左边第1个; count=-2 - 从后向前,删除2个 r0.lrem("list1", -1, '1') # 将列表中所有的"22"删除 a = r0.lrange('list1', 0, -1) print(a) # lpop(name) 删除并返回; rpop(name) 表示从右向左操作 b = r0.lpop('list1') print(b) a = r0.lrange('list1', 0, -1) print(a) a = r0.lrange('list2', 0, -1) print(a) # lindex(name, index) 取值(根据索引号取值) r = r0.lindex('list1', 2) print(r) # rpoplpush(src, dst) 移动 元素从一个列表移动到另外一个列表 移动list2的右边的一个元素,从左边插入到list1 r0.rpoplpush('list2', 'list1') a = r0.lrange('list1', 0, -1) print(a) a = r0.lrange('list2', 0, -1) print(a)
4、无序set
以集合的方式储存,且是无序的。
r0.sadd('set1', 1, 2, 3) r0.sadd('set2', 1, 22, 33) a = r0.smembers('set1') print(a) b = r0.smembers('set2') print(b) c = a - b print(c) # sdiff(keys, *args) 差集 print(r0.sdiff('set1', 'set2')) # 在集合set1但是不在集合set2中 print(r0.sdiff("set2", "set1")) # 在集合set2但是不在集合set1中 # sdiffstore(dest, keys, *args) 差集--差集存在一个新的集合中 r0.sdiffstore("set3", "set1", "set2") # 在集合set1但是不在集合set2中 b = r0.smembers('set3') print(b) # sinter(keys, *args) 交集 print(r0.sinter('set1', 'set2')) # 取2个集合的交集 # sinterstore(dest, keys, *args) 交集--交集存在一个新的集合中 r0.sinterstore('set4', 'set1', 'set2') print(r0.smembers('set4')) # sunion(keys, *args) 并集 print(r0.sunion("set1", "set2")) # 取2个集合的并集 # sunionstore(dest,keys, *args) 并集--并集存在一个新的集合 r0.sunionstore("set5", "set1", "set2") # 取2个集合的并集 print(r0.smembers("set5")) # sismember(name, value) 判断是否是集合的成员 类似in print(r0.sismember('set1', 1)) # smove(src, dst, value) 将某个成员从一个集合中移动到另外一个集合 r0.smove("set1", "set2", 2) print(r0.smembers("set1")) print(r0.smembers("set2")) # srem(name, values) 指定值删除 print(r0.srem("set2", 33)) # 从集合中删除指定值 1 print(r0.smembers("set2"))
5、有序set(暂无,需要可百度其他地方)
#1、至少需要六台服务器,才能搭建集群
#2、一个 Redis 集群包含 16384 个插槽(hash slot), 数据库中的每个键都属于这 16384 个插槽的其中一个
#3、连接redis集群的时候,会将集群的所有端口都链接上,去获取数据
#4、当主机挂掉后,从机立马会接替主机的工作,继续提供服务(从机就会变成主机,后续之前的主机修复好会变成从机)
集群连接
from rediscluster import RedisCluster def cmd_cluster(): try: startup_nodes = [ {'host': "127.0.0.1", 'port': 6379}, {'host': "127.0.0.1", 'port': 6380}, {'host': "127.0.0.1", 'port': 6381}, {'host': "127.0.0.1", 'port': 6382}, {'host': "127.0.0.1", 'port': 6383}, {'host': "127.0.0.1", 'port': 6384}, ] # 连接redis集群 redis_conn = RedisCluster(startup_nodes=startup_nodes, password='111111').connection if not redis_conn: print("连接redis集群失败") exit() else: print("连接redis集群成功") except Exception as e: print(e) print("错误,连接redis 集群失败")
1、 redis穿透:
概念:大量请求一个不存在的key
缓存穿透产生的原因:请求根本不存在的资源(DB不存在,redis也不存在)
举例:客户端发送大量不可响应的请求
当大量的客户端发送出该图的请求是,就可能导致缓存穿透的情况出现。
因为数据库中没有该数据,redis中也没有该数据,那么这些请求在redis得不到响应,就会去DB,导致DB压力过大而卡死或死机。
#解决方式:
#1、对空值进行缓存:
假如有多个请求的时候,redis就会对该数据进行缓存(key=0, value=null),当请求到达redis的时候就会返回一个null给客户端,避免了大量无法访问的数据直接请求DB。
这样的话,假如出现很多个不同存在的请求,譬如id=-1,id=-2,…,将空值进行缓存会占用很多redis空间,所以要给key设置过期时间,而且时间不能太长
此解决方法炜被动防御方式,假如黑客暴力请求到很多不存在的数据的时候,会写很多空值到redis数据库中,可能会导致内存不足的情况
#2、实时监控:
对redis进行实时监控,发现redis命中率下降的时候,对访问对象和访问数据进行原因的排查和分析,将其拉入黑名单,禁止服务(有可能是黑客攻击)。
#3、使用布隆过滤器
将所有可以访问的资源放入到布隆过滤器,当一个请求来的时候,先进性布隆过滤器的判断,如果有再放行,否则就直接拦截。
布隆过滤器的特点是:判断不存在是一定不存在,判断存在不一定存在,所以其判断有一定的误差;所以需要做一些其他操作来解决其特点,譬如进行接口限流,权限校验等
#4、进行接口校验
类似与用户拦截之类的,对于无效的访问直接进行拦截,不允许这些访问到数据库(redis,DB)上
2、redis缓存雪崩:
概念:redis中大量的key过期
缓存雪崩产生的原因:大量并发来请求这些过期的key(DB有数据,redis没有数据)
#解决方式:
#1、将失效的时间分隔开:
使用自动随机数生成key过期时间,防止集体过期
#2、设置缓存标记
记录缓存数据是否过期,假如过期会通知后台去更新实际的key
#3、使用多级架构去缓存数据
使用nginx缓存+redis缓存+其他缓存,不同层使用不同的缓存,可靠性更强
#4、使用锁或者队列的形式
如果查不到就加上排他锁,其他的请求只能等待
3、redis缓存击穿:
概念:redis中的热点key过期
产生原因:大量的请求这一个过期的key(DB有数据,redis没有数据)
#举例:
对于热搜,这时候大量用户都在访问该热点事件,但是可能优于某种原因,redis的这个热点key过期了,那么这时候大量高并发对于该key的请求就得不到redis的响应,那么就会将请求直接打在DB服务器上,导致整个DB瘫痪死机。
#解决方式:
#1、提前对热点的key进行设置
对于这些热点数据,预先设置到redis中
#2、监控数据,进行调整
监控哪些数据是热门数据,然后对key的过期时间进行调整
#3、使用锁机制
当数据不存在时,只有一个请求可以获取到互斥锁,然后将DB中的数据写入到redis数据库中,之后的所有请求就会从redis数据库响应。
1、内存储存
Redis将数据存储在内存中,这样可以快速读取和写入数据。同时,Redis还支持将内存中的数据持久化到磁盘中,实现数据的持久化存储。
RDB和AOF储存
RDB快照形式:是直接把内存中的数据保存到一个dump文件中,定时保存。有一段时间的数据没有
AOF储存:在配置中开启appendonly yes,redis每执行一条修改数据的命令,都会被记下来,添加到AOF文件中;所以其文件体积比RDB储存大很多。
#redis默认的是RDB快照储存
2、单线程模型
Redis采用单线程模型来处理客户端请求。在单线程模型下,Redis通过事件轮询机制来处理客户端的请求。这种方式可以避免多线程之间的竞争和锁的开销,提高了数据处理的效率。
3、命令解析和执行:
当客户端发送请求给Redis服务器时,Redis会根据请求的类型和参数来解析请求,并执行相应的命令。命令执行过程中,会涉及到对数据的读取、写入和计算等操作。
4、网络通信:
Redis使用TCP/IP协议进行客户端和服务器之间的通信。客户端通过发送请求到Redis服务器来获取数据或修改数据。
TCP协议:负责在网络中建立稳定连接,来确保数据传送的可靠性
IP协议:负责数据传输,将数据从一个节点传输到另一个节点
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。