文章目录
前言
本片内容包含了对redis中间件的三部分内容:
① 初识学习:基础知识,如是什么、用来做什么等
② 进阶学习:日志持久化等
③ 深入理解:如实现、源码、操作系统相关、资源利用
可根据需求,点击目录到对应位置查看
一、初识学习
1.redis简介
-
Redis 是一个开源(BSD 许可)的内存中的数据结构存储,用作数据库、缓存和消息代理。
-
支持多种类型的数据结构,如字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)以及范围查询、bitmaps、hyperloglogs 和地理空间索引(geospatial indexes)等。
-
Redis 内建了复制(replication)、Lua 脚本、LRU 驱逐、事务以及不同级别的磁盘持久化,并通过 Redis Sentinel 和自动分区(Redis Cluster)提供高可用性。
2.核心概念
-
内存数据库: Redis 是一个内存数据库,这意味着所有数据都保存在内存中,从而提供非常高的读写速度。Redis 还支持将内存中的数据异步地保存到磁盘,以实现持久化。
-
数据结构存储:Redis 不仅支持简单的键值对存储,还支持多种复杂的数据结构,如字符串、哈希、列表、集合、有序集合、位图、hyperloglog 和地理空间索引。
-
单线程模型: Redis 使用单线程事件驱动模型处理请求。虽然是单线程,但由于其高效的 I/O 多路复用机制,Redis 能够处理大量的并发连接和请求。6.0开始引入多线程,但命令执行依然是单线程中的。
-
高可用性:Redis 支持主从复制(master-slave replication),并通过 Redis Sentinel 提供自动故障转移和集群模式(Redis Cluster)以实现高可用性和扩展性。
3.应用场景
-
缓存: Redis 可以作为缓存层,以极低的延迟和高吞吐量来加速读取速度,减少对后端数据库的压力。常用命令:
SETEX
、EXPIRE
、TTL
。 -
会话存储: 存储用户会话信息,由于 Redis 的快速读写性能和过期功能,非常适合存储短期数据。 常用命令:
SET
、GET
、DEL
、EXPIRE
。 -
实时分析: 通过列表、集合、有序集合和位图等数据结构,Redis 可以用于实时统计、排行榜、频率控制等场景。 常用命令:
INCR
、ZINCRBY
、BITCOUNT
。 -
消息队列: 利用 Redis 列表实现简单的消息队列,结合
BLPOP
、BRPOP
命令实现阻塞式读取。 常用命令:LPUSH
、RPUSH
、BLPOP
、BRPOP
。 -
分布式锁: 通过
SETNX
和EXPIRE
命令实现分布式锁,用于控制并发访问。 常用命令:SETNX
、GET
、DEL
、EXPIRE
。
4.数据结构类型
Redis 支持多种数据结构,每种数据结构都有其特定的命令和用例。
-
字符串(Strings): 最基本的数据类型,可以存储任何形式的字符串,包括二进制数据。 常用命令:
SET
、GET
、INCR
、DECR
、APPEND
、STRLEN
。 -
哈希(Hashes): 存储键值对集合,适合存储对象。 常用命令:
HSET
、HGET
、HGETALL
、HDEL
、HLEN
、HMSET
、HMGET
。 -
列表(Lists): 有序的字符串列表,可以用作队列或栈。 常用命令:
LPUSH
、RPUSH
、LPOP
、RPOP
、LRANGE
、LLEN
。 -
集合(Sets): 无序的唯一字符串集合,支持集合操作(交集、并集、差集)。 常用命令:
SADD
、SREM
、SMEMBERS
、SCARD
、SINTER
、SUNION
、SDIFF
。 -
有序集合(Sorted Sets): 带有分数的有序集合,可以根据分数进行排序。 常用命令:
ZADD
、ZREM
、ZRANGE
、ZRANGEBYSCORE
、ZREVRANGE
、ZCARD
。 -
位图(Bitmaps): 用于位级别操作的字符串,可以处理大规模的位数组。 常用命令:
SETBIT
、GETBIT
、BITCOUNT
、BITOP
。 -
HyperLogLog: 用于基数估计算法,适合大规模去重操作。 常用命令:
PFADD
、PFCOUNT
、PFMERGE
。 -
地理空间索引(Geospatial Indexes): 支持地理位置的存储和操作。 常用命令:
GEOADD
、GEODIST
、GEORADIUS
、GEORADIUSBYMEMBER
。
5.Linux上搭建及使用
以操作系统 Ubuntu 22.4 为例
-
安装redis
Ubuntu 22.4如下:sudo apt install redis-server sudo systemctl start redis-server sudo systemctl enable redis-server # 开机自启
CentOS系统如下:
sudo yum update sudo yum install redis sudo systemctl start redis sudo systemctl enable redis sudo systemctl status redis
其他系统自行处理吧。
-
配置文件
打开配置文件可看到默认监听端口: port 6379sudo vim /etc/redis/redis.conf
密码配置只需要在配置文件找到requirepass 项即可,没有可以自己添加,之后重启就会生效。公网映射的redis一定要设置密码,并且不能简单(不然系统很容易被破坏,坦然的说我的服务器被这样入侵过)。详解redis密码
requirepass dujingning123456
-
redis-cli 客户端
安装默认带有客户端redis-cli
,使用也很简单,输入并回测即可启动并进入redis默认连接(127.0.0.1 6379),如有密码可以使用auth [your password]
进行验证,也可在命令行[jn@jn ~]$ redis-cli 127.0.0.1:6379>
也可命令行
-h
指定IP、-a
指定密码(我这里没设置密码就不指定了)[jn@jn ~]$ redis-cli -h 127.0.0.1 127.0.0.1:6379>
无密码就可以直接操作redis内存数据库,有密码
auth [your password]
进行验证就行了。[root@VM-24-13-centos ~]# redis-cli -h 127.0.0.1 -a dujingning123456 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 127.0.0.1:6379>
或者
[root@VM-24-13-centos ~]# redis-cli -h 127.0.0.1 127.0.0.1:6379> auth dujingning123456 OK 127.0.0.1:6379>
redis常用命令行用例看这篇(重要,初学请动手操作):
redis常用命令行用例 【命令行实操】 各种数据结构操作及其他命令基本都有罗列
二、进阶学习
1.高性能
- Redis 以内存为存储介质,提供极高的读写速度。单机处理超过 10 万次读写操作每秒。
- 高性能的根本原因:
1.内存数据库:读写速度、响应时间本身就快 2.内存分配优化:对内存分配有优化,Redis 默认使用高效的内存分配器 Jemalloc,能够减少内存碎片并提高内存分配和释放的效率。 3.单线程模型:Redis 使用单线程模型处理请求,避免了多线程环境下的上下文切换和竞争条件问题。6.0之后把一些IO操作、命令解析等放入多线程中去处理进一步提升性能。 4.I/O多路复用:封装了`select/epoll/evport/kqueue`I/O多路复用技术 。 5.高效的数据结构:SDS 是 Redis 实现字符串的基础数据结构,提供自动扩展、预分配和内存紧凑等功能。 6.高效的客户端协议和命令:`+/-/*/:/$`
- 可用性方面
1.高效的持久化机制:RDB、AOP、混合等。 2.主从复制:主从复制保障高可用。
另附图:我的ddr5内存读取速度可达到104.41GB/秒,写入速度90.371GB/每秒,相对磁盘来说是相当惊人的。我的固态磁盘的标称有7000MB/秒,而一般硬盘也就几十兆到一两百兆而已。
2.持久化
- Redis 提供了多种持久化机制,确保数据在内存中发生变化后能够保存在磁盘上,以防止数据丢失。主要的持久化机制包括 RDB(Redis Database)快照、AOF(Append Only File)日志和混合持久化(Hybrid Persistence)。每种持久化方式各有优缺点,可以根据具体需求选择合适的方案。详解redis持久化
a.RDB(Redis Database)
RDB 是 Redis 将内存中的数据在某个时间点生成快照(snapshot)并保存到磁盘上的一种持久化方式。
Redis 会在指定的间隔时间内将内存中的数据生成一个 RDB 文件,保存到磁盘中。
-
配置
打开配置文件/etc/redis/redis.conf:save <seconds> <changes> # 指定在多少秒内有多少次写操作时触发快照。 dbfilename dump.rdb # 配置文件名 dir <directory> # 设置 RDB 文件保存的路径。
-
优点
高性能:RDB 文件的生成过程对 Redis 的性能影响较小。
快速恢复:RDB 文件体积较小,恢复数据时速度较快。
数据备份:RDB 文件是一个压缩的二进制文件,适合数据备份。 -
缺点
数据丢失:如果 Redis 在快照生成之间发生故障,可能会丢失最近一次快照后的数据。
生成过程开销:生成 RDB 文件时需要 fork 子进程,会消耗一定的内存和 CPU 资源。
b.AOF(Append Only File)
AOF 是 Redis 通过将每个写操作(如 SET、DEL)记录到日志文件中的一种持久化方式。AOF 文件记录了所有的写操作命令,可以通过重新执行这些命令来恢复数据。
-
配置
打开配置文件/etc/redis/redis.conf:appendonly yes # 启用 AOF 持久化。 appendfilename "appendonly.aof" # 设置 AOF 文件名。 appendfsync everysec # 设置 AOF 文件的同步策略,有三种策略. no-appendfsync-on-rewrite yes # 在重写 AOF 文件时不进行同步操作。
appendfilename的三种策略:
① always:每次写操作后都进行同步,性能较差,但数据安全性最高。
② everysec:每秒同步一次,性能和数据安全性平衡较好。
③ no:不主动进行同步,由操作系统决定何时同步,性能最好,但数据安全性最差。 -
优点
数据安全:AOF 可以提供更高的数据安全性,因为它记录了每个写操作。
可控性:可以通过配置不同的同步策略来平衡性能和数据安全性。 -
缺点
文件体积大:AOF 文件记录了所有写操作命令,文件体积可能较大。
恢复速度慢:恢复数据时需要重新执行所有写操作命令,速度较慢。
c.混合持久化(Hybrid Persistence)
混合持久化结合了 RDB 和 AOF 的优点,在 Redis 4.0 引入。数据恢复时,优先使用 RDB 快照进行快速恢复,再应用 AOF 日志来保证数据的一致性。
-
配置
混合持久化的配置在 Redis 配置文件中没有单独的选项,通过配置 AOF 重写相关参数启用。# AOF 重写配置 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb
-
优点
高效恢复:混合持久化可以在数据恢复时结合 RDB 的快速恢复和 AOF 的高数据安全性。
数据一致性:通过应用 AOF 日志,确保数据的最终一致性。 -
缺点:
实现复杂:混合持久化的实现较为复杂,配置和管理也相对繁琐。
3.主从复制 [待补]
- 支持异步复制,将数据从主节点复制到一个或多个从节点,实现读写分离和高可用性。
4.自动故障转移 [待补]
- 使用 Redis Sentinel 实现主节点故障检测和自动故障转移,确保服务的高可用性。
5.分布式 [待补]
- 通过 Redis Cluster 实现分布式部署,自动进行数据分片和负载均衡,适应大规模数据存储和处理。
6.发布订阅
redis发布订阅缺陷:不保证消息一定到达 限制了发布订阅模式的使用场景
建议使用kafka、RabbitMQ,专业的MQ中间件
三、深入理解
核心处理为什么单线程:redis之父认为CPU不是瓶颈,内存和网络可能是瓶颈
1.为什么快
1.基于内存,内存读写很快
2.核心处理单线程,避免多线程上下文切换开销和资源竞争
3.数据结构简单、高效
4.I/O多路复用 [源码中见 ae.c,封装了 select/epoll/evport/kqueue;可读文章 I/O多路复用技术最佳学习实践及总结(含完整实现源码) ]
5.io异步操作(接收,发送和解析命令)在多线程中 [redis 6.0开始引入多线程,需要配置开启],命令执行依然是单线程
6.CPU、Memery、磁盘、系统等软硬件资源的合理利用[CPU亲和性、内存管理机制(SDS-Simple Dynamic String[源码见sds.c],内存分配器,对象池、)、持久化方式、I/O多路复用[源码见ae.c] ]
- 数据结构:Redis 是一个内存中的数据结构存储,支持多种复杂的数据结构。为了高效地实现这些数据结构,Redis 在底层使用了多种数据结构和算法。这些底层数据结构包括:
1. 动态字符串(SDS) 2. 链表(Linked List) 3. 字典(Hashtable) 4. 跳表(Skip List) 5. 压缩列表(Ziplist) 6. 整数集合(Intset) 7. 快速列表(Quicklist) 8. 哈希表(Hash Table) 9. 压缩跳表(CRDT-based Ziplists)
2.ACID分析
通过确保原子性、一致性、隔离性和持久性,数据库系统能够在复杂的事务处理中提供可靠的数据管理和并发控制,从而确保数据的完整性和系统的稳定性。
- 原子性:确保事务的所有操作要么全部完成,要么全部不完成。事务在执行过程中如果出现错误,所有已经执行的操作都会被回滚到事务开始前的状态。
- 一致性:确保事务执行前后数据库都保持一致状态。数据库从一个一致状态转换到另一个一致状态,所有约束条件都必须得到满足。
- 隔离性:确保并发执行的事务彼此之间不干扰,每个事务在执行过程中感受到的环境是独立的。隔离性防止脏读、不可重复读和幻读等并发问题。
- 持久性:确保一旦事务提交,数据库的更改将被永久保存,即使系统发生故障(如断电或崩溃),数据仍然能够恢复。
ACID的实践:
事务日志(Transaction Log):记录事务的所有操作,用于回滚和恢复。
锁机制(Locking Mechanism):控制并发事务的访问,确保隔离性。
一致性检查:确保事务执行前后数据的一致性。
恢复机制(Recovery Mechanism):确保系统故障后数据的一致性和持久性。
3.缓存雪崩、缓存穿透、缓存击穿
理解需要先理解的几个名词:
Redis值过期:Redis允许设置键值对的过期时间。这意味着在一段时间后,键将自动从数据库中删除。过期时间可以通过EXPIRE命令设置,也可以在设置键时通过EXPIRE参数来设置。
布隆过滤器:布隆过滤器是一种数据结构,用于检查元素是否属于集合中的一种方法。
一致性哈希:一致性哈希是一种分布式哈希算法,用于将键或数据分布到多个节点(如服务器)上。
a.缓存雪崩:
缓存雪崩是指在某个时间点,缓存集中过期或失效,导致大量请求直接打到数据库,造成数据库压力骤增,可能引起数据库宕机或系统崩溃。这是分布式缓存系统中的一个严重问题,特别是在高并发的场景下。
①产生原因
缓存集中过期、缓存服务器宕机、缓存更新策略不合理
②相关问题
数据库压力骤增、系统响应变慢、服务不可用
③解决方案
1.缓存过期时间的随机化:随机值过期值,避免大量缓存数据在同一时间点过期.
2.双重缓存:设置两个缓存,一个缓存长期有效的数据,另一个缓存短期有效的数据。当短期缓存过期时,从长期缓存中获取数据。
3.数据预热:在高峰期之前,提前将热点数据加载到缓存中,避免缓存集中过期。
4.请求限流和降级:对请求进行限流,防止高并发请求打到数据库。同时,对部分非关键请求进行降级处理,减少对数据库的压力。
5.定期刷新缓存:后台任务定期刷新缓存,保证缓存中的数据始终有效,避免缓存集中失效。
6.使用多级缓存:在应用服务器和数据库之间增加多级缓存,如本地缓存、分布式缓存等,分散缓存压力。
b.缓存穿透
缓存穿透是指查询一个不存在的数据(数据库也不存在),由于缓存中没有相应的键值对,导致每次请求都直接落到数据库上,绕过缓存。频繁的缓存穿透会给后端数据库带来很大的压力,可能导致数据库崩溃或服务不可用。
①产生原因
查询不存在的数据、恶意攻击、缓存没有存储空值
②相关问题
数据库压力增大、系统响应可能变慢、服务可能不可用
③解决方案
1.缓存空值:当请求的数据在数据库中不存在时,将空值存入缓存,防止下一次请求再次穿透到数据库。
2.布隆过滤器(Bloom Filter):在缓存层之前增加一个布隆过滤器,用于快速判断某个数据是否存在,过滤掉不存在的数据请求,减少对数据库的查询。
[注意!:布隆过滤器只能确认一定不在,不能确认一定在,即无假阴性/存在假阳性。布隆过滤器可能会误判某个元素存在(假阳性),即使该元素实际上不存在。这意味着可能会有少量无效的数据库查询。但如果布隆过滤器判断不存在,那就一定不存在。]
3.参数校验:对请求参数进行合法性校验,过滤掉明显非法的请求。
4.一致性哈希:使用一致性哈希将请求分散到不同的缓存节点上,减轻单个节点的压力。
c.缓存击穿:
缓存击穿是指在高并发场景下,某个缓存中的热点数据突然失效,大量的请求同时涌入数据库(mysql中有该数据),导致数据库压力骤增甚至宕机。这种情况通常发生在缓存数据的过期时间到期,但在实际使用中,大量并发请求同时访问该缓存数据,进而直接请求数据库。
①产生原因
热点数据过期、高并发访问
②相关问题
数据库压力增大、系统响应可能变慢、服务可能不可用
③解决方案
1.互斥锁(Mutex):当缓存失效后,通过加锁的方式,只有一个请求能够加载数据并更新缓存,其他请求等待,避免大量并发请求同时访问数据库。
2.预先加载缓存(Cache Warming): 在缓存即将失效之前,提前加载数据到缓存中,确保缓存中始终有热点数据,避免缓存失效。
3.使用高并发优化(如一致性哈希、限流等): 通过一致性哈希将请求分散到不同的缓存节点上,减轻单个节点的压力。以及对请求进行限流,防止高并发请求打到数据库。
4.设置合理的缓存过期策略: 根据业务需求,合理设置缓存的过期时间,避免集中失效。
5.热点数据不设置expire。