一、认识Redis
一、基本概念
Redis(Remote Dictionary Server,远程字典服务器)是一款开源、基于内存运行的高性能键值对(Key-Value)NoSQL 数据库。它通常被用作数据库、缓存、消息代理和流式处理引擎,除了这些之外,目前较新版本的Redis还支持AI领域的一些应用,包括向量数据库、增强检索生成RAG以及AI Agent和聊天机器人。Redis 内置了复制功能,并提供不同级别的磁盘持久化。它支持复杂数据类型(例如字符串、哈希、列表、集合、有序集合以及 JSON),并为这些数据类型定义了原子操作。
二、核心优势
1. 极致的读写性能
Redis 将所有数据存储在系统内存中,避免了传统磁盘 I/O 带来的性能瓶颈。因此,它能提供亚毫秒级(甚至微秒级)的响应时间,单机即可支持每秒数十万次的查询率(QPS),非常适合高并发场景。
2. 丰富的数据结构
不同于传统的简单键值存储,Redis 原生支持多种复杂的数据结构,包括:字符串(String)、哈希(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)。此外还支持位图(Bitmap)、HyperLogLog、地理空间(Geospatial)以及流(Stream)等高级数据类型,能够轻松应对各种业务需求。
3. 数据持久化与高可用
虽然基于内存,但 Redis 提供了 RDB(内存快照)和 AOF(日志追加)两种持久化机制,确保在服务器宕机或重启后数据不会丢失。同时,它支持主从复制、哨兵模式(Sentinel)以及分布式集群(Cluster),为构建高可用和可扩展的系统提供了强有力的保障。
4. 简单易用与单线程模型
Redis 采用简洁的命令结构,开发者可以用更少的代码实现复杂的逻辑。其核心命令执行采用单线程模型,不仅规避了多线程带来的锁竞争和上下文切换开销,还天然保证了操作的原子性,无需担心并发竞争问题。
三、典型应用场景
- 缓存系统: 减轻后端关系型数据库的负担,提高网页或应用的响应速度。
- 会话存储: 在 Web 应用中快速读写用户的登录信息和购物车状态。
- 排行榜与计数器: 利用有序集合高效维护游戏分数排名或页面实时访问量。
- 消息队列: 通过发布/订阅模式和列表结构,在生产者和消费者之间高效传递消息。
- 实时分析与地理位置服务: 用于高频交易监控、附近的人/店铺查询等。
二、Redis的安装与启动
官方文档:https://redis.io/docs/latest/get-started/
系统环境:Ubuntu 22.04
Redis安装版本:8.0.0
1.安装必要的依赖
#更新软件包列表
apt-get update
#安装必要的工具和库
apt-get install -y sudo
sudo apt-get install -y --no-install-recommends \ca-certificates \wget \dpkg-dev \gcc \g++ \libc6-dev \libssl-dev \make \git \cmake \python3 \python3-pip \python3-venv \python3-dev \unzip \rsync \clang \automake \autoconf \libtool
2.安装cmake
#安装指定版本的cmake
pip3 install cmake==3.31.6
#创建软链接(类似于快捷方式),/usr/bin(系统默认可执行文件路径,这样就可以在任意位置cmake)
sudo ln -sf /usr/local/bin/cmake /usr/bin/cmake
#检查版本
cmake --version
3.下载Redis源码并解压
#创建好目录并进入
mkdir -p /mydata/redis
cd /mydata/redis
#下载tar.gz包
wget https://download.redis.io/releases/redis-8.0.0.tar.gz
#解压
tar xzf redis-8.0.0.tar.gz
#进入解压目录
cd redis-8.0.0
4.构建环境变量和编译
#构建环境变量
export BUILD_TLS=yes
export BUILD_WITH_MODULES=yes
export INSTALL_RUST_TOOLCHAIN=yes
export DISABLE_WERRORS=yes
#编译(网络不好可以先关闭模块的编译,要不然很慢)
make -j$(nproc) BUILD_WITH_MODULES=no
5.执行目录和源码分开
#PREFIX用于指定执行目录存放的位置
make install PREFIX=/mydata/redis/redis
#创建conf目录并拷贝一份redis.conf
cd /mydata/redis/redis
mkdir -p conf
cp /mydata/redis/redis-8.0.0/redis.conf /mydata/redis/redis/conf/
#授权
cd conf
chmod -R 777 redis.conf
6.启动Redis
#启动Redis
cd /mydata/redis/redis/bin
./redis-server ../conf/redis.conf
出现如下界面说明启动成功!

7.连接Redis
注意:这里我们需要换一个命令窗口去操作,不要直接在启动Redis这里直接ctrl+c!!
#使用redis-cli连接已启动的Redis服务,-h指定host,-p指定端口
./redis-cli -h 127.0.0.1 -p 6379
#set命令设置key-value键值对
set name zhangsan
#get命令根据key获取value
get name
退出当前客户端
exit
停止Redis服务
./redis-cli -p 6379 shutdown
三、Redis全局命令
keys命令用于列出所有的key,支持通配符,不过如果是在生产环境中,key特别多的情况下不要乱用,因为Redis会把所有的key全部遍历一遍,时间复杂度是O(N)
keys *
keys na*

dbsize命令用于返回当前key的总量,这个和上面的不一样,不会把所有的key遍历一遍统计总数,Redis内部维护了一个key的总量,dbsize命令直接拿的这个数据,时间复杂度是O(1)

EXISTS命令用于返回指定key是否存在,存在返回1,不存在返回0
set stu1 xiaoming
set stu2 xiaohong
EXISTS stu1
EXISTS stu3

EXISTS命令后面也可以指定多个key
EXISTS stu1 stu2
EXISTS stu1 stu2 stu3

del命令用于删除key,删除存在的key返回1,不存在的返回0,支持删除多个key
127.0.0.1:6379> set stu1 zs
OK
127.0.0.1:6379> set stu2 ww
OK
127.0.0.1:6379> set stu3 ls
OK
127.0.0.1:6379> del stu1
(integer) 1
127.0.0.1:6379> del stu2 stu3
(integer) 2
127.0.0.1:6379> del stu1
(integer) 0
expire命令支持对key设置过期时间,单位为秒,超过过期时间自动删除,ttl命令用来查看key的剩余过期时间,当key被自动删除不存在了,返回-2,如果是未设置过期时间,返回-1
127.0.0.1:6379> set stu2 ls
OK
127.0.0.1:6379> expire stu2 10
(integer) 1
127.0.0.1:6379> ttl stu2
(integer) 6
127.0.0.1:6379> ttl stu2
(integer) 5
127.0.0.1:6379> ttl stu2
(integer) -2
127.0.0.1:6379> ttl stu1
(integer) -1
设置过期时间需要注意以下几点:
- 如果设置过期时间的key不存在,返回0;
- 过期时间为负值,等价于
del命令; persist命令用于清除key的过期时间
127.0.0.1:6379> expire stu1 20
(integer) 1
127.0.0.1:6379> ttl stu1
(integer) 16
127.0.0.1:6379> persist stu1
(integer) 1
127.0.0.1:6379> ttl stu1
(integer) -1
- 对于字符串类型的key,执行set命令会清除它的过期时间;
127.0.0.1:6379> expire stu1 99
(integer) 1
127.0.0.1:6379> ttl stu1
(integer) 91
127.0.0.1:6379> set stu1 ll
OK
127.0.0.1:6379> ttl stu1
(integer) -1
- Redis不支持二级数据结构(例如哈希、列表)内部元素的过期功能,不能对二级数据结构做过期时间设置;
type命令用于返回键的类型
127.0.0.1:6379> type stu1
string
randomkey用于返回一个随机的key
127.0.0.1:6379> randomkey
"stu1"
rename命令用于对key重命名,注意:如果新名已存在,则会把已存在的那个key的值给覆盖
127.0.0.1:6379> get stu1
"ll"
127.0.0.1:6379> get stu2
"lxs"
127.0.0.1:6379> rename stu1 stu2
OK
127.0.0.1:6379> get stu2
"ll"
我们可以使用 renamenx命令来保证不会把别的key给覆盖,它会判断新的key名是否存在
127.0.0.1:6379> set stu1 lsls
OK
127.0.0.1:6379> keys *
1) "stu1"
2) "stu2"
127.0.0.1:6379> renamenx stu1 stu2
(integer) 0
127.0.0.1:6379> keys *
1) "stu1"
2) "stu2"
四、常用的数据结构
Redis常用的数据结构有五种:字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(ZSet)。
一、字符串
1、常用命令
我们前面使用的 set命令就是字符串的常用命令,它包含如下的几个选项:
- ex:设置过期时间,和expire作用一致;
- px:也是设置过期时间,不过是毫秒级的;
- nx:只有key不存在才能set成功,常用于分布式锁;
- xx:只有key存在才能成功,用于更新;
127.0.0.1:6379> keys *
1) "stu1"
2) "stu2"
3) "stu3"
127.0.0.1:6379> set stu1 zhuzhu nx ex 99
(nil)
127.0.0.1:6379> set stu4 zhuzhu nx ex 99
OK
127.0.0.1:6379> set stu5 lili xx ex 99
(nil)
127.0.0.1:6379> set stu4 lili xx
OK
setex命令是 set和 ex的组合命令,setnx命令是 set和 nx的组合命令
127.0.0.1:6379> setex stu4 99 liubang
OK
127.0.0.1:6379> setnx stu4 jk
(integer) 0
get命令根据key获取value,没有则返回nil空
127.0.0.1:6379> get stu1
"lsls"
127.0.0.1:6379> get stu5
(nil)
mset命令和 mget命令用于批量设置和获取
127.0.0.1:6379> mset a 1 b 2 c 3 d 4
OK
127.0.0.1:6379> mget a b c d
1) "1"
2) "2"
3) "3"
4) "4"
incr命令用于value自增(整数才行),如果key不存在,则从0开始自增
127.0.0.1:6379> EXISTS age
(integer) 0
127.0.0.1:6379> incr age
(integer) 1
127.0.0.1:6379> incr age
(integer) 2
append命令用于字符串追加
127.0.0.1:6379> set address jiangxi
OK
127.0.0.1:6379> append address nanchang
(integer) 15
127.0.0.1:6379> get address
"jiangxinanchang"
strlen用于返回字符串的长度,注意中文占三个字节
127.0.0.1:6379> strlen address
(integer) 15
127.0.0.1:6379> set name "张三"
OK
127.0.0.1:6379> strlen name
(integer) 6
getset命令也是用于设置value,但是会返回原值,如果没有,则返回nil
127.0.0.1:6379> getset address "jiangxi nanchang"
"jiangxinanchang"
127.0.0.1:6379> getset province jiangxi
(nil)
127.0.0.1:6379> get province
"jiangxi"
setrange命令用于设置指定位置的字符,下标从0开始
127.0.0.1:6379> setrange province 4 " "
(integer) 7
127.0.0.1:6379> get province
"jian xi"
getrange命令用于截取字符串
127.0.0.1:6379> getrange province 0 3
"jian"
2、使用场景
- 缓存:最常见的使用场景,将Mysql访问频繁的数据缓存到Redis中,用户请求过来直接从Redis拿;
- 计数:使用Redis快速计数,比如网站的实时访问量;
- 会话Session:用户的登录信息,会话信息放在Redis中,方便各个服务使用;
- 限速:比如为了保证短信接口不被频繁访问,限制用户获取验证码的频率;
二、哈希(Hash)
Redis里的哈希和我们java里的HashMap结构差不多,哈希包含key,field和value三部分,key对应的是整个哈希结构本身,也就是整个HashMap,field-value对应的是哈希结构里面包含的每一个键值对,就和我们HashMap里面的Entry一样。
2.1 常用命令
hset命令用于对哈希结构进行设置,可以单独对其中的一个field-value操作,也可以对多个field-value进行操作。
127.0.0.1:6379> hset stus stu1 xiaoming
(integer) 1
127.0.0.1:6379> hset stus stu2 xiaohong stu3 xiaohua
(integer) 2
hget命令用于获取field对应的value,如果不存在返回nil
127.0.0.1:6379> hget stus stu1
"xiaoming"
127.0.0.1:6379> hget stus stu4
(nil)
hdel命令用于删除一个或多个指定的field
127.0.0.1:6379> hdel stus stu1 stu2
(integer) 2
hlen命令用于返回哈希结构中包含field的个数
127.0.0.1:6379> hlen stus
(integer) 1
hmset命令用于批量设置,hmget用于批量获取,注意:hset也可以同时设置多个,但是它返回值是个数,而hmset返回的是布尔值。
127.0.0.1:6379> hmset stus stu1 lili stu2 judy
OK
127.0.0.1:6379> hmget stus stu1 stu2
1) "lili"
2) "judy"
hexists命令用于判断指定field是否存在,存在返回1,不存在返回0
127.0.0.1:6379> hexists stus stu1
(integer) 1
127.0.0.1:6379> hexists stus stu4
(integer) 0
hkeys命令用于返回所有的field,hvals用于返回所有的value
127.0.0.1:6379> hkeys stus
1) "stu3"
2) "stu1"
3) "stu2"
127.0.0.1:6379> hvals stus
1) "xiaohua"
2) "lili"
3) "judy"
hgetall命令用于返回所有的field-value
127.0.0.1:6379> hgetall stus
1) "stu3"
2) "xiaohua"
3) "stu1"
4) "lili"
5) "stu2"
6) "judy"
hstrlen命令用于返回value的长度
127.0.0.1:6379> hstrlen stus stu1
(integer) 4
2.2 使用场景
哈希结构比较适宜存放对象类型的数据,比如我们的Student学生对象,它里面有姓名,年龄,班级这些信息。如果使用字符串结构来存放对象信息的话,需要使用较多的key,而哈希结构只需要一个key,也方便集中管理。
三、列表(List)
Redis里的列表和我们java里的ArrayList差不多,可以存储多个字符串元素,元素有序,可以通过下标癞获取元素,并且元素还可以重复。
3.1 常用命令
rpush命令用于从列表右侧插入元素
127.0.0.1:6379> rpush strList aa bb cc dd
(integer) 4
lrange命令用于从左到右列出指定范围内的元素,下标从0开始,如果是列出所有元素,可以指定为0 -1.
127.0.0.1:6379> lrange strList 0 3
1) "aa"
2) "bb"
3) "cc"
4) "dd"
127.0.0.1:6379> lrange strList 0 -1
1) "aa"
2) "bb"
3) "cc"
4) "dd"
127.0.0.1:6379> lrange strList 0 4
1) "aa"
2) "bb"
3) "cc"
4) "dd"
lpush命令用于从列表左侧插入元素
127.0.0.1:6379> lpush strList d c b a
(integer) 8
127.0.0.1:6379> lrange strList 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "aa"
6) "bb"
7) "cc"
8) "dd"
linsert命令用于在指定元素前后插入元素
127.0.0.1:6379> linsert strList BEFORE "aa" "aaa"
(integer) 9
127.0.0.1:6379> linsert strList AFTER "aa" "aaa"
(integer) 10
127.0.0.1:6379> lrange strList 0 -11) "a"2) "b"3) "c"4) "d"5) "aaa"6) "aa"7) "aaa"8) "bb"9) "cc"
10) "dd"
如果匹配元素在列表的存在多个,只在匹配的第一个元素那里插入
127.0.0.1:6379> linsert strList BEFORE "aaa" "hello"
(integer) 11
127.0.0.1:6379> lrange strList 0 -11) "a"2) "b"3) "c"4) "d"5) "hello"6) "aaa"7) "aa"8) "aaa"9) "bb"
10) "cc"
11) "dd"
lpop命令用于从列表左侧弹出元素,rpop命令用于从列表右侧弹出元素,可以指定弹出元素的个数,注意,这个操作会删除元素。
127.0.0.1:6379> lpop strList 1
1) "a"
127.0.0.1:6379> lpop strList 2
1) "b"
2) "c"
127.0.0.1:6379> rpop strList 1
1) "dd"
127.0.0.1:6379> lrange strList 0 -1
1) "d"
2) "hello"
3) "aaa"
4) "aa"
5) "aaa"
6) "bb"
7) "cc"
lrem命令用于删除指定的元素,可以指定删除的数量count,分三种情况:
- count>0:从左往右删除count个指定元素;
- count<0:从右往左删除count绝对值个指定元素;
- count=0:将指定元素全部删除
127.0.0.1:6379> rpush remList "aa" "aa" "aa" "bb" "aa" "aa" "aa"
(integer) 7
127.0.0.1:6379> lrange remList 0 -1
1) "aa"
2) "aa"
3) "aa"
4) "bb"
5) "aa"
6) "aa"
7) "aa"
127.0.0.1:6379> lrem remList 1 "aa"
(integer) 1
127.0.0.1:6379> lrange remList 0 -1
1) "aa"
2) "aa"
3) "bb"
4) "aa"
5) "aa"
6) "aa"
127.0.0.1:6379> lrem remList -1 "aa"
(integer) 1
127.0.0.1:6379> lrange remList 0 -1
1) "aa"
2) "aa"
3) "bb"
4) "aa"
5) "aa"
127.0.0.1:6379> lrem remList 0 "aa"
(integer) 4
127.0.0.1:6379> lrange remList 0 -1
1) "bb"
ltrim命令用于截取修剪列表,保留指定范围内的元素,如果指定范围为0 -1,表示不修剪
127.0.0.1:6379> ltrim strList 0 -1
OK
127.0.0.1:6379> lrange strList 0 -1
1) "d"
2) "hello"
3) "aaa"
4) "aa"
5) "aaa"
6) "bb"
7) "cc"
127.0.0.1:6379> ltrim strList 0 3
OK
127.0.0.1:6379> lrange strList 0 -1
1) "d"
2) "hello"
3) "aaa"
4) "aa"
lset命令用于修改下标的元素,lindex命令用于指定下标的元素
127.0.0.1:6379> lset strList 0 "ddd"
OK
127.0.0.1:6379> lindex strList 0
"ddd"
llen命令用于获取列表的长度
127.0.0.1:6379> llen strList
(integer) 4
blpop和brpop两个命令是lpop和rpop的阻塞式版本,当列表中没有元素时,会进入阻塞状态,可以同时支持多个列表,也可以设置阻塞时间,单位为秒,如果为0表示会一直阻塞,直到有元素进入列表为止。

这个时候我们可以新开一个客户端去插入元素
127.0.0.1:6379> rpush strList "hello"
(integer) 1
插入完毕,我们回到被阻塞的那个客户端

3.2 使用场景
可以用来作为消息队列来使用,客户端使用rpush等命令发送消息,多个客户端可以使用blpop命令阻塞式等消费消息。
四、集合(Set)
集合也是用来保存多个字符串元素的,但是和列表不同的是,集合内的元素是不能重复的,并且无序,无法通过下标来获取元素。
4.1 常用命令
sadd命令用于添加元素
#实际只加进去四个
127.0.0.1:6379> sadd mySet a a b b c c d d
(integer) 4
srem命令用于删除元素,可同时指定多个
127.0.0.1:6379> srem mySet a b
(integer) 2
scard用于返回集合内元素个数
127.0.0.1:6379> scard mySet
(integer) 2
sismember命令用于判断元素是否在集合内,是返回1,不是返回0
127.0.0.1:6379> sismember mySet c
(integer) 1
127.0.0.1:6379> sismember mySet a
(integer) 0
srandmember命令用于随机返回集合内元素,默认返回1个,可返回指定个数
127.0.0.1:6379> srandmember mySet
"a"
127.0.0.1:6379> srandmember mySet 2
1) "c"
2) "d"
spop命令用于从集合内随机弹出元素,默认弹出一个,可指定弹出多个,弹出后元素即删除
127.0.0.1:6379> spop mySet
"d"
127.0.0.1:6379> spop mySet 2
1) "c"
2) "a"
smembers命令用于返回集合内所有的元素,不删除
127.0.0.1:6379> smembers mySet
1) "b"
除了对单个集合操作,Redis还提供了对多个集合之间操作的命令。
sinter命令用于对多个集合之间求交集
127.0.0.1:6379> sadd set1 a b c d
(integer) 4
127.0.0.1:6379> sadd set2 e f g h
(integer) 4
127.0.0.1:6379> sinter set1 set2
(empty array)
sunion命令用于对多个集合求并集
127.0.0.1:6379> sunion set1 set2
1) "e"
2) "g"
3) "c"
4) "a"
5) "b"
6) "d"
7) "h"
8) "f"
sdiff命令用于对多个集合求差集
127.0.0.1:6379> sdiff set1 set2
1) "a"
2) "b"
3) "d"
4) "c"
Redis还提供了sinterstore、sunionstore和sdiffstore命令用于将上述的结果保存到一个新的集合内。
127.0.0.1:6379> sunionstore unionset set1 set2
(integer) 8
127.0.0.1:6379> smembers unionset
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
7) "g"
8) "h"
4.2 使用场景
比较常见的就是一些标签、分类信息,比如:买书的话会有历史、人文、科学等不同类型的书籍;买手机的话会有华为、小米、oppo不同品牌的手机。
五、有序集合(ZSET)
有序集合相较于前面的集合来说,它的元素是有序的,元素之间依据score来进行排序。
5.1 常用命令
zadd命令用于有序集合的元素添加。命令格式如下:

127.0.0.1:6379> zadd stuScore 90 xiaoming
(integer) 1
127.0.0.1:6379> zadd stuScore 81 xiaohong
(integer) 1
127.0.0.1:6379> zadd stuScore 69 xiaohua
(integer) 1
zcard命令用于返回有序集合内的成员个数
127.0.0.1:6379> zcard stuScore
(integer) 3
zscore命令用于返回某个成员的score,成员不存在则返回nil
127.0.0.1:6379> zscore stuScore xiaohua
"69"
127.0.0.1:6379> zscore stuScore xiaoli
(nil)
zrank和zrevrank命令用于指定成员的排名,前者是按照score从小到大排的,后者是按照score从大到小排的。
127.0.0.1:6379> zrank stuScore xiaoming
(integer) 2
127.0.0.1:6379> zrevrank stuScore xiaoming
(integer) 0
zrem命令用于删除指定成员,可以指定多个。
127.0.0.1:6379> zrem stuScore xiaoming xiaohong
(integer) 2
zincrby命令用于增加指定成员的分数。
127.0.0.1:6379> zincrby stuScore 20 xiaohua
"89"
zrange和zrevrange命令用于返回指定排名范围内的元素,前者从小到大,后者从大到小。

127.0.0.1:6379> zrange stuScore 0 -1
1) "xiaoli"
2) "zhangsan"
3) "xiaohua"
127.0.0.1:6379> zrevrange stuScore 0 -1
1) "xiaohua"
2) "zhangsan"
3) "xiaoli"
zrangebyscore和zrevrangebyscore命令用于返回指定分数范围内的元素,前者从小到大,后者从大到小。

#返回score介于85-90之间的元素,withscores会把它们的score也一起返回
127.0.0.1:6379> zrangebyscore stuScore 85 90 withscores
1) "zhangsan"
2) "88"
3) "xiaohua"
4) "89"
#-inf表示无限小,+inf表示无限大
127.0.0.1:6379> zrangebyscore stuScore -inf +inf withscores
1) "xiaoli"
2) "78"
3) "zhangsan"
4) "88"
5) "xiaohua"
6) "89"
zcount命令用于返回指定分数范围内的元素个数。
127.0.0.1:6379> zcount stuScore 80 90
(integer) 2
5.2 使用场景
常见的使用场景就是排行榜,比如我们个人博客的文章的阅读量排名,音乐榜单聆听人数前十的歌曲等等。
