Redis 初相识:开启缓存世界大门
Redis 概述
什么是 Redis
Redis 是一个开源(BSD 许可)的,内存中的数据结构存储系统,它可以充当数据库、缓存以及消息中间件等多种角色。从数据存储角度来看,它基于内存,通过键值对的方式来存储各种类型的数据,比如字符串、哈希、列表、集合、有序集合等都是它所支持的数据结构形式。而且,Redis 具备持久化功能,有 RDB 快照方式和 AOF 日志方式这两种持久化策略,能够保证在服务器重启后依然可以恢复之前的数据。另外,Redis 使用单线程事件循环模型来处理请求,这种独特的网络模型让它在应对高并发请求时也有着优异的表现。
Redis 的优势
Redis 之所以在现代应用中备受青睐,是因为它有着诸多优势。首先是高性能,由于其操作缓存是直接基于内存的,内存的读写速度相较于磁盘要快得多,所以数据的访问速度非常快,能够快速响应各种操作请求。其次是高并发,它能够承受大量的请求同时涌入,轻松应对高并发场景。再者,Redis 的数据类型十分丰富,涵盖了字符串、哈希、列表、集合、有序集合等多种类型,不同的数据类型可以满足各式各样的业务场景需求,比如利用有序集合就能方便地构建实时排行榜。同时,它还支持集群模式,可将数据分布在多个节点上实现分布式部署,进一步提升系统的扩展性和可靠性。此外,Redis 支持事务处理,确保一组操作的原子性,并且通过发布 / 订阅模式,还能实现简单的消息队列和消息订阅功能,为消息传递与处理提供了便捷的途径。
Redis 的数据结构
常用数据结构总览
Redis 支持多种丰富的数据结构,比如字符串(strings),它是最基本的数据结构,可以存储字符串、整数或浮点数等;散列(hashes),类似于字典,能够存储字段和值的映射关系;列表(lists),是有序的字符串列表,可在列表的两端进行插入和删除操作;集合(sets),属于无序的字符串集合,有着不允许重复元素的特点;还有有序集合(sorted sets),和集合类似,但每个元素都关联一个分数(score),可根据分数实现元素的排序。这些多样的数据结构,能满足不同场景下的数据存储与操作需求。
各数据结构详解及应用场景
String
String 数据结构常用的命令有很多,例如set命令可用于设置一个键值对,将键key的值设置为value;get命令则能获取指定键的值。像INCR可以将指定键的值递增 1,DECR反之能将指定键的值递减 1,还有INCRBY、DECRBY能按照指定的增量来增减键对应的值。APPEND命令可把新的value追加到指定键的值的末尾,STRLEN能获取指定键的值的长度,SETEX可以设置一个带有过期时间的键值对,SETNX则是在键不存在时,将键的值设置为给定值。
其应用场景十分广泛,在常规的 key-value 缓存应用中,通过将数据存储在 Redis 的字符串里,能够快速地读写数据,从而提升应用程序的性能,像缓存数据库查询结果、API 响应等场景就很常用。另外,它还可以用于计数,比如实现微博数、粉丝数的统计,利用INCR和DECR等命令方便地对相应的计数进行操作。
Hash
Hash 数据结构常用的命令包含hget、hset等。hset命令可以将多个 field-value(域 - 值)对设置到哈希表key中,hget用于获取存储在哈希表中指定字段的值。除此之外,还有hmget能一次获取哈希表中多个字段的值,hkeys可获取所有哈希表中的字段,hvals用来获取哈希表中的所有值,hlen能获取哈希表中字段的数量等。
Hash 结构适合存储对象,相比将对象存储为 String 类型,它占用更少的内存空间,并且在修改对象的字段值时更加便利。例如可以用于存储用户信息,将用户的各个属性(如姓名、年龄、地址等)作为字段,对应的值作为字段值存入 Hash 结构中;也能用于存储商品信息,像商品的编号、名称、价格等信息都可以通过 Hash 结构来进行组织和存储,方便后续的查询与修改操作。
List
List 数据结构常用命令诸如lpush、rpush、lpop、rpop等。lpush命令可将一个或者多个元素从左侧放入(头插)到list中,如果key不存在会新建key;rpush则是将一个或者多个元素从右侧放入(尾插)到list中。lpop用于从list左侧取出元素(即头删),rpop从list右侧取出元素(即尾删)。还有lrange命令可以获取从指定start到end区间的所有元素(左闭右闭区间),llen能获取list的长度等。
List 作为双向链表,有着诸多应用场景。在社交平台中,可用于实现微博关注列表、粉丝列表等功能,例如使用lpush或者rpush来添加关注的人或者粉丝,通过lrange查看列表信息。也可以用于消息列表的功能实现,将新消息通过lpush等命令插入列表头部,方便按顺序展示消息。而且它还支持分页查询功能,通过合理设置lrange的参数,就能获取指定页面范围的元素内容。
Set
Set 数据结构常用的命令有sadd、spop、sismember、smembers等。sadd用于往集合key中存入元素,如果元素存在则忽略,若key不存在则新建;spop可从集合key中随机选出元素,并将其从key中删除;sismember能够判断指定元素是否存在于集合key中;smembers则用来获取集合key中的所有元素。此外,还有用于求交集的SINTER、求并集的SUNION、求差集的SDIFF等操作相关的命令。
Set 的一个重要特性就是自动排重,保证集合中的元素都是唯一的。它可用于求交集、并集、差集等操作,在微博应用中,能方便地计算出共同关注、共同粉丝等功能。比如两个用户分别有自己关注的公众号集合,通过SINTER命令就能快速求出他们共同关注的公众号列表;在抽奖活动中,也可以利用 Set 的去重特性,保证同一个用户不会中奖两次,将参与抽奖的用户添加到 Set 中,进行抽奖相关的操作。
Sorted Set
Sorted Set 在 Set 的基础上增加了权重参数score,通过这个score可以让元素按一定顺序排列,元素本身依然是唯一的,只是多了这个用于排序的属性。
常用的命令比如ZADD,用于向有序集合添加一个或多个成员,或者更新已存在成员的分数;ZRANGE能通过索引区间返回有序集合指定区间内的成员,返回的元素默认按得分从最低到最高排列;ZANK可返回有序集合中指定成员的排名(索引)等。
Sorted Set 适用于很多需要根据某个权重进行排序的应用场景,例如游戏中的玩家排名,根据玩家的得分作为score,可以快速获取排名情况,展示排行榜信息;在电商平台中,商品可以按照销量、好评率等作为score来进行排序展示,方便用户查找热门或者优质的商品等。
Redis 的安装与基本使用
安装步骤
在不同的操作系统上安装 Redis 的步骤有所不同,下面为大家介绍在 Ubuntu 和 macOS 系统上安装 Redis 的详细流程。
Ubuntu 系统安装 Redis 步骤如下:
- 更新系统软件包:在安装 Redis 之前,首先需要确保系统软件包是最新的版本。可以通过以下命令来更新系统:
sudo apt update
sudo apt upgrade
- 安装 Redis:使用以下命令安装 Redis:
sudo apt install redis-server
安装完成后,可以通过以下命令检查 Redis 是否成功启动:
sudo systemctl status redis-server
- 配置 Redis:Redis 的配置文件位于/etc/redis/redis.conf,可以通过编辑该文件来配置 Redis。可以通过以下命令来编辑配置文件:
sudo nano /etc/redis/redis.conf
可以根据具体需求修改配置文件,如修改监听端口、设置密码等。
4. 启动 Redis:配置完成后,可以使用以下命令启动 Redis 服务:
sudo systemctl start redis-server
并可设置 Redis 为开机自启动:
sudo systemctl enable redis-server
- 测试 Redis:最后,可以通过以下命令测试 Redis 是否正常运行:
redis-cli ping
如果返回PONG,则表示 Redis 已成功安装并运行。
macOS 系统安装 Redis 步骤如下:
方式一(使用 Homebrew 安装):
- 安装前置条件检查:首先需要保证你的 mac 电脑安装了 Homebrew,我们可以通过以下命令进行校验:
brew --version
若显示报错,则需要安装 Homebrew,执行以下命令:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
- 安装 Redis:执行以下命令安装 Redis:
brew install redis
- 操作启动:可以使用以下命令启动 Redis 服务:
redis-server
或者
brew services start redis
- 验证:通过brew services info redis命令查看 redis 信息,也可以通过命令行redis-cli校验,例如在命令行输入redis-cli进入客户端后,执行set key01 hello-world,再执行get key01能获取到对应设置的值,就说明服务正常运行。
- 停止:通过brew services stop redis命令停止 Redis。
方式二(手动编译安装,相对复杂些):
- 由于需要用到编译,所以先安装 Xcode,注意利用 App Store 安装 Xcode 后,记得打开 Xcode 点install,也可以建立一个 macOS 项目,运行下试下。
- 去官网(Redis - The Real-time Data Platform)下载 Redis 安装包,然后执行make test(这步会比较耗时),make test完毕后再执行sudo make install,之后运行redis-server来启动 Redis。
基本命令操作
掌握 Redis 的基本命令操作,能够帮助你快速上手使用 Redis 进行数据的存储与管理等操作,以下是一些常用命令介绍。
存储和获取数据
- 字符串(String)类型常用命令:
-
- set:用于设置一个键值对,例如set mykey "myvalue",就是将键mykey的值设置为myvalue。
-
- get:获取指定键的值,如执行get mykey就能获取到之前设置的myvalue。
-
- INCR:可以将指定键的值递增 1,例如键count的值为 10,执行INCR count后其值就变为 11 了,常用于计数场景,且该键对应的值要是数字类型,若不存在会先初始化为 0 再递增。
-
- DECR:反之能将指定键的值递减 1,比如键num的值为 5,执行DECR num后变为 4,同样要求键对应的值为数字类型,不存在时先初始化为 0 再递减。
-
- INCRBY和DECRBY:能按照指定的增量来增减键对应的值,像INCRBY mynum 5就是让mynum键对应的值增加 5,DECRBY mynum 3就是让其减少 3。
-
- APPEND:可把新的value追加到指定键的值的末尾,例如键msg原本值为Hello,执行APPEND msg ", World!"后,msg的值就变为Hello, World!了。
-
- STRLEN:能获取指定键的值的长度,执行STRLEN msg就会返回msg键对应值的长度,对于上面的msg键会返回 13(包含空格等字符)。
-
- SETEX:可以设置一个带有过期时间的键值对,如SETEX tempkey 60 "tempvalue",表示设置tempkey键值对,且 60 秒后过期,过期后自动删除该键值对。
-
- SETNX:则是在键不存在时,将键的值设置为给定值,例如SETNX newkey "newvalue",如果newkey不存在就设置成功并返回 1,若存在则不做操作返回 0。
- 哈希表(Hash)类型常用命令:
-
- hset:可以将多个 field-value(域 - 值)对设置到哈希表key中,例如hset userinfo name "Alice" age 25,就是在userinfo这个哈希表中设置了name字段值为Alice,age字段值为 25。
-
- hget:用于获取存储在哈希表中指定字段的值,如执行hget userinfo name就会返回Alice。
-
- hmget:能一次获取哈希表中多个字段的值,比如hmget userinfo name age可以一次性获取userinfo哈希表中name和age两个字段的值。
-
- hkeys:可获取所有哈希表中的字段,执行hkeys userinfo会返回name和age等所有字段名。
-
- hvals:用来获取哈希表中的所有值,对于上面的userinfo哈希表,执行hvals userinfo会返回Alice、25这些值。
-
- hlen:能获取哈希表中字段的数量,执行hlen userinfo会返回 2,表示有两个字段。
- 列表(List)类型常用命令:
-
- lpush:可将一个或者多个元素从左侧放入(头插)到list中,如果key不存在会新建key,例如lpush mylist "a" "b",会将a和b依次插入到mylist列表的头部,此时mylist里元素顺序为b、a。
-
- rpush:则是将一个或者多个元素从右侧放入(尾插)到list中,比如rpush mylist "c",会将c插入到mylist列表的尾部,此时mylist里元素顺序为b、a、c。
-
- lpop:用于从list左侧取出元素(即头删),执行lpop mylist会将b取出并删除,此时mylist里元素变为a、c。
-
- rpop:从list右侧取出元素(即尾删),如执行rpop mylist会将c取出并删除,mylist剩下a这个元素了。
-
- lrange:命令可以获取从指定start到end区间的所有元素(左闭右闭区间),例如lrange mylist 0 0会返回a,如果执行lrange mylist 0 -1则会返回整个列表的所有元素。
-
- llen:能获取list的长度,执行llen mylist对于上述剩下a元素的mylist会返回 1。
- 集合(Set)类型常用命令:
-
- sadd:用于往集合key中存入元素,如果元素存在则忽略,若key不存在则新建,例如sadd myset "a" "b",会往myset集合中添加a和b元素,如果再次执行sadd myset "a",因为a已经存在则不会重复添加。
-
- spop:可从集合key中随机选出元素,并将其从key中删除,执行spop myset会随机从myset中取出一个元素并删除它。
-
- sismember:能够判断指定元素是否存在于集合key中,比如执行sismember myset "a",如果a在集合中则返回 1,不存在返回 0。
-
- smembers:则用来获取集合key中的所有元素,执行smembers myset会返回集合中当前所有的元素。
-
- 还有用于求交集的SINTER、求并集的SUNION、求差集的SDIFF等操作相关的命令,例如有两个集合set1和set2,执行SINTER set1 set2就能获取到它们的交集元素。
- 有序集合(Sorted Set)类型常用命令:
-
- ZADD:用于向有序集合添加一个或多个成员,或者更新已存在成员的分数,例如ZADD myzset 10 "member1" 20 "member2",就是往myzset有序集合中添加了member1(分数为 10)和member2(分数为 20)两个成员。
-
- ZRANGE:能通过索引区间返回有序集合指定区间内的成员,返回的元素默认按得分从最低到最高排列,比如执行ZRANGE myzset 0 -1会按分数从小到大返回myzset有序集合中的所有成员。
-
- ZANK:可返回有序集合中指定成员的排名(索引)等,执行ZANK myzset "member1"会返回member1在myzset中的排名情况。
设置过期时间
可以使用EXPIRE命令以秒为单位给key设置过期时间,例如EXPIRE mykey 60,表示设置mykey这个键 60 秒后过期,过期后 Redis 会自动删除该键值对。也可以使用PEXPIRE命令以毫秒为单位设置过期时间,如PEXPIRE myotherkey 60000(60000 毫秒即 60 秒)。此外,还有EXPIREAT和PEXPIREAT命令可以指定一个具体的时间戳作为过期时间(分别以秒和毫秒为时间戳单位),例如EXPIREAT mykey 1678900000(这里是假设的一个时间戳示例)。
如果想要移除键的过期时间,让其永不过期,可以使用PERSIST命令,例如PERSIST mykey,执行成功后mykey就不会再受之前设置的过期时间限制了。
查看键的类型
使用TYPE命令可以查看当前key所储存的值的类型,例如执行TYPE mykey,如果mykey存储的是字符串类型的值,就会返回string,若是列表类型则返回list,集合类型返回set等等,方便我们了解数据在 Redis 中的存储形式,便于后续相应的操作处理。
Redis 的高级特性与应用场景
高级特性
数据持久化
Redis 支持多种数据持久化方式,其中包括快照(snapshotting)和日志(logging)。快照方式,也就是 RDB 持久化,在默认情况下,Redis 会将数据库快照保存在名为 dump.rdb 的二进制文件中。其工作原理是,当需要保存该文件时,服务器先执行 fork () 操作,同时拥有父进程和子进程,接着子进程把数据集写入到一个临时 RDB 文件里,待子进程完成新 RDB 文件的写入后,Redis 会用新 RDB 文件替换原来的文件,并删除旧文件。RDB 持久化的触发分为手动触发与定时触发,手动触发可通过 save(不过此命令会阻塞当前 Redis 服务器,线上一般禁止使用)、bgsave(通过 fork 子进程负责持久化,阻塞只在 fork 子进程时发生)命令来进行,而定时触发则根据配置文件里的 save m n 配置规则等情况触发。
日志方式,即 AOF(追加文件)持久化,它会记录每次对服务器写的操作,当服务器重启时,会重新执行这些命令来恢复原始的数据。AOF 主要有两个步骤,一是对修改命令进行实时写入,二是对 AOF 重写以减少文件大小,重写可以手动(通过 bgrewriteaof 命令)或者自动根据配置规则触发。
这些数据持久化方式的重要作用在于,即便 Redis 服务器遇到重启等情况,依然能够加载之前保存的数据,保障数据的安全性与完整性,避免数据丢失。
发布订阅模式
Redis 的发布订阅模式是一种高效的消息传递机制,用于实现消息的发布和接收。在这个模式中,包含发布者、订阅者和 Channel 三个重要部分,发布者和订阅者都是 Redis 客户端,而 Channel 则为 Redis 服务器端。发布者能通过 PUBLISH 命令将消息发送到某个指定的频道,而订阅了该频道的订阅者就能接收到这条消息。例如,订阅者可以使用 SUBSCRIBE 命令来订阅感兴趣的频道,一旦有消息发布到这些频道,订阅者就会接收到相应的消息。
其应用场景十分广泛,比如在实时聊天场景中,当有用户发送消息(发布者发布消息到聊天频道),其他订阅了该聊天频道的在线用户(订阅者)就能实时收到消息,实现实时消息推送;在分布式系统里,各个节点之间需要互相通知发生的事件,像节点的上线、下线、状态变更等情况时,可以通过发布订阅模式,将事件消息发布到对应的频道,相关订阅的节点就能收到通知;另外在日志处理方面,可将收集到的日志发布到特定频道,订阅该频道的处理模块就能实时接收到日志进行相应处理。
事务支持
Redis 的事务操作有着独特的特点,它能够将多个操作打包成原子操作,然后按照顺序依次执行。例如,我们可以把一组相关的数据修改、查询等操作放在一个事务当中,确保这些操作要么全部成功执行,要么全部不执行,以此来实现基本的事务控制。在实际应用中,比如在电商系统里,当用户下单时,涉及库存扣减、订单生成、支付记录等多个操作,就可以利用 Redis 的事务功能,把这些操作打包成一个事务,保证数据的一致性和完整性,避免出现部分操作成功、部分操作失败而导致的数据不一致等问题,为业务逻辑的准确执行提供了有力保障。
其他特性
Redis 还具备诸多其他高级特性。比如它支持 Lua 脚本,通过编写 Lua 脚本可以将复杂的业务逻辑在 Redis 端进行处理,减少客户端与服务器之间的交互次数,提高执行效率;管道(pipeline)特性允许客户端一次性发送多个命令到服务器,服务器按顺序依次处理并返回结果,能够有效减少网络开销,提升批量操作的性能;在分布式环境中,Redis 的分布式、复制、高可用等特性发挥着重要作用,通过复制功能可以创建多个从节点来分担主节点的读压力,并且在主节点出现故障时,从节点能快速接替工作,保证系统的高可用性,而分布式的部署方式则能让数据分散存储在多个节点上,提升系统的扩展性,满足大规模数据存储与高并发访问的需求。
应用场景
缓存应用
Redis 作为缓存层,在现代应用程序中有着极为重要的作用,尤其是在提升应用程序性能和响应时间方面表现出色。例如在新闻网站中,每天有大量的新闻资讯被频繁访问,如果每次都从数据库中查询读取,会耗费较多的时间和资源,而将新闻数据缓存到 Redis 中,用户再次访问时就能直接从 Redis 快速获取,极大地缩短了响应时间;社交媒体平台上,用户的动态、好友关系等数据量庞大且访问频繁,利用 Redis 缓存这些数据,能够加快数据的读取速度,提升用户体验;电子商务网站同样如此,商品信息、购物车数据等都可以存储在 Redis 缓存中,方便快速展示给用户,提高系统整体的性能,让用户操作更加流畅。
会话存储
在 Web 应用程序中,会话管理是一项关键任务,而 Redis 在这方面有着显著优势。特别是在多台服务器构成的分布式环境下,不同服务器之间需要共享会话信息,Redis 就能很好地承担起这个任务。它可以方便地存储用户的会话数据,并且能够灵活地管理会话的过期时间。例如在大型的电商平台或者社交平台,用户可能会在不同的服务器节点上进行操作,通过将用户会话信息存储在 Redis 中,各个服务器都能获取到准确的会话状态,确保用户的操作连贯性,同时过期时间的有效管理也能避免会话数据长时间占用资源,保障系统的高效运行。
分布式锁
在分布式系统中,经常会遇到并发问题,多个进程可能会同时访问共享资源,从而导致数据不一致等情况。Redis 通过 SETNX 等命令可以有效地解决这个问题,实现分布式锁的功能。其原理是,当一个进程需要访问共享资源时,它可以使用 SETNX 命令尝试创建一个锁,这个锁有对应的过期时间设置,若创建成功(即该锁对应的键不存在,SETNX 返回成功),则表示获取到了锁,该进程可以对共享资源进行操作,在操作完成后释放锁;若创建失败(说明已经有其他进程持有该锁),则需要等待一段时间后再次尝试获取锁。通过这样的机制,就能避免多个进程同时访问共享资源,保证分布式系统中数据的准确性和一致性。
限流
为了防止恶意用户滥用系统资源,保障系统的稳定性和正常服务,利用 Redis 可以轻松实现限流功能。例如,可以基于 Redis 的计数器和定时器来实现对特定用户或 IP 地址访问资源数量的限制。通过对用户或 IP 对应的键设置计数器,每当有访问请求时,计数器的值就相应增加,同时结合定时器来判断一定时间范围内的访问次数是否超过设定的阈值,若超过则限制该用户或 IP 的访问,比如可以返回提示信息告知用户访问过于频繁等,直到经过一定时间后计数器重置,才允许继续正常访问,以此来合理控制资源的访问量,确保系统的健康运行。
排行榜
Redis 的有序集合数据结构为实现各类排行榜功能提供了便利。比如在游戏应用中,根据玩家的得分作为有序集合中元素的分数(score),通过相关命令可以快速获取玩家的排名信息、更新玩家的分数,还能方便地删除过期的排行榜数据等。在电商平台上,商品可以按照销量、好评率等作为 score 来进行排序展示,用户能够直观地看到热门或者优质的商品,方便查找心仪的商品。此外,在社交平台的各种榜单,如活跃度榜单、影响力榜单等也都可以借助 Redis 的有序集合轻松构建和维护,满足不同业务场景下对于排行榜功能的需求。