前言
Redis安装使用入门,包含基本知识和命令行客户端使用。
什么是Redis
Redis是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库。Redis的全称是REmote DIctionary Server
。
Redis 提供数据结构,例如字符串、哈希、列表、集合、带有范围查询的排序集、位图、HyperLogLog、地理空间索引和流。 Redis 具有内置复制、Lua 脚本、LRU 逐出、事务和不同级别的磁盘持久性,并通过 Redis Sentinel 和 Redis 集群的自动分区提供高可用性。
另外,膜拜一下作者大佬的博客,风格太简约了😄。
Redis快速安装
Docker安装:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38# author: SilenceZheng66 2023.8.11
# 拉取镜像
docker search redis
docker pull redis
# 创建配置文件目录
mkdir myredis
mkdir myredis/config
# 创建持久化目录
mkdir myredis/data
# 配置文件下载
wget -O myredis/config/redis.conf http://download.redis.io/redis-stable/redis.conf
# 启动一个名为"myredis"的Redis容器,并根据指定的配置文件和参数进行配置
docker run --restart=always --log-opt max-size=50m --log-opt max-file=1 -p 6379:6379 --name myredis -v /path/to/myredis/redis.conf:/etc/redis/redis.conf -v /path/to/myredis/data:/data -d redis redis-server /etc/redis/redis.conf
# 以下是各个参数的解释:
# `--restart=always`: 设置容器在退出时总是自动重启。
# `--log-opt max-size=100m`: 设置容器日志文件的最大大小为100MB。当日志文件达到该大小时,将进行轮转。
# `--log-opt max-file=2`: 设置容器日志文件的最大数量为2个。当日志文件数量超过该值时,最旧的日志文件将被删除。
# `-p 6379:6379`: 将宿主机的6379端口映射到容器的6379端口,允许从宿主机访问Redis服务。
# `--name myredis`: 为容器指定一个名称,即"myredis"。
# `-v /path/to/myredis/redis.conf:/etc/redis/redis.conf`: 将主机上的 `/path/to/myredis/redis.conf` 文件挂载到容器内的 `/etc/redis/redis.conf` 路径,用作Redis配置文件。
# `-v /path/to/myredis/data:/data`: 将主机上的 `/path/to/myredis/data` 目录挂载到容器内的 `/data` 路径,用作Redis数据目录。
# `-d redis`: 在后台运行一个Redis容器。
# `redis-server /etc/redis/redis.conf`: 指定要运行的Redis服务器,并指定使用 `/etc/redis/redis.conf` 作为配置文件。
# 查看容器运行日志
docker logs --since 30m myredis
# 查找所有与端口号相关的网络连接和监听端口
netstat -an | grep 6379
# 进入容器redis命令行客户端
docker exec -it myredis redis-cli
Redis基础介绍
查看Redis信息
1 | # 查看全部信息 |
数据库
Redis默认有16个数据库,这个可以在配置文件redis.conf中做出修改:
1 | databases 16 |
这16个数据库以编号0-15命名,不支持修改名字,而且各个数据库之间的数据并不具备完全的隔离性,比如我们切换到任意一个数据库,执行命令flushall
就可以清空所有数据库的数据,所以并不建议通过数据库来隔离不同的业务系统数据,但是我们可以针对同一个业务系统中的不同模块将其设置到不同的数据库中。
数据类型
Redis的基本数据类型如下图:
但还有其他一些数据类型可扩展,截至目前,官网包含如下数据类型:
以下是常用数据结构的简要介绍:
Strings(字符串):
- 存储文本、二进制数据等。
- 可用于缓存、计数器等。
Lists(列表):
- 有序、可重复的元素集合。
- 支持在列表头部和尾部添加、删除元素,以及获取子列表。
- 适用于实现消息队列、最新动态等。
Sets(集合):
- 无序、不重复的元素集合。
- 支持添加、删除、判断元素是否存在等操作。
- 适用于存储不重复的标签、好友关系等。
Sorted Sets(有序集合):
- 与集合类似,但每个元素都有一个分数(score)用于排序。
- 支持按照分数范围获取元素。
- 适用于排行榜、优先级队列等。
Hashs(哈希):
- 存储对象,每个字段存储一个属性。
- 支持单个字段的读写、删除,以及获取所有字段。
- 适用于存储用户信息、商品属性等。
Bitmaps(位图):
- 位存储结构,适合表示某些状态或事件。
- 支持位的设置、清除、查询等操作。
- 适用于用户在线状态、签到等。
HyperLogLog(基数估算):
- 用于估算集合中不重复元素的数量,占用很少的内存。
- 支持添加元素,以及计算估算的基数数量。
- 适用于统计不重复 IP 数量、UV 数量等。
Geospatials(地理位置):
- 存储地理位置信息。
- 支持添加地点、计算两个地点之间的距离等操作。
- 适用于附近商店查找、位置服务等。
这些数据结构的特点在于快速的读写操作,以及许多方便的命令和功能。
Key命名规范
在 Redis 中,Key 的命名是非常重要的,它不仅影响到数据存储的性能,还会影响到代码的可读性和维护性。以下是一些 Redis Key 命名的规范和建议:
清晰而有意义的命名:Key 应该能够清楚地表达出它所对应的数据含义,不要使用过于简单的名称,可以使用类似于命名空间的方式来分隔不同业务领域的数据。
避免特殊字符:Key 不应该包含特殊字符,特别是空格、换行符等。建议使用字母、数字、下划线、英文冒号等字符组成。
长度适中:Key 的长度应该适中,不要过长,尽量不要超过1024字节,这不仅消耗内存,而且会降低查找的效率。
小写字母:建议使用小写字母来命名 Key,这样可以避免在大小写不敏感的 Redis 配置中引起问题。
使用分隔符:在 Key 中使用分隔符,以提高可读性,比如使用冒号(:)或下划线(_)来分隔不同的层级。注意虽然可以使用分隔符方式划分 Key,但不要过度嵌套,以免增加查找和维护的复杂性。
避免重复:确保不同业务使用不同的 Key,以免冲突和混淆。
避免敏感信息:避免在 Key 中包含敏感信息,比如密码、安全令牌等。
合理的命名规范可以提高代码的可读性和维护性,同时也能更好地利用 Redis 的性能优势。根据业务需求和团队的约定,可以制定适合自己的 Key 命名规范。
下面列举一些键命名示例:1
2
3
4
5
6
7
8命名规范:user:{user_id}:name
示例:user:123:name
命名规范:post:{post_id}
示例:post:456
命名规范:online:{date}
示例:online:2023-06-01
Redis使用入门(CLI)
下面使用Redis命令行客户端进行一些操作,加深对上述知识的理解😄。
通用操作
1 | 127.0.0.1:6379> select 1 # 数据库选择 |
字符串(Strings)
在 Redis 中,字符串是最简单的数据类型,但也是最通用和常用的,它不仅可以存储文本、整数、浮点数,甚至包括任何二进制数据,例如图像和序列化的对象。
这是因为在 Redis 中,字符串是二进制安全的(Binary-safe)。这意味着 Redis 的字符串值可以包含任何类型的数据,包括文本、图像、序列化的对象等,而不会对其中的二进制数据做任何处理或解释。
如果需要对存储的二进制数据进行解码,比如将其转换为特定的对象或文件格式,需要在应用程序中处理解码操作。
设/取值
1 | # 单个设置 |
SET
命令支持设置过期时间,一般分布式锁就是基于带过期时间的这个命令来实现的。
1 | set key value EX|PX 18 # EX表示秒,PX表示毫秒 |
增减
字符串类型包含整数和浮点数。
1 | 127.0.0.1:6379> SET counter 10 |
对于浮点运算,不存在DECRBYFLOAT
,而是通过INCRBYFLOAT
负值来进行减少。
最重要的是,INCR
等指令本身就具有原子操作的特性,所以我们完全可以利用redis的INCR、INCRBY、DECR、DECRBY
等指令来实现多客户端原子计数的效果,不少网站都利用redis的这个特性来实现业务上的统计计数需求。
更多操作
在值后新增内容&获取值的子串:1
2
3
4
5
6127.0.0.1:6379> append test:1:string "Zheng66"
(integer) 14
127.0.0.1:6379> get test:1:string
"SilenceZheng66"
127.0.0.1:6379> GETRANGE test:1:string 2 10
"lenceZhen"
列表(Lists)
在 Redis 中,List 是一个有序的字符串集合,它允许存储多个字符串值,并且保持它们的插入顺序。每个值都被称为元素(element)。Redis 中的 List 是一个双向链表(double-ended list),这使得在两端进行插入和删除操作非常快速。
基础操作
下面称列表的左侧为头部,右侧为尾部。
lpush
:将一个或者多个value
插入到列表key的头部,不存在则创建列表key。lpushx
:将value
插入到列表key的头部,不存在则不做任何处理。lpop
:移除并返回列表key指定数量的头元素,默认1。rpush
、rpushx
:尾部插入,对应关系同上。rpop
:尾部推出,同上。llen
:返回列表key的长度。lindex
:获取列表key指定索引位置上的元素,头部从0开始,尾部从-1开始。lrange
:返回列表key中下标start到stop之间的元素,包含边界。lset
:将value设置到列表key中指定index位置。key不存在或者index超出范围报错。lrem
:从列表key中删除指定数量的匹配值。ltrim
:修剪原列表,只保留指定范围内的元素,包含边界。linsert
:在列表中指定元素前或后插入新元素。
1 | 127.0.0.1:6379> LPUSH mylist item1 |
更多操作
BLPOP / BRPOP
BLPOP key [key ...] timeout
: 阻塞式左弹出操作,等待并弹出第一个非空列表的元素。BRPOP key [key ...] timeout
: 阻塞式右弹出操作,等待并弹出第一个非空列表的元素。
1 | # 从多个列表中弹出元素,等待时间为10秒 |
集合(Sets)
Redis中的集合是一个String类型的无序集合,集合中元素唯一不可重复。
Sets在Redis中的常用函数有:
SADD key member [member ...]
:将一个或多个成员添加到集合key中。SCARD key
:返回集合key的基数(集合中元素的数量)。SISMEMBER key member
:判断member元素是否是集合key的成员。SREM key member [member ...]
:移除集合key中的一个或多个member元素。SMEMBERS key
:返回集合key中的所有成员。SPOP key [count]
:移除并返回集合key中的count个随机元素。SRANDMEMBER key [count]
:从集合key中随机获取count个元素。SDIFF key [key ...]
:返回所有给定集合之间的差集。SINTER key [key ...]
:返回所有给定集合的交集。SUNION key [key ...]
:返回所有给定集合的并集。
1 | 127.0.0.1:6379> SADD myset value1 value2 value3 |
有序集合(Sorted sets)
在Redis中,Sorted Set(有序集合)是一种可以排序的集合数据结构,它的每个成员都有一个相关的分数(score),根据分数的排列顺序对成员进行排序。
Sorted Set主要用于处理需要排序和去重的数据。
添加操作
因为添加操作的参数较多,单独拿出来说一下。ZADD
命令用于将一个或多个成员添加到有序集合(Sorted Set)中,或者更新已存在成员的分数。
下面是ZADD
命令的各种用法示例:
- 添加单个成员到有序集合:
1 | 127.0.0.1:6379> ZADD myzset 3 "member1" |
- 添加多个成员到有序集合:
1 | 127.0.0.1:6379> ZADD myzset 2 "member2" 4 "member3" 1 "member4" |
- 使用
NX
选项,仅在成员不存在时才添加:
1 | 127.0.0.1:6379> ZADD myzset NX 3 "member1" |
- 使用
XX
选项,仅在成员已存在时才更新分数:
1 | 127.0.0.1:6379> ZADD myzset XX 5 "member1" |
- 使用
CH
选项,返回更新或添加的成员数量,包括分数未变动的成员:
1 | 127.0.0.1:6379> ZADD myzset CH 5 "member1" 2 "member2" |
- 使用
INCR
选项,将分数作为增量进行更新:
1 | 127.0.0.1:6379> ZADD myzset INCR 2 "member1" |
- 结合
NX
、CH
和INCR
选项的多功能用法:
1 | 127.0.0.1:6379> ZADD myzset NX CH INCR 3 "member1" |
基础操作
Sorted Sets在Redis中的常用函数有:
ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
:将一个或多个成员添加到有序集合key中,或者更新已存在成员的分数。ZCARD key
:返回有序集合key的基数(有序集合中元素的数量)。ZSCORE key member
:返回成员member的分数。ZCOUNT key min max
:返回有序集合key中分数介于min和max之间的成员数量。ZINCRBY key increment member
:将成员member的分数增加increment。ZRANGE key start stop [WITHSCORES]
:返回有序集合key中索引从start到stop之间的成员。ZREVRANGE key start stop [WITHSCORES]
:返回有序集合key中索引从start到stop之间的成员,按分数从大到小排列。ZRANK key member
:返回成员member在有序集合key中的排名,从0开始计数。ZREVRANK key member
:返回成员member在有序集合key中的排名,从高到低排列。ZREM key member [member ...]
:移除有序集合key中的一个或多个成员。ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
:返回有序集合key中分数介于min和max之间的成员。ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
:返回有序集合key中分数介于max和min之间的成员,按分数从大到小排列。
1 | 127.0.0.1:6379> ZADD mysset 1 member1 2 member2 |
哈希表(Hashs)
在Redis中,Hashs是一种用于存储字段和值的数据结构,每个字段都与一个值相关联,类似于Python中的字典。
Hashs主要用于存储对象,以及需要多个字段来表示的数据。
Redis中Hashs的常用函数有:
HSET key field value
:将哈希表key中的字段field的值设置为value。HSETNX key field value
:将哈希表key中的字段field的值设置为value,如果field已存在,则不执行任何操作。HGET key field
:返回哈希表key中给定字段field的值。HMSET key field1 value1 [field2 value2 ...]
:同时将多个field-value对设置到哈希表key中。HMGET key field1 [field2 ...]
:返回哈希表key中给定字段的值。HDEL key field1 [field2 ...]
:删除哈希表key中的一个或多个指定字段。HGETALL key
:返回哈希表key中所有字段和值。HKEYS key
:返回哈希表key中的所有字段。HVALS key
:返回哈希表key中的所有值。HLEN key
:返回哈希表key中字段的数量。HEXISTS key field
:查看哈希表key中是否存在指定字段。HINCRBY key field increment
:为哈希表key中的字段field的值增加increment。HINCRBYFLOAT key field increment
:为哈希表key中的字段field的值增加浮点数increment。
1 | 127.0.0.1:6379> HSET myhash field1 value1 |
位图(Bitmaps)
在Redis中,Bitmaps是一种特殊的数据结构,它可以表示一系列位的集合,每个位的值要么是0,要么是1。
比如存储数据格式一般为:100110000111,这里的0和1就是bit值,设置的时候可以设置指定位置(偏移量)的bit值。
Bitmaps通常用于存储布尔值的信息,如用户的在线状态、用户活跃情况等。
Redis中Bitmaps的常用函数有:
SETBIT key offset value
:将key对应的Bitmap中的offset位设置为value(0或1)。GETBIT key offset
:返回key对应的Bitmap中offset位的值。BITCOUNT key [start end]
:统计key对应的Bitmap中[start, end]范围内值为1的位的数量。BITOP operation destkey key [key ...]
:对多个Bitmap执行位运算,并将结果保存到destkey中,operation可以是AND、OR、XOR、NOT。BITPOS key bit [start] [end]
:返回key对应的Bitmap中值为bit的第一个位的位置,[start, end]范围内。BITFIELD key [GET type offset] [SET type offset value]
:执行多种位域操作,可以进行位取反、位截取、位增加等操作。
1 | 127.0.0.1:6379> SETBIT online_users 1000 1 |
基数估算(HyperLogLog)
HyperLogLog本身是一种算法,其来源于论文《HyperLogLog the analysis of a near-optimal cardinality estimation algorithm》。
在Redis中,HyperLogLog是一种用于统计基数(集合中不重复元素的数量)的数据结构,它通过使用固定的空间来估计集合的基数,占用的空间相对较小。
HyperLogLog主要用于对大型数据集合的去重统计,适用于对数据的近似计数,而不需要实际存储所有元素。
在Redis里面,每个HyperLogLog键只需要花费12KB内存,就可以计算接近2^64 个不同元素的基数,但是也可能有0.81%的错误率。
HyperLogLog在Redis中的常用函数有:
PFADD key element [element ...]
:将一个或多个元素添加到指定的HyperLogLog中。PFCOUNT key [key ...]
:返回指定HyperLogLog的基数估算值。PFMERGE destkey sourcekey [sourcekey ...]
:合并多个HyperLogLog为一个HyperLogLog。
1 | 127.0.0.1:6379> PFADD myhll element1 element2 element3 |
地理空间(Geospatials)
在Redis中,Geospatials数据结构用于存储地理位置信息(经纬度)和相关的数据,然后可以通过位置信息进行距离计算和范围查询。
Redis提供了一种叫做Geohash的算法来将地理位置映射到字符串,从而可以在Redis中高效地进行位置查询和计算。
Geospatial数据在Redis中的常用函数有:
GEOADD key longitude latitude member [longitude latitude member ...]
:将一个或多个地理位置成员添加到指定的key中。GEODIST key member1 member2 [unit]
:返回两个地理位置成员之间的距离。GEOHASH key member [member ...]
:返回指定地理位置成员的Geohash字符串。GEOPOS key member [member ...]
:返回指定地理位置成员的经纬度坐标。GEORADIUS key longitude latitude radius unit [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]
:在指定的经纬度范围内查找地理位置成员。GEORADIUSBYMEMBER key member radius unit [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]
:在指定地理位置成员附近查找其他地理位置成员。GEODEL key member [member ...]
:从指定key中删除一个或多个地理位置成员。
以下是一些配合cli示例:
1 | 127.0.0.1:6379> GEOADD mygeo 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" |
Redis的使用场景
Redis是基于内存操作,具备高可用、高性能等特点,同时也提供了丰富的数据类型。一般可用于如下场景:
1、数据缓存。项目早期一般都是将数据存储到MySQL、oracle
等关系型数据库中,所有的数据读写都是基于磁盘操作。随着业务的不断扩大,通过传统的方式进行数据的读取,系统在读写方面都会遇到瓶颈。针对这一情况,将数据存放在内存中,所有的读操作都通过内存进行查询,提高了系统的数据查询能力。对于数据的读,在高并发的业务场景下,也可以将数据先写入内存中,在通过异步的方式持久化到磁盘中,提高了系统的并发能力。
2、存储用户登录token
。针对用户登录鉴权,一般可以基于cookie
、jwt来实现。cookie
是基于文件存储,并且cookie
会涉及到跨域、分布式架构问题,jwt由于是基于客户端断存储方案,服务端无法直接控制登录token
的状态。由于Redis是具备分布式部署架构,很好的解决了分布式架构token
鉴权、用户登录状态等问题的控制。同时将登录token
存放在Redis中,每次读取都采用内存读取,也提高了整个系统的性能。
3、秒杀场景。对于秒杀业务场景,对于系统的并发能力都是非常高的。在该场景下,将商品数据存储到Redis中,提高了系统的查询能力,减少了MySQL的压力。将商品库存都存储到Redis中,因Redis采用的是单线程架构,也可以实现商品超卖问题。
4、用户签到。可以使用 bitmap
数据类型,将用户签到存储在Redis中,然后通过异步线程将数据存储到MySQL中。既节约了内存,也提供了系统的读写能力。
5、消息队列。Redis提供 list
数据类型,技能用来做消息队列,也能用来做栈等场景。在 Redis5.0 开始,也提供了一种 stream
数据类型,提高了消息队列的可靠性。
6、社交场景。Redis提供了两种集合数据类型(set sortset),可以用在积分排行、好友推荐等场景。
7、就近推荐。Redis中提供了一种 Geospatials
的数据类型来进行位运算。可以根据用户当前的经纬度,来计算附近的酒店、商场等场所的搜索与推荐功能。
8、分布式锁。当分布式架构中,需要对共享数据的读写操作(例如商品秒杀)。为了保证数据的一致性,一般是采用分布式锁实现,Redis能够非常简单的实现分布式锁功能。可以直接使用 setnx key value + expire time
操作,为了实现原子性操作,也可以直接使用 lua
实现。
参考
[1] https://zhuanlan.zhihu.com/p/411888708
[2] https://redis.io/docs/getting-started/
[3] https://zhuanlan.zhihu.com/p/609596571
[4] https://zhuanlan.zhihu.com/p/270168739
后记
首发于 silencezheng.top,转载请注明出处。