三、Redis高级特性和应用

一、慢查询

1、redis的命令执行流程

说明:在第3步运行时间超过10ms的时候记录为慢查询;

2、redis的慢查询

多慢算慢?  --->   超出阈值算慢

3、慢查询配置

10000微秒 --> 10毫秒;

动态设置:

4、慢查询操作命令

查询慢查询记录:slowlog get count

清空慢查询链表:slowlog reset

5、慢查询分析

单元素操作快

范围操作慢

统计操作快

不同数据结构时间复杂度分析:

二、PipeLine

1、什么是PipeLine?

RTT:往返时间,数据花在网络上的时间;

将所有的指令组装成pipeline,减少RTT;节约网络开销做批量处理;

2、注意事项:

pipeline设置的时候不宜设置的太大

redis使用pipeline的时候,内核输入输出的缓冲区为4K ~ 8K

单个TCP报文的最大值为1460 byte(1500 - IP头20 - TCP头20)

建议pipeline最大长度不超过1460 byte

三、事务

1、什么是事务?

都执行或者都不执行

Redis的事务是弱事务

不推荐使用Redis做事务

只有语法错误的时候才会做回滚,非法操作不会做回滚

2、命令

命令

作用

multi

开启事务

exec

提交事务

3、Watch机制

是一个监控机制,监控某个key

CAS:乐观锁

使用watch关键字监控某个key,如果在事务提交前这个key被其他客户端修改,那么当前客户端的事务会失败

4、pipeline和事务的区别

pipeline是客户端行为,在客户端将多个命令组装到pipeline中,发送给redis后做批处理

事务是一个特殊的命令,在提交之前不会正真执行

pipeline可以使用multi命令开启事务

四、Lua

1、什么是Lua?

本质是一个脚本语言,类似存储过程

2、使用Lua的好处

减少网络开销:可以将多个命令放到一个脚本中

原子操作:redis会将lua脚本作为整体执行(redis执行命令是单线程)

复用性:redis可以存储客户端发送的lua脚本,客户端可以复用脚本

3、命令

一个演示命令:

eval "return redis.call('mset',KEYS[1],ARGV[1],KEYS[2],ARGV[2])" 2 key1 key2 first second

解析:

eval:基础命令

redis.call:使用脚本调用redis指令

“2” :标识key的个数,剩下的就是value

script load “...” 命令可以保存一个脚本

返回一个SHA1的标识

使用【evalsha + 标识】调用脚本

五、redis + Lua语言实现限流

lua脚本可以设置某个用户在固定时间的固定访问次数

常用限流算法

1、固定窗口算法

在固定时间限制固定访问次数

弊端:可以在临界时间时,短时间内通过两份最大请求数量

例如:59s ~ 60s 时进入100个请求,60s ~ 61s 时进入100个请求,这时在2s内进入了200个请求

2、滑动窗口算法

让服务端在同一时间段内只接收count次请求,让客户端在接收响应后才向后滑动窗口

3、漏桶算法

放请求

先有一个桶,桶的容量是固定的

请求来了先放到桶中,桶满的时候就溢出,丢弃请求

桶底有个小洞,慢慢流出请求到服务端

4、令牌桶算法

取令牌

先有一个桶,桶的容量是固定的,用来存放令牌

以固定速率向桶中放令牌,桶满了就不放了

请求过来时先去桶中取若干个令牌,取到就执行,取不到就被限流

可以提前在桶里放多个令牌,来应对服务刚启动时过来了多个请求

5、桶限流缺点

时间复杂度高

六、发布 订阅

Redis不单纯干缓存,提供了许多即插即用的功能

1、结构图:

2、命令

命令

作用

返回值

publish channel message

向channel频道发布消息(message)

返回订阅该频道的客户端个数

subscribe channel1

订阅channel频道的消息

具体消息

pubsub channels c*

查看当前所有频道

pubsub numsub channel 

查看订阅channel频道的订阅者

第一个是channel名称

后面是订阅者个数

3、特点

发送即忘原则

七、Stream

1、是一个数据结构,用于消息中间件

2、结构

消息id结构:毫秒-自增 // 一个毫秒内自增

id = 0-0 :从头开始

id = $ :从尾部开始

3、命令

命令

作用

xadd stream1 * key value ...

生产一个消息,* 是采用redis自带的消息id

xrange stream1 start end

消费一个消息队列的消息

参数是start end

start:

-:代表最早的;

id:消息id之后的

end:

+:代表最晚的;

消息id之前的

xlen stream1

查询消息个数

xdel stream1 id1 ...

删除特定id的消息

4、单消费者

类似于一个list结构,一端放消息,一端取消息;

命令

作用

xread count 10 streams stream1 id

从stream1读取消息

count 10:本次读取10条

streams:读取消息类型

stream1:消息队列的key

id:从哪条消息开始读取(不包括id对应的这条消息)

xread block 0 count 1 streams stream1 $

起一个消息监听,有新消息就打印

block 0:一直阻塞(大于0就是阻塞多少毫秒)

$ :获取当前最新的消息

读取到一个消息后,解除阻塞,打印消息

5、群组消费者

分布式系统中消息中间件的三大作用:

解耦

异步执行

削峰填谷(流量削峰)

场景:订单系统并发量高(10W) --> 持久层系统并发量低(1000)

方案:消费端需要一个群组增加并发量

命令

作用

xgroup create stream1 consumerGroup1 0-0

创建一个消费者群组

xgroup create 组合命令激活命令提示

stream1 目标消息队列名称

consumerGroup1 群组名称

0-0:指定从id=-0-0的消息开始消费(从头消费)

任何消息的id都是 数字-数字(默认时间戳-自增id)

xgroup create stream1 consumerGroup3 $

创建一个消费者群组

$ :指定从将来最新的消息开始消费,舍弃掉之前的所有消息;

xinfo stream stream1

查询某个stream的详细信息

xinfo stream 组合命令激活命令提示

stream1 目标消息队列的名称

xreadgroup group consumerGroup1 consumer1 count 1 block 0 streams stream1 >

使用群组消费一条消息

xreadgroup 激活命令提示

group consumerGroup1 键值对,指定使用哪个群组

consumer1 指定一个消费者

count 1 键值对,指定消费几条消息

block 0 键值对,如果消费到消息就阻塞,一旦消费到就解除阻塞;

streams stream1 键值对,指定消费哪个消息队列

> 打印符号

xinfo consumers stream1 consumerGroup1

查询某个stream的群组信息

xinfo consumers 组合命令激活命令提示

stream1 消息队列名称

consumerGroup1 群组名称

xack stream1 consumerGroup1 id

ack确认

xack 激活命令提示

stream1 消息队列名称

consumerGroup1 消费群组名称

id 确认哪条消息

八、群组结构

1、创建

在同一个群组中,每接入一个客户端,就对应地创建一个消费者实例

2、消息发送

消息队列会将消息自动投递到它的所有群组中

3、群组详情:

群组有一个属性:last_delivered_id,标识了当前群组从消息队列的哪一条消息开始消费

这个属性是保存在redis的数据结构中的

4、消费者(群组成员)详情

具体消费者有个pending数组,这个数组记录了该消费者消费过的消息id

一旦消费者挂掉,可以通过pending数组回溯

5、ack确认

确定好了消费者消费了哪些消息后,还需要进行确认

确认后,具体消费者的pending数组就不再记录该条消息

6、问题

stream消息数量过多会怎样?

一个消息队列最大消息数量 maxlen = 1024,增加一个时,会删除最早的一个;

忘记ack确认怎么办?

PEL:会到消费者的pending数组查找自动确认;

PEL如何避免消息丢失?

故障转移:XCLAIM

死信问题:

任何消费者都消费不了的消息;

需要手动消除:xdel命令;

Stream的高可用?

主从复制,哨兵集群;

异步执行,可能出现少量消息丢失;

分区Partition?

手动设计;

九、key 与 value 的数据结构组织

1、全局哈希表

数组 + 链表 :链表每个节点保存键值对

键:String

值:String,List,Hash,Set,ZSet

2、Hash冲突和HashMap一样

3、链表解决Hash冲突

4、ReHash问题

导致IO阻塞,卡顿

Hash表扩容

初始化第二张Hash表,扩容后从第一个hash表迁移到第二个hash表

先rehash完全部数据,再执行后面的请求;阻塞时间长

渐进式Rehash

每次来一个新请求的时候,会捎带着做一次rehash

分摊阻塞时间,让用户“无感”阻塞

5、结构图

  • 25
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值