Redis
2021-11-03 10:21:09 0 举报
AI智能生成
Redis知识图谱
作者其他创作
大纲/内容
C语言开发
Redis中所有的key都存在一个很大的字典中,这个字典结构和Java中的HashMap一样,scan指令返回的游标就是一维数组的位置索引,我们将这个位置索引称为slot(槽)
在集群环境下,如果某个key太大,会导致数据迁移卡顿
在内存分配上,如果key太大,当他需要扩容时,会一次性申请更大的一块内存,也会造成卡顿
当大key被删除,内存被一次性回收也会产生卡顿
大key扫描
redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.1
Redis基础介绍
Redis是用单线程处理用户请求的,所以对于时间复杂度为O(n)的指令要谨慎使用,否则一不小心就会造成Redis卡顿
非阻塞IO
多路复用(select)
多路复用(epoll)
线程IO模型
NIO
Redis Serialization Protocol的缩写
是一种直观的文本协议,实现过程异常简单,解析性能极好
通信协议RESP
一次全量备份
内存数据的二进制序列化形式,在存储上非常紧凑
使用操纵系统的多进程COW(copy on write)机质来实现快照持久化
RDB
连续的增量备份,只记录对内存进行修改的指令记录
Redis在收到客户端的修改指令后,进行参数校验,逻辑处理,没问题再将该指令文本存储到AOF日志中
AOF日志瘦身,记录内存数据修改的指令记录文本,AOF日志在长期的运行过程中会变得无比庞大,需要定期进行AOF重写,给AOF日志瘦身
数据库重启时需要进行AOF重放
fsync
AOF
将rdb文件的内容和增量的AOF日志文件存在一起,这里的AOF日志是自持久化开始到持久化结束这段时间发生的增量AOF日志,通常这部分AOF日志很小
混合持久化
外框
持久化
管道
watch
multi
exec
discard
常用指令
所有指令在exec之前不执行,而是缓存在服务器的一个事务队列中,服务器一旦受到exec指令,才开始执行整个事务队列,因为redis是单线程的,可以保证事务中的命令得到“原子性”执行,但其实,指令失败后,后续的指令还是会执行。所以Redis事务其实不具备原子性,而是仅仅满足了事务的隔离性
watch是一种乐观锁,当exec指令执行时,会检查watch中的变量是否修改,如果修改了会返回Null,客户端可以选择重试
事务
小对象压缩
google的tcmalloc
facebook的jemalloc
redis将内存分配的细节交给了第三方内存分配库去实现
Redis并不总是将空闲内存立即归还给操作系统
内存回收机质
Redis原理
Consistent:一致性
Availability:可用性
Partition tolerance:分区容忍性
CAP
当网络分区发生时,一致性和可用性难以两全
buffer环
偏移量
增量同步
快照同步死循环
无盘复制
快照同步
wait指令
主从同步
从从同步
最终一致性
增加从节点
监控主从节点的健康
挂掉的主节点恢复后不会抢主
min-slaves-to-write 1
min-slaves-max-lag 10
无法保证该消息完全不丢失
默认端口是26379
Sentinel
可用性
中国人开发
Go语言开发
使用Redis协议对外提供服务
只是一个转发代理中间件,是无状态的
特点
crc32算法
默认将key划分为1024个槽位,槽位信息存储在zk或者etcd中
zookeeper
etcd
不同Codis实例之间槽位关系同步
Codis Proxy需要通过Proxy来定位目标节点的槽位信息
SLOTSSCAN
扩容
自动均衡
分片原理
不能再支持事务了
rename操作可能无法正确完成
单个key对应的value不宜过大
因为增加了Proxy作为中转层,所以在网络开销上比单个Redis大
增加了zookeeper运维的代价
Codis的代价
设计上比Redis Cluster官方集群方案简单,因为将分布式的问题交给了zookeeper或etcd去负责
Codis的优点
因为不是Redis的官方项目,它总要被官方Redis牵着鼻子走
Codis的缺点
将key按照所分配的实例打散分组,然后依次对每个实例调用mget方法,最后将结果汇总为一个返回给客户端
mget指令操作
Codis
Redis的亲儿子
通过特殊的二进制协议交互集群信息
去中心化,分为16384个槽位,槽位信息存储于每个节点中
纠正机质
crc16算法
Redis Cluster的客户端来连接集群时,会得到一份集群的槽位配置信息。当客户端要查找某个key时,可以直接定位到目标节点
允许用户强制把某个key挂在特定的槽位上,通过key字符串里面嵌入tag标记
-MOVED 3999 127.0.0.1:6381
跳转,当客户端像一个错误的节点发出了指令后,该节点会发现指令key所在的槽位并不归自己管理,这事它会向客户端发送一个特殊的跳转指令携带目标操作的节点地址,告诉客户端去连接这个节点以获取数据
源节点的状态为migrating
中间过渡状态
目标节点的状态为importing
节点状态
迁移过程中出现网络故障,当前两个节点依旧处于中间过渡状态,待下次迁移工具重新连接上时,会提示用户继续进行迁移要避免产生大key,否则迁移会很慢
迁移过程中,客户端访问流程
迁移,Redis Cluster提供了工具redis-trib,可以让运维人员手动调整槽位的分布情况,也提供了自动化平移槽位工具
容错,Redis Cluster可以为每个主节点设置若干个从节点,当主节点发生故障时,集群会自动将某个从节点提升为主节点如果某个主节点没有从节点,那么当他发生故障时,集群将完全处于不可用状态
网络抖动
可能下线PFail与确定下线Fail
不支持事务,mget方法比redis慢很多,rename方法不再是原子的,因为要将数据从源节点转移到目标节点
集群变更感知
Redis Cluster
集群方案
集群
内部表示是一个字符数组,类似于Java的ArrayList
采用预分配冗余空间的方式来减少内存的频繁分配
字符串长度小于1MB时,加倍扩容,超过1MB时,一次增加1MB,最大支持512MB
set
mset
get
mget
exists
setnx
incr
incrby
decr
常用命令
String 字符串
相当于Java语言中的LinkedList,是链表而不是数组,插入删除快,查找慢
底层数据结构是“快速链表”
rpush
lpush
rpop
lpop
llen
lindex
ltrim
list 列表
相当于Java语言中的HashMap,是无序字典,结构上也是数组+链表实现
采用渐进式rehash策略
hset
hmset
hgetall
hlen
hincrby
hash 字典
相当于Java语言里面的HashSet,内部键值对是无序唯一的,内部实现相当于一个特殊的字典,字典中所有的value都是Null
sadd
smembers
sismember
scard
spop
set 集合
类似于Java语言中的SortedSet和HashMap的集合体,可以给每个value赋予一个score,代表这个value的排序权重
内部实现是“跳跃列表”
zadd
zrange
zrevrange
zcard
zscore
zrank
zrangebyscore
zrem
zset有序列表
最小的单位bit,每个bit的值只能是0或1
零存整取
整存零取
bitcount
bitpos
bitfield
bitmap位图
提供不精确的去重计数方案,标准误差是0.81%
在计数比较小的时候,采用稀疏矩阵存储,当占用空间超过阈值时,会一次性转变为稠密矩阵,占用12kb的存储空间
记录低位连续零位的最大长度K,通过这个K值估算出随机数的数量N
pfadd
pfcount
pfmerge
HyperLogLog
用来解决去重问题的,在起到去重作用的同时,在空间上还能节省90%以上,有一定的误判概率
布隆说某个值存在,可能不存在
布隆说某个值不存在,一定不存在
可以理解为一个不怎么精确的set结构
Redis4.0之后才出现,作为一个插件加载到Redis Server中
bf.add
bf.exists
bff.madd
bf.mexists
使用前可以通过bf.reserve创建,需要三个参数,key,错误率和初始size
底层实现是一个大型的位数组和几个不一样的无偏hash函数
当用户来查询某个row时,先通过布隆过滤器过滤掉大量不存在的row请求,然后在再去磁盘中进行查询
Bloom Filter布隆过滤器
采用漏斗算法
cl.throttle k 15 30 60 1
返回允许或者拒绝,漏洞容量,漏斗剩余容量,需要多久再次重试,过多久完全空出来
cl.throttle
Redis-Cell限流模块
3.2版本后增加
geoadd
geodist
georadiusbymember
georadius
存储结构上使用的是zset,意味着我们可以使用zset相关的指令来操作Geo数据
GeoHash模块
2.8版本后增加
服务器不需要要位游标保存状态,游标的唯一状态就是scan返回给客户端的游标整数
返回的结果可能会重复,需要客户端去重
单次的结果是空并不意味着遍历结束,而是要看返回的游标值是否为零
scan 0 match key99* count 1000
采用高位进位加法,防止扩容和缩容时槽位遍历重复和遗漏
scan
数据结构
(1)create if not exists(2)drop if no elements(3)设置过期时间是以对象为单位的,如果一个字符串设置了过期时间, 再使用set方法修改他,过期时间会消是
分布式锁的本质上要实现在Redis中占一个坑,一般使用指令setnx加锁,执行完再调用del释放锁
在锁上加上过期时间,set k v ex time nx
分布式锁
Redis
0 条评论
回复 删除
下一页