redis基础介绍
Redis简介
Redis(Remote Dictionary Server)是一个开源的内存数据结构存储系统。它以键值对形式存储数据,支持多种数据结构,它可以用作数据库、缓存和消息中间件。 它基于内存运行并支持持久化的NoSQL数据库,是当前最热门的NoSQL数据库之一。
- MySQL:数据关系型数据库,使用的是表结构。
- Redis:非关系型数据库,使用的是key-value
核心特性
- 支持持久化功能,也就是将数据从内存保存到磁盘中。
- 支持丰富的数据类型,包括:string、set、sort set、list、hash
- 支持数据的备份,也就是主从复制。
Redis的优点
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
- 丰富的特性 – Redis还支持publish/subscribe, 通知, key过期等等特性。
常用命令
单进程模型来处理客户端的请求,对读写等事件的响应通过对epoll的包装来做到。
默认16个数据库,编号0-15,可以通过select + num切换数据库
DEL key 删除key |
基本数据结构
类型 | 简介 | 特性 | 场景 |
---|---|---|---|
String(字符串) | 二进制安全 | 可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M | — |
Hash(字典) | 键值对集合,即编程语言中的Map类型 | 适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去) | 存储、读取、修改用户属性 |
List(列表) | 链表(双向链表) | 增删快,提供了操作某一段元素的API | 1,最新消息排行等功能(比如朋友圈的时间线) 2,消息队列 |
Set(集合) | 哈希表实现,元素不重复 | 1、添加、删除、查找的复杂度都是O(1) 2、为集合提供了求交集、并集、差集等操作 | 1、共同好友 2、利用唯一性,统计访问网站的所有独立ip 3、好友推荐时,根据tag求交集,大于某个阈值就可以推荐 |
Sorted Set(有序集合) | 将Set中的元素增加一个权重参数score,元素按score有序排列 | 数据插入集合时,已经进行天然排序 | 1、排行榜 2、带权重的消息队列 |
1. 字符串(String)
最基本的类型,你可以理解成一个key对应一个value,string 类型的值最大能存储512MB 。
存储文本或二进制数据
常用命令:
SET key value 设定指定key的值
MGET/MSET key1 [value1] key2 [value2] 获取设置多个给定的key值
GET key 获取指定key的值
GETRANGE key start end 返回字符串的子串
SETRANGE key offset value 用value覆盖字符串的值,从offset开始
GETSET key value将给定key的值设为value ,并返回key的旧值(old value)。
SETEX 将值 value 关联到 key,并设置 key 的过期时间为 seconds (以秒为单位)。
INCR/INCRBY key [num] 对value值加1/加num,value必须是数字
2. 哈希(Hash)
一个string 类型的field(字段)和value(值)的映射表。
存储对象属性
Key-value模式不变,但value是一个键值对,相当于map<key, map<key1, value>>
常用命令:
HSET key field value 将哈希表 key 中的字段 field 的值设为 value
HMSET key field1 value1 [field2 value2 …]同时将多个 field-value (域-值)对设置到哈希表 key 中
HGET key field / HMGET key field1 [field2] 获取给定字段的值
HGETALL key 获取在哈希表中指定 key 的所有字段和值
HKEYS key 获取所有哈希表中的字段
HVALS key 获取哈希表中所有值
3. 列表(List)
- 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
实现消息队列
常用命令:
LPUSH key value1 value2 … 将一个或多个值插入到列表头部,头插法
RPUSH key value1 value2 … 将一个或多个值插入到列表尾部,尾插法
LPOP key 队头出队
RPOP key 队尾出队
LRANGE key start stop 获取列表指定范围内的元素
支持下标,下标从0开始
LSET key index value 通过下标设置列表元素的值
LINDEX key index 通过下标获取列表中的元素
LREM key count value 从队头开始移除count个值为value的列表元素
4. 集合(Set)
String类型的无序集合
通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
存储唯一元素
常用命令:
SADD key member1 member2 … 向集合添加一个或多个成员
SCARD key 获取集合的成员数
SMEMBERS key 返回集合中的所有成员
SISMEMBER key member 判断 member 元素是否是集合 key 的成员
SMOVE source destination member 将member元素从source集合移动到destination集合
SREM key value 删除集合中值为value的元素
SRANDMEMBER key num 在集合中随机选出num个数
SPOP key [num] 移除并返回集合中的一个/num个随机元素
5. 有序集合(ZSet)
带权重的元素集合,每个元素都会关联一个double****类型的分数(权重)。redis正是通过分数来为集合中的成员进行从小到大的排序。
string类型元素的集合,且不允许重复的成员,有序集合的成员是唯一的,但分数(权重,score)却可以重复。。
常用命令:
向有序集合添加一个或多个成员,或者更新已存在成员的分数
ZADD key score1 member1 [score2 member2]
ZRANGE key start stop [WITHSCORES] 通过索引区间返回有序集合指定区间内的成员
ZRANGEBYLEX key min max [LIMIT offset count] 通过字典区间返回有序集合的成员(分数要一致)
ZCARD key 获取有序集合的成员数
ZCOUNT key min max 计算在有序集合中指定区间分数的成员数
持久化机制
Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘;当下次Redis重启时,利用持久化文件实现数据恢复。
RDB(Redis Database)
将当前数据保存到硬盘(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),在指定的时间间隔能对你的数据进行快照存储.指定的时间间隔内,执行指定次数的写操作,则会将内存中的数据写入到磁盘中。即在指定目录下生成一个dump.rdb文件。Redis 重启会通过加载dump.rdb文件恢复数据。(/var/lib/redis/6379)
触发RDB快照的方式
在指定的时间间隔内,执行指定次数的写操作
执行save(阻塞, 只管保存快照,其他的等待) 或者是bgsave (异步)命令
执行flushall 命令,清空数据库所有数据,意义不大
执行shutdown 命令,保证服务器正常关闭且不丢失任何数据,意义不大。
Conf# redis.conf配置 |
优缺点
优点
- 适合大规模数据的恢复,恢复速率是比较快的
- 如果业务对数据完整性和一致性要求不高,RDB是很好的选择。
- 使用的是二进制进行存储
缺点
- 数据的完整性和一致性不高,因为RDB可能在最后一次备份时宕机了。
- 备份时占用内存,因为Redis 在备份时会独立创建一个fork子进程,将数据写入到一个临时文件
(此时内存中的数据是原来的两倍哦),最后再将临时文件替换之前的备份文件。
AOF(Append Only File)
记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据, AOF命令以redis协议追加. Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大.保存每次写的操作到文件末尾
默认的AOF持久化策略是每秒钟fsync一次(fsync是指把缓存中的写指令记录到磁盘中),因为在这种情况下,redis仍然可以保持很好的处理性能,即使redis故障,也只会丢失最近1秒钟的数据。
appendonly yes |
重写
AOF 的运作方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件的体积也会变得越来越大。
可以在不打断服务客户端的情况下, 对 AOF 文件进行重建(rebuild)。执行 BGREWRITEAOF命令, Redis 将生成一个新的 AOF 文件, 这个文件包含重建当前数据集所需的最少命令。
set k1 100 |
Redis 2.4 则可以自动触发 AOF 重写, 具体信息请查看 配置文件。自动触发命令:
Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大 |
优缺点
优点
- 对数据的完整性与一致性的比较高
- 数据的丢失比较小(相对RDB而言)
缺点
- 不适合大规模数据的恢复,因为恢复的速率比较慢,需要将所有的写命令重新执行一次
- 因为使用的是文件追加的模式,所以文件的体积会比较大
总论
- 两种持久化的方式都可以同时存在,如果对数据的恢复速率比较快,可以选择rdb持久化;如果对
数据的完整性与一致性要求比较高(更加精确),可以选择aof持久化 - 单独使用aof持久化的方式,也是可以启动服务器的
- 如果aof持久化是唯一的方式,那么如果该文件损坏了,就不能启动服务器
- 如果aof文件损坏了,可以使用修复命令进行修复文件,redis-check-aof
事务与锁机制
概念
Redis事务可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序的串行化执行,而不会被其他命令插入,不许加塞。Redis事务是通过命令队列机制实现的批量操作执行方式,与传统关系型数据库的ACID事务有本质区别。
Redis事务有以下三个重要的保证:
- 批量操作在发送 EXEC 命令前被放入队列缓存。
- 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
- 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
其核心特点是:
- 非阻塞式执行:命令进入队列时不立即执行
- 无隔离级别:事务执行期间不保证数据隔离
- 弱原子性:仅保证命令连续执行,不保证整体成功
命令
命令 | 作用描述 |
---|---|
MULTI |
开启事务,进入命令排队模式 |
EXEC |
执行事务队列中的所有命令 |
DISCARD |
取消事务,清空命令队列 |
WATCH |
监视指定key,实现乐观锁(若被监视key在EXEC前被修改,则事务失败) |
UNWATCH |
取消所有WATCH监视 |
事务执行流程
1、正常执行 MULTI+EXEC 分三步:开始,加入队列,执行
2、放弃事务 DISCARD 类似mysql中的rollback
3、事务执行中有错误的命令:部分执行成功or全部不执行?
如果输入命令后显示的是QUEUED,表示入队成功,部分执行。
如果提示ERROR,事务被放弃,全部不执行。
总结:编译时出错和运行时出错的区别。
4、WATCH监控 如果watch监控的keys发生了变化,EXEC执行的事务将被放弃
5、UNWATCH取消监控
6、一旦执行EXEC,WATCH监控会被取消。
> WATCH balance # 监控账户余额 |
redis的事务是没有原子性的,也就是在事务中每一条命令执行成功与否,对其他命令没有影响
队列原子性:EXEC执行时队列命令连续执行,不会被其他客户端命令打断
# 情况2:命令执行时出错(如类型错误) |
特性
特性 | Redis事务 | 关系型数据库事务 |
---|---|---|
原子性 | 部分原子(单命令原子) | 完整原子性 |
隔离性 | 无隔离 | 支持多种隔离级别 |
持久性 | 依赖持久化配置 | 通常保证持久性 |
回滚机制 | 不支持 | 支持完整回滚 |
执行方式 | 批量执行 | 交互式执行 |
锁机制 | 乐观锁(WATCH) | 悲观锁(行锁/表锁 |
乐观锁和悲观锁
悲观锁:先加锁再操作,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,当其他线程想要访问数据时,都需要阻塞挂起。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁、表锁,读锁,写锁等,都是在操作之前先上锁。
乐观锁(Optimistic Lock),无锁并发控制机制,核心思想是: “先操作,后校验” —— 默认认为并发操作冲突的概率较低,允许用户直接修改数据,但在提交时会验证数据是否被其他操作修改过。若发生冲突,则通过回滚或重试策略解决。
在 Redis 中实现乐观锁主要依赖 WATCH
命令 + 事务机制,其本质是通过数据版本校验实现的 CAS(Compare and Swap)操作
version方式:一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。
CAS操作方式:即 Compare And Swap,CAS是乐观锁技术,涉及到三个操作数,数据所在的内存值V,预期值A,新值B。当需要更新时,判断当前内存值V与之前取到的值A是否相等,若相等,则用新值更新,若失败则重试,一般情况下是一个自旋操作,即不断的重试。
维度 | 悲观锁 | 乐观锁 |
---|---|---|
设计哲学 | “先加锁再操作”(宁错杀不放过) | “先操作后校验”(信任但验证) |
冲突预期 | 认为数据冲突概率高 | 认为数据冲突概率低 |
锁机制类型 | 独占锁(排他锁) | 无锁机制(CAS机制) |
典型实现 | 数据库行锁、synchronized、ReentrantLock | 版本号机制、CAS原子操作、Redis WATCH |
资源消耗 | 高(锁维护成本) | 低(无锁竞争) |
适用场景 | 写操作密集型场景 | 读操作密集型场景 |
失败处理 | 线程阻塞等待 | 事务回滚、重试 |
高可用架构
主从复制
是Redis实现数据冗余和高可用的核心机制,通过建立主节点(Master)与从节点(Replica)的数据同步关系,实现:
- 一主多从架构:1个主节点可对应多个从节点
- 单向数据同步:数据从主节点流向从节点
- 读写分离:主节点处理写操作,从节点提供读服务

核心必要性
1. 数据冗余与灾备
- 数据热备份:从节点实时复制主节点数据
- 故障恢复:主节点宕机后可从从节点快速恢复
- 防止数据丢失:即使主节点硬盘损坏,从节点仍保留数据副本
2. 高可用基石
- 故障转移基础:为哨兵模式提供节点切换能力
- 服务不间断:主节点故障时可手动/自动切换从节点
- 零停机维护:主节点维护期间从节点可继续服务
3. 读性能扩展
- 负载均衡:通过多个从节点分散读请求压力,由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载
- 地理级扩展:在不同机房部署从节点加速区域访问
- 大数据分析:在从节点执行耗时统计操作,避免影响主节点
使用方式
由于需要启动多个Redis实例,我们先把多个实例使用的配置文件做好修改。
需要修改的配置信息有:
- 先拷贝多份配置文件,用不同的名字命名
- 守护进程启动 daemonize yes
- Pid 文件名字
- 指定一个端口
- Log日志文件名
- Dump.rdb文件名
- Appendfilename “”
- 等等
通过刚改好的多个配置文件启动多个redis服务程序
Redis-server /path/to/***.conf
主从复制的开启,完全是在从节点发起的;不需要我们在主节点做任何事情。
从节点开启主从复制,有3种方式:
(1)配置文件
在从服务器的配置文件中加入:slaveof <masterip> <masterport>
(2)启动命令
redis-server启动命令后面加入 –slaveof
(3)客户端命令
Redis服务器启动后,直接通过客户端执行命令:slaveof
,则该Redis实例成为从节点。 通过info replication可以查看主从信息。
复制流程:
- 全量同步:主节点生成RDB发送给从节点
- 增量同步:通过复制缓冲区持续同步
- 作为主机的程序结束,从机的角色不会变化(角色还是slave)。
- 主机重新启动,从机可以继续与主机保持连接(从机原地待命)。
- 从机的程序重启后,角色变成了master,从机每次与master断开连接后,都需要重新连接,除非把slaveof配置到配置文件里。
- 只要重新连接master,一次完全同步(全量复制)将被自动执行。
主从复制存在的一个问题是故障恢复无法自动化
哨兵模式
哨兵模式(Sentinel) 是Redis官方提供的高可用解决方案,基于Redis主从复制,通过独立进程监控主从架构,解决主节点故障恢复的自动化问题,实现自动故障发现和主节点切换,进一步提高系统的高可用性。哨兵系统由多个哨兵节点组成,共同完成以下核心任务:
- 持续监控:检测主从节点健康状态
- 自动故障转移:主节点故障时选举新主
- 配置中心:提供最新的主节点地址
- 通知告警:通过API通知运维系统
Redis Sentinel是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress),这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。
虽然 Redis Sentinel 释出为一个单独的可执行文件 redis-sentinel , 但实际上它只是一个运行在特殊模式下的 Redis 服务器, 你可以在启动一个普通 Redis 服务器时通过给定 –sentinel 选项来启动 Redis Sentinel 。启动 Sentinel 实例必须指定相应的配置文件, 系统会使用配置文件来保存 Sentinel 的当前状态, 并在 Sentinel 重启时通过载入配置文件来进行状态还原。如果启动 Sentinel 时没有指定相应的配置文件, 或者指定的配置文件不可写(not writable), 那么 Sentinel 会拒绝启动。
#在/etc/redis下面建一个文件sentinel.conf,然后在其中添加如下命令 |
哨兵节点的启动有两种方式,二者作用是完全相同的:
redis-sentinel /path/to/sentinel.conf
redis-server /path/to/sentinel.conf –sentinel
经典面试题
缓存雪崩
概念:大量热点数据在同一时间失效,导致本来可以在缓存中查找到的数据,必须要到底层数据库下面
进行查找,会对底层数据库的压力比较大。

解决方案:1、分散数据的失效时间(随机过期时间) 2、可以延长热点数据的失效时间或者让数据不失效
缓存击穿
问题:某个热点数据失效了,导致本来可以在缓存中访问到的,现在只能到底层数据库中进行查找,会
增加底层数据库的压力
解决方法:1、延长热点数据的失效时间或者让数据永远不失效 2、让每个客户端互斥访问数据库(加
锁),一旦查到数据就缓存至Redis内,避免其他大量请求同时穿过Redis访问底层数据库

缓存穿透
问题:要访问的数据本身是不存在,在缓存中找不到,就会到底层数据库中进行查找,也会增加对底层
数据库的访问压力。
解决方案:1、可以设置键值对,存放在缓存中,value为空,<key1,NULL>
2、布隆过滤器
布隆过滤器是一个位数组(Bit Array) + 多个哈希函数组成的数据结构,通过以下机制工作:
添加元素:使用k个哈希函数计算元素值,将对应位数组位置置1
查询元素
:检查所有哈希位置是否均为1
- 存在可能:所有位为1,高效查找的同时存在哈希冲突的可能性,比如不同的两数据可能都落在所有的相同位置,而事实上,可能数据库中并不存在其中一个数据,存在误判的情况。
- 绝对不存在:任一位置为0(无漏判)

方案 | 适用场景 | 不适用场景 |
---|---|---|
布隆过滤器 | 海量数据存在性判断 | 需要精确判断的场景 |
空值缓存 | 数据量小的低频请求 | 数据动态变化的场景 |
Redis为什么快?
内存存储:数据操作的物理极限
- 零磁盘访问 所有数据存储在内存中,读写操作无需磁盘I/O,内存访问速度比磁盘快10万倍以上(内存访问约100ns,机械磁盘寻道约10ms)。
- 避免传统数据库瓶颈 传统数据库(如MySQL)需要维护磁盘数据一致性,涉及Buffer Pool、Redo Log、锁竞争等开销,而Redis直接操作内存,规避了这些瓶颈。
单线程模型:无锁竞争的极致
- 避免上下文切换 单线程处理所有命令,无需线程切换、锁竞争,减少CPU资源浪费。
- 原子性操作 所有命令按顺序执行,天然保证原子性,无需加锁。
- 非阻塞设计
- 通过IO多路复用(epoll/kqueue)处理网络请求。
- 异步处理客户端连接、命令解析,主线程仅处理核心逻辑。
网络IO优化:最大化吞吐量
- IO多路复用 Redis使用
epoll
(Linux)或kqueue
(BSD)实现非阻塞IO,单线程可管理数万连接。 - 管道化(Pipeline) 客户端可将多个命令打包发送,减少网络往返次数,提升吞吐量。
- 协议简单 Redis协议为二进制安全的文本协议,解析效率高。
持久化策略:平衡速度与可靠性
- RDB快照
- 通过
fork
子进程生成内存快照,主进程无阻塞。 - 数据恢复速度快(直接加载二进制文件)。
- 通过
- AOF日志
- 支持
appendfsync everysec
策略,每秒刷盘一次,平衡性能与数据安全。 - AOF重写时使用子进程,避免影响主线程。
- 支持
其他优化细节
- 内存分配器(jemalloc) 默认使用高效内存分配器,减少内存碎片。
- LRU近似算法 淘汰策略通过随机采样近似LRU,避免全局排序开销。
- Lua脚本缓存 重复执行的Lua脚本会被缓存,避免重复解析。
最佳实践建议
- 生产环境务必启用持久化
- 主从节点建议分散在不同物理机
- 内存占用不超过物理内存的70%
- 使用Pipeline提升批量操作性能