缓存的基本原理:
实现客户端向后端进行请求存储层数据,插入缓存层,完成数据的极速获取,此功能可以完成以下方面:
1、快速获取存储层数据
2、若缓存层没有数据,则去请求存储层(穿透查询),存储层数据会种到缓存层后(回种),再返回客户端,这样下次请求同样数据时可以直接从缓存层获取到数据
3、当存储层挂掉或者无法提供服务时,可以让客户端的请求直接打到缓存层上,不管是否请求到数据,都直接返回(熔断)
------------------------------------------------------------------------------------
Memcache和redis的区别
Memcache的优点是简单易用,且跟hash非常类似,可以直接用过hash这种数据结构来实现
缺点不支持数据的持久化、不支持主从同步、不支持主从(sharding)
Redis的优点:
1.支持多种数据类型(set,zset,hash,String,list)
2.支持数据持久化
3.支持主从同步
4.支持分片(sharding)(redis3.1后支持)
为什么Redis快
1.官方提供100000Qps(每秒内查询次数)实际生产40000Qps左右
2.完全基于内存的,大多是内存操作,执行效率高
3.采用单进程、单线程模型的kv数据库 C语言编写,数据存储在内存中,读写时不会受到硬盘的IO限制
4.数据结构简单,对数据操作也很简单(redis不使用表,不会对数据进行编译关联)
------------------------------------------------------------------------------------
Redis的数据类型
1.String 最基本的数据类型,二进制安全,最大可以存储512M
保存 set name “redis” 获取 get name incr(自增1)
2.Hash:String元素组成的字典 适用于对象
3.List:列表,按照String插入顺序排序
4.Set:String元素组成的无序集合,通过hash表实现,不可重复
5.Sorted Set:通过分数来为集合中的成员做从小到大排序
除此之外还有 用于计数的HyperLogLog,用于支持存储地理位置信息的Geo
如何从海量数据中获取到某一固定前缀的Key
1.摸清数据量
一、使用Keys 一次性返回所有匹配的key 数量过大的时候会使服务卡顿
二、使用SCAN cursor 给定游标0 然后每次获取上一次返回游标的值传入下一次查询,注意去重(可能游标比上一次小)
------------------------------------------------------------------------------------
通过Redis实现分布式锁
分布式锁需要解决的问题
互斥性:任意时刻只能有一个客户端获取锁
安全性:锁中只能由持有锁的客户端删除,不能被其他客户端删除
死锁:获取锁的客户端因为某些原因而宕机未能释放锁
容错:当redis宕机时 依然可以获取到锁
SETNX key value:如果key不存在,则创建并赋值
时间复杂度:0(1)
返回值:设置成功,返回1;设置失败,返回0
EXPIPE key secands
设置key的生存时间,当key过期,会被自动删除
缺点:原子性得不到保证 虽然都是原子性,但是组合在一起不能保证原子性
RedisService redisService = SpringUtils。getBean(RedisService.class)
long status = redisService.setnx(key,"1");
if( status == 1){
//设置过期时间
redisService.expire(key expire);
//执行独占资源逻辑
do0cuppiedWork();
}
解决如上无法保证原子性的问题
至redis2.6以后 可以使用SET key value [EX sconds][PX milliseconds][NX|XX]
EX sconds:设置键的过期时间 seconds秒
PX milliseconds:设置过期时间为millisecond 毫秒
NX:只要间不存在时,才对键进行设置操作
XX:只在键已存在时,才对键进行设置操作
SET操作成功完成时,返回OK,否则返回nil
String result = redisService.set(lockKey, requestId,SET_IF_NOT_EXIST,SET_WITH_EXPIRE,expireTime);
if ("OK".equalks(result)) {
//执行独占资源逻辑
do0cuppiedWork();
}
-------------------------------------------------------------------------------------
如何使用redis做异步队列
使用list作为队列 ,RPUST生产消息,LPOP消费消息
缺点:没有等待队列中有值就直接消费
弥补:可以通过代码引入Sleep机制调用LPOP重试
BLPOP key timeout 阻塞知道有消息或者超时
缺点:只能供一个消费者消费
使用Redis pub/sub:主题订阅者模式
subscribe mytopic 订阅消息
publish mytopic 发布消息
缺点:无法保证消息一定被接收到
------------------------------------------------------------------------------------
Redis如何做持久化
RDB(快照)持久化:保存某个时间点的全量数据快照
redis.conf ->save 900 1 表示900秒内有一次写入操作就执行保存快照
save 300 10 表示300秒内有10次写入操作就执行保存快照
save 60 10000表示60秒内有10000次写入操作就执行保存快照
stop-writes-on-bgsave-error yes 当备份进程出错的时候,主进程就停止写入操作了,可以保证持久化数据一致性
rdbcompression yes 压缩后持久化(建议设置为no)
save:阻塞redis服务器进程,直到RDB文件被创建完毕:
BGSAVE:Fork出一个紫禁城出来创建RDB文件,不阻塞服务器进程
自动化触发RDB持久化得方式
①根据redis.conf配置里的save m n 定时触发(使用的是BGSAVE)
②主从复制时,主节点自动触发
③执行Debug Reload
④执行Shutdown且没有开启AOF持久化
缺点:内存数据全量同步,数据量大会由于IO而影响性能
可能会因为Redis挂掉而丢失从当前至最近一次快照期间的数据
AOF持久化:保存写状态
appendonly yes
appendfilename “appendonly.aof”
appendfsync everysec 写入方式 always 只要发生写操作就写入aof;
everysec美妙写入一次(推荐)
no交给操作系统决定
redis4.0后支持RDB-AOF混合持久化方式
BGSAVE 做镜像的全量持久化,AOF做增量持久化
------------------------------------------------------------------------------------
Redis 的同步机制
全量同步过程:
Salve发送sync命令到Master
Master启动一个后台进程,将Redis中的数据快照保存到文件中(BGSAVE)
Master将保存数据快照期间接收的写命令缓存起来
Master完成写文件操作后,将文件发送给salve
使用新的AOF文件替换掉旧的AOF文件
Master将这期间手机的增量写命令发送给salve端
增量同步操作
Master接收到的用户指令,判断是否需要传播到Salve
将操作记录追加到AOF文件中
将操作传播到其他Slave:1.对其主从库;2.往响应缓存写入指令
将缓存中的数据发送给Slave
Redis Sentine(哨兵)
解决主从同步Master当即后的主从切换问题
监控:检查主从服务器是否运行正常
提醒:通过API向管理员或者其他应用程序发送故障通知
自动故障迁移:主从切换(使用投票协议)
流言协议 Gossip
在杂乱无章中寻求一致
每个节点都随机与对方通信,最终所有节点装填达成一致
每个种子节点定期随机向其他节点发送节点列表以及需要传播的消息
不保证信息一定会传递给所有节点,但是最终会趋于一致
----------------------------------------------------------------------------------------------------
Redis的集群原理
从海量数据里快速找出所需?
分片:按照某种规则去划分数据,分散存储在多个节点上
常规的按照哈希划分无法实现节点的动态增减
一致性哈希算法:对2^32取模。将哈希值空间自称虚拟的圆环(0=2^32)
当节点较少时,hash环的数据倾斜问题(解决方法:使用虚拟节点映射,通常设置32个虚拟节点以上)