Redis笔记(二)Redis其他功能

慢查询

生命周期

两个配置

  • slowlog-max-len:慢查询队列长度
  • slowlog-log-slower-than:慢查询阈值(单位:微秒)
  • slowlog-log-slower-than=0, 记录所有命令
  • slowlog-log-slower-than<0, 不记录任何命令

配置方法

  • 默认值
    • config get slowlog-max-len = 128
    • config get slowlog-log-slower-than = 10000
  • 修改配置文件重启
  • 动态配置

    • config set slowlog-max-len 1000
    • config set slowlog-log-slower-than 1000

三个命令

  • slowlog get [n]:获取慢查询队列
  • slowlog len:获取慢查询队列长度
  • slowlog reset:清空慢查询队列

运维经验

  1. slowlog-max-len不要设置过大,默认10ms,通常设置1ms
    Redis的QPS是万级的,也就是一条命令平均0.1ms就执行结束了。通常我们翻10倍,设置1ms。
  2. slowlog-log-slower-than不要设置过小,通常设置1000左右
    慢查询队列默认长度128,超过的话,按先进先出,之前的慢查询会丢失。通常我们设置1000。

  3. 理解命令生命周期
    慢查询发生在第三阶段

  4. 定期持久化慢查询
    slowlog get或其他第三方开源工具

pipeline

什么是流水线

未使用pipeline的批量网络通信模型

假设客户端在上海,Redis服务器在北京。相距1300公里。假设光纤速度≈光速2/3,即30000公里/秒2/3。那么一次命令的执行时间就是(13002)/(300002/3)=13毫秒。Redis万级QPS,一次命令执行时间只有0.1毫秒,因此网络传输消耗13毫秒是不能接受的。在N次命令操作下,Redis的使用效率就不是很高了。

使用pipeline的网络通信模型

客户端实现

引入maven依赖

<dependency>
  <groupId>redis.clients</groupId>
  <artifacId>jedis</artifacId>
  <version>2.9.0</version>
  <type>jar</type>
  <scope>compile</scope>
</dependency>
// 不用pipeline
Jedis jedis = new Jedis("127.0.0.1", 6379);
for (int i = 0; i < 10000; i++) {
    jedis.hset("hashkey" + i, "field" + i, "value=" + i);
}

不用pipeline,10000次hset,总共耗时50s,不同网络环境可能有所不同

// 使用pipeline, 我们将10000条命令分100次pipeline,每次100条命令
Jedis jedis = new Jedis("127.0.0.1", 6379);
for (int i = 0; i < 100; i++) {
    Pipeline pipeline = jedis.pipeline();
    for (int j = i * 100; j < (i + 1) * 100; j++) {
        pipeline.hset("hashkey:" + j, "field" + j, "value" + j);
    }
    pipeline.syncAndReturnAll();
}

使用pipelne,10000次hset,总共耗时0.7s,不同网络环境可能有所不同。

可见在执行批量命令时,使用pipeline对Redis的使用效率提升是非常明显的。

与M原生操作对比

mset、mget等操作是原子性操作,一次m操作只返回一次结果。
pipeline非原子性操作,只是将N次命令打个包传输,最终命令会被逐条执行,客户端接收N次返回结果。

pipeline使用建议

  1. 注意每次pipeline携带数据量
    pipeline主要就是压缩N次操作的网络时间。但是pipeline的命令条数也不建议过大,避免单次传输数据量过大,客户端等待过长。
  2. Redis集群中,pipeline每次只作用在一个Reids节点上

发布订阅

角色

  • 发布者(publisher)
  • 订阅者(subscriber)
  • 频道(channel)

模型

订阅者可以订阅多个频道

API

发布

API:publish channel message

redis> publish sohu:tv "hello world"
(integer) 3 #订阅者个数
redis> publish sohu:auto "taxi"
(integer) #没有订阅者

订阅

API:subscribe [channel] #一个或多个

redis> subscribe sohu:tv
1) "subscribe"
2) "sohu:tv"
3) (integer) 1
1) "message"
2) "sohu:tv"
3) "hello world"

取消订阅

API:unsubscribe [channel] #一个或多个

redis> unsubscribe sohu:tv
1) "unsubscribe"
2) "sohu:tv"
3) (integer) 0

其他API

  • psubscribe [pattern…] #订阅指定模式
  • punsubscribe [pattern…] #退订指定模式
  • pubsub channels #列出至少有一个订阅者的频道
  • pubsub numsubs [channel…] #列出给定频道的订阅者数量

对比消息队列

消息队列模型

发布订阅模型,订阅者均能收到消息。消息队列,只有一个订阅者能收到消息。因此使用发布订阅还是消息队列,要搞清楚使用场景。

geo

geo是什么

GEO:存储经纬度,计算两地距离,范围计算等。

相关命令

API:geoadd key longitude latitude member # 增加地理位置信息

redis> geoadd cities:locations 116.28 39.55 bejing
(integer) 1
redis> geoadd cities:locations 117.12 39.08 tianjin 114.29 38.02 shijiazhuang 118.01 39.38 tangshan 115.29 38.51 baoding
(integer) 4

API:geopos key member [member…] # 获取地理位置信息

redis> geopos cities:locations tianjin
1)1) "117.12000042200088501"
  2) "39.0800000535766543"

API:geodist key member1 member2 [unit] # 获取两位置距离,unit:m(米)、km(千米)、mi(英里)、ft(尺)

reids> geodist cities:locations tianjin beijing km
"89.2061"

API:
获取指定位置范围内的地理位置信息集合
georadius key longitude latitude radius m|km|ft|mi [withcoord] [withdist] [withhash] [COUNT count] [asc|desc] [store key] [storedist key]

georadiusbymember key member radius m|km|ft|mi [withcoord] [withdist] [withhash] [COUNT count] [asc|desc] [store key] [storedist key]

withcoord: 返回结果中包含经纬度
withdist: 返回结果中包含距离中心节点的距离
withhash: 返回结果中包含geohash
COUNT count:指定返回结果的数量
asc|desc:返回结果按照距离中心节点的距离做升序/降序
store key:将返回结果的地理位置信息保存到指定键
storedist key:将返回结果距离中心点的距离保存到指定键

redis> georadiusbymember cities:locations beijing 150 km
1)"beijing"
2) "tianjin"
3) "tangshan"
4) "baoding"

相关说明

  1. since redis3.2+

  2. redis geo是用zset实现的,type geokey = zset

  3. 没有删除API,可以使用zset的API:zrem key member

标签:Redis 发布于:2019-10-31 18:22:37