4-------扩展篇
Stream
一个强大的支持多播的可持久化消息队列。
消息链表,将所有加入的信息都串起来,每个消息都有一个唯一的ID和对应的内容。消息是持久化的,重启内容还在的。
每个Stream都有唯一的名称,他就是Redis的key,在首次使用xdd指令追加消息时自动创建
- 每个Stream都挂有多个消费组,每个消费组都有一个last_delivered_id在stream数组之上往前移动,表示当前消费组已经在消费到了哪条信息。
- 每个消费组都有一个Stream内唯一的名称,消费组不会自动创建,它需要单独的指令xgroup_create进行创建,并且初始化last_delivered_id变量。
- 同意消费组可以挂接多个消费者,这些消费者之间是竞争关系,任意一个消费者读取了信息都会移动游标
- 消费者内部有一个pending_ids,记录当前已经被客户端读取,但是还没有ack的消息。如果客户端没有ack,这个变量里面的消息ID就会越来越来多。
消息ID
消息ID形式:时间戳+本次时间内的第几条
1-2:当前时间为1毫秒,这个消息时这个时刻产生的第二条消息
消息内容
消息内容就是键值对,形如hash结构的键值对
增删改查
xadd:向Stream中追加消息
xdel:从Stream中删除消息
xrange:获取Stream中的消息列表
xlen:获取Stream消息长度
del:删除整个Stream消息列表中的所有信息
独立消费
客户端:xread block 1000 count 1 streams name
阻塞1s,如果有消息的话,就出来,没有的话就没用。
创建消费组
xgroup create name cg1 0-0;;;;没什么用的
消费
Stream消息太多怎么办
使用xadd指令删除掉。
消息如果忘记ack会怎样
不怎么样,PEL会越来越长
PEL如何避免丢失
反正保存在了PEL当中,等连接上了再传就行了。
Stream的高可用
可以在分布式集群中使用
分区Partition
Stream没有分区的能力,只能多创建几个Stream,并把不同的数据发送到不同的Stream上供消费
小结
感觉应该不会用到的,所以觉得没用
Info指令
获得Redis内部的一些参数
Server | 服务器运行的环境参数 |
Clients | 客户端相关信息 |
Memory | 服务器运行内存统计数据 |
Persistence | 持久化信息 |
Stats | 通用统计数据 |
Replication | 主从复制相关信息 |
CPU | CPU使用情况 |
Cluster | 集群信息 |
KeySpace | 键值对统计数据信息 |
再谈分布式锁
当主节点挂掉了,从节点取而代之;但是有可能客户端申请成功了一把锁,但是此时主节点挂了,但是从节点也没有同步这个加锁的操作就升级成了主节点,那么这个时候就出问题了。另外一个客户端申请了锁,问题更大了,鸠占鹊巢
Redlock算法
需要导入redlock模块
加锁时:客户端向过半节点发送加锁请求,请求成功了就加锁成功;释放锁的时候,需要向所有节点发送del指令。
Redlock使用场景
但是很慢哦
过期策略
Redis所有的数据结构都可以设置过期时间,时间一到,就会被自动删除。
Redis是单线程的,收割的时间也会占用线程的处理时间,如果收割的太过频繁,会导致卡顿
过期的key的集合
Redis会将每个设置了过期时间的key放入一个独立的字典中,之后会定时遍历这个字典来删除到期的key。
除了定时删除,它还会使用惰性策略来删除过期的key。所谓惰性删除就是在客户端访问这个key的时候,Redis对key的过期时间进行检查,如果过期了就立即删除。
定时删除:集中处理
惰性删除:零散处理
定时扫描策略
默认每秒10次扫描
- 从过期字典中随机选出20个key
- 删除这20个key中已经过期的key
- 过期的key超过了1/4,那就重复一次
为了保证扫描不会出现循环过度,导致线程卡死的现象,算法还增加了扫描时间的上限,默认不会超过25ms
当客户端请求到来时,服务器如果正好进入过期扫描状态,客户端的请求将会等待至少25ms才会处理,如果客户端将超时时间设置得比较短,那么就会出现很多超时关闭。
所以业务开发人员一定要注意过期时间,如果有大批量得key过期,要给过期时间设置一个随机范围,而不能全部在同一时间过期。
通过随机化过期时间总是很好得解决定期扫描过期得事情。
从节点的过期策略
从节点不会过期扫描,从节点对过期得处理是被动得。主节点在key到期时,会在AOF文件中增加一条del指令。然后从节点删除过期得节点。但是可能导致主节点中删除了,但是从节点中没有删除得现象。
优胜劣汰-LRU
当Redis内存超出了物理内存限制时,内存得数据会开始和磁盘产生频繁得交换(Swap)。但是redis是不能存在数据交换操作得
所以当超内存之后会有以下机中方法:
- noeviction:不会继续服务写请求
- volatile-lru:尝试淘汰设置了过期时间得key,最少使用得key优先被淘汰
- volatile-ttl:比较设置过过期时间得key,但是比较每个key剩余得生命ttl,来选择淘汰得key
- volatile-random:跟上面得一样,但是淘汰得是过期得key集合
- allkeys-lru:对所有得key来一次lru
- allkeys-random:淘汰得随机得key
总结:volatile-xxx只针对带过期时间得key进行淘汰,allkeys-xxx策略会对所有得key进行淘汰。
LRU算法
实现LRU算法除了需要key/value字典外,还需要附加一个链表。
当空间满的时候,会踢掉链表尾部的元素。当字典的某个元素被访问,就会被移动到表头。所以链表的元素排列就是元素最近被访问的时间顺序。
近似LRU算法
Redis使用的是一种近似的LRU算法,跟Lru算法有一点不一样。之所以不适用Lru算法,是因为需要大量的额外空间。
Redis给每个key增加一个额外的小字段,这个字段的长度是24个bit,也就是最后一个被访问的时间戳。
RedisLru算法采用的是懒惰处理,随机采样5个key,然后淘汰最旧的key,如果淘汰后还是超内存,就继续采样淘汰。
是否只对设置了过期的key进行LRU算法,取决于maxmemory-policy设置。
删除的东西会放在淘汰池中,慢慢删除。
懒惰删除
后台删除线程
Redis为什么使用懒惰删除
删除大对象还是很慢的,所以要异步丢给后台删除线程处理
flush
flushdb、flushall都是很慢的操作,因为是直接删除完,但是可以flushall async丢给后台线程慢慢处理
异步队列
一头再往里面加删除的数据,一边在删除,所以这个队列需要线程安全的
AOF Sync
也是开辟一个线程,进行实时的同步写日志文件
更多异步删除点
redis4.0给下面的指令也是带来的异步删除
slave-lazy-flush:从节点接受完rdb文件后的flush操作
lazyfree-lazy-eviction:内存达到maxmemory时进行删除
lazyfree-lazy-expire key:过期删除
lazyfree-lazy-server-del rename:指令删除destKey
Jedis
Redis开源客户端
Jedispool,jedis连接池
需要使用try-with-resource语句来保护jedis对象,一定要释放连接啊。
重试
没有重试机制,需要自己写重试。
保护Redis
指令安全
- redis可以设置rename-command指令,给一些危险的指令重命名。
端口安全
不要使redis服务器的网址暴露在外面
Lua脚本安全
让redis以普通用户的方式启动,防止黑客拿到root权限
SSL代理
redis不支持SSL,意味着客户端和服务器之间的交互数据不能直接暴露在公网上传输。但是可以使用SSL代理。
使用spipedSSH对通道进行二次加密
Redis安全通信
使用ssl给数据加密
spiped原理
在客户端和服务器端都开启一个spiped的线程
一个加密和解密的过程
spiped进程监听一个端口接收数据,并且使用这个端口发送数据;客户端先将数据发送到piped上进行加密,然后传输到服务器端,服务器端进行解密,发送到服务器上。
spiped
可以同时支持多个客户端连接的数据转发工作,还可以通过参数来限定允许的最大客户端连接数,但是对于服务器spiped,它不能同时支持多个服务器之间的转发。需要为每一个server节点启动一个spiped进程来代收消息。