Redis Basic

缓存初识

缓存在应用中的架构

struct

缓存中间件

Memcache

  • 支持简单数据类型
  • 不支持数据持久化存储
  • 不支持主从
  • 不支持分片

Redis

  • 数据类型丰富
  • 支持数据持久化存储
  • 支持主从
  • 支持分片

为什么Redis速度快

  • 完全基于内存,不受限存储器io
  • 数据结构简单,数据操作简单
  • 单线程处理高并发,多核可启动多实例
  • 多路IO复用模型,非阻塞IO

IO模型

FD

  • File Descriptor,文件描述符

一个打开的文件通过唯一的描述符进行引用,该描述符是打开文件的元数据到文件本身的映射

传统的阻塞IO模型

iomodel

多路IO复用模型

  • Selector负责监听文件描述符,不堵塞程序

selector

IO多路复用函数

  • epoll/kqueue/evport/select

  • 根据环境选择

  • 优先选择O(1)函数
  • 保底选择O(n)函数select(扫描全部监听符)
  • 基于react设计模式监听IO

文件事件处理器使用多路IO复用模块,同时监听多个FD,当read,close,write等事件发生,回调FD绑定的事件处理器,实现单线程对多个FD的监控。

Redis常用数据类型

  • String:二进制安全,512MB,可以包含任何数据(jpg等)
  • Hash:String元素组成的字典,适合存储对象
hmset rex name "rex" age 23 title "student"
hget rex age
26
hset rex title "researcher"
  • List:列表,按照String元素插入顺序排序
lpush mylist aaa
lpush mylist bbb
lpush mylist ccc
lrange mylist 0 10
ccc
bbb
aaa
  • Set:String元素组成的无序集合,通过Hash实现,不允许重复
sadd myset 111
1
sadd myset 222
1
sadd myset 111
0
  • Sorted Set:通过分数来为集合中的成员从小到大排序

zset

  • HyperLogLog(计数),Geo(地理位置信息)

找出固定前缀的Key

  • keys [pattern]:查找所有符合给定模式的key

keys k1*

返回数据量大的话,内存消耗大

  • scan cursor [pattern] [count]

基于游标的迭代器,需要基于上一次游标,延续之前的迭代过程

以0作为游标开始新一次的迭代,知道命令返回游标0完成一次遍历

一次返回数量不可控

scan

实现分布式锁

  • 互斥性(任意时刻只有一个客户端获取锁)
  • 安全性(只能被持有者开锁)
  • 死锁
  • 容错(部分节点down掉依旧可以获取锁)

setnx key value

如果key不存在,创建并赋值O(1),success:1,failure:0

expire key seconds

设置key生存时间,过期会被删除

简单的分布式锁:

lock

缺点:不符合原子性

set [key] [value] [seconds] [milliseconds] [NX|XX]

  • NX:键不存在时操作
  • XX:键存在时操作
  • success:ok,failure:nil

大量key同时过期

  • 清理大量key耗时造成卡顿
  • 解决:设置过期时间时,增加随机值

实现异步队列

使用List作为队列

  • RPUSH生产消息,LPOP消费消息

  • 缺点:没有等待队列有值

  • 解决:应用层引入sleep机制

blpop [key] [timeout]

  • 优点:替代sleep机制

  • 缺点:只能提供一个消费者消费

pub/sub

  • 主题订阅者模式
  • pub发送消息,sub接收消息
  • sub可以订阅任意数量的频道

sp

subscribe [topic]

publish [topic] [message]

pub/sub发布无状态,无法保证可达,下线后无法收到

需要消息队列技术栈解决

Redis如何做持久化

RDB

  • 快照持久化:保存某个时间点的全部数据快照

redis.conf

rdb

900s 内写入1次就存储

60s 内写入10000次就存储

增加 save “”即可禁用

conf1

yes:备份进程出错,主进程停止写入操作

保护持久化数据一致性

conf2

将RDB数据压缩后再保存,会占用系统资源

文件存储在src/dump.rdb文件中(二进制文件)

保存某时刻的快照方法:

  • save:阻塞Redis服务器进程,知道RDB文件创建完毕
  • bgsave:fork一个子进程创建RDB文件,不阻塞服务器进程

可用lastsave指令查看是否成功

bgsave

fork创建进程,将所有资源复制给子进程,效率低下,linux进行了更改copy-on-write

copyonwrite

缺点:

  • 内存数据全部同步,数据量大影响性能(慢IO)
  • 可能因为Redis挂掉丢失当前到最近一次快照而数据

AOF

  • 保存写状态
  • 记录除了查询以外的所有变更数据库状态的指令
  • 以append形式追加保存到AOF文件中

默认关闭

redis.conf

aof

保存策略

aof2

每秒/总是/从不

  • 日志重写解决AOF文件大小逐渐增大问题

1、调用fork(),创建子进程

2、子进程把新的AOF写到一个临时文件,不依赖原来的AOF文件

3、主进程持续将新的变动同时写道内存和原来的AOF

4、完成重写,发送信号给主进程,并将buffer重定向到新AOF

5、使用新AOF替换旧AOF

可手动触发

RDB&AOF共存情况下的数据恢复

  • 优先加载AOF

优缺点

  • RDB:全量数据快照,文件小,恢复快
  • RDB:无法保存最近一次快照后的数据
  • AOF:本质是日志,可读性高,适合保存增量数据,数据不易丢失
  • AOF:文件体积大,恢复时间长

混合持久化

  • 默认使用
  • 先RDB备份,再AOF记录增量数据

Pipeline & 主从同步

Pipeline

  • Redis基于请求/响应模型,单个请求处理需要一一应答
  • Pipeline批量执行指令,节省多次IO往返时间
  • 有需要顺序依赖的指令需要分批发送

主从同步

ms

master:写操作 slave:读操作

  • 全同步过程

1、salve发送sync到master

2、master启动后台进程,将redis中的数据快照保存到文件

3、master将保存数据快照期间受到的写命令缓存

4、master完成写文件操作后,将该文件发送给slave

5、slave使用心得AOF文件替换旧的

  • 增量同步过程

1、master收到指令,判断是否需要传播到slave

2、将操作记录追加到AOF文件

3、将操作传播到其他slave:对齐master,往相应缓存里写入指令

4、将缓存的数据发送给slave

主从模式缺少高可用性,master挂掉不能服务

  • Redis Sentinel

集群管理工具

1、监控:检查主从服务器是否运行正常

2、提醒:通过API向管理员或者其他应用发送故障信息

3、自动故障迁移:主从切换,s变为m

tip:Gossip流言协议

  • 混乱中寻求一致
  • 每个节点都随即与对方通信,最终所有节点状态相同
  • 种子节点每秒随机向其他节点发送节点列表和需要传播的信息
  • 新加入的节点会被知晓
  • 不保证信息一定会传递到到所有节点,但会趋于一致

Redis集群

  • 数据分片:划分数据分散到多个节点
  • 无中心
  • 普通hash算法不利于节点数量改变(key/node取模)

一致性hash算法

  • 对2^32取模,组成虚拟圆环

rediscluster

  • 宕机后只影响之间的一部分数据(增加同理)

  • hash环倾斜问题(节点分布不均匀)

hash

解决:引入虚拟节点,虚拟节点均匀分布,再重映射

  • Copyrights © 2019-2020 Rex