Redis其他功能(命令操作)

一、慢查询

Redis生命周期

Redis一次请求完整的生命周期:

  1. 发送请求(可以是Jedis客户端等)
  2. 排队等待请求被Redis处理
  3. Redis执行命令
  4. 返回结果

Redis请求生命周期
又因为Redis是单线程应用,也就是说只要有一个请求正在执行,后面的请求就必须全部等待。这也是我们为什么需要去关心慢查询的原因。假设有一个命令keys *,该命令需要执行10s,而该命令后的所有请求都将等待keys *的执行。而这10s将会导致后续所有命令的滞后,甚至是请求超时!

跟我们集成Druid或者相关监控是一样的道理,Druid为我们揪出了慢sql语句,而Redis则为我们揪出慢查询语句。并且Redis由于是单线程应用,优化慢查询显得更为重要。而我们需要做的就是监控Redis,记录监控所有慢查询语句,定期进行优化

配置慢查询

在redis中有专门的一个先进先出队列用于记录慢查询操作,我们需要做的是根据自己的需求进行配置,揪出慢查询,以供优化。其中慢查询默认的队列长度是128,超过1000微秒,也就是10ms的算作是慢查询。这个值并非适用于所有项目,因此我们需要根据自己的项目进行设置

如果你的Redis已经启动,那么不建议进行重启,最好的方式是进行动态配置,也就是在Redis客户端中发送。

# 慢查询队列长度
config set slowlog-max-len 1000
# 慢查询阀值,也就是当请求处理时间大于1ms时记录为慢查询
config set slowlog-log-slower-than 1000

当Redis还没启动时,可以通过修改配置文件的方式进行配置。运维小组一般也是在上线前通过配置制定好再进行上线

命令使用

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

二、Pipeline 流水线

在数据结构那节我们介绍了字符串有mget mset操作,可以一次发送多条设置查询命令,减少网络延迟,但是并非所有的数据结构或者命令都有批量操作,Redis为我们提供了pipeline将多条命令进行一次打包,发送给redis-server,减少多次网络开销(当然)

假设发送网络延迟和响应延迟均为50ms,处理1次Redis时间为1ms(一般1ms已经算慢查询了)

  1. 如果我们分100次发送,则总时长 = 100次发送网络延迟 * 50ms + 100次响应延迟 * 50ms + 100次 * 1ms = 10100ms
  2. 如果我们适用Pipeline,打包100次请求,一次发送。则总时长 = 1次发送网络延迟 * 50ms + 1次响应延迟 * 50ms + 100次 * 1ms = 200ms

效果是很客观的,该命令跟sql中单条savebatchSave的思想是一样的,也就是将多条命令一次提交,减少网络延迟带来的时间浪费。但是需要注意的是

  1. batchSave是一次原子操作,也就是说这100条sql命令会被一起执行。但是Redis则不然,虽然我们一次性提交了100次操作,但是这些操作会根据顺序进入到等待队列中(中间往往会穿插一些其他客户端的请求)
  2. 每次我们请求的pipeline也不宜太大,虽然pipeline并非原子操作,也就是不会阻塞其他客户端同一时间的操作请求。但是如果数量太大,势必引起后续请求的阻塞,同时也会导致当前pipeline的返回时间过长,导致超时
  3. 后续我们会讲到集群,也就是多个redis实例。而pipeline则只能作用于1个Redis节点

Jedis

// 无pipeline
Jedis jedis = new Jedis("127.0.0.1", 6379);
for (int i = 0; i < 10000; i++) {
  jedis.hset("key" + i, "field" + i, "value" + i);
}

// pipeline
Jedis jedis = new Jedis("127.0.0.1", 6379);
for (int i = 0; i < 100; i++) {
  Pipeline pipeline = jedis.pipeliend();
  for (int j = i * 100; j < (i + 1) * 100; j++) {
      jedis.hset("key" + j, "field" + j, "value" + j);
  }
  pipeline.syncAndReturnAll();
}

三、发布订阅

redis提供了发布订阅的功能,这里我们只是做一个简单的介绍,因为这部分我们往往会选择像kafkarabbitmq跟专业的中间件

角色

发布订阅的功能类似看电视,首先发布者适用publish channel message将需要发布的内容发布到频道中,而所有的订阅者都将收到这份消息,也就是说这是一个1对多的操作。

  1. 发布者(publisher)
  2. 订阅者(subscriber)
  3. 频道(channel)

命令

# publish channel message
# 发布消息到频道中,返回订阅者个数

# subscribe unsubscribe
# 订阅频道 取消订阅

# psubscribe punsubscribe
# 订阅频道 取消订阅 使用通配符

# pubsub channels
# 列出至少有一个订阅者的频道

# pubsub numsub [channel] 
# 列出给定频道的订阅者数量

四、消息队列

消息队列发布订阅的区别在于,发布订阅就像电视,每个人都可以收看订阅某个频道,每个人也都将收到信息。而消息队列则是抢红包的概念,虽然多个客户端都订阅了该队列,但是只有一个客户端会收到该消息,也就是只有一个客户端能抢到红包。

redis原生并不支持消息队列,但是由于Redis是单线程应用,因此我们可以通过Redis的队列数据结构进行消息队列的实现。当然了,我们还是跟推荐适用专业的Rabbitmq等中间件

五、Bitmap 位图

位图本质就是2进制串,如0101110111这么一个串,长度限制512mb。这种数据结构特别适合做稠密图。假设一个APP有10w用户量,要统计每天用户的登录情况,只需生成一个....0000...的位图,pkid为1的用户登录,则将第一位置为1,即...00001,而一天统计用户登录情况所需的内存空间为100000b。如果存储的是pkid,每个pkid需要32b。也就是说,当每天用户登录量小于100000b / 32b时,所用空间更占优势,当数量大于100000b / 32b时,则位图跟占优势。这也就是所说的稀疏图稠密图的概念

命令使用

# setbit key offset value
# 设置第offset位的比特位为value,返回原比特位的值
127.0.0.1:6381> get bit
"a"
127.0.0.1:6381> setbit bit 6 1
(integer) 0
127.0.0.1:6381> get bit
"c"
127.0.0.1:6381> getbit bit 6
(integer) 1
# bitcount key [start end]
# 获取范围内1的个数
127.0.0.1:6381> bitcount bit 0 -1
(integer) 4
# bitop op destkey key [key]
# op: and交 or或 not非 xor异或
127.0.0.1:6381> get bit
"c"
127.0.0.1:6381> set opbit 0
OK
127.0.0.1:6381> bitop and bit opbit
(integer) 1
127.0.0.1:6381> get bit
"0"
# bitpos key targetBit [start] [end](start end指字节,不是bit位)
# 获取第一个targitBit出现的位置
# bit = 00110000
127.0.0.1:6381> bitpos bit 1
(integer) 2

六、hyperLogLog

本质为字符串,使用极小的空间实现统计功能。

注意:hyperLogLog只能用于统计,加入的数据无法像map一样进行取出,只能是不断插入,最后进行统计!而且hyperLogLog存在一定几率的错误,因此一般是做大数据量的统计,如一个百万流量APP,统计每天用户活跃数。需要的只是一个大致的数字,而非确切数字

# pfadd key elment
# 添加
# pfcount key 
# 统计个数
# pfmerge destkey sourcekey
# 合并
127.0.0.1:6381> pfadd ids:0301 "uid1" "uid2" "uid3"
(integer) 1
127.0.0.1:6381> pfcount ids:0301
(integer) 3
127.0.0.1:6381> pfadd ids:0302 "uid3" "uid4" "uid5"
(integer) 1
127.0.0.1:6381> pfmerge ids:0301-0302 ids:0301 ids:0302
OK
127.0.0.1:6381> pfcount ids:0301-0302
(integer) 5

七、GEO 地理位置

顾名思义,就是经纬度给坐标的,用于计算坐标差,或者距离点的。比如摇一摇、外卖、附近商家等都可以使用。这里给大家做个介绍而已,知道有这些功能,需要用时再去查就行

# geoadd key 经度 纬度 member
# geopos key member
# 获取地理信息
127.0.0.1:6381> geoadd cities 116.28 39.55 beijing 117.12 39.08 tianjing
(integer) 2
127.0.0.1:6381> geopos cities beijing
1) 1) "116.28000229597091675"
   2) "39.5500007245470826"
# geodis key member1 member2 unit
# 获取两地距离
127.0.0.1:6381> geodist cities beijing tianjing km
"89.2061"
# georadius 

猜你喜欢

转载自blog.csdn.net/chaitoudaren/article/details/106170901