Redis
约 2661 字大约 9 分钟
2025-04-10
一、介绍
关系型数据库 和 非关系型数据库
关系型数据库:MySQL Oracle ..
特点:数据结构严谨(库,表,字段..),插入数据严格符合声明的数据类型。
ACID:原子性,一致性,独立性,持久性
非关系型数据库:Redis Hbase ...
特点:数据结构不严谨、松散,
CAP:强一致性,可用性,分区容错性
WEB 1.0 和 WEB 2.0
NoSQL :not only sql
特性
多数据库。(默认16个 [ 0~15 ])
select 库索引 可以选择数据库存数据。
dbsize 查看当前数据库长度
flush 删除数据库内容
消息的订阅与发布
subscribe 订阅关键字 (完全匹配)
public 发布 键 值
psubscribe 订阅关键字(关键字匹配)
二、数据类型
键约束:长度不能超过1024字节,见名知意
五种数据类型
redis类型 对应java类型 String String (内存缓存) Has HashMap (复杂的内存缓存) List LinkedList (避免数据推送丢失 rpop lpush) Set HashSet (查看访问用户的数量[去重]) SortedSet TreeSet (实时排名
三、连接池
用法
//1. 设置初始化参数。 JedisPoolConfig pc = new JedisPoolConfig(); pc.setMaxTotal(100);//最大链接数 pc.setMaxIdle(30);//最大空闲连接数 pc.setMinIdle();//最小空闲连接数 pc.setMaxWaitMillis();//最大等待时间 //2. 根据初始化参数创建连接池 JedisPool pool = new JedisPool(pc,"ip",6379); //3. 从连接池获取链接。 Jedis jedis = pool.getResource(); //4. 使用链接。 jdeis.get(key); //5. 存回连接池。 jedis.close(); //省略了fiinally包起来
'池'思想
原理 :
创建容器,预先存储若干资源。
使用资源时从容器中取出现成的。
使用完毕,放回容器。
特点:效率高,节约资源。
四、持久化
redis 的数据都是在内存中的,有安全隐患(关系型数据库备份)。redis 自身实现了持久化:
RDB (模式官方推荐,默认开启 [Repeat DataBase])
隔一段时间将 redis 数据 序列化到磁盘。
实现策略
save 900 1 #15分钟,有1个key 改变,就序列化。 save 300 10 #5分钟,有10个key 改变,就序列化。 save 60 10000 #在1分钟内 有1w个key 改变,就序列化。
存储位置:dbfilename dump.rdb
AOF 模式。(Append Only File)
当数据有变化时,就序列化到磁盘
实现策略
#redis.conf 配置文件里 appendonly no yes #启用 #(用哪个就把注释干掉) # appendfsync always # appendfsync everysec # appendfsync no
存储位置:appendonly.aof
五、Redis 单线程模型详解 (摘自Guide哥)
Redis 基于 Reactor 模式来设计开发了自己的一套高效的事件处理模型 (Netty 的线程模型也基于 Reactor 模式,Reactor 模式不愧是高性能 IO 的基石),这套事件处理模型对应的是 Redis 中的文件事件处理器(file event handler)。由于文件事件处理器(file event handler)是单线程方式运行的,所以我们一般都说 Redis 是单线程模型。
既然是单线程,那怎么监听大量的客户端连接呢?
Redis 通过IO 多路复用程序 来监听来自客户端的大量连接(或者说是监听多个 socket),它会将感兴趣的事件及类型(读、写)注册到内核中并监听每个事件是否发生。
这样的好处非常明显: I/O 多路复用技术的使用让 Redis 不需要额外创建多余的线程来监听客户端的大量连接,降低了资源的消耗(和 NIO 中的 Selector
组件很像)。
另外, Redis 服务器是一个事件驱动程序,服务器需要处理两类事件: 1. 文件事件; 2. 时间事件。
时间事件不需要多花时间了解,我们接触最多的还是 文件事件(客户端进行读取写入等操作,涉及一系列网络通信)。
《Redis 设计与实现》有一段话是如是介绍文件事件的,我觉得写得挺不错。
Redis 基于 Reactor 模式开发了自己的网络事件处理器:这个处理器被称为文件事件处理器(file event handler)。文件事件处理器使用 I/O 多路复用(multiplexing)程序来同时监听多个套接字,并根据 套接字目前执行的任务来为套接字关联不同的事件处理器。
当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
虽然文件事件处理器以单线程方式运行,但通过使用 I/O 多路复用程序来监听多个套接字,文件事件处理器既实现了高性能的网络通信模型,又可以很好地与 Redis 服务器中其他同样以单线程方式运行的模块进行对接,这保持了 Redis 内部单线程设计的简单性。
可以看出,文件事件处理器(file event handler)主要是包含 4 个部分:
- 多个 socket(客户端连接)
- IO 多路复用程序(支持多个客户端连接的关键)
- 文件事件分派器(将 socket 关联到相应的事件处理器)
- 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)
六、redis集群
redis最开始使用主从模式做集群,若master宕机需要手动配置slave转为master;后来为了高可用提出来哨兵模式,该模式下有一个哨兵监视master和slave,若master宕机可自动将slave转为master,但它也有一个问题,就是不能动态扩充,所有有了现在的cluster集群模式
结构特点
redis节点彼此互联(ping-pong机制),内部使用二进制协议
fail通过投票来判断
客户端随意连接其中一个redis即可
节点=>插槽=>数据
插槽
搭建集群的时候会把0~16383个插槽分配给节点(服务器),就类似于标识,0~5000 都是第一个节点,5000~10000就是第二个节点,剩余的就是第三个节点
在redis集群执行 “set a a” 往里放值 (get a 取数同理)
连接任意一个节点 例如node3
对key,就是命令的a,进行crc16算法的计算,得到一个数字,也就是进行 16384 的求余,结果的范围就会是在0~16383之中,例如某个数字对3取余:
1&3=1,2%3=2,3%3=0,4%3=1....,结果就是在0~2之间。
假如上个步骤得到的数字为3000,就在集群中查找有3000这个插槽slot的节点,此时找到node1
连接跳转到node1,在node1上执行 "set a a "
Redis Cluster主从模式
redis cluster 为了保证数据的高可用性,加入了主从模式,一个主节点对应一个或多个从节点,主节点提供数据存取,从节点则是从主节点拉取数据备份,当这个主节点挂掉后,就会有这个从节点选取一个来充当主节点,从而保证集群不会挂掉
上面那个例子里, 集群有ABC三个主节点, 如果这3个节点都没有加入从节点,如果B挂掉了,我们就无法访问整个集群了,A和C的slot也无法访问
所以我们在集群建立的时候,一定要为每个主节点都添加了从节点, 比如像这样, 集群包含主节点A、B、C, 以及从节点A1、B1、C1, 那么即使B挂掉系统也可以继续正确工作
B1节点替代了B节点,所以Redis集群将会选择B1节点作为新的主节点,集群将会继续正确地提供服务。 当B重新开启后,它就会变成B1的从节点
不过需要注意,如果节点B和B1同时挂了,Redis集群就无法继续正确地提供服务了
集群是如何判断是否有某个节点挂掉
首先要说的是,每一个节点都存有这个集群所有主节点以及从节点的信息。它们之间通过互相的ping-pong判断是否节点可以连接上。如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机了,然后去连接它的备用节点
集群进入fail状态的必要条件
- 某个主节点和所有从节点全部挂掉,我们集群就进入faill状态
- 如果集群超过半数以上master挂掉,无论是否有slave,集群进入fail状态
- 如果集群任意master挂掉,且当前master没有slave.集群进入fail状态
七、Redis淘汰策略
详情点击见内存淘汰策略
八、缓存穿透和缓存击穿
简短来说就是:”穿透“ 打透了什么都没有,“击穿” 破甲之后拿到了。
缓存穿透:大量请求去请求一个本身就不存在的数据,比如数据库中user表userId是“1,2,3,4,5...”,这个时候有大量的请求来取id=0或者id=-1的数据,发现缓存中没有就去数据库中,然后发现数据库中也没有。
缓存击穿:某个key可能再某个瞬间到期了,导致所有的请求都去数据库中去取值。
缓存雪崩:大量key在某个时间失效,造成大量请求都去请求数据库,增加数据库的压力
九、先更新缓存还是先更新数据库?
没有最完美的方案,只有最适合的方案。每个方案都有自己的缺陷也有自己的优点
常见的策略有:
- cache aside (旁路缓存)
- Read/Write through
- Write behind caching
cache aside