一站式学习Redis, 从入门到高可用分布式实践-04redis其它功能
04-瑞士军刀redis其它功能
- 慢查询
-
生命周期、两个配置、三个命令、运维经验
-
生命周期两点说明:
慢查询发生在第三阶段(执行命令);
客户端超时不一定是慢查询,但是慢查询是客户端超时的一个可能因素 -
两个配置:
-
slowlog-max-len:
先进先出队列、固定长度、保存在内存内 -
slowlog-log-slower-than:
慢查询阈值(单位:微秒)、
slowlog-log-slower-than=0,记录所有命令
slowlog-log-slower-than<0,不记录任何命令 -
默认值
config get slowlog-max-len
config get slowlog-log-slower-than
-
修改配置文件重启,不建议
-
动态配置
config set slowlog-max-len 1000
config set slowlog-log-slower-than 1000 -
慢查询命令
slowlog get [n] 获取慢查询队列
slowlog len 获取慢查询队列长度
slowlog reset 清空慢查询队列 -
运维经验
slowlog-log-slower-than不要设置过大,默认值是10ms,通常设置1ms
slowlog-max-len慢查询队列大小,默认值是128
理解命令的生命周期
定期持久化慢查询
- pipeline
(1)什么是流水线、客户端时间、与原生操作对比、使用建议
(2)什么是流水线
一次pipeline(n条命令) = 一次网络时间+n次命令时间
(3)流水线的作用
- reids的命令时间是微秒级别的
- pipeline每次条数要控制网略
(4)流水线的作用-续
(5)流水线pipeline效率比对
import time
import redis
pool = redis.ConnectionPool(host="xxxxx", port=6382, db=1, password="xxxx")
r = redis.Redis(connection_pool=pool)
# 不使用pipeline时
"""
# 计时开始
start = time.time()
for i in range(10000):
r.hset(f"hashkey:{i}", f"field{i}", f"value{i}")
print(time.time() - start) # 执行时间312秒
"""
# 使用pipeline时
start = time.time()
for i in range(100):
pipe = r.pipeline() # 管道/流水线默认是原子的,也可以关闭transaction=False
for j in range(100*i, 100*(i+1)):
pipe.hset(f"hashkey:{j}", f"field{j}", f"value{j}")
pipe.execute()
print(time.time() - start) # 执行耗时7s, 比上面不使用pipeline快了40多倍
# 使用pipeline时-2调整每次传输100个命令为1000个命令,效率又显著提高了
start = time.time()
for i in range(10):
pipe = r.pipeline() # 管道/流水线默认是原子的,也可以关闭transaction=False
for j in range(1000*i, 1000*(i+1)):
pipe.hset(f"hashkey:{j}", f"field{j}", f"value{j}")
pipe.execute()
print(time.time() - start) # 执行耗时1s, 比上面不使用pipeline快了300多倍
(6)使用建议
- 注意每次pipeline携带的数据量
- pipeline每次只能作用在一个redis节点上
- M操作与pipeline的区别
- 发布订阅
(1)角色、模型、API、发布订阅与消息队列
(2)角色:发布者publisher、订阅者subscriber、频道channel
(3)模型:
(4)发布订阅角色和模型
(5)发布订阅API
publish subscribe unsubscribe 其它
(6)发布订阅案例
一个发布者,两个订阅者
- 两个订阅者
import redis
from threading import Thread, current_thread
pool = redis.ConnectionPool(host="xxxxxx", port=6382, db=0, password="xxxxxx")
r = redis.Redis(connection_pool=pool)
class PubSub(object):
def __init__(self):
self.pub = r.pubsub()
def subscribe(self, *args):
self.pub.subscribe(*args)
self.pub.parse_response()
self.pub.parse_response()
return self.pub
def subscribe(p):
while True:
msg = p.parse_response()
for i in msg:
print(current_thread().name, i.decode(encoding="utf8"))
if __name__ == '__main__':
# 开启一个订阅者
t1 = Thread(target=subscribe, args=(PubSub().subscribe("my-first-channel", "my-second-channel"),))
t1.start()
# 开启第二个订阅者
t2 = Thread(target=subscribe, args=(PubSub().subscribe("my-first-channel", "my-third-channel"),))
t2.start()
# 等待所有子线程结束,主线程在结束
t1.join()
t2.join()
- 一个发布者
import redis
pool = redis.ConnectionPool(host="xxxxxx", port=6382, db=0, password="xxxxx")
r = redis.Redis(connection_pool=pool)
r.publish("my-first-channel", "first:哈哈哈")
r.publish("my-second-channel", "second:嘿嘿嘿")
r.publish("my-third-channel", "third:呵呵呵")
-
bitmap
-
HyperLogLog
(1)新的数据结构
基于hyperloglog算法:极小空间完成独立数量统计
本质还是字符串
(2)三个命令
pfadd key element [element] 向hyperloglog中添加元素
pfcount key 计算Hyperloglog独立总数
pfmerge destkey sourcekey [sourcekey ...] 合并多个hyperloglog
(3)内存消耗
(4)使用经验