Redis学习笔记(个人向)
1. 概述
- 是一个高性能的 key-value 数据库;
- 其具有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储(丰富的存储数据结构)。
- Redis支持数据备份,即master-slave模式的数据备份。
- Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过
MULTI
和EXEC
指令包起来; - Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。当然,这样Redis可以做很多内部复杂性很强的事情,因为相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单(
计组内容+数据结构
); - 由于在磁盘格式方面是紧凑地以追加的方式产生的,因为Redis并不需要进行随机访问;
2. 安装和配置
- 详细看Redis 下载安装和Redis 配置即可;
3. 数据类型
- Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(
sorted set:有序集合
);
3.1 String
- 是redis最基本的类型,是一个类似于键值对的结构,一个
key
对应一个value
; - string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象;
- string类型的值最大能存储 512MB;
关于各数据类型的常用命令放在另外的文档中,此处略。
3.2 Hash
- 是一个键值(
key=>value
)对集合,即哈希表; - Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象;
- 每个
hash
表可以存储 2 32 − 1 2^{32} -1 232−1 键值对(40多亿); - 对于Hash的初值设置,我们可以使用
HGET
和HMSET
命令,其中前者获取
对应field
对应的value
,后者设置了field=>value
对的值;//赋值 HMSET Hashname fieldname1 value1 fieldname2 value2,…… //获取键名为fieldname(k)的值 HGET Hashname fieldname(k)
3.3 List
- 是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边),也就是只能头插或者尾插;
- 每个列表最多可存储 2 32 − 1 2^{32} - 1 232−1元素 (4294967295, 每个列表可存储40多亿);
3.5 Set
- 是
string
类型的无序集合; - 通过哈希表实现,添加,删除,查找的复杂度都是 O(1);
- 当然,由于集合的元素唯一性,重复插入元素会被忽略,并返回0;
- 下面引入
sadd
命令:sadd setname value1,value2,··· //成功返回1,失败返回0
3.6 Zset
zset
和set
一样也是string类型元素的集合,且不允许重复的成员;- 不同的是每个元素都会关联一个double类型的分数(
score
)。redis通过分数来为集合中的成员进行从小到大的排; - zset的成员是唯一的,但分数(score)可以重复,但分数也重复时,按照元素值的字典顺序进行二次排序,字典顺序就是字符串的自然顺序;
- 在这里引入
zadd
命令,格式为:zadd keyname score1 membername1 score2 membername2 ··· //keyname就是zset的名字
4. 命令
- 用于在 redis 服务上执行操作;
- 要在 redis 服务上执行命令需要一个 redis 客户端。Redis 客户端在我们之前下载的的 redis 的安装包中;
- 常见的命令形式见于另一处文档,此处只叙述如何启动服务器:
//基本语法,用于启动客户端 $ redis-cli //接下来我们检查服务器是否在运行,当输出是PONG时正常。 PING//在远程的redis上执行命令,同样使用redis-cli redis-cli -h <主机地址> -p <端口码数> -a <账户密码>
5. 键/Key
- 用于管理和使用key;
- 基本语法格式为:
COMMAND KEY_NAME (KEY_VALUE)
;
序号 | 命令 | 描述 |
---|---|---|
1 | DEL key | 该命令用于在 key 存在时删除 key。 |
2 | DUMP KEY | 序列化给定 key,并返回序列化的值。 |
3 | EXISTS key | 检查给定 key 是否存在。 |
4 | EXPIRE key seconds | 为给定 key 设置过期时间,以秒计。 |
5 | EXPIREAT key timestamp | EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置过期时间。不同在于 EXPIREAT 命令接受的时间戳是 UNIX 时间(unix timestamp)。 |
6 | PEXPIRE key milliseconds | 设置 key 的过期时间以毫秒计。 |
7 | PEXPIREAT key milliseconds-timestamp | 设置 key 过期时间的时间戳(以 UNIX 时间戳,unix timestamp 格式)以毫秒计。 |
8 | KEYS pattern | 查找符合给定模式(pattern)的 key。 |
9 | MOVE key db | 将当前数据库的 key 移动到指定的数据库 db 当中。 |
10 | PERSIST key | 移除 key 的过期时间,key 将持久保持。 |
11 | PTTL key | 以毫秒为单位返回 key 的剩余过期时间。 |
12 | TTL key | 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。 |
13 | RANDOMKEY | 从当前数据库中随机返回一个 key。 |
14 | RENAME key newkey | 重命名 key 为 newkey。 |
15 | RENAMENX key newkey | 仅当 newkey 不存在时,将 key 改名为 newkey。 |
16 | SCAN cursor [MATCH pattern] [COUNT count] | 迭代当前数据库中的 key 集。 |
17 | TYPE key | 返回 key 所存储的值的类型。 |
6. String
- 主要命令参见 Redis 字符串(String);
- 或者我们可以阅读 官方档案;
7. Hash表
- 主要命令参见Redis 哈希(Hash);
8. List
参见Redis 列表(List);
9. Set
参见Redis 集合(Set);
10. Zset
参见Redis 有序集合;
11. HyperLogLog*
- 这是在2.8.9版本中新增加的结构,用来做基数统计的算法(
即一个数据集中的唯一元素的个数是多少
); - 特点是:
- 在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的;
- 只会根据输入元素来计算基数,而不会储存输入元素本身,所以无法存储并返回具体的各个元素信息;
- HyperLogLog 基于概率算法,它提供的是近似的基数估算,但误差非常小(标准误差约为 0.81%);
- HyperLogLog 允许将多个集合的基数估算合并为一个估算值,这使得它非常适合分布式基数估算;
常见的命令形式:
-
PFADD - 向 HyperLogLog 集合添加元素:
- 命令格式:PFADD key element [element …]
- 功能:将一个或多个元素添加到指定的 HyperLogLog 键中。如果元素已经存在,则不会重复添加。
- 返回值:返回 1 如果至少有一个元素被添加,否则返回 0。
-
PFCOUNT - 计算 HyperLogLog 集合的基数:
- 命令格式:PFCOUNT key [key …]
- 功能:返回给定 HyperLogLog 键的基数估算值。如果有多个键,返回这些键的并集的基数估算值。
- 返回值:返回估算的基数。
-
PFMERGE - 合并多个 HyperLogLog 集合:
- 命令格式:PFMERGE destkey sourcekey [sourcekey …]
- 功能:将一个或多个 HyperLogLog 键合并到一个目标 HyperLogLog 键中。合并后的 HyperLogLog 键将包含所有输入键的元素。
- 返回值:总是返回 OK。
12. 发布订阅模式
- 是一种消息通信模式,其中消息的发送者(发布者)不会将消息直接发送给特定的接收者(订阅者),而是将消息发布到一个频道(Channel),订阅了该频道的客户端都能接收到发布的消息。;
- 非常适合实现消息队列、实时通知、聊天室等功能;
- 以下是 Redis 发布订阅的一些关键概念和命令:
-
频道(Channel):是发布订阅中消息发布的目的地,订阅者订阅频道以接收消息。
-
模式(Pattern):在发布订阅中,可以使用模式匹配来订阅一组频道,这使得消息的过滤和分发更加灵活。
-
发布者(Publisher):向频道发送消息的客户端。
-
订阅者(Subscriber):订阅一个或多个频道,接收频道上的消息。
-
消息(Message):在频道上发送的数据,可以是任何字符串。
-
- 发布订阅的特点:
- 消息的无持久性:发布订阅的消息不是持久化的,一旦订阅者断开连接,将无法收到之前的消息。
- 实时性:发布订阅支持实时消息传递,适合需要快速响应的应用场景。
- 广播:发布的消息会被发送给所有订阅该频道的订阅者。
- 模式匹配:通过模式订阅,可以实现更灵活的消息分发机制。
- 发布订阅的命令:
PUBLISH <channel> <message>
: 将消息发送到指定的频道,返回值是接收到消息的订阅者数量;SUBSCRIBE <channel_1> [<channel_2> ...]
:订阅一个或多个频道,接收这些频道上的消息。当服务器进入订阅模式后,开始接收被订阅频道的消息;UNSUBSCRIBE [<channel_1> [<channel_2> ...]]
:退出订阅模式,或取消订阅一个或多个频道,不再接受来自频道的信息;PSUBSCRIBE pattern_1 [pattern_2 ...]
:订阅与模式匹配的频道,接受匹配模式的频道信息(类似于接收广播信号
);PUNSUBSCRIBE [pattern [pattern ...]]
:取消模式订阅,或退出模式订阅模式;PUBSUB <subcommand> [argument [argument ...]]
:用于查看订阅与发布系统状态,它由数个不同格式的子命令组成,将返回由活跃频道组成的列表;
- 总结
发布订阅模式在需要实现一对多或多对多通信的场景中非常有用,例如社交网络的通知系统、实时数据推送服务等。然而,由于消息的无持久性,它不适合需要保证消息可靠性传递的场景。
13. 事务
-
是一个用于将多个命令打包在一起执行的功能,它可以确保这些命令要么全部执行,要么全部不执行,从而保持操作的原子性(
单个 Redis 事务内命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务间的执行并不是原子性的
); -
Redis事务并不提供传统数据库事务的所有特性,如回滚到事务开始前的状态;
-
事务具有以下三个特点:
- 批量操作在发送 EXEC 命令前被放入队列缓存;
- 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行(
因为是队列的结构
); - 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中(
类原子性,且插入到末尾不会影响开头的输出
);
-
事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做;
-
由上面可知,一个事务会经历以下三个阶段:
- 开始事务;
- 事务中的命令入队;
- 执行事务;
//一个典型的例子 redis 127.0.0.1:6379> MULTI OKredis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days" QUEUEDredis 127.0.0.1:6379> GET book-name QUEUEDredis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series" QUEUEDredis 127.0.0.1:6379> SMEMBERS tag QUEUEDredis 127.0.0.1:6379> EXEC 4) OK 5) "Mastering C++ in 21 days" 6) (integer) 3 7) 1) "Mastering Series"1) "C++"2) "Programming"
-
根据事务的发展阶段,有以下的命令形式:
- 事务开始于 MULTI 命令,这个命令会告诉 Redis 接下来的操作应该被视为一个事务的一部分;
- 在
MULTI
命令之后,你可以发送任意数量的命令,这些命令将不会被立即执行,而是放入一个队列中等待。当命令在队列中,redis也会在执行前进行语法检查,如果有语法错误,EXEC 将返回失败; - 使用 EXEC 命令执行事务。
EXEC
命令会触发之前用MULTI
开始的事务,并执行所有入队的命令。如果事务过程中发生错误,Redis 会返回null
作为事务的结果,并且EXEC
命令将返回空数组; - 如果你不想执行事务队列中的命令,可以使用 DISCARD 命令来取消事务。
- Redis 提供了 WATCH [key1][key2,···]命令来监控一个或多个键,当然也可以用
UNWATCH
取消,如果在执行 EXEC 之前这些键被其他客户端改变,则事务将不会执行;
-
事务的用例
- 【计数器】:用于实现原子递增或递减操作。
- 【用户会话】:同时更新多个字段。
- 【缓存更新】:在更新数据库的同时更新缓存;
14. 脚本
-
Redis使用
Lua
解释器来执行脚本,从2.6版本开始内嵌支持; -
执行脚本的常用命令是:
EVAL
; -
常用脚本命令如下:
序号 命令及描述 1 EVAL script numkeys key[key ...] arg[arg...]
执行 Lua 脚本。2 (未提供描述,可能是遗漏) 3 EVALSHA sha1 numkeys key[key ...] arg[arg...]
执行 Lua 脚本。4 SCRIPT EXISTS script[script ...]
查看指定的脚本是否已经被保存在缓存当中。5 SCRIPT FLUSH
从脚本缓存中移除所有脚本。6 SCRIPT KILL
杀死当前正在运行的 Lua 脚本。7 SCRIPT LOAD script
将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。
15. 连接
-
连接命令主要是用于连接 redis 服务;
-
以下为常用的连接命令:
序号 命令及描述 1 AUTH password
验证密码是否正确2 ECHO message
打印字符串3 PING
查看服务是否运行4 QUIT
关闭当前连接5 SELECT index
切换到指定的数据库
16. 服务器
- 服务器命令主要是用于管理 redis 服务;
- 常见的服务器命令如下:
序号 | 命令及描述 |
---|---|
1 | BGREWRITEAOF 异步执行一个 AOF(Append Only File)文件重写操作 |
2 | BGSAVE 在后台异步保存当前数据库的数据到磁盘 |
3 | CLIENT KILL [ip:port] [ID client-id] 关闭客户端连接 |
4 | CLIENT LIST 获取连接到服务器的客户端连接列表 |
5 | CLIENT GETNAME 获取连接的名称 |
6 | CLIENT PAUSE timeout 在指定时间内暂停运行来自客户端的命令 |
7 | CLIENT SETNAME connection-name 设置当前连接的名称 |
8 | CLUSTER SLOTS 获取集群节点的映射插槽 |
9 | COMMAND 获取Redis命令详情数组 |
10 | COMMAND COUNT 获取Redis命令总数 |
11 | COMMAND GETKEYS 获取给定命令的所有键 |
12 | TIME 返回当前服务器时间 |
13 | COMMAND INFO command-name [command-name ...] 获取指定Redis命令描述的数组 |
14 | CONFIG GET parameter 获取指定配置参数的值 |
15 | CONFIG REWRITE 对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写 |
16 | CONFIG SET parameter value 修改 Redis 配置参数,无需重启 |
17 | CONFIG RESETSTAT 重置 INFO 命令中的某些统计数据 |
18 | DBSIZE 返回当前数据库的 key 的数量 |
19 | DEBUG OBJECT key 获取 key 的调试信息 |
20 | DEBUG SEGFAULT 让 Redis 服务崩溃 |
21 | FLUSHALL 删除所有数据库的所有 key |
22 | FLUSHDB 删除当前数据库的所有 key |
23 | INFO [section] 获取 Redis 服务器的各种信息和统计数值 |
24 | LASTSAVE 返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间格式表示 |
25 | MONITOR 实时打印出 Redis 服务器接收到的命令,调试用 |
26 | ROLE 返回主从实例所属的角色 |
27 | SAVE 同步保存数据到硬盘 |
28 | SHUTDOWN [NOSAVE].[SAVE] 异步保存数据到硬盘,并关闭服务器 |
29 | SLAVEOF host_port 将当前服务器转变为指定服务器的从属服务器(slave server) |
30 | SLOWLOG subcommand [argument] 管理 Redis 的慢日志 |
31 | SYNC 用于复制功能(replication)的内部命令 |
17. GEO
-
主要用于存储地理位置信息,并对存储的信息进行操作;
-
首先是
geoadd
命令,用于添加地理位置的坐标。语法格式如下:GEOADD key longitude latitude member [longitude latitude member ...]
//一个实例: redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"(integer) 2
-
然后是
geopos
方法,用于从给定的 key 里返回所有指定名称(member)
的位置(经度和纬度),不存在的返回nil
。其语法格式为:GEOPOS key member [member ...]
-
之后是
geolist
方法,用于返回两个给定位置之间的距离。可以在最后指定距离单位,如:m/米、km/千米、mi/英里、ft/英尺,其具体语法格式为:GEODIST key member1 member2 [m|km|ft|mi]
-
georadius
和georadiusbymember
都能找出与中心的距离不超过给定最大距离的元素,前者是给定经纬度为中心;后者是选择给定的键值元素位置为中心。两者的具体语法格式是:GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key] GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key] //参数说明: m :米,默认单位。 km :千米。 mi :英里。 ft :英尺。 WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 WITHCOORD: 将位置元素的经度和维度也一并返回。 WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。 COUNT 限定返回的记录数。 ASC: 查找结果根据距离从近到远排序。 DESC: 查找结果根据从远到近排序。
//一个实例: redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"(integer) 2redis> GEORADIUS Sicily 15 37 200 km WITHDIST1) 1) "Palermo"2) "190.4424"2) 1) "Catania"2) "56.4413"redis> GEORADIUS Sicily 15 37 200 km WITHCOORD1) 1) "Palermo"2) 1) "13.36138933897018433"2) "38.11555639549629859"2) 1) "Catania"2) 1) "15.08726745843887329"2) "37.50266842333162032"redis> GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD1) 1) "Palermo"2) "190.4424"3) 1) "13.36138933897018433"2) "38.11555639549629859"2) 1) "Catania"2) "56.4413"3) 1) "15.08726745843887329"2) "37.50266842333162032"redis>
-
最后是
geohash
。它用于保存地理位置的坐标,可以一次获取一个乃至多个位置元素的值。其具体语法格式如下:GEOHASH key member [member ...]
18. Stream
-
是 Redis 5.0 版本新增加的数据结构;
-
主要用于消息队列(MQ,Message Queue),它是针对发布订阅(pub/sub)消息无法持久化(
网络断开、Redis宕机等会导致消息被丢弃
)的缺点,开发出的能提供高性能的、持久化的、有序的消息传递的机制。它可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失; -
Redis Stream的结构主体是一个消息链表,将所有加入的消息痘串起来,每个消息都有一个唯一的 ID 和对应的内容。
-
以下是Streams的主要特性:
- 消息流(Stream)
- Redis Stream 是一个有序的、持久化的消息流。;
- 消息以时间顺序追加到流中,并且每个消息都有一个唯一的ID;
- 消息可以按照发布者-订阅者模式进行分发;
- 消息
- 消息由一个包含键值对的条目组成;
- 消息条目(Entry) 由一个唯一的 ID 和一个字段-值对的集合组成;
- 消息流中的每个消息都有一个自增的唯一 ID,这个 ID 在消息流中是全局唯一的;
- 消费者组(Consumer Group)
- 消费者组是一组逻辑上关联的消费者(
消费者消费信息
); - 消费者组可以共同消费一个消息流中的消息,每个消息条目只会被消费者组中的一个消费者消费;
- 消费者组可以实现消息的负载均衡和高可用性;
- 消费者组是一组逻辑上关联的消费者(
- 消息流(Stream)
-
以下介绍
信息流
、信息
、信息条目
之间的关系:- 一个信息流可以包含多个信息(Message);
- 每个信息(Message)由一个或多个信息条目(Entry)组成,其中信息所谓唯一的ID是信息中最后一个信息条目的ID;
- 每个信息条目都有一个唯一的ID,用于标识和区分不同的信息条目;
-
每个 Stream 都有唯一的名称,它就是 Redis 的 key,我们可以向其中添加新的信息条目,并从中读取和处理信息。它由我们在首次使用
xadd
命令追加消息的时候自动创建; -
-
消息队列相关命令:
XADD
- 添加消息到尾部XTRIM
- 对流进行修剪,限制长度XDEL
- 删除消息XLEN
- 获取流包含的元素数量,即消息长度XRANGE
- 获取消息列表,会自动过滤已经删除的消息XREVRANGE
- 反向获取消息列表,ID 从大到小XREAD
- 以阻塞或非阻塞方式获取消息列表;
-
消费者组相关命令:
XGROUP CREATE
- 创建消费者组XREADGROUP GROUP
- 读取消费者组中的消息XACK
- 将消息标记为“已处理”XGROUP SETID
- 为消费者组设置新的最后递送消息IDXGROUP DELCONSUMER
- 删除消费者XGROUP DESTROY
- 删除消费者组XPENDING
- 显示待处理消息的相关信息XCLAIM
- 转移消息的归属权XINFO
- 查看流和消费者组的相关信息XINFO GROUPS
- 打印消费者组的信息XINFO STREAM
- 打印流信息
-
-
以下具体语法介绍,详见于Redis Stream方法一文;
-
一个实例:
//使用XADD创建消息队列,这里“*”的意思是生成唯一的ID
redis> XADD mystream * name Sara surname OConnor"1601372323627-0"redis> XADD mystream * field1 value1 field2 value2 field3 value3"1601372323627-1"redis> XLEN mystream(integer) 2//XRANGE中的“-”和“+”代表从最早的消息开始,和从最新的消息开始。连着写代表获取全部的信息。
//当然你也可以指定从新到旧读取的信息数,即使用COUNT <数字>;
//又或者使用消息的ID指定范围。
redis> XRANGE mystream - +1) 1) "1601372323627-0"2) 1) "name"2) "Sara"3) "surname"4) "OConnor"2) 1) "1601372323627-1"2) 1) "field1"2) "value1"3) "field2"4) "value2"5) "field3"6) "value3"redis>
19. 数据备份和数据恢复
- Redis 的
SAVE
命令用于创建当前数据库的备份,该命令将在 redis 安装目录中创建dump.rdb
文件; - 如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可;
- 获取 redis 目录可以使用
CONFIG
命令,查找redis的安装位置可以使用CONFIG GET dir
; - 除此以外,redis还可以使用
BGSAVE
(Background saving
)命令,它可以在后台执行备份任务;
20. 安全
- 可以通过 redis 的配置文件设置密码参数,这样客户端连接到 redis 服务就需要密码验证,这样可以让你的 redis 服务更安全;
- 可以使用
CONFIG get requirepass
查看是否设置了密码验证。当输出的参数显示是空的,则说明当前无需通过密码验证就可以连接到 redis 服务; - 你可以通过设置
set requirepass <密码>
的方式来设置密码验证; - 当你需要登录时,可以使用
AUTH <密码>
进行登录;
21. 性能测试
- 是通过同时执行多个命令实现的;
- 测试使用redis-benchmark这个自带的实用工具进行;
- 基本命令如下:
redis-benchmark [option] [option value] //该命令是在 redis 的目录下执行的,而不是 redis 客户端的内部指令。
- 关于测试的详细内容,我在另一份文档中呈现;
22. 客户端连接
- Redis 与客户端之间的连接是通过网络协议实现的。Redis 使用自己的轻量级协议,称为 RESP(REdis Serialization Protocol),来与客户端进行通信;
- Redis 采用经典的客户端-服务器架构,其中服务器负责处理客户端的请求,并返回响应、客户端可以是任何支持Redis协议的应用程序或库,用于向 Redis 服务器发送命令并接收响应:
连接过程
- Redis 服务器监听一个特定的 TCP 端口(默认是6379)或者Unix socket 的方式,等待客户端连接;客户端通过 TCP/IP 协议连接到 Redis 服务器的指定端口。客户端与 Redis 服务器之间建立 TCP 连接后,可以开始发送命令和接收响应。此时,客户端 socket 会被设置为非阻塞模式(
因为 Redis 在网络事件处理上采用的是非阻塞多路复用模型
)。然后,为这个 socket 设置TCP_NODELAY
属性,禁用Nagle
算法。最后创建一个可读的文件事件用于监听这个客户端 socket 的数据发送;
RESP协议
- 是 Redis 用于客户端-服务器通信的协议。它简单、高效,支持多种数据类型;
- 它的主要特性有:
- 简单字符串以 + 开头,例如:
+OK\r\n
; - 错误消息以 - 开头,例如:
-Error message\r\n
; - 整数以 : 开头,例如:
:1000\r\n
; - 批量字符串以 $ 开头,例如:
$6\r\nfoobar\r\n
; - 数组:以 * 开头,例如:
*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n
- 简单字符串以 + 开头,例如:
命令执行流程
- 客户端发送命令: 客户端通过 TCP 连接发送命令给 Redis 服务器。命令是按 RESP 协议格式化的,例如:
SET key value\r\n
; - 服务器解析命令: Redis 服务器接收到命令后,解析并执行相应的操作;
- 服务器返回响应: 命令执行完毕后,Redis 服务器通过 TCP 连接将结果按 RESP 格式返回给客户端;
连接方式
- 持久连接: 客户端与 Redis 服务器之间的连接在多次请求间保持打开状态。适用于需要频繁与 Redis 交互的应用;
- 短连接: 每次请求后客户端关闭连接。这种方式适用于偶尔与 Redis 交互的应用;
连接管理
- 连接池: 一些 Redis 客户端库实现了连接池,管理多个连接以提高性能和并发性;
- 超时设置: 可以配置客户端和服务器的连接超时,以防止长时间的空闲连接占用资源;
- 最大连接数:在 Redis2.4 中,最大连接数是被直接硬编码在代码里面的,而在 Redis2.6 版本中这个值变成可配置的。maxclients 的默认值是 10000,你也可以在
redis.conf
中对这个值进行修改,如redis-server --maxclients <想要的值>
;
关于客户端连接,有一些命令:
客户端命令
S.N. | 命令 | 描述 |
---|---|---|
1 | CLIENT LIST | 返回连接到 redis 服务的客户端列表 |
2 | CLIENT SETNAME | 设置当前连接的名称 |
3 | CLIENT GETNAME | 获取通过 CLIENT SETNAME 命令设置的服务名称 |
4 | CLIENT PAUSE | 挂起客户端连接,指定挂起的时间以毫秒计 |
5 | CLIENT KILL | 关闭客户端连接 |
23. 管道命令
- 详见于专门的笔记,此处略;
24. 分区
- 分区是分割数据到多个Redis实例的处理过程,因此每个实例只保存key的一个子集(
云计算实现的关键技术
); - 分区具有以下优势:
- 通过利用多台计算机内存的和值,允许我们构造更大的数据库;
- 通过多核和多台计算机,允许我们扩展计算能力;通过多台计算机和网络适配器,允许我们扩展网络带宽;
- 分区具有一些不足:
- 多个key的操作通常是不被支持的。举例来说,当两个set映射到不同的redis实例上时,你就不能对这两个set执行交集操作;
- 涉及多个key的redis事务不能使用;
- 当使用分区时,数据处理较为复杂,比如你需要处理多个rdb/aof文件,并且从多个实例和主机备份持久化文件;
- 增加或删除容量也比较复杂。redis集群大多数支持在运行时增加、删除节点的透明数据平衡的能力,但是类似于客户端分区、代理等其他系统则不支持这项特性。然而,一种叫做
presharding
的技术对此是有帮助的。
- Redis 有两种类型分区:
- 范围分区
- 最简单的分区方式是按范围
(ID)
分区,就是映射一定范围的对象到特定的Redis实例; - 这种方式是可行的,并且在实际中使用。不足就是要有一个区间范围到实例的映射表。这个表要被管理,同时还需要各 种对象的映射表,通常对Redis来说并非是好的方法;
- 最简单的分区方式是按范围
- 哈希分区
- 另外一种分区方法是hash分区。这对任何key都适用,也无需是object_name:这种形式;
- 其具体做法类似于:
- 用一个hash函数将key转换为一个数字,比如使用crc32 hash函数。对key foobar执行crc32(foobar)会输出类似93024922的整数;
- 对这个整数取模,将其转化为0-3之间的数字,就可以将这个整数映射到4个Redis实例中的一个了。93024922 % 4 = 2,就是说key foobar应该被存到R2实例中。注意:取模操作是取除的余数,通常在多种编程语言中用%操作符实现;
`** 的技术对此是有帮助的。
- 范围分区
- Redis 有两种类型分区:
- 范围分区
- 最简单的分区方式是按范围
(ID)
分区,就是映射一定范围的对象到特定的Redis实例; - 这种方式是可行的,并且在实际中使用。不足就是要有一个区间范围到实例的映射表。这个表要被管理,同时还需要各 种对象的映射表,通常对Redis来说并非是好的方法;
- 最简单的分区方式是按范围
- 哈希分区
- 另外一种分区方法是hash分区。这对任何key都适用,也无需是object_name:这种形式;
- 其具体做法类似于:
- 用一个hash函数将key转换为一个数字,比如使用crc32 hash函数。对key foobar执行crc32(foobar)会输出类似93024922的整数;
- 对这个整数取模,将其转化为0-3之间的数字,就可以将这个整数映射到4个Redis实例中的一个了。93024922 % 4 = 2,就是说key foobar应该被存到R2实例中。注意:取模操作是取除的余数,通常在多种编程语言中用%操作符实现;
- 范围分区