Memcache与Redis的区别
首先我们得知道为啥要用Redis
Memcache
- 支持简单数据类型
- 不支持数据持久化存储
- 不支持主从
- 不支持分片
Redis
- 数据类型丰富
- 支持磁盘持久化
- 支持主从
- 支持分片
为什么Redis能这么快
官方给出的是支持10W+QPS(QPS-query per second ,每秒查询次数)
- 完全基于内存,绝大部分请求是纯粹的 内存操作,执行效率高
- 数据结构简单,对数据操作简单
- 采用单线程,单线程可以处理高并发请求,多核启动多实例
- 使用多路IO复用模型,并非阻塞IO
多路I\O复用模型
首先知道一个概念
FD:File Descriptor文件描述符
一个打开的文件通过唯一的描述符进行引用,描述符石打开文件的元数据到文件本身的映射
Redis使用的是多路复用IO模型,防止阻塞影响性能
将监控文件是否可读,交给selector,那么线程就可以做点别的事情去了
根据不同的系统,使用不同的多路复用函数,因为所有的系统都会支持select,所以在Redis发现本系统没有更好的可用时会用select
IO多路复用函数:epoll/kqueue/evport/select
- 因地制宜
- 优先选择时间复杂度O(1)的作为底层实现
- 以时间复杂度位O(n)的select作为保底(所有操作系统都实现此函数)
- 给予react设计模式监听I/O事件
Redis数据类型
- String:最基本的数据类型,二进制安全
- Hash:String元素组成的字典,适合存放对象
- List:列表,按照String元素插入序列排序
- Set:String元素组成的无序集合,通过哈希表实现,不允许重复
- Sorted Set 不可重复,但是可以排序
- HyperLogLog用于计数
- Geo用来存储地理位置信息
从海量key查询出某一固定前缀的key
首先我们要知道数据量到底有多大,再决定使用什么方式查询
keys命令可能带来的隐患
大数据量下会阻塞,2000W数据,卡住执行80s+
SCAN 指令
还是刚才的场景,我们用scan指令查询
这样查询不会阻塞,但是可能会出现重复的情况,我们可能需要在应用程序中进行去重
如何通过Redis实现分布式锁
分布式锁需要解决的问题:
- 互斥性
- 安全性
- 死锁
- 容错
解决方案(SETNX):
SETNX key value :如果key不存在,那么创建并返回
####应用原理
一个线程占用资源时,先SETNX一个值,在执行结束后将值删除
在此期间,别的线程使用相同资源时,先SETNX同样的key,设置无效则证明资源没被释放
如何解决SETNX长期有效的问题
EXPIRE key seconds
如果使用资源长期不被释放,那么资源就会一直被占用,我们可以通过设置key过期时间
例如:我们在程序中可以如下设计
long status = redisService.setnx(key,"1");
if(status == 1){
redisService.expire(key,expire);
// 处理单独占用资源的逻辑
}
设计缺陷
原子性得不到满足,如上设计方案执行SETNX后挂了,那么过期时间还是没设置啊,这不还是完蛋?
解决方案(SET key+参数)
使用方式
SET key value [EX seconds] [PX milliseconds ] [NX|XX]
- EX second:设置键的过期时间为second秒
- PX millisecond:设置键的过期时间为millisecond
- NX:当前无,则插入
- XX:当前有,才插入
SET操作成功返回OK,否则返回nil
具体实现
使用以下可以保证原子性
long result = redisService.set(key,requestId,SET_IF_NOT_EXIST,SET_WITH_EXPIRE_TIME,EXPIRETIME);
if(result == "OK"){
// 处理单独占用资源的逻辑
}
大量key同时过期,造成卡顿
设置过期时间时,会随机增加毫秒数,防止同一时间过期
如何使用Redis做异步队列
使用List进行一个入栈,出栈操作,请忽略中间两步弟弟操作。。
POP
如果pop返回nil,那就说明消费完了,我们程序调用可能需要在此时进行一个延时操作(sleep一会儿再访问)
BLPOP
sleep的方式,总感觉会被面试官锤!!!那么BLPOP闪亮登场
BLPOP key timeout:阻塞至队列有消息或超时
缺点:只能提供给一个消费者
那肯定不得劲~还得升级!
pub\sub主题订阅者模式
发送者pub发送消息,订阅者可以关注任意数量的频道
缺点是
消息发布无状态,无法保证到达
Redis如何持久化
RDB持久化策略
在redis.conf文件中,这些是根据不同情况做的不同策略
当备份进程出错,停止写入操作,保护数据
自动化触发RDB持久化的方式
保存备份有两种模式,save和bgsave
- save会阻塞当前服务,直到备份完毕
- bgsave会创建一个子线程备份,不会阻塞当前备份,轮训访问备份是否完毕
Copy-on-Write
当Redis需要备份时,系统fork()创建一个子进程,父进程继续处理客户端的操作,当执行写入时,系统创建一个副本给父进程,子线程备份完毕后,父进程将副本覆盖当前资源
RDB缺点
- 内存数据的全量同步,数据量大由于IO而严重影响性能
- 可能因为Redis挂掉而丢失当前至最近一次快照期间的数据
AOF持久化
AOF(Append-Only-File)持久化,保存写命令
默认不开启,需要conf文件配置,开启后需要重启
可以执行config set appendonly yes开启增量备份
日志文件过大如何处理
RDB于AOF优缺点
可以使用RDB-AOF混合持久化方式,4.0版本以后默认此方式
BGSAVE做镜像全量持久化,AOF做增量持久化
Pipeline的好处
Redis同步机制
主从同步原理
只有主节点做写操作,从节点只做读操作
全同步过程
增量同步过程
Redis Sentinel
解决主从同步Master宕机后主从切换
流言协议Gossip
在杂乱无章种寻求一致
Redis的集群
现在假设有4个对象:object1-object4,将四个对象hash后映射到环形空间中:
一个cache就是一个redis节点哈
接下来把chche映射到hash空间(基本思想就是讲对象和cache都映射到同一hash数值空间中,并且使用相同的hash算法,可以使用cache的ip地址或者其他因子),假设现在有三个cache:
每个key顺时针往下走,找到的第一个cache节点就是存储位置:
现在移除一个cacheB节点、这时候key4将找不到cache,key4继续使用一致性hash算法运算后算出最新的cacheC,以后存储与读取都将在cacheC上:
移除节点后的影响范围在该节点逆时针计算到遇到的第一个cache节点之间的数据节点。