2个主要原因。(1) Redis
支持多种复杂的数据类型,并且在这些数据类型上定义了原子操作
。可直接暴露给程序员;(2) Redis
不仅是一个内存数据库,还支持数据持久化到磁盘。实现了在内存容量内的高速读写数据。
以64 bit
计算机为例。
过去,Redis
开发人员曾尝试使用虚拟内存和其他系统来允许大于RAM
的数据集。 因此,目前尚无计划为Redis
创建磁盘后端。 毕竟,Redis
的大部分功能都是其当前设计的直接结果。
如果你真正的问题不是所需的总RAM
,而是需要将数据集拆分为多个Redis
实例的事实,请阅读Redis官方文档 分区以获取更多信息。
是的。一个常见的设计模式是:有少量数据需要经常写,将这些数据放到Redis
中,最终与磁盘数据库中的数据保持一致。
见官方的 Redis内存优化
Redis
可能会被Linux
内核OOM Killer
杀死,由于错误而崩溃,或者开始变慢。
Redis
具有内置保护功能,允许用户使用配置文件中的maxmemory
选项设置Redis
可以使用的内存限制,从而设置内存使用的最大限制。 如果达到此限制,Redis
将会只接受只读命令,发送错误给写命令。
INFO
命令返回Redis
当前的内存使用量,可以据此写脚本监控Redis
服务。
对于Redis而言,命令的原子性指的是:一个操作的不可以再分,操作要么执行,要么不执行。
Redis
支持将当前数据的快照存成一个数据文件的持久化机制。Redis借助了fork命令的copy on write
机制。在生成快照时,将当前进程fork
出一个子进程,然后在子进程中循环所有的数据,将数据写成为RDB
文件,而主进程继续接受读写请求。Redis持久化与数据库持久化
Redis持久化:RDB(快照)和AOF(写命令)
通常而言,CPU
并不是Redis
的使用瓶颈。 主要瓶颈是内存或网络限制。所以,如果使用的Redis
命令多为O(N)
、O(log(N))
时间复杂度,那么基本上不会出现CPU瓶颈的情况。
为了最大程度地利用CPU,可以在同一机器中启动多个 Redis
实例,并将它们视为不同的服务器。详情见 Redis官方文档 Partitioning page
在Redis 4.0之后,后端删除对象、blocking commands 实现了多线程。
Redis
最多可以处理232 个key。实验表明,每一个Redis
实例至少可以处理2.5亿个key。
每一个hash
、list
、set
、sorted set
最多可容纳232 个元素。
换句话说,您的限制可能是系统中的可用内存,而不是Redis
本身。
redis
提供两种方式进行持久化,一种是RDB持久化
(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF持久化
(原理是将Reids的操作日志以追加的方式写入文件)。
如果你为这些key设置了 Redis
过期时间,那么这是正常现象。
Maste
r在与slave
的第一次同步时生成RDB
文件。RDB
文件不包括master
中已过期但仍在内存中的key。这些key仍然存在于master
的内存中(逻辑上,这些key已经过期了,所以在master上认为这些key已经不存在了),但是通过INFO
命令DBSIZE
命令能都看到这些信息。slave
读取RDB
文件时,并不会加载这些过期的key。REmote DIctionary Server
的缩写。
Redis是单线程的
,这也就是为什么Redis
能够保证原子性。
对于Redis而言,命令的原子性指的是:一个操作的不可以再分,操作要么执行,要么不执行。
问题来了,既然Redis
是单线程,可以保证原子性,那么它的异步和非阻塞是什么?单线程如何实现异步和非阻塞?
再查阅了很多资料之后,我发现我对于同步/异步
、阻塞/非阻塞
以及单线程/多线程的概念有些不清晰,下面给出简单解释。
同步/异步:首先同步和异步主要是从消息通知机制来讲起的。
同步
:一个任务的完成必须依赖另一个任务,两个要么都成功要么都失败,是一种可靠的任务序列
。当一个同步调用发生后,调用者必须等待返回结果,才能继续后面任务的执行。
异步
:不需要等待被依赖任务的完成,只需要完成自己的任务就可以,所以是不可靠任务序列
。当一个异步调用发生后,调用者不必等待返回结果,调用者可以去做其他的事情,被调用部件在处理完成后,通过(状态、通知、回调)来通知调用者。
阻塞/非阻塞:阻塞和非阻塞和调用者等待消息通知时的状态有关。很重要,不要和同步混淆。
阻塞
:调用者在等待通知的过程中,不能执行其他业务,傻傻的等待通知到来。
非阻塞
:和阻塞相反,调用者可以去执行其他业务。
原文 redis的持久化方式RDB和AOF的区别
原文 Redis详解(六)------ RDB 持久化
原文 Redis持久化:RDB(快照)和AOF(写命令)
RDB持久化
是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork
一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
RDB持久化
可以手动触发和自动触发,保存RDB
数据有两个命令,一个是save
,一个是bgsave
(常用这个,会fork一个子进程来实现生成RDB文件,不阻塞主进程)。
AOF持久化
以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof
),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save
的时候,再做备份(rdb
)。rdb
这个就有些最终一致性(eventually consistent)
的意思了。不过生产环境其实更多都是二者结合使用的。
详情见 原文 Redis主从复制原理总结
假设 Redis
的主从架构如下:
对其总结一下:
Redis
主从复制可以根据是否是全量分为全量同步
和增量同步
。
全量同步
。一般发生在slave
初始化节点,因为slave
需要把master
上的所有数据都复制一份。具体过程如下:增量同步
。mater
的写操作要同步到slave
上。master
每执行一个写命令就向slave
发送相同的写命令,slave
接收并执行收到的写命令。redis 的策略
是,无论如何,首先会尝试进行增量同步,如不成功,要求slave进行全量同步。
master为复制流维护一个内存缓冲区(in-memory backlog)
。master
和slave
都维护一个复制偏移量(replication offset)
和master run id
,当连接断开时,slave会重新连接上master,然后请求继续复制,假如master和slave的两个master run id相同,并且指定的偏移量在内存缓冲区中还有效,复制就会从上次中断的点开始继续。如果其中一个条件不满足,就会进行完全重新同步(在2.8版本之前就是直接进行完全重新同步)。因为主运行id不保存在磁盘中,如果slave重启了的话就只能进行完全同步
了。
部分同步这个新特性内部使用PSYNC
命令,旧的实现中使用SYNC
命令。Redis2.8版本可以检测出它所连接的服务器是否支持PSYNC
命令,不支持的话使用SYNC
命令。
详情见原文 Redis系列八:redis主从复制和哨兵
Redis 主从的缺点
主从故障如何故障转移(failover
)
master
)故障,从节点slave
端执行slaveof no one
后变成新主节点;基于Redis主从的确定,所以 Redis
通过Redis Sentinel
来保证高可用。
Redis Sentinel 也叫哨兵机制。原理:当主节点出现故障时,由Redis Sentinel自动完成故障发现和转移,并通知应用方,实现高可用性。
Sentinel的功能如下:
Redis哨兵(Sentinel)模式
Redis 官方文档 sentinel
详情见 原文 redis 数据库主从不一致问题解决方案
详情请见 Redis 如何保持和MySQL数据一致
读请求:先Redis,后Mysql。
写请求:先Mysql,后删Redis,重新写入。
MySQL处理实时性数据,例如金融数据、交易数据
Redis处理实时性要求不高的数据,例如网站最热贴排行榜,好友列表等
详情见 Redis集群详解
Redis 有3中集群模式:
主从模式
。单机数据基本上就是全部数据。sentinel模式
。单机数据基本上就是全部数据。cluster模式
。所有Redis节点的数据之和才是全部数据。特点:
master可以进行读写操作,当读写操作导致数据变化时会自动将数据同步给slave
slave一般都是只读的,并且接收master同步过来的数据
一个master可以拥有多个slave,但是一个slave只能对应一个master
slave挂了不影响其他slave的读和master的读和写,重新启动后会将数据从master同步过来
master挂了以后,不影响slave的读,但redis不再提供写服务,master重启后redis将重新对外提供写服务。master挂了以后,不会自动在slave节点中重新选一个master,需要手动操作。
工作机制:
当slave启动后,主动向master发送
SYNC
命令。master接收到SYNC
命令后在后台保存快照(RDB持久化
)和缓存保存快照这段时间的命令,然后将保存的快照文件和缓存的命令发送给slave。slave接收到快照文件和命令后加载快照文件和缓存的执行命令。
全量复制
完成后,进行增量复制
,master每次接收到的写命令都会同步发送给slave,保证主从数据一致性。
由于上面的主从模式没有failover
,master挂了(Redis
不在对外提供写操作),需要手动切换,不满足高可用性,所以产生了Sentinel模式
。
特点:
sentinel模式
是建立在主从模式的基础上,如果只有一个Redis
节点,sentinel就没有任何意义
当master挂了以后,sentinel
会在slave中选择一个做为master,并修改它们的配置文件,其他slave的配置文件也会被修改,比如slaveof属性会指向新的master
当旧的master重新启动后,它将不再是master而是做为slave接收新的master的同步数据
因为sentinel
也是一个进程有挂掉的可能(单点故障
),所以sentinel
也会启动多个形成一个sentinel集群
。多sentinel
配置的时候,sentinel
之间也会自动监控
当主从模式配置密码时,sentinel
也会同步将配置信息修改到配置文件中,不需要担心
一个sentinel
或sentinel
集群可以管理多个主从Redis
,多个sentinel也可以监控同一个Redis
sentinel
最好不要和Redis
部署在同一台机器,避免当这台机器出问题时,Redis
和Sentinel
都挂了。
工作机制:
每个
sentinel
以每秒钟一次的频率向它所知的master,slave以及其他sentinel实例发送一个PING
命令。心跳检测
如果一个实例距离最后一次有效回复PING
命令的时间超过down-after-milliseconds
选项所指定的值, 则这个实例会被sentinel
标记为主观下线
。 如果一个master被标记为主观下线,则正在监视这个master的所有sentinel
要以每秒一次的频率确认master的确进入了主观下线状态
当有足够数量的sentinel
(大于等于配置文件指定的值)在指定的时间范围内确认master的确进入了主观下线状态, 则master会被标记为客观下线
在一般情况下, 每个sentinel
会以每 10 秒一次的频率向它已知的所有master,slave发送 INFO 命令 。 当master被sentinel
标记为客观下线时,sentinel向下线的master的所有slave发送 INFO 命令的频率会从 10 秒一次改为 1 秒一次
若没有足够数量的sentinel
同意master已经下线,master的客观下线状态就会被移除;若master重新向sentinel
的 PING 命令返回有效回复,master的主观下线状态就会被移除。
当使用sentinel模式
的时候,client 就不要直接连接Redis
,而是连接sentinel
的ip和port,由sentinel
来提供具体的可提供服务的Redis
实现,这样当master节点挂掉以后,sentinel
就会感知并将新的master节点提供给使用者。
主从模式和Sentinel模式应对的是请求相当多而数据完全能够存放在一台机器中的情况。在大数据的情况下,就需要将数据分布在不同的机器上,这也就是Redis Cluster。
特点:
多个Redis节点网络互联,数据共享
所有的节点都是一主一从(也可以是一主多从,),其中从不提供服务,仅作为备用。
不支持同时处理多个key(如MSET/MGET),因为Redis需要把key均匀分布在各个节点上,
并发量很高的情况下同时创建key-value会降低性能并导致不可预测的行为(见 Redis的分布式锁)
支持在线增加、删除节点
客户端可以连接任何一个主节点进行读写
Redis cluster集群是去中心化的,每个节点都是平等的,连接哪个节点都可以获取和设置数据。
其余关于Redis的问题 见 面试中关于Redis的问题看这篇就够了