目录
引申:BIO、NIO、IO Multplexing、Asynchronous IO
redis的fork和cow(copy on write写时复制)
解决redis的容量问题-redis的Sharding分片机制
redis中的cluster引入(查询路由-也属于redis分区)
Redis官方网址:
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
CRUG网站 Redis Redis文档中心 -- Redis中国用户组(CRUG)
redis单线程、单实例为什么效率高?
redis单线程为什么执行速度这么快-Redis-PHP中文网
引申:BIO、NIO、IO Multplexing、Asynchronous IO
10.BIO、NIO、AIO、多路复用IO的区别(图解)_扛麻袋的少年的博客-CSDN博客_io多路复用和nio的关系
redis中value数据结构sortedSet的原理:
使用时skip list(跳跃表)
【老荀】3分钟讲解redis中的跳跃列表_哔哩哔哩_bilibili
Redis zset的数据结构:SkipList(跳表)的原理及实现__Yasin的博客-CSDN博客
如何构建跳跃表:当插入一个数据时,随机获得这个节点的高度,没错,就是随机!每涨一层的概率为p,这个认为设置,一般为0.25或者0.5,这样层数越高的节点就越少(这种结构跟平衡树有点像)。
每一个结点不单单只包含指向下一个结点的指针,可能包含很多个指向后续结点的指针,这样就可以跳过一些不必要的结点,从而加快查找、删除等操作。对于一个链表内每一个结点包含多少个指向后续元素的指针,这个过程是通过一个随机函数生成器得到,这样子就构成了一个跳跃表。这就是为什么论文“Skip Lists : A Probabilistic Alternative to Balanced Trees ”中有“概率”的原因了,就是通过随机生成一个结点中指向后续结点的指针数目。
redis管道pipeline的使用
- 管道(Pipelining):学习如何一次发送多个命令,节省往返时间。
redis的发布订阅
例子:
发布者:
订阅者:
redis:redis的一种使用场景(聊天记录)
redis事务的使用
redis是单线程的,谁的exec先到达就先执行谁的事务。
redis事务的几个相关命令:MULTI (开启事务)、 EXEC 、 DISCARD 和 WATCH 是 Redis 事务相关的命令
EXEC 命令负责触发并执行事务中的所有命令:
redis作为缓存的使用
访问是不会延迟过期时间的,set(写)会剔除过期时间,也可以设置到倒计数以及定时过期时间,ttl命令可以看到过期剩余的时间。
将redis当做使用LRU算法的缓存来使用:
回收策略:REDIS lru-cache -- Redis中国用户组(CRUG) LFU和LRU
redis如何淘汰过期的keys:
1,被动式 2,轮询主动式
redis持久化机制
参考文档:10分钟彻底理解Redis的持久化机制:RDB和AOF - Java知音号 - 博客园
RDB(快照)是默认开启的:
redis的fork和cow(copy on write写时复制)
如下:fork只会创建一个redis子进程,只复制地址映射,里面的指针还是指向主没存中的数据,cow父子进程互相不影响。
当数据发生改变时,比如把物理内存的x改成w,应该是先在物理内存中先出现w,若子进程改只需要将子线程中的指针(虚拟地址)指向物理内存中的w即可。对于redis的rdb来说子进程是不会修改数据的,他只会读数据往磁盘输出文件,主进程才对外提供增删改操作。
redis的持久化机制AOF
AOF持久化的策略。redis默认使用everysec,就是说每秒持久化一次,而always则是每次操作都会立即写入aof文件中。而no则是不主动进行同步操作,是默认30s一次。当然always一定是效率最低的,个人认为everysec就够用了,数据安全性能又高。(类似于flush的概念)
Redis集群
redis(六):AKF架构解决Redis单机单节点下的弊端_DoYa~的博客-CSDN博客(AKF架构解决Redis单机单节点问题)
集群解决的问题:
redis的AFK原理:
AKF
X:全量,镜像 Y:业务,功能 Z:优先级,逻辑再拆分
多个redis产生的数据问题
第一种:同步阻塞所有的redis都操作成功才通知客户端成功,慢如果出现其中一个出现故障也麻烦
第二种:异步,先返回,然后再去同步数据
第三章:通过组件kafka先把命令写入,写入成功就返回
redis中的主备和主从
主备和主从的区别:主备 主从 主主模式 - madtank - 博客园
对主机如何做监控,sentinel
REDIS sentinel-old -- Redis中国用户组(CRUG)
区别:Redis Sentinel 与 Redis Cluster_devillyd2018的博客-CSDN博客
Redis-Sentinel(哨兵模式)是Redis官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端)都没有实现自动进行主备切换,而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自懂切换。它的主要功能有以下几点:
- 监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
- 提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
- 自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
-
Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。
虽然 Redis Sentinel 释出为一个单独的可执行文件 redis-sentinel , 但实际上它只是一个运行在特殊模式下的 Redis 服务器, 你可以在启动一个普通 Redis 服务器时通过给定 –sentinel 选项来启动 Redis Sentinel 。
redis的主从复制原理
从是只能读不能写的
如何设置追随: REPLICAOF 127.0.0.1 6380
redis和spring整合
解决redis的容量问题-redis的Sharding分片机制
客户端分区:
一、概念
1. 分片机制:允许数据存放在不同的机器上,对客户端透明
2. Redis分片机制:减轻单台Redis实例的压力,扩展存储能力和计算能力
上面的主从复制其实解决的是redis的压力问题(从可以作为读取数据的服务器),以及高可用(HA);下面讲解的是redis的容量问题
y轴上进行redis的业务逻辑划分,然后client端去进行访问
数据没办法划分拆解时的解决办法
其中有一个hash取模:hash(key)%N,根据余数,决定映射到那一个节点。这种方式比较简单,属于静态的分片规则。但是一旦节点数量变化,新增或者减少,由于取模的N 发生变化,数据需要重新分布。所以需要更好的解决方案一致性hash取模有,这三种模式其实都有弊端都不适合做数据库的使用
redis(六):AKF架构解决Redis单机单节点下的弊端_DoYa~的博客-CSDN博客(AKF架构解决Redis单机单节点下的弊端)
一致性hash的详解
代理分区
对于server端,redis的连接成本很高
代理分区机制:predixy:一款吊打众对手的redis代理,你喜欢吗?_简易得的博客-CSDN博客_predixy
redis中的cluster引入(查询路由-也属于redis分区)
slot:槽一共有16384个所以槽的编号是从0到16383;假如有三台主机,那么每一个的主机所分的槽为,一号主机:[0-5460];二号主机[5641-10922];三号主机[10923-16383]
REDIS cluster-tutorial -- Redis中文资料站 -- Redis中国用户组(CRUG)
高可用Redis:Redis Cluster - 割肉机 - 博客园
redis cluster主主模型/无主模型
客户端访问任意节点时,对数据key按照CRC16规则进行hash运算,然后对运算结果对16383进行取作,如果余数在当前访问的节点管理的槽范围内,则直接返回对应的数据
如果不在当前节点负责管理的槽范围内,则会告诉客户端去哪个节点获取数据,由客户端去正确的节点获取数据
缺点:因为数据hash计算后可能在不同的节点上所以数据分治。聚合操作很难实现,事务都会有问题,那么需要认为的把数据放在一个节点上
比如加hash tag, 比如:key是{OO}k1 ,{OO} k2 那么只对(OO)进行hash计算,他们两个数据肯定会放在一个节点上。
redis面试
1,击穿、穿透、雪崩
REDIS缓存穿透,缓存击穿,缓存雪崩原因+解决方案 - 大码哥 - 博客园
击穿:
穿透:
有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。
雪崩:
redis的分布式锁
redisApi的简单介绍
public void testRedis(){// stringRedisTemplate.opsForValue().set("hello01","china");
//
// System.out.println(stringRedisTemplate.opsForValue().get("hello01"));RedisConnection conn = redisTemplate.getConnectionFactory().getConnection();
conn.set("hello02".getBytes(),"mashibing".getBytes());
System.out.println(new String(conn.get("hello02".getBytes())));
// HashOperations<String, Object, Object> hash = stringRedisTemplate.opsForHash();
// hash.put("sean","name","zhouzhilei");
// hash.put("sean","age","22");
//
// System.out.println(hash.entries("sean"));
Person p = new Person();
p.setName("zhangsan");
p.setAge(16);// stringRedisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
Jackson2HashMapper jm = new Jackson2HashMapper(objectMapper, false);
stringRedisTemplate.opsForHash().putAll("sean01",jm.toHash(p));
Map map = stringRedisTemplate.opsForHash().entries("sean01");
Person per = objectMapper.convertValue(map, Person.class);
System.out.println(per.getName());
stringRedisTemplate.convertAndSend("ooxx","hello");RedisConnection cc = stringRedisTemplate.getConnectionFactory().getConnection();
cc.subscribe(new MessageListener() {
@Override
public void onMessage(Message message, byte[] pattern) {
byte[] body = message.getBody();
System.out.println(new String(body));
}
}, "ooxx".getBytes());while(true){
stringRedisTemplate.convertAndSend("ooxx","hello from wo zi ji ");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}}