目录
一、Redis介绍
1.1定义
Redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。
Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。
1.2为什么要有Redis
一、高性能的数据存储与访问
-
内存存储
- Redis 将数据存储在内存中,这使得它能够以极快的速度进行数据读写操作。与传统的基于磁盘存储的数据库相比,Redis 可以在毫秒甚至微秒级别响应请求,极大地提高了系统的响应速度。例如,在高并发的 Web 应用中,对于频繁访问的热点数据,如用户会话信息、商品库存等,存储在 Redis 中可以快速获取,避免了频繁地从磁盘读取数据带来的延迟。
- 对于需要实时处理大量数据的场景,如金融交易系统、实时数据分析平台等,Redis 的高性能内存存储能够满足对数据处理速度的严格要求。
-
高效的数据结构
- Redis 提供了丰富的数据结构,如字符串、哈希表、列表、集合、有序集合等。这些数据结构针对不同的应用场景进行了优化,使得开发者可以根据具体需求选择最合适的数据结构来存储和操作数据。
- 例如,使用哈希表可以方便地存储对象属性,快速获取和修改特定属性的值;列表可以用于实现消息队列、栈等数据结构;集合和有序集合则适用于实现去重、排行榜等功能。
二、数据缓存
-
减轻数据库压力
- 在很多应用中,数据库往往是系统的性能瓶颈。通过将频繁访问的数据缓存到 Redis 中,可以减少对数据库的访问次数,从而降低数据库的负载。例如,在电商系统中,商品详情页的访问量非常大,如果每次都从数据库中读取商品信息,会给数据库带来巨大的压力。而将商品信息缓存到 Redis 中,大部分请求可以直接从 Redis 中获取数据,只有在数据发生变化时才更新缓存和数据库,这样可以显著提高系统的性能和稳定性。
- 对于一些复杂的查询结果,也可以缓存到 Redis 中,避免重复执行复杂的数据库查询操作。
-
提高响应速度
- 由于 Redis 的高速读写特性,从缓存中获取数据比从数据库中获取数据要快得多。这可以大大缩短用户的等待时间,提高用户体验。例如,在社交网络应用中,用户的好友列表、动态消息等可以缓存到 Redis 中,当用户刷新页面时,可以快速获取这些数据,而无需等待数据库查询的完成。
三、分布式锁
-
保证数据一致性
- 在分布式系统中,多个节点可能同时对共享资源进行访问和修改,这可能导致数据不一致的问题。Redis 可以实现分布式锁,确保在同一时间只有一个节点能够对共享资源进行操作。例如,在电商系统中,当多个用户同时抢购一件商品时,需要使用分布式锁来保证商品库存的正确扣减,避免超卖现象的发生。
- 分布式锁可以通过 Redis 的 SETNX(SET if Not eXists)命令来实现。当一个节点尝试获取锁时,它会使用 SETNX 命令在 Redis 中设置一个特定的键值对。如果设置成功,说明该节点获取到了锁;如果设置失败,则说明锁已经被其他节点持有,该节点需要等待锁释放后再尝试获取。
-
提高系统可靠性
- 分布式锁还可以用于保证分布式任务的正确执行顺序。例如,在分布式任务调度系统中,多个任务可能需要按照特定的顺序执行。通过使用分布式锁,可以确保每个任务在执行前先获取到相应的锁,从而保证任务的执行顺序正确,避免因任务执行顺序混乱而导致的系统故障。
四、消息队列
-
异步处理
- Redis 的列表数据结构可以用作简单的消息队列。生产者可以将消息推入列表的一端,消费者可以从列表的另一端取出消息进行处理。这种方式可以实现异步处理,将耗时的操作从主线程中分离出来,提高系统的响应速度和吞吐量。
- 例如,在用户注册场景中,当用户提交注册信息后,系统可以将注册成功的消息推入 Redis 队列,然后由后台的异步任务从队列中取出消息,发送欢迎邮件、初始化用户数据等操作。这样可以避免用户在注册过程中等待这些耗时操作的完成,提高用户体验。
-
任务分发
- Redis 消息队列还可以用于任务分发。在分布式系统中,可以将任务分配给不同的节点进行处理。生产者将任务推入 Redis 队列,各个节点作为消费者从队列中获取任务并进行处理。这种方式可以实现任务的动态分配和负载均衡,提高系统的处理能力和可靠性。
- 例如,在图片处理系统中,可以将图片处理任务推入 Redis 队列,各个处理节点从队列中获取任务,对图片进行压缩、裁剪等操作。这样可以根据系统的负载情况动态调整处理节点的数量,提高系统的处理效率。
五、数据持久化
-
防止数据丢失
- 虽然 Redis 将数据存储在内存中,但它也提供了数据持久化的功能,以防止数据因系统故障而丢失。Redis 支持两种持久化方式:RDB(Redis Database)和 AOF(Append Only File)。
- RDB 持久化是通过将内存中的数据快照保存到磁盘文件中来实现的。可以定期执行 RDB 持久化操作,将当前内存中的数据保存到磁盘上。在系统启动时,可以从 RDB 文件中恢复数据。
- AOF 持久化则是将 Redis 执行的所有写命令记录到一个追加文件中。在系统启动时,可以重新执行 AOF 文件中的写命令来恢复数据。
-
数据备份与恢复
- 数据持久化还可以用于数据备份和恢复。可以定期将 Redis 的数据备份到其他存储设备上,如远程服务器、云存储等。在系统发生故障时,可以从备份中恢复数据,保证数据的安全性和可靠性。
六、其他优势
-
支持主从复制
- Redis 支持主从复制功能,可以将数据从一个 Redis 实例复制到多个从实例上。主从复制可以实现数据的冗余备份,提高系统的可靠性。同时,从实例可以分担主实例的读负载,提高系统的读性能。
- 在主从复制架构中,主实例负责接收写请求,并将写操作同步到从实例上。从实例只负责处理读请求,从而减轻主实例的负载。如果主实例发生故障,可以将一个从实例提升为主实例,继续提供服务,实现高可用。
-
简单易用
- Redis 的命令简洁明了,易于学习和使用。它提供了丰富的客户端库,支持多种编程语言,使得开发者可以方便地在自己的项目中集成 Redis。
- 此外,Redis 的配置相对简单,不需要复杂的安装和部署过程。它可以在各种操作系统上运行,并且可以根据实际需求进行灵活的配置和扩展。
1.3 Redis和Mysql的对比
对比项目 | Redis | MySQL |
---|---|---|
数据存储介质 | 内存为主,可配置持久化到磁盘 | 磁盘 |
数据类型 | 丰富的数据结构如字符串、哈希、列表、集合、有序集合等 | 关系型数据,以表结构存储 |
性能 | 读写速度极快,通常在毫秒甚至微秒级别 | 相对较慢,尤其是在处理大量复杂查询时 |
适用场景 | 适合缓存热点数据、实现分布式锁、作为消息队列等 | 适合存储持久化的、结构化的业务数据 |
数据持久性 | 可配置持久化,但相比 MySQL 持久性稍弱 | 数据持久性强,通过事务等机制保证数据完整性 |
可扩展性 | 支持主从复制、集群等,扩展性较好 | 也可通过主从复制、分库分表等方式扩展,但相对复杂 |
数据一致性 | 在某些配置下保证强一致性较难,更注重性能 | 通过事务等机制保证强一致性 |
查询语言 | 简单的命令式操作 | SQL 语言,功能强大但相对复杂 |
1.4 Redis的一些常见命令
命令 | 作用 | 例子 |
---|---|---|
SET | 设置键值对 | SET key value,如 SET name "Tom" 设置键为 name,值为 "Tom" |
GET | 获取键对应的值 | GET name,获取键 name 对应的值,如果之前设置了 name 为 "Tom",则返回 "Tom" |
DEL | 删除键 | DEL key,如 DEL name 删除键 name |
EXISTS | 判断键是否存在 | EXISTS key,如 EXISTS name 判断键 name 是否存在 |
INCR | 将键的值自增 1 | INCR counter,假设键 counter 初始值为 0,执行后变为 1 |
DECR | 将键的值自减 1 | DECR counter,若 counter 为 1,执行后变为 0 |
LPUSH | 将一个或多个值插入到列表的左端 | LPUSH listItem "item1" "item2",向名为 listItem 的列表左边插入 "item1" 和 "item2" |
RPUSH | 将一个或多个值插入到列表的右端 | RPUSH listItem "item3",向名为 listItem 的列表右边插入 "item3" |
LRANGE | 获取列表指定范围内的元素 | LRANGE listItem 0 -1,获取名为 listItem 的列表的所有元素 |
HSET | 将哈希表 key 中的域 field 的值设为 value | HSET userInfo name "Alice",在名为 userInfo 的哈希表中设置域 name 的值为 "Alice" |
HGET | 获取哈希表 key 中给定域 field 的值 | HGET userInfo name,获取名为 userInfo 的哈希表中域 name 的值 |
SADD | 将一个或多个 member 元素加入到集合 key 当中 | SADD setItem "element1" "element2",向名为 setItem 的集合中加入元素 "element1" 和 "element2" |
SMEMBERS | 返回集合 key 中的所有成员 | SMEMBERS setItem,返回名为 setItem 的集合中的所有元素 |
ZADD | 将一个或多个 member 元素及其 score 值加入到有序集合 key 当中 | ZADD sortedSet 10 "member1" 20 "member2",向名为 sortedSet 的有序集合中加入元素 "member1" 和 "member2" 及其对应的分数 |
ZRANGE | 返回有序集合 key 中,指定区间内的成员 | ZRANGE sortedSet 0 -1,返回名为 sortedSet 的有序集合中的所有元素 |
二、Redis 常见的数据结构
一、字符串(String)
这是最基本的数据结构,可以存储二进制安全的字符串,包括文本、序列化对象等。
- 用途:
- 缓存用户信息、商品信息等简单的键值对数据。例如,存储用户的登录状态信息,将用户 ID 作为键,存储包含用户登录状态、最后登录时间等信息的字符串作为值。
- 计数器。可以用于统计网站的访问次数、用户的操作次数等。例如,每次有用户访问网站时,使用 INCR 命令对特定的访问计数器键进行自增操作。
二、哈希(Hash)
哈希是一个键值对集合,它是字符串字段和字符串值之间的映射。
- 用途:
- 存储对象信息。比如存储用户对象,可以将用户 ID 作为哈希的键,字段可以包括用户名、年龄、性别等属性,每个字段对应的值就是具体的属性值。这样可以方便地对单个用户的属性进行操作,而无需在数据库中进行复杂的查询。
- 存储配置信息。可以将不同的配置项作为哈希的字段,方便进行配置的读取和修改。
三、列表(List)
列表是一个简单的字符串列表,按照插入顺序排序。
- 用途:
- 消息队列。生产者可以使用 LPUSH 命令将消息插入列表的左端,消费者使用 RPOP 命令从列表的右端取出消息进行处理。例如,在分布式任务系统中,任务生成器将任务描述作为消息推入列表,各个任务执行节点从列表中获取任务并执行。
- 栈和队列。可以通过 LPUSH 和 LPOP 实现栈的功能,先入后出;通过 LPUSH 和 RPOP 实现队列的功能,先入先出。
四、集合(Set)
集合是无序的、唯一的字符串集合。
- 用途:
- 去重。可以用于存储不重复的元素,比如存储用户的 ID,确保每个用户在集合中只出现一次。在用户签到系统中,可以使用集合来记录每天签到的用户,方便统计签到用户的数量和进行用户去重。
- 交集、并集和差集运算。可以用于找出不同集合之间的共同元素、合并元素或者找出不同元素。例如,在社交网络中,可以使用集合来存储用户的关注列表和粉丝列表,通过交集运算可以找出共同关注的用户,通过差集运算可以找出单向关注的用户。
五、有序集合(Sorted Set)
有序集合是每个元素都关联一个分数(score)的集合,元素按照分数从小到大排列。
- 用途:
- 排行榜。可以根据元素的分数进行排序,比如游戏中的得分排行榜、商品的销量排行榜等。每个玩家的游戏得分作为元素的分数,玩家 ID 作为元素存储在有序集合中,通过 ZRANGE 命令可以获取排行榜的前几名。
- 范围查询。可以根据分数范围查询元素,比如查询得分在一定范围内的玩家。在实时数据处理中,可以使用有序集合存储时间戳作为分数,数据作为元素,方便进行基于时间范围的查询。
三、Redis的应用场景
一、缓存
- 页面缓存:存储不常变化的页面内容,减少数据库访问压力,提高响应速度。如电商网站的商品分类页面等。
- 数据缓存:缓存频繁访问的数据,如用户信息、商品详情等,提高访问效率。
二、计数器和限速器
- 计数器:可实现网站访问次数、用户操作次数等统计。例如统计网站每日访问量。
- 限速器:限制用户在一定时间内的请求次数,防止过度请求。
三、分布式锁
- 确保分布式系统中同一时间只有一个节点能操作共享资源,避免数据不一致。如电商抢购防止超卖。
- 保证分布式任务调度中任务执行顺序正确。
四、消息队列
- 异步处理:将耗时操作分离出来,提高系统响应速度和吞吐量。如用户注册后异步发送欢迎邮件。
- 任务分发:实现任务动态分配和负载均衡。如图片处理系统分配任务。
五、排行榜
- 游戏排行榜:根据玩家得分进行排名。
- 商品销量排行榜:方便用户查看畅销商品,商家调整营销策略。
六、会话存储
- 在分布式 Web 服务器架构中存储用户会话信息,实现快速访问和分布式存储。
七、地理位置服务
- 存储用户地理位置信息,进行附近商家推荐、用户查找等操作。如外卖配送系统分配订单。
四、实验练习
4.1redis
部署
实验环境:
红帽九主机。
实验步骤:
1.源码安装
官网下载解压:
安装依赖项:
编译:
2.启动
3.解决报错问题
[root@redis-node1 utils]# vim install_server.sh
#bail if this system is managed by systemd
#_pid_1_exe="$(readlink -f /proc/1/exe)"
#if [ "${_pid_1_exe##*/}" = systemd ]
#then
# echo "This systems seems to use systemd."
# echo "Please take a look at the provided example service unit files in
this directory, and adapt and install them. Sorry!"
# exit 1
#fi
4.再次启动,查看
一直回车选默认的就行
5.配置redis
[root@redis-node1 utils]# vim /etc/redis/6379.conf
bind * -::*
4.2 redis
主从复制
实验环境:
红帽九主机
实验步骤:
1.修改mastser
点的配置文件
[root@redis-node1 ~]# vim /etc/redis/6379.confprotected-mode no#node2,node3都要关
2.配置slave
节点
[root@redis-node2 ~]# vim /etc/redis/6379.conf
replicaof 172.25.254.100 6379
#node3也同样操作
3.测试
4.3哨兵模式(高可用)
实验环境:
红帽九主机
实验步骤:
1.备份一份配置文件
所有主机都要做:
2.在master:node1
节点中
编辑配置文件:
[root@redis-node1 ~]# cd redis-7.4.0/
[root@redis-node1 redis-7.4.0]# cp sentinel.conf /etc/redis/
[root@redis-node1 redis-7.4.0]# vim /etc/redis/sentinel.conf
protected-mode no #关闭保护模式
port 26379 #监听端口
daemonize no #进入不打如后台
pidfile /var/run/redis-sentinel.pid #sentinel进程pid文件
loglevel notice #日志级别
sentinel monitor mymaster 172.25.254.100 6379 2 #创建sentinel监控监控master主机,2表示必须得到2票
sentinel down-after-milliseconds mymaster 10000 #master中断时长,10秒连不上视为
sentinel parallel-syncs mymaster 1 #发生故障转移后,同时开始同步新
sentinel failover-timeout mymaster 180000 #整个故障切换的超时时间为3分钟
复制配置文件到其他主机:
3.启动服务
所有主机都要启动:
4.测试
再开一个node1窗口,讲redis服务停掉,模拟下线:
这是哨兵模式会监控,十秒后,node2,node3会提示node1下线,达到两票,则会重新选取新的主,下面这里选取的30为新的主
连到node3查看是否为主:
node1恢复后会变成slave:
4.4部署redis cluster
实验环境:
需要六台红帽9,构建三主三从的架构。
实验步骤:
1.添加认证和密码
[root@redis-node1 ~]# vim /etc/redis/redis.conf
masterauth "123456"
requirepass "123456"
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000
root@redis-node1 ~]# systemctl enable --now redis
其余主机使用scp传输过去。
2.部署集群
3.检测redis集群状态
[root@redis-node1 ~]# redis-cli -a 123456 -- cluster info 172.25.254. 10: 6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not b
e safe.
172.25.254.11:6379 (0492aeca ... ) -> 0 keys | 5461 slots | 1 slaves.
172.25.254.30:6379 (a1lab250. .. ) -> 0 keys | 5461 slots | 1 slaves.
4.5 集群扩容
实验环境:
相同。
实验步骤:
1.添加master
再准备两台虚拟机,IP为172.25.254.(50,150)并将其添加到集群里。
[root@redis-master1 ~]# redis-cli -a 123456 --cluster info 172.25.254.10:6379
Warning: Using a password with '-a' or '-u' option on the command line interface
may not be safe.
172.25.254.11:6379 (5ab2e93f...) -> 0 keys | 5461 slots | 1 slaves.
172.25.254.50:6379 (009571cb...) -> 0 keys | 0 slots | 0 slaves.
172.25.254.21:6379 (ba504e78...) -> 1 keys | 5462 slots | 1 slaves.
172.25.254.31:6379 (1fcaeb1d...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 1 keys in 4 masters.
0.00 keys per slot on average.
2.分配槽位
3.添加salve
[root@redis-master1 ~]# redis-cli -a 123456 --cluster add-node
172.25.254.150:6379 172.25.254.11:6379 --cluster-slave --cluster-master-id
009571cb206a89afa6658b60b2d403136056ac09
4.查看
4.6集群的维护
实验环境:
相同。