【慢查询】
1 # 1 我们配置一个时间,如果查询时间超过了我们设置的时间,我们就认为这是一个慢查询 2 # 2 慢查询是一个先进先出的队列,固定长度,保存在内存中--->通过设置慢查询,以后超过我们设置时间的命令,就会放在这个队列中 3 # 3 后期我们通过查询这个队列,过滤出 慢命令--》优化慢命令 4 5 6 # 4 实操: 7 1 配置慢查询 8 # 设置记录所有命令 9 config set slowlog-log-slower-than 0 10 # 最多记录100条 11 config set slowlog-max-len 100 12 # 持久化到本地配置文件 13 config rewrite 14 15 2 查看慢查询队列 16 slowlog get [n] #获取慢查询队列 17 ''' 18 日志由4个属性组成: 19 1)日志的标识id 20 2)发生的时间戳 21 3)命令耗时 22 4)执行的命令和参数 23 ''' 24 slowlog len #获取慢查询队列长度 25 slowlog reset #清空慢查询队列 26 27 28 # mysql : slow_query_log
。
。
【pipline命令管道】
1 #1 Redis的pipeline(管道)功能在命令行中没有,但redis是支持pipeline的,而且在各个语言版的client中都有相应的实现 2 3 # 2 pipeline期间将“独占”链接,多个命令,放到一个pipline(管道中),要么都执行,要么都不执行 4 5 # 3 python中使用pipline 6 import redis 7 8 pool = redis.ConnectionPool(host='192.168.241.129', port=6379, password='jh123') 9 conn = redis.Redis(connection_pool=pool) 10 # pipe = r.pipeline(transaction=False) 11 # 创建pipeline 12 pipe =conn.pipeline(transaction=True) 13 # 开启事务 14 pipe.multi() 15 16 pipe.set('name', 'jh') 17 # 其他代码,可能出异常 18 pipe.set('role', 'nb') 19 20 pipe.execute() 21 22 23 # 4 事务四大特性 24 -原子性 25 -持久性 26 -一致性 27 -隔离性 28 # 6 redis有没有事务,能不能有这四大特性? 29 -因为redis,能实现事务的四大特性---》咱们说它支持 30 -通过pipline实现原子性--》通过pipline可以实现事务 31 -pipline只支持单实例,集群环境,不支持---》集群环境不支持事务 32 33 34 # 7 原生操作,实现乐观锁 35 36 # 7.1 mutil 开启事务,放到管道中一次性执行 37 multi # 开启事务 38 set name xxxx 39 set age 18 40 exec ,然后再去查,就发现数据改了 41 42 43 # 7.2 模拟事务回顾 ,乐观锁 44 # 在开启事务之前,先watch 45 watch age 46 multi 47 decr age 48 exec 49 50 # 另一台机器 51 multi 52 decr age 53 exec # 先执行,上面的执行就会失败(乐观锁,被wathc的事务不会执行成功) 54 55 56 57 # 7.3 使用redis实现乐观锁 58 59 60 ## 利用redis的乐观锁,实现秒杀系统的数据同步(基于watch实现), 61 ## 用户1 62 import redis 63 conn = redis.Redis(host='192.168.241.129',port=6379) 64 with conn.pipeline() as pipe: 65 # 先监视,自己的值没有被修改过 66 conn.watch('count') 67 # 事务开始 68 pipe.multi() 69 old_count = conn.get('count') 70 count = int(old_count) 71 input('我考虑一下') 72 if count > 0: # 有库存 73 pipe.set('count', count - 1) 74 75 # 执行,把所有命令一次性推送过去 76 ret = pipe.execute() 77 print(type(ret)) 78 print(ret) 79 ## 用户2 80 import redis 81 conn = redis.Redis(host='127.0.0.1',port=6379) 82 with conn.pipeline() as pipe: 83 # 先监视,自己的值没有被修改过 84 conn.watch('count') 85 # 事务开始 86 pipe.multi() 87 old_count = conn.get('count') 88 count = int(old_count) 89 if count > 0: # 有库存 90 pipe.set('count', count - 1) 91 # 执行,把所有命令一次性推送过去 92 ret=pipe.execute() 93 print(type(ret)) 94 95 # 注:windows下如果数据被修改了,不会抛异常,只是返回结果的列表为空,mac和linux会直接抛异常 96 97 # 秒杀系统核心逻辑测试,创建100个线程并发秒杀(代码有问题) 98 import redis 99 from threading import Thread 100 def choose(name, conn): 101 with conn.pipeline() as pipe: 102 # 先监视,自己的值没有被修改过 103 conn.watch('count') 104 # 事务开始 105 pipe.multi() 106 old_count = conn.get('count') 107 count = int(old_count) 108 # input('我考虑一下') 109 # time.sleep(random.randint(1, 2)) 110 if count > 0: # 有库存 111 pipe.set('count', count - 1) 112 113 # 执行,把所有命令一次性推送过去 114 ret = pipe.execute() 115 print(ret) 116 if len(ret) > 0: 117 print('第%s个人抢购成功' % name) 118 else: 119 print('第%s个人抢购失败' % name) 120 121 122 if __name__ == '__main__': 123 conn = redis.Redis(host='192.168.241.129', port=6379) 124 for i in range(100): 125 126 t = Thread(target=choose, args=(i, conn)) 127 t.start()
。
。
【发布订 1 # 发布订阅(观察者模式):发布者发布了消息,所有的订阅者都可以收到,就是生产者消费者模型
2 -生产者消费者 发布订阅模型 3 -生产者消费者 队列 4 5 # 原生实现 6 -发布消息: 7 publish channel message 8 -订阅(现有订阅者,然后发布者才有消息) 9 subscribe channel 10 -接收消息 11 -只要发布者一发布,订阅者都会受到 12 13 14 # python+redis实现 15 import redis 16 # 连接到Redis服务器 17 r = redis.Redis(host='localhost', port=6379, db=0) 18 # 发布者 19 20 r.publish('channel', 'message') 21 22 23 24 import redis 25 # 连接到Redis服务器 26 r = redis.Redis(host='localhost', port=6379, db=0) 27 # 订阅者 28 sub = r.pubsub() 29 sub.subscribe('channel') 30 for message in sub.listen(): 31 print(message)
if isinstance(message['data'],bytes):
print(message['data'].decode('utf-8'))
if message['data'].decode('utf-8')['type']=='下单':
print(message['data'].decode('utf-8')['user'],'发送短信')
。
。
【bitmap位图】
1 #1 本质是字符串 2 3 #2 操作比特位 4 b i g 5 01100011 01101001 01100111 6 set hello big #放入key位hello 值为big的字符串 7 getbit hello 0 #取位图的第0个位置,返回0 8 getbit hello 1 #取位图的第1个位置,返回1 如上图 9 10 # 我们可以直接操纵位 11 setbit key offset value #给位图指定索引设置值 12 setbit hello 7 1 #把hello的第7个位置设为1 这样,big就变成了cig 13 14 15 # 3 独立用户统计---》统计日活---》用户量足够大--》节约内存 16 -10亿用户 用户id1 2 3 10亿 17 18 1个bytes--》8个比特位---》能表示多少种变化? 19 2的7次方-1 :-128 到127之间 20 8个bytes--》64个比特位--》9223372036854775808 21 22 如果以集合存储:存一个用户,就要8个bytes---》存1亿用户 8 bytes*1亿 23 24 -统计日活,只要用户登录,就把用户id放到集合中 25 -晚上只需要统计一下 集合大小---》就能统计出日活 26 -使用集合存储---》1--》32位--》1亿用户 5千万左右---》需要 200MB空间 27 int8个比特位表示范围 -128--127之间 28 int16 29 int32 个比特位表示范围 -2的31次方---2的31次方 2147483648 30 31 -使用位图---》12.5MB空间 32 33 34 # 获取前3位中1的个数 35 bitcount name 0 3
。
。
【hyperloglog】
1 # 1 基于HyperLogLog算法:极小的空间完成独立数量统计,本质还是字符串 2 3 # 2 4 -放值:pfadd uuids "uuid1" "uuid2" "uuid3" "uuid4" 5 -统计个数:pfcount uuids 6 -判断一个值是否在里面:pfadd uuids "uuid1"(返回1/0) 7 8 # 3 统计日活用户 9 10 # 4 去重:爬过的网址,就不爬了--》存一下爬过的 11 'www.baidu.com'--->放到 pfadd 中--》返回1,说明没爬过--》继续爬取--》如果返回0,不爬了 12 13 # 5 黑白名单 14 15 # 6 注意 16 百万级别独立用户统计,百万条数据只占15k 17 错误率 0.81% 18 无法取出单条数据,只能统计个数 19 20 # 7 类似于布隆过滤器,算法不一样
。
。
【geo】
1 # 1 geo 地理位置信息 2 GEO(地理信息定位):存储经纬度,计算两地距离,范围等 3 北京:116.28,39.55 4 天津:117.12,39.08 5 可以计算天津到北京的距离,天津周围50km的城市,外卖等 6 7 # 2 经纬度哪里来? 8 - web端:js获取--》掉接口,传给后端 9 - 安卓,ios端:线程的代码 10 -微信小程序 11 12 # 3 js获取经纬度 13 if (navigator.geolocation) { 14 navigator.geolocation.getCurrentPosition(function(position) { 15 var latitude = position.coords.latitude; 16 var longitude = position.coords.longitude; 17 console.log("经度:" + longitude); 18 console.log("纬度:" + latitude); 19 }); 20 } else { 21 console.log("浏览器不支持Geolocation API"); 22 } 23 24 25 # 4 增加地理位置信息 26 geoadd key longitude latitude member #增加地理位置信息 27 28 geoadd cities:locations 116.28 39.55 beijing #把北京地理信息天津到cities:locations中 29 geoadd cities:locations 117.12 39.08 tianjin 30 geoadd cities:locations 114.29 38.02 shijiazhuang 31 geoadd cities:locations 118.01 39.38 tangshan 32 geoadd cities:locations 115.29 38.51 baoding 33 34 35 # 5 获取天津的经纬度 geopos key member #获取地理位置信息 36 geopos cities:locations tianjin 37 # 根据经纬度--》文字 38 from geopy.geocoders import Nominatim 39 geolocator = Nominatim(user_agent="my_application") 40 def geolocate_point(latitude, longitude): 41 location = geolocator.reverse(f"{latitude}, {longitude}") 42 return location.address 43 # 示例使用经纬度 44 latitude = 39.983424 45 longitude = 116.307224 46 address = geolocate_point(latitude, longitude) 47 print(address) 48 49 # 6 统计两个地理位置之间的距离 50 geodist cities:locations beijing tianjin km #北京到天津的距离,89公里 51 52 # 7 统计某个地理位置方圆xx公里,有xx 53 georadiusbymember cities:locations beijing 150 km
。
。
【持久化】
1 # 1 什么是持久化 2 redis的所有数据保存在内存中,对数据的更新将异步的保存到硬盘上 3 4 # 2 持久化的实现方式 5 快照:某时某刻数据的一个完成备份, 6 -mysql的Dump:写一个mysql自动定时备份和清理前后端程序 7 -redis的RDB:某一刻,把内存中得数据,保存到硬盘上这个操作就是rbd的持久化 8 写日志:任何操作记录日志,要恢复数据,只要把日志重新走一遍即可 9 -mysql的 Binlog 10 -Redis的 AOF 11 12 # 3 redis有三种持久化方案 13 -rdb:快照 14 -aof:日志 15 -混合持久化:rdb+aof混合方案
。
rdb
1 # 4 rdb方案 :三种方式 2 1 人工同步:客户端 : save # 同步操作,会阻塞其他命令--》单线程架构 3 2 人工异步:客户端:bgsave # 异步操作,不会阻塞其他命令 4 3 配置文件 5 save 900 1 #配置一条 6 save 300 10 #配置一条 7 save 60 10000 #配置一条 8 9 save 60 5 10 11 # 5 最佳配置 12 #最佳配置 13 save 900 1 14 save 300 10 15 save 60 10000 16 dbfilename dump-6379.rdb #以端口号作为文件名,可能一台机器上很多reids,不会乱 17 dir ./bigdiskpath #保存路径放到一个大硬盘位置目录 18 stop-writes-on-bgsave-error yes #出现错误停止 19 rdbcompression yes #压缩 20 rdbchecksum yes #校验 21 22 23 # 6 确定 RDB问题 24 耗时,耗性能: 25 不可控,可能会丢失数据
。
aof
1 # 1 客户端每写入一条命令,都记录一条日志,放到日志文件中,如果出现宕机,可以将数据完全恢复 2 # 2 AOF的三种策略日志不是直接写到硬盘上,而是先放在缓冲区,缓冲区根据一些策略,写到硬盘上always:redis–》写命令刷新的缓冲区—》每条命令fsync到硬盘—》AOF文件everysec(默认值):redis——》
写命令刷新的缓冲区—》每秒把缓冲区fsync到硬盘–》AOF文件no:redis——》写命令刷新的缓冲区—》操作系统决定,缓冲区fsync到硬盘–》AOF文件 3 # 3 配置文件appendonly yes #将该选项设置为yes,打开appendfilename "appendonly-${port}.aof" 4 #文件保存的名字appendfsync everysec 5 #采用第二种策略dir /bigdiskpath 6 #存放的路径no-appendfsync-on-rewrite yesappendonly yesappendfilename "appendonly.aof"appendfsync everysecno-appendfsync-on-rewrite yes 7 8 # 4 放在了文件中appendonly.aof.1.base.rdb :永久的appendonly.aof.1.incr.aof :临时的appendonly.aof.manifest: 哪些文件存了数据
标签:count,---,hyperloglog,--,redis,bitmap,pipe,位图,conn From: https://www.cnblogs.com/liuliu1/p/18278625