当前位置: 首页 > news >正文

Redis使用详解

redis学习手册

1 什么是redis

​ Redis(Remote Dictionary Server ,即远程字典服务

​ Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单个value的最大限制是1GB,另外Redis也可以对存入的Key-Value设置expire时间,

2 Redis能干吗

  • 内存存储,持久化,内存中断电即失,所以有持久化数据(rdb,aof)
  • 效率高,可以与用于高速缓存
  • 发布订阅系统
  • 地图信息分析
  • 计时器,计数器,(浏览量)

特性

  • 多样的数据类型
  • 持久化
  • 集群
  • 事务

3 windows安装

1.下载安转包:https://github.com/tporadowski/redis/releases

2.得到安转包:redis

3.解压到本地文件夹

4.开启redis:双击运行服务即可

4 liunx安装

1.现在安转:[http://redis.io/download](https://redis.io/download.

本教程使用的稳定版本为 2.8.17(官网为7.0.2),下载并安装:

$ wget http://download.redis.io/releases/redis-2.8.17.tar.gz
$ tar xzf redis-2.8.17.tar.gz
$ cd redis-2.8.17
$ make

make 完后 redis-2.8.17目录下会出现编译后的redis服务程序redis-server,还有用于测试的客户端程序 redis-cli 都会位于安装目录中的 src 目录下。

下面启动redis服务.

$ cd src
$ ./redis-server

注意这种方式启动 redis 使用的是默认配置。也可以通过启动参数告诉 redis 使用指定配置文件使用下面命令启动。

$ ./redis-server redis.conf

redis.conf 是一个默认的配置文件。我们可以根据需要使用自己的配置文件。

启动 redis 服务进程后,就可以使用测试客户端程序 redis-cli 和 redis 服务交互了。 比如:

$ cd src
$ ./redis-cli
redis> set foo bar
OK
redis> get foo
"bar"

5 Redis配置文件

1.查看配置项命令

redis 127.0.0.1:6379> CONFIG SET 配置项名称 配置项参数值
  • 查看日志级别
127.0.0.1:6379> CONFIG SET loglevel "verbose"
OK
127.0.0.1:6379> CONFIG GET loglevel
1. "loglevel"
2. "verbose"

2.更改配置文件

Redis 某些配置信息无法直接通过命令修改,此时就需要修改配置文件,比如设置 Redis 允许远程连接的功能。配置文件修改如下:

1.注释掉本地IP地址,绑定要访问的外部IP
#bind 127.0.0.1 ::1
bind 192.168.1.1
2.关闭保护模式(把yes改为no.
protected-mode no
3.重启服务器,windows重启
redis-server --service-stop
redis-server --service-start
Linux重启
sudo /etc/init.d/redis-server restart

6 redis数据类型

​ reids支持的数据类型有五种:

6.1 String类型

  • String 是 Redis 最基本的数据类型。字符串是一组字节,在 Redis 数据库中,字符串具有二进制安全(binary safe)特性,这意味着它的长度是已知的,不由任何其他终止字符决定的,一个字符串类型的值最多能够存储 512 MB 的内容。

  • 二进制安全:是一种主要用于字符串操作函数的计算机编程术语。只关心二进制化的字符串,不关心具体的字符串格式,严格的按照二进制的数据存取。这保证字符串不会因为某些操作而遭到损坏。

  • set 和 get 命令:

127.0.0.1:6379> set website "www.biancheng.net"
OK
127.0.0.1:6379> get website
"www.biancheng.net"
  • 存取多个值命令:MSET 和 MGET
127.0.0.1:6379> MSET name www.biancheng.net topic Redis
OK
127.0.0.1:6379> MGET name topic
1. "www.biancheng.net"
2. "Redis"

6.2 hash散列

  • hash 散列是由字符串类型的 field 和 value 组成的映射表,可以把它理解成一个包含了多个键值对的集合。由于 Hash 类型具有上述特点,所以一般被用来存储对象。
  • HMSET 和 HGETALL 命令来存取一个包含了用户基本信息的对象
127.0.0.1:6379> HMSET userid:1 username xiaoming password 123456 website www.biancheng.net
OK
127.0.0.1:6379> HGETALL userid:1
1. "username"
2. "xiaoming"
3. "password"
4. "123456"
5. "website"
6. "www.biancheng.net"

6.3 list列表

  • Redis List 中的元素是字符串类型,其中的元素按照插入顺序进行排列,允许重复插入,最多可插入的元素个数为 2^32 -1 个(大约40亿个),可以添加一个元素到列表的头部(左边)或者尾部(右边)。

  • LPUSH 和 LRANGE 命令对 List 数据类型进行存取

  • 注意:Redis 的列表类型同样遵循索引机制。

#LPUSH 列表添加元素命令
127.0.0.1:6379> LPUSH biancheng Java
(integer. 1
127.0.0.1:6379> LPUSH biancheng Python
(integer. 2
127.0.0.1:6379> LPUSH biancheng C
(integer. 3
127.0.0.1:6379> LPUSH biancheng SQL
(integer. 4
127.0.0.1:6379> LPUSH biancheng Redis
(integer. 5
127.0.0.1:6379> LPUSH biancheng Golang
(integer. 6
#LRANGE 查看列表元素
#最开始插入的在最后,最后插入位于第一个位置,和队列相似。
127.0.0.1:6379> LRANGE biancheng 0 6
1. "Golang"
2. "Redis"
3. "SQL"
4. "C"
5. "Python"
6. "Java"

6.4 set集合

  • Redis Set 是一个字符串类型元素构成的无序集合。在 Redis 中,集合是通过哈希映射表实现的,所以无论是添加元素.删除元素,亦或是查找元素,它们的时间复杂度都为 O(1.。

  • 下面通过 SADD 命令添加 string 元素到 Set 集合中,若添加成功则返回 1,如果元素已经存在,则返回 0。示例如下:

127.0.0.1:6379> SADD www.biancheng.net HTML
(integer. 1
127.0.0.1:6379> SADD www.biancheng.net Pandas
(integer. 1
127.0.0.1:6379> SADD www.biancheng.net NumPy
(integer. 1
127.0.0.1:6379> SADD www.biancheng.net Matplotlib
(integer. 1
127.0.0.1:6379> SADD www.biancheng.net JS
(integer. 1
127.0.0.1:6379> SADD www.biancheng.net HTML
(integer. 0
127.0.0.1:6379> SADD www.biancheng.net HTML
(integer. 0
#SMEMBERS命令查看集合中元素,元素会无序排列
127.0.0.1:6379> SMEMBERS www.biancheng.net
1. "Matplotlib"
2. "HTML"
3. "JS"
4. "Pandas"
5. "NumPy"
  • 由于 Set 集合中的成员具有唯一性,所以重复插入 HTML 元素不会成功,集合的同样可容纳 2^32 -1 个元素。

6.5 zset 有序集合

  • Redis zset 是一个字符串类型元素构成的有序集合,集合中的元素不仅具有唯一性,而且每个元素还会关联一 个 double 类型的分数,该分数允许重复。Redis 正是通过这个分数来为集合中的成员排序。
  • 下面通过 zadd 命令添加元素到集合,若元素存在于集合中,则不能添加成功。示例如下:
127.0.0.1:6379> del biancheng
(integer. 1
127.0.0.1:6379> zadd biancheng 0 Python
(integer. 1
127.0.0.1:6379> zadd biancheng 1 Java
(integer. 1
127.0.0.1:6379> zadd biancheng 2 C++
(integer. 1
127.0.0.1:6379> zadd biancheng 3 MySQL
(integer. 1
127.0.0.1:6379> zadd biancheng 4 Redis
(integer. 1
#重复元素无法添加成功
127.0.0.1:6379> zadd biancheng 4 Redis
(integer. 0
#重复分值添加成功
127.0.0.1:6379> zadd biancheng 4 GOLANG
(integer. 1
#查看指定成员的分值
127.0.0.1:6379> ZSCORE biancheng Redis
"4"
查看zset中的所有成员
127.0.0.1:6379> zrange biancheng 0 4
1. "Python"
2. "Java"
3. "C++"
4. "MySQL"
5. "GOLANG"
6. "Redis"

7 Redis命令行模式

Redis 命令用于在 Redis 服务器上执行一些操作,而命令运行的方式是通过客户端命令行来执行的,这种方式也被称为“命令行模式”。因此想要在 Redis 服务器上运行命令,您首先需要开启一个 Redis 客户端

在 CMD 命令行输入以下命令启动一个 Redis 客户端:

redis-cli

7.1 本地服务器运行命令

  • 本地服务器指的是,Redis 服务器和客户端安装在同一台计算机上,本教程中 Redis 运行环境都是以本地服务器来运行的。

  • 在计算机上打开一个 Redis 客户端输入以下命令,验证客户端与Redis 服务器是否成功连接。

C:\Users\Administrator>redis-cli
127.0.0.1:6379> PING
PONG
127.0.0.1:6379>
  • 通过执行命令 PING,以检查服务器是否正在运行,结果返回 PONG,说明已经成功连接了本地 Redis 服务器。

7.2 远程服务器上运行命令

远程服务器顾名思义指的是服务器安装在另外一台计算机上,而非本地。这台远程计算机可以是局域网中的一台,也可以是 Internet 联网状态下的远程计算机。Redis 提供了连接远程服务器的命令,格式如下:

C:\Users\Administrator>redis-cli -h host -p port -a password

参数说明:

  • -h:用于指定远程 Redis 服务器的 IP 地址;
  • -p:用于指定 Redis 远程服务器的端口号;
  • -a:可选参数,若远程服务器设置了密码,则需要输入;

下面示例展示了如何连接到 Redis 远程服务器。

服务器在主机 IP 是 192.168.31.1,端口号为 6379 ,密码为 123456。

C:\Users\Administrator>redis-cli -h 127.0.0.1 -p 6379 -a 123456
redis 127.0.0.1:6379>
redis 127.0.0.1:6379> PING 
PONG

8 Redis key键

Redis 是一种键值(key-value)型的缓存型数据库,它将数据全部以键值对的形式存储在内存中,并且 key 与 value 一一对应。这里的 key 被形象的称之为密钥,Redis 提供了诸多操作这把“密钥”的命令,从而实现了对存储数据的管理。

您可以把 key 看成 value 的变量,通过检索 key 就可以找到对应的 value 值。为了更加全面的了解 key,我们将从以下三个维度做深入讲解:

  • key 的类型
  • key 的命名规范
  • key 的过期时间

8.1 key的特点

8.1.1 key的类型

​ key 的类型对应着 value 的类型,同样也有五种(string.list.hash.set.zset)。如果 key 指向的是一个字符串类型的值,那么 key 的类型就是字符串。我们可以通过TYPE命令来查看 key 的类型,示例如下:

# 字符串
redis> SET weather "sunny"
OK
redis> TYPE weather
string# 列表
redis> LPUSH book_list "programming in scala"
(integer. 1
redis> TYPE book_list
list# 集合
redis> SADD pat "dog"
(integer. 1
redis> TYPE pat
set
8.1.2 命名规范

key 的命名需要遵循以下规则:

  • key 取值不可以太长,否则会影响 value 的查找效率,并且浪费内存空间。
  • key 取值也不能过短,否则会使得 key 可读性变差。
  • 在 key 的取值上, Redis 官方建议使用“见名知意”的字符串格式,因为这样便于我们理解 key 的含义。
8.1.3 key过期时间策略

​ redis缓存key的删除策略,

  • 定期删除

  • 惰性策略

  • 当内存占满时,会使用内存淘汰机制

    noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。(默认选项,一般不会选用)
    allkeys-lru:当内存不足以容纳新写入数据时,在整个键空间中,移除最近最少使用的key。(这个是最常用的)
    allkeys-lfu:当内存不足以容纳新写入数据时,在整个键空间中,移除最不经常(最少)使用的key。
    allkeys-random:当内存不足以容纳新写入数据时,在整个键空间中,随机移除某个key。
    volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
    volatile-lfu:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最不经常(最少)使用的key。
    volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
    volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。

  • redis用的是,定期删除+惰性策略

​ Redis 允许你为 key 设置一个过期时间(使用 EXPIRE 等命令),也就是“到点自动删除”,这在实际业务中是非常有用的,一是它可以避免使用频率不高的 key 长期存在,从而占用内存资源;二是控制缓存的失效时间。

Redis 会把每个设置了过期时间的 key 存放到一个独立的字典中,并且会定时遍历这个字典来删除到期的  key。除了定时遍历之外,它还会使用“惰性策略”来删除过期的 key。所谓“惰性策略”指的是当客户端访问这个 key 的时候,Redis 对  key 的过期时间进行检查,如果过期了就立即删除。Redis 使用两种方式相结合的方法来处理过去的 key。 

​ 过期时间,有许多的应用场景,比如购物 App 会在特定的时间节点推出相关的活动,比如双十一.双十二.618购物节等,这些活动都是一年一度如期开办,因此当下一期举行时,上一期的活动的数据就没有意义了,在这种情景下就可以给 key 设置一个过期时间,从而减少无用数据占用内存资源。

8.2 key命令格式

1.了解完 key 的相关规范,接下来看一下和 key 相关的命令,它的语法格式如下所示:

redis 127.0.0.1:6379> COMMAND KEY_NAME
  • COMMAND:表示 key 的命令;
  • KEY_NAME:表示 key 的名字。

2.通过示例进一步说明,DEL代表删除命令,而 www.biancheng.net 是键。如果成功删除了键,则将的返回整数 1,否则将返回整数 0。示例如下:

redis 127.0.0.1:6379> SET www.biancheng.net "编程帮你好"
OK
#删除key
redis 127.0.0.1:6379> DEL  www.biancheng.net
(integer. 1
#若键不存在删除失败
redis 127.0.0.1:6379> DEL age
(integer. 0

8.3 Redis键命令汇总

命令说明
DEL key若键存在的情况下,该命令用于删除键。
DUMP key用于序列化给定 key ,并返回被序列化的值。
EXISTS key用于检查键是否存在,若存在则返回 1,否则返回 0。
EXPIRE key设置 key 的过期时间,以秒为单位。
EXPIREAT key该命令与 EXPIRE 相似,用于为 key 设置过期时间,不同在于,它的时间参数值采用的是时间戳格式。
PEXPIRE key设置 key 的过期,以毫秒为单位。
PEXPIREAT key与 PEXPIRE 相似,用于为 key 设置过期时间,采用以毫秒为单位的时间戳格式。
KEYS pattern此命令用于查找与指定 pattern 匹配的 key。
MOVE key db将当前数据库中的 key 移动至指定的数据库中(默认存储为 0 库,可选 1-15中的任意库)。
PERSIST key该命令用于删除 key 的过期时间,然后 key 将一直存在,不会过期。
PTTL key用于检查 key 还剩多长时间过期,以毫秒为单位。
TTL key用于检查 key 还剩多长时间过期,以秒为单位。
RANDOMKEY从当前数据库中随机返回一个 key。
RENAME key newkey修改 key 的名称。
RENAMENX key newkey如果新键名不重复,则将 key 修改为 newkey。
SCAN cursor基于游标的迭代器,用于迭代数据库中存在的所有键,cursor 指的是迭代游标。
TYPE key该命令用于获取 value 的数据类型。

8.4 常用命令

8.4.1 DUMP序列化命令

该命令用于将键对应的值做序列化处理,实例如下:

127.0.0.1:6379> SET num 12
OK
127.0.0.1:6379> DUMP num
"\x00\xc0\x0c\t\x00\xec\xd8\xa9\x9d\b\x82\xdfd"

如果 key 不存在时,则返回 nil。

8.4.2 EXPIRE设置过期时间命令

该命令用于设置 key 的过期时间,当 key 过期后将不可以再使用。

127.0.0.1:6379> set www.biancheng.net Python
OK
127.0.0.1:6379> set www.biancheng.net Python EX 60
OK
127.0.0.1:6379> EXPIRE www.biancheng.net 120
(integer. 1

上面介绍了两种设置过期时间的方法,它们都可以实现过期时间设置,key 过期后将自动被删除。

8.4.3 PEXPIREAT设置过期时间

以时间戳格式设置过期时间,并以毫秒为单位。

127.0.0.1:6379> set www.biancheng.net PythonOK127.0.0.1:6379> PEXPIREAT www.biancheng.net 12000000000(integer. 1

设置成功返回 1,若 key 不存在或者不能为其设置过期时间,则返回 0。

8.4.4 KEYS命令查找键

查找指定模式的键。

redis 127.0.0.1:6379> SET course1 redis
OK
redis 127.0.0.1:6379> SET course2 php
OK
redis 127.0.0.1:6379> SET course3 python
OK
127.0.0.1:6379> keys course*
1. "course1"
2. "course2"
3. "course3"
#获取所有key
127.0.0.1:6379> keys *
1. "course1"
2. "course2"
3. "course3"
4. "num"
5. "www.biancheng.net"

注意:keys * 会返回当前库中所有的键。

8.4.5 SCAN cursor

SCAN 命令是一个基于游标的迭代器,每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 否则将无法继续跌代。如果新游标返回 0 则表示迭代结束。

SCAN 命令的语法格式如下:

SCAN cursor [MATCH pattern] [COUNT count]

参数说明:

  • cursor :指定游标,从 0 开始新的迭代。
  • pattern:指定匹配的模式。
  • count:返回多少个元素,默认值为 10 。

SCAN 令可以迭代数据库中的所有键,如果想针对特定的数据类型迭代,那么命令自然也要做相应的变化。如下所示:

  • SSCAN 命令用于迭代集合键中的元素。
  • HSCAN 命令用于迭代哈希键中的键值对。
  • ZSCAN 命令用于迭代有序集合中的元素。

该命令的使用示例如下

    127.0.0.1:6379> SCAN 01. "3"2.  1. "name"2. "website"3. "biancheng2"4. "www.biancheng.net"5. "biancheng3"6. "biancheng1"7. "course2"8. "topic"9. "course1"10. "age"127.0.0.1:6379> SCAN 31. "0"2. 1. "biancheng"2. "course3"3. "userid:1"4. "num"
8.4.6 TTL命令

在 key 设置过期时间的情况下,使用该命令检查 key 剩余的过期时间。

当键没有设置过期时间,表示是永久有效时,TTL 命令返回 -1;当键过期或者被删除时,TTL 命令返回 -2。示例如下:

127.0.0.1:6379> SET www.biancheng.net hello
OK
127.0.0.1:6379> ttl www.biancheng.net
(integer. -1
127.0.0.1:6379> SET user:1 Jack EX 120
OK
127.0.0.1:6379> TTL user:1
(integer. 108
127.0.0.1:6379> DEL user:1
(integer. 1
127.0.0.1:6379> TTL user:1
(integer. -2

9 redis密码设置

​ Redis 提供了诸多安全策略,比如为了保证数据安全,提供了设置密码的功能。Redis 密码设置主要有两种方式:

  • CINFIG命令来设置密码;
  • 手动修改 Redis 的配置文件密码;

9.1 命令配置密码

通过执行以下命令查看是否设置了密码验证:

127.0.0.1:6379> CONFIG get requirepass
1. "requirepass"
2. ""

在默认情况下 requirepass 参数值为空的,表示无需通过密码验证就可以连接到 Redis 服务。

下面执行以下命令设置密码。如下所示:

127.0.0.1:6379> CONFIG set requirepass "www.biancheng.net"
OK
127.0.0.1:6379> CONFIG get requirepass
1. "requirepass"
2. "www.biancheng.net"

执行完上述操作后,客户端要连接到 Redis 服务就需要密码验证,如果不验证就无法操作 Redis 数据库。如下所示:

127.0.0.1:6379> set key name www.biancheng.net
#报错无法操作
(error. NOAUTH Authentication required.

使用AUTH命令验证密码:

127.0.0.1:6379> AUTH www.biancheng.net
OK
#执行命令成功
127.0.0.1:6379> SET name www.biancheng.net
OK
127.0.0.1:6379> GET name
www.biancheng.net

注意:通过命令行设置的密码并非永久有效,当您重启服务后密码就会失效,所以一般不采用这种方式。下面介绍一种永久有效的修改方式,也就是手动配置密码。

9.2 手动配置密码

​ 手动修改配置密码也非常的简单,首先,您要在 Redis 的安装目录中找到 redis.windows.conf 配置文件,然后打开该文件,并使用 Ctrl+F 搜索 requirepass 关键字,找到配置项并配置密码,如下所示:

# requirepass foobared
requirepass www.biancheng.net //配置自己的密码

然后使用更改后的配置文件重启服务器,依次执行以下命令:

#首先停止服务:
C:\Users\Administrator>redis-server.exe --service-stop
#重启服务器
C:\Users\Administrator>redis-server.exe --service-start
#重新登陆
C:\Users\Administrator>redis-cli.exe -h 127.0.0.1 -p 6379 -a www.biancheng.net
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
#命令执行成功
127.0.0.1:6379>config get requirepass
1."requirepass"
2."www.biancheng.net"

​ 手动配置无须验证密码,只需要重新启动 Redis 服务器。这种配置方式,密码永远有效。如果想取消密码设置,您需要将配置文件更改回原来的状态,然后再次重启服务器,即可取消。

除了需要为 Redis 配置密码外,我们在使用 Redis 时也需要注意一些常见的安全风险以及防范措施,从而避免数据泄露和丢失,以及人为操作失误等。

9.3 指令安全

​ Redis 有一些非常危险的命令,这些命令会对 Redis 的稳定以及数据安全造成非常严重的影响。比如 keys 指令会导致 Redis 卡顿,而 flushdb 和 flushall 会让 Redis 的所有数据全部清空。那么如何避免这些操作失误带来的灾难性后果呢?

Redis 在配置文件中提供了 rename-command 指令用于将某些危险的指令修改成特别的名称,用来避免人为误操作。比如在配置文件的 security 模块增加以下内容:

rename-command keys 123keys123

​ 如果您还想执行 keys 命令,那就需要在命令行输入123keys123。 当然也可以将指令 rename 成空字符串,这样就无法通过字符串来执行 keys 命令了。

rename-command flushall ""

9.4 端口安全

​ Redis 默认监听*:6379,如果当前的服务器主机有外网地址,那么 Redis 的服务将会直接暴露在公网上,别有用心的人使用适当的探测工具就可以对 IP 地址进行端口扫描,从而威胁您的系统安全。

​ 如果 Redis 的服务地址一旦可以被外网直接访问,其内部数据就彻底丧失了安全性。黑客们可以通过 Redis 执行 Lua 脚本拿到服务器权限,然后清空您的 Redis 数据库。因此务必在 Redis 的配置文件中绑定要监听的 IP 地址,避免类似的情况发生。如下所示:

bind 193.168.1.1 #绑定外网ip地址

不仅如此,还可以增加 Redis 的密码访问限制,客户端必须使用 auth 命令传入正确的密码才可以访问 Redis。

requirepass yourspassword

这样即使地址暴露出去了,普通黑客也无法对 Redis 服务器进行任何指令操作。

密码配置也会影响到主从复制。要求从机必须配置与主服务相同的密码才可以进行主从复制。

masterauth yourspassword

9.5 SSH代理

​ Redis 不支持 SSL 链接,这意味着客户端和服务器交互的数据不应该在公网上传输,否则会有被窃听的风险。如果必须要在公网上,可以考虑使用 SSL 代理。SSL 代理比较常见的有 ssh。Redis 官方也推荐了一种代理工具,也就是 [spiped](http://www.tarsnap.com/spiped.html. (点击了解.。 其功能虽然单一,但使用起来比较简单,易于理解。

10 Redis客户端(client)命令

10.1 客户端最大连接数

在 Redis 配置文件中,有一个maxclients的配置项,它指定了连接到 Redis 服务器的最大客户端数量。其默认值是 10000。配置项如下所示:

127.0.0.1:6379> config get maxclients
1. "maxclients"
2. "10000"
#更改最大连接数量
127.0.0.1:6379> config set maxclients 20000
OK
127.0.0.1:6379> config get maxclients
1. "maxclients"
2. "20000"

10.2 常用命令

命令说明
CLIENT LIST以列表的形式返回所有连接到 Redis 服务器的客户端。
CLIENT SETNAME设置当前连接的名称。
CLIENT GETNAME获取通过 CLIENT SETNAME 命令设置的服务名称。
CLIENT PAUSE挂起客户端连接,将所有客户端挂起指定的时间(以毫秒为计算)。
CLIENT KILL关闭客户端连接。
CLIENT ID返回当前客户端 ID。
CLIENT REPLY控制发送到当前连接的回复,可选值包括 on|off|skip。

使用示例,如下所示:

127.0.0.1:6379> CLIENT ID
(integer. 2557
127.0.0.1:6379> CLIENT LIST
id=2556 addr=127.0.0.1:64684 fd=30 name= age=2422 idle=339 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=client
id=2557 addr=127.0.0.1:49502 fd=43 name= age=537 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client
127.0.0.1:6379> CLIENT REPLY ON
OK
127.0.0.1:6379> CLIENT SETNAME "www.biancheng.net"
OK
127.0.0.1:6379> CLIENT GETNAME
"www.biancheng.net"
127.0.0.1:6379> CLIENT KILL 127.0.0.1:49502
OK

10.3 Redis IO多路复用

Redis 的底层是一个单线程模型,单线程指的是使用一个线程来处理所有的网络事件请求,这样就避免了多进程或者多线程切换导致的 CPU 消耗,而且也不用考虑各种锁的问题。

Redis 为了充分利用单线程,加快服务器的处理速度,它采用 IO 多路复用模型来处理客户端与服务端的连接,这种模型有三种实现方式,分别是 select.poll.epoll。Redis 正是采用 epoll 的方式来监控多个 IO 事件。当客户端空闲时,线程处于阻塞状态;当一个或多个 IO 事件触发时(客户端发起网路连接请求),线程就会从阻塞状态唤醒,并同时使用epoll来轮询触发事件,并依次提交给线程处理。

注意:“多路”指的是多个网络连接,“复用”指的是复用同一个线程。多路 IO 复用技术可以让单个线程高效的处理多个连接请求。

11 常用服务器命令

Redis 提供了诸多操作服务器的命令,这些命令都有着各自重要的作用,比如BGSAVE命令,用异步的方式将 Redis 数据库的数据同步到本地磁盘中,实现数据的持久化存储,这对服务器的数据安全有着重要的作用

命令说明
BGREWRITEAOF在后台以异步的方式执行一个 AOF 文件的重写操作,对源文件进行压缩,使其体积变小。 AOF 是实现数据持久化存储的方式之一。
BGSAVE在后台执行初始化操作,并以异步的方式将当前数据库的数据保存到磁盘中。
CLIENT KILL [ip:port] [ID client-id]关闭客户端连接。
CLIENT LIST获取连接到服务器的客户端连接列表。
CLIENT GETNAME获取当前连接客户端的名称。
CLIENT PAUSE timeout使服务器在指定的时间停止执行来自客户端的命令。
CLIENT SETNAME connection-name设置当前连接客户端的名称。
COMMAND返回所有 Redis 命令的详细描述信息。
COMMAND COUNT此命令用于获取 Redis 命令的总数。
COMMAND GETKEYS获取指定命令的所有键。
INFO [section]获取 Redis 服务器的各种信息和统计数值。
COMMAND INFO command-name [command-name …]用于获取指定 Redis 命令的描述信息。
CONFIG GET parameter获取指定配置参数的值。
CONFIG REWRITE修改启动 Redis 服务器时所指定的 redis.conf 配置文件。
CONFIG SET parameter value修改 Redis 配置参数,无需重启。
CONFIG RESETSTAT重置 INFO 命令中的某些统计数据。
DBSIZE返回当前数据库中 key 的数量。
DEBUG OBJECT key获取 key 的调试信息。当 key 存在时,返回有关信息;当 key 不存在时,返回一个错误。
DEBUG SEGFAULT使用此命令可以让服务器崩溃。
FLUSHALL清空数据库中的所有键。
FLUSHDB清空当前数据库的所有 key。
LASTSAVE返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 格式表示。
MONITOR实时打印出 Redis 服务器接收到的命令。
ROLE查看主从实例所属的角色,角色包括三种,分别是 master、slave、sentinel。
SAVE执行数据同步操作,将 Redis 数据库中的所有数据以 RDB 文件的形式保存到磁盘中。 RDB 是 Redis 中的一种数据持久化方式。
SHUTDOWN [NOSAVE] [SAVE]将数据同步到磁盘后,然后关闭服务器。
SLAVEOF host port此命令用于设置主从服务器,使当前服务器转变成为指定服务器的从属服务器, 或者将其提升为主服务器(执行 SLAVEOF NO ONE 命令)。
SLOWLOG subcommand [argument]用来记录查询执行时间的日志系统。
SYNC用于同步主从服务器。
SWAPDB index index用于交换同一 Redis 服务器上的两个数据库,可以实现访问其中一个数据库的客户端连接,也可以立即访问另外一个数据库的数据。
TIME此命令用于返回当前服务器时间。

下面是对上述的命令做简单的演示,您可以跟着敲一遍命令,从加深对命令的理解与记忆:

#查看redis命令的描述信息
127.0.0.1:6379> COMMAND INFO SET GET ZADD
1. 1. "set"2. (integer. -33. 1. write2. denyoom4. (integer. 15. (integer. 16. (integer. 1
2. 1. "get"2. (integer. 23. 1. readonly2. fast4. (integer. 15. (integer. 16. (integer. 1
3. 1. "zadd"2. (integer. -43. 1. write2. denyoom3. fast4. (integer. 15. (integer. 16. (integer. 1
#最近一次执行数据持久化存储的时间
127.0.0.1:6379> LASTSAVE
(integer. 1610717455
127.0.0.1:6379> LASTSAVE
(integer. 1610717455
#实时打印redis服务器接收的命令
127.0.0.1:6379> MONITOR
OK
1610951376.523762 [0 127.0.0.1:60257] "COMMAND"
^C
#查看前两条日志信息
127.0.0.1:6379> SLOWLOG get 2
1. 1. (integer. 132. (integer. 16109502583. (integer. 464994. 1. "info"5. "127.0.0.1:58561"6. ""
2. 1. (integer. 122. (integer. 16109502013. (integer. 199174. 1. "COMMAND"5. "127.0.0.1:58561"6. ""
#共有多少条日志记录
127.0.0.1:6379> SLOWLOG len
(integer. 14
#清空所有日志记录
127.0.0.1:6379> SLOWLOG reset
OK
127.0.0.1:6379> SLOWLOG len
(integer. 0
#用于同步主从服务器数据
127.0.0.1:6379> SYNC
Entering replica output mode... (press Ctrl-C to quit.
SYNC with master, discarding 1719 bytes of bulk transfer...
SYNC done.Logging commands from master.
"PING"
"PING"
"PING"
"PING"
"PING"
^C
C:\Users\Administrator>redis-cli
#查看当前服务器时间
#第一个字符串是当前时间以 UNIX 时间戳格式表示
#第二个字符串表示:当前这一秒钟已经逝去的微秒数
127.0.0.1:6379> TIME
1. "1610953086"
2. "17499"

12 Redis HyperLoglog基数统计

Redis 经常使用的数据类型有字符串.列表.散列.集合和有序集合,但这些类型并不能满足所有的应用场景,因此,Redis 的后续版本不断的扩增其他数据类型来增强 Redis 适用能力。在 Redis 2.8.9 版本中新增了 HyperLogLog 类型。

12.1 什么是HyperLoglog

HyperLoglog 是 Redis 重要的数据类型之一,它非常适用于海量数据的计算.统计,其特点是占用空间小,计算速度快。

HyperLoglog 采用了一种基数估计算法,因此,最终得到的结果会存在一定范围的误差(标准误差为 0.81%)。每个 HyperLogLog key 只占用 12 KB 内存,所以理论上可以存储大约2^64个值,而 set(集合)则是元素越多占用的内存就越多,两者形成了鲜明的对比 。

12.2 基数定义

基数定义:一个集合中不重复的元素个数就表示该集合的基数,比如集合 {1,2,3,1,2} ,它的基数集合为 {1,2,3} ,所以基数为 3。HyperLogLog 正是通过基数估计算法来统计输入元素的基数。

HyperLoglog 不会储存元素值本身,因此,它不能像 set 那样,可以返回具体的元素值。HyperLoglog 只记录元素的数量,并使用基数估计算法,快速地计算出集合的基数是多少。

12.3 场景应用

HyperLogLog 也有一些特定的使用场景,它最典型的应用场景就是统计网站用户月活量,或者网站页面的 UV(网站独立访客.数据等。

UV 与 PV(页面浏览量. 不同,UV 需要去重,同一个用户一天之内的多次访问只能计数一次。这就要求用户的每一次访问都要带上自身的用户 ID,无论是登陆用户还是未登陆用户都需要一个唯一 ID 来标识。

当一个网站拥有巨大的用户访问量时,我们可以使用 Redis 的 HyperLogLog 来统计网站的 UV (网站独立访客)数据,它提供的去重计数方案,虽说不精确,但 0.81% 的误差足以满足 UV 统计的需求。

12.4 常用命令

命令说明
PFADD key element [element …]添加指定元素到 HyperLogLog key 中。
PFCOUNT key [key …]返回指定 HyperLogLog key 的基数估算值。
PFMERGE destkey sourcekey [sourcekey …]将多个 HyperLogLog key 合并为一个 key。

12.5 基本命令用法

HyperLogLog 提供了三个常用命令,分别是PFADD.PFCOUNTPFMERGE

下面看一组实例演示:假设有 6 个用户(user01-user06.,他们分别在上午 8 与 9 点访问了www.biancheng.netC语言中文网。

#向指定的key中添加用户
127.0.0.1:6379> PFADD user:uv:2021011308 user01 user02 user03
(integer. 1
#向指定的key中添加用户
127.0.0.1:6379> PFADD user:uv:2021011309 user04 user05
(integer. 1
#统计基数值
127.0.0.1:6379> PFCOUNT user:uv:2021011308
(integer. 3
#重复元素不能添加成功,其基数仍然为3
127.0.0.1:6379> PFADD user:uv:2021011308 user01 user02
(integer. 0
127.0.0.1:6379> PFCOUNT user:uv:2021011308
(integer. 3
#添加新元素值
127.0.0.1:6379> PFADD user:uv:2021011308 user06
(integer. 1
#基数值变为4
127.0.0.1:6379> PFCOUNT user:uv:2021011308
(integer. 4
#统计两个key的基数值
127.0.0.1:6379> PFCOUNT user:uv:2021011308 user:uv:2021011309
(integer. 6
#将两个key值合并为一个
127.0.0.1:6379> PFMERGE user:uv:2021011308-09 user:uv:2021011308 user:uv:2021011309
OK
#使用合并后key统计基数值
127.0.0.1:6379> PFCOUNT user:uv:2021011308-09
(integer. 6

13 Redis PubSub发布订阅

Redis PubSub 模块又称发布订阅者模式,是一种消息传递系统,实现了消息多播功能。发布者(即发送方)发送消息,订阅者(即接收方)接收消息,而用来传递消息的链路则被称为 channel。在 Redis 中,一个客户端可以订阅任意数量的 channel(可译为频道)。

13.1 订阅者/等待接收消息

首先打开 Redis 客户端,然后订阅了一个名为“www.biancheng.net”的 channel,使用如下命令:

#订阅channel
127.0.0.1:6379> SUBSCRIBE www.biancheng.net
Reading messages...(press Ctrl-C to quit.
1. "subscribe"
2. "www.biancheng.net"
3. (integer. 1 

上述示例使用SUBSCRIBE命令订阅了名为 www.biancheng.net 的 channel。命令执行后该客户端会出处于等待接收消息的阻塞状态。

13.2 发布者/发送消息

下面再启动一个 Redis 客户端,输入如下命令:

127.0.0.1:6379> PUBLISH www.biancheng.net "this is website"
(integer. 1
127.0.0.1:6379> PUBLISH www.biancheng.net "hello world"
(integer. 1
127.0.0.1:6379> PUBLISH www.biancheng.net "how are you"
(integer. 1

通过上述PUBLISH命令发布了三条信息。现在两个客户端在处于同一个名为“www.biancheng.net”的频道上,前者负责接收消息,后者负责发布消息。

13.3 订阅者/成功接收消息

完成了上述操作后,您会在接收消息的客户端得到如下输出结果:

127.0.0.1:6379> SUBSCRIBE www.biancheng.net
Reading messages...(press Ctrl-C to quit.
1. "subscribe"
2. "www.biancheng.net"
3. (integer. 1
1. "message"
2. "www.biancheng.net"
3. "this is website"
1. "message"
2. "www.biancheng.net"
3. "hello world"
1. "message"
2. "www.biancheng.net"
3. "how are you"

13.4 常用命令汇总

命令说明
PSUBSCRIBE pattern [pattern …]订阅一个或多个符合指定模式的频道。
PUBSUB subcommand [argument [argument …]]查看发布/订阅系统状态,可选参数 1) channel 返回在线状态的频道。 2) numpat 返回指定模式的订阅者数量。 3) numsub 返回指定频道的订阅者数量。
PUBSUB subcommand [argument [argument …]]将信息发送到指定的频道。
PUNSUBSCRIBE [pattern [pattern …]]退订所有指定模式的频道。
SUBSCRIBE channel [channel …]订阅一个或者多个频道的消息。
UNSUBSCRIBE [channel [channel …]]退订指定的频道。

13.5 基本命令应用

下面对上述常用命令做演示:

#订阅指定模式的频道,*代表通配符,会匹配所有www开头的频道
127.0.0.1:6379> PSUBSCRIBE www*
Reading messages...(press Ctrl-C to quit.
1. "psubscribe"
2. "www*"
3. (integer. 1
#按ctrl+c退出阻塞状态
^C
C:\Users\Administrator>redis-cli
#查看发布订阅系统状态,返回相应的频道
127.0.0.1:6379> PUBSUB channels
1. "www.biancheng.net"
#退订指定模式的频道
127.0.0.1:6379> PUNSUBSCRIBE www*
1. "punsubscribe"
2. "www*"
3. (integer. 0
#退订指定频道
127.0.0.1:6379> UNSUBSCRIBE www.biancheng.net
1. "unsubscribe"
2. "www.biancheng.net"
3. (integer. 0

注意:每个模式以*作为匹配符,比如 www* 匹配所有以 www 开头的频道,比如 www.baidu.com .www.biancheng.net 等等。

14 Redis Stream消息队列

Redis Stream 是 Redis 5.0 版本引入的一种新数据类型,同时它也是 Redis 中最为复杂的数据结构,本节主要对 Stream 做相关介绍。

什么是Stream?

Stream 实际上是一个具有消息发布/订阅功能的组件,也就常说的消息队列。其实这种类似于 broker/consumer(生产者/消费者.的数据结构很常见,比如 RabbitMQ 消息中间件.Celery 消息中间件,以及 Kafka 分布式消息系统等,而 Redis Stream 正是借鉴了 Kafaka 系统。

14.1 优点

Strean 除了拥有很高的性能和内存利用率外, 它最大的特点就是提供了消息的持久化存储,以及主从复制功能,从而解决了网络断开.Redis 宕机情况下,消息丢失的问题,即便是重启 Redis,存储的内容也会存在。

14.2 流程

Stream 消息队列主要由四部分组成,分别是:消息本身.生产者.消费者和消费组,对于前述三者很好理解,下面了解什么是消费组。

一个 Stream 队列可以拥有多个消费组,每个消费组中又包含了多个消费者,组内消费者之间存在竞争关系。当某个消费者消费了一条消息时,同组消费者,都不会再次消费这条消息。被消费的消息 ID 会被放入等待处理的 Pending_ids 中。每消费完一条信息,消费组的游标就会向前移动一位,组内消费者就继续去争抢下消息。

Redis Stream 消息队列结构程如下图所示:

![Redis Stream结构图](http://c.biancheng.net/uploads/allimg/210913/15253613F-0.gif.
图1:Redis Stream流程处理图

下面对上图涉及的专有名词做简单解释:

  • Stream direction:表示数据流,它是一个消息链,将所有的消息都串起来,每个消息都有一个唯一标识 ID 和对应的消息内容(Message content)。
  • Consumer Group :表示消费组,拥有唯一的组名,使用 XGROUP CREATE 命令创建。一个 Stream 消息链上可以有多个消费组,一个消费组内拥有多个消费者,每一个消费者也有一个唯一的 ID 标识。
  • last_delivered_id :表示消费组游标,每个消费组都会有一个游标 last_delivered_id,任意一个消费者读取了消息都会使游标 last_delivered_id 往前移动。
  • pending_ids :Redis 官方称为 PEL,表示消费者的状态变量,它记录了当前已经被客户端读取的消息 ID,但是这些消息没有被 ACK(确认字符.。如果客户端没有 ACK,那么这个变量中的消息 ID 会越来越多,一旦被某个消息被 ACK,它就开始减少。
14.3 ACK

ACK(Acknowledge character)即确认字符,在数据通信中,接收方传递给发送方的一种传输类控制字符。表示发来的数据已确认接收无误。在 TCP/IP 协议中,如果接收方成功的接收到数据,那么会回复一个 ACK 数据。通常 ACK 信号有自己固定的格式,长度大小,由接收方回复给发送方。

15 Redis布隆过滤器

布隆过滤器(Bloom Filter)是 Redis 4.0 版本提供的新功能,它被作为插件加载到 Redis 服务器中,给 Redis 提供强大的去重功能。

相比于 Set 集合的去重功能而言,布隆过滤器在空间上能节省 90% 以上,但是它的不足之处是去重率大约在 99% 左右,也就是说有 1% 左右的误判率,这种误差是由布隆过滤器的自身结构决定的。俗话说“鱼与熊掌不可兼得”,如果想要节省空间,就需要牺牲 1% 的误判率,而且这种误判率,在处理海量数据时,几乎可以忽略。

15.1 应用场景

布隆过滤器是 Redis 的高级功能,虽然这种结构的去重率并不完全精确,但和其他结构一样都有特定的应用场景,比如当处理海量数据时,就可以使用布隆过滤器实现去重。

下面举两个简单的例子:

15.1.1 示例:

百度爬虫系统每天会面临海量的 URL 数据,我们希望它每次只爬取最新的页面,而对于没有更新过的页面则不爬取,因策爬虫系统必须对已经抓取过的 URL 去重,否则会严重影响执行效率。但是如果使用一个 set(集合)去装载这些 URL 地址,那么将造成资源空间的严重浪费。

15.1.2 示例:

垃圾邮件过滤功能也采用了布隆过滤器。虽然在过滤的过程中,布隆过滤器会存在一定的误判,但比较于牺牲宝贵的性能和空间来说,这一点误判是微不足道的。

15.2 工作原理

布隆过滤器(Bloom Filter)是一个高空间利用率的概率性数据结构,由二进制向量(即位数组)和一系列随机映射函数(即哈希函数)两部分组成。

布隆过滤器使用exists(.来判断某个元素是否存在于自身结构中。当布隆过滤器判定某个值存在时,其实这个值只是有可能存在;当它说某个值不存在时,那这个值肯定不存在,这个误判概率大约在 1% 左右。

15.2.1 工作流程-添加元素

布隆过滤器主要由位数组和一系列 hash 函数构成,其中位数组的初始状态都为 0。

下面对布隆过滤器工作流程做简单描述,如下图所示:

![Redis布隆过滤器](http://c.biancheng.net/uploads/allimg/210913/152TA292-0.gif.
图1:布隆过滤器原理

当使用布隆过滤器添加 key 时,会使用不同的 hash 函数对 key 存储的元素值进行哈希计算,从而会得到多个哈希值。根据哈希值计算出一个整数索引值,将该索引值与位数组长度做取余运算,最终得到一个位数组位置,并将该位置的值变为 1。每个 hash 函数都会计算出一个不同的位置,然后把数组中与之对应的位置变为 1。通过上述过程就完成了元素添加(add.操作。

15.2.2 工作流程-判定元素是否存在

当我们需要判断一个元素是否存时,其流程如下:首先对给定元素再次执行哈希计算,得到与添加元素时相同的位数组位置,判断所得位置是否都为 1,如果其中有一个为 0,那么说明元素不存在,若都为 1,则说明元素有可能存在。

15.2.3 为什么是可能“存在”

您可能会问,为什么是有可能存在?其实原因很简单,那些被置为 1 的位置也可能是由于其他元素的操作而改变的。比如,元素1 和 元素2,这两个元素同时将一个位置变为了 1(图1所示)。在这种情况下,我们就不能判定“元素 1”一定存在,这是布隆过滤器存在误判的根本原因。

15.3 安装与使用

在 Redis 4.0 版本之后,布隆过滤器才作为插件被正式使用。布隆过滤器需要单独安装,下面介绍安装 RedisBloom 的几种方法:

15.3.1 docker安装

docker 安装布隆过滤器是最简单.快捷的一种方式:

docker pull redislabs/rebloom:latest
docker run -p 6379:6379 --name redis-redisbloom redislabs/rebloom:latest
docker exec -it redis-redisbloom bash
redis-cli
#测试是否安装成功
127.0.0.1:6379> bf.add www.biancheng.net hello
15.3.2 直接编译安装

如果您对 docker 不熟悉,也可以采用直接编译的方式来安装。

下载地址:
https://github.com/RedisBloom/RedisBloom
解压文件:
unzip RedisBloom-master.zip
进入目录:
cd RedisBloom-master
执行编译命令,生成redisbloom.so 文件:
make
拷贝至指定目录:
cp redisbloom.so /usr/local/redis/bin/redisbloom.so
在redis配置文件里加入以下配置:
loadmodule /usr/local/redis/bin/redisbloom.so
配置完成后重启redis服务:
sudo /etc/init.d/redis-server restart
#测试是否安装成功
127.0.0.1:6379> bf.add www.biancheng.net hello

15.4 常用命令汇总

命令说明
bf.add只能添加元素到布隆过滤器。
bf.exists判断某个元素是否在于布隆过滤器中。
bf.madd同时添加多个元素到布隆过滤器。
bf.mexists同时判断多个元素是否存在于布隆过滤器中。
bf.reserve以自定义的方式设置布隆过滤器参数值,共有 3 个参数分别是 key、error_rate(错误率)、initial_size(初始大小)。
15.4.1 命令应用
127.0.0.1:6379> bf.add spider:url www.biancheng.net
(integer. 1
127.0.0.1:6379> bf.exists spider:url www.biancheng.net
(integer. 1
127.0.0.1:6379> bf.madd spider:url www.taobao.com www.123qq.com
1. (integer. 1
2. (integer. 1
127.0.0.1:6379> bf.mexists spider:url www.jd.com www.taobao.com
1. (integer. 0
2. (integer. 1
15.4.2 解决错误率过高的问题

错误率越低,所需要的空间也会越大,因此就需要我们尽可能精确的估算元素数量,避免空间的浪费。我们也要根据具体的业务来确定错误率的许可范围,对于不需要太精确的业务场景,错误率稍微设置大一点也可以。

注意:如果要使用自定义的布隆过滤器需要在 add 操作之前,使用 bf.reserve 命令显式地创建 key,格式如下:

client.execute_command("bf.reserve", "keyname", 0.001, 50000.

布隆过滤器相比于平时常用的的列表.散列.集合等数据结构,其占用空间更少.效率更高,但缺点就是返回的结果具有概率性,并不是很准确。在理论情况下,添加的元素越多,误报的可能性就越大。再者,存放于布隆过滤器中的元素不容易被删除,因为可能出现会误删其他元素情况。

16 Redis Transaction事务

Redis 事务的目的是方便用户一次执行多个命令。执行 Redis 事务可分为三个阶段:

  • 开始事务
  • 命令入队
  • 执行事务

16.1 Redis事务特性

Redis 事务具有两个重要特性:

16.1.1 单独的隔离操作

事务中的所有命令都会被序列化,它们将按照顺序执行,并且在执行过的程中,不会被其他客户端发送来的命令打断。

16.1.2 不保证原子性

在 Redis 的事务中,如果存在命令执行失败的情况,那么其他命令依然会被执行,不支持事务回滚机制。

注意:Redis 不支持事务回滚,原因在于 Redis 是一款基于内存的存储系统,其内部结构比较简单,若支持回滚机制,则让其变得冗余,并且损耗性能,这与 Redis 简单.快速的理念不相符合。

16.2 Redis事务命令

命令说明
MULTI开启一个事务
EXEC执行事务中的所有命令
WATCH key [key …]在开启事务之前用来监视一个或多个key 。如果事务执行时这些 key 被改动过,那么事务将被打断。
DISCARD取消事务。
UNWATCH取消 WATCH 命令对 key 的监控。

16.3 Redis事务应用

您可以把事务可以理解为一个批量执行 Redis 命令的脚本,但这个操作并非原子性操作,也就是说,如果中间某条命令执行失败,并不会导致前面已执行命令的回滚,同时不会中断后续命令的执行(不包含监听 key 的情况)。示例如下:

开启事务
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCR 1
QUEUED #命令入队成功
127.0.0.1:6379> SET num 10
QUEUED
#批量执行命令
127.0.0.1:6379> EXEC
1. (integer. 1
2. OK

若您在事务开启之前监听了某个 key,那么您不应该在事务中尝试修改它,否则会导致事务中断。

开启事务之前设置key/value,并监听
127.0.0.1:6379> set www.biancheng.net hello
OK
127.0.0.1:6379> WATCH www.biancheng.net
OK
127.0.0.1:6379> get www.biancheng.net
"hello"
#开启事务
127.0.0.1:6379> MULTI
OK
#更改key的value值
127.0.0.1:6379> set www.biancheng.net HELLO
QUEUED
127.0.0.1:6379> GET www.biancheng.net
QUEUED
#命令执行失败
127.0.0.1:6379> EXEC
(error. EXECABORT Transaction discarded because of previous errors.
#取消监听key
127.0.0.1:6379> UNWATCH 
OK 

17 Redis Benchmark性能测试

为了解 Redis 在不同配置环境下的性能表现,Redis 提供了一种行性能测试工具 redis-benchmark(也称压力测试工具),它通过同时执行多组命令实现对 Redis 的性能测试。

性能测试的作用是让我们了解 Redis 服务器的性能优劣。在实际的业务场景中,性能测试是必不可少的。在业务系统上线之前,我们都需要清楚地了解 Redis 服务器的性能,从而避免发生某些意外情况,比如数据量过大会导致服务器宕机等。

17.1 测试命令格式

执行测试命令,要在 Redis 的安装目录下执行,命令如下所示:

redis-benchmark [option] [option value]

其中 option 为可选参数, option value 为具体的参数值。 redis-benchmark 命令的可选参数如下所示:

参数选项说明
-h指定服务器主机名。
-p指定服务器端口。
-s指定服务器 socket。
-c指定并发连接数。
-n指定请求的具体数量。
-d以字节的形式指定 SET/GET 值的数据大小。
-k1 表示 keep alive;0 表示 reconnect,默认为 1。
-rSET/GET/INCR 使用随机 key, SADD 使用随机值。
-PPipeline 请求
-q强制退出 Redis,仅显示 query/sec 值。
–csv以 CSV 格式输出。
-l生成循环,永久执行测试。
-t仅运行以逗号分隔的测试命令列表。
-I(大写i)空闲模式,打开 N 个空闲连接并等待连接。

在 Windows 系统下,其目录文件如图所示:

![Redis压力测试](http://c.biancheng.net/uploads/allimg/210913/15411J018-0.png.
图1:Redis Benchmark性能测试

17.2 执行测试命令

17.2.1 Windows环境

在 Windows 10 系统环境下,同时执行了 10000 个命令来检测 Redis 服务器的性能,示例如下:

D:\Redis-x64-5.0.10>redis-benchmark.exe -n 10000 -q
PING_INLINE: 21786.49 requests per second
PING_BULK: 21231.42 requests per second
#每秒执行22935.78个请求
SET: 22935.78 requests per second
GET: 22573.36 requests per second
INCR: 19011.41 requests per second
LPUSH: 7473.84 requests per second
RPUSH: 20618.56 requests per second
LPOP: 17793.60 requests per second
RPOP: 21367.52 requests per second
SADD: 15847.86 requests per second
HSET: 21551.72 requests per second
SPOP: 19531.25 requests per second
LPUSH (needed to benchmark LRANGE.: 18348.62 requests per second
LRANGE_100 (first 100 elements.: 6835.27 requests per second
LRANGE_300 (first 300 elements.: 4535.15 requests per second
LRANGE_500 (first 450 elements.: 3913.89 requests per second
LRANGE_600 (first 600 elements.: 3177.63 requests per second
MSET (10 keys.: 15128.59 requests per second

注意:若是 Linux 系统,其每秒钟执行的请求数量是 Windows 系统的好几倍。

17.2.2 Linux环境

Linux 环境下,Redis 的性能测试结果,如下所示:

$ redis-benchmark -n 10000  -q
PING_INLINE: 141043.72 requests per second
PING_BULK: 142857.14 requests per second
#服务器每秒执行的请求数量
SET: 141442.72 requests per second
GET: 145348.83 requests per second
INCR: 137362.64 requests per second
LPUSH: 145348.83 requests per second
LPOP: 146198.83 requests per second
SADD: 146198.83 requests per second
SPOP: 149253.73 requests per second
LPUSH (needed to benchmark LRANGE.: 148588.42 requests per second
LRANGE_100 (first 100 elements.: 58411.21 requests per second
LRANGE_300 (first 300 elements.: 21195.42 requests per second
LRANGE_500 (first 450 elements.: 14539.11 requests per second
LRANGE_600 (first 600 elements.: 10504.20 requests per second
MSET (10 keys.: 93283.58 requests per second
17.2.3 执行指定的测试命令

带参数的命令,使用示例如下:

D:\Redis-x64-5.0.10>redis-benchmark.exe -h 127.0.0.1 -p 6379 -n 10000 -t set,get,lpush -q
SET: 17064.85 requests per second
GET: 16051.36 requests per second
LPUSH: 14224.75 requests per second

18.Redis分区技术

Redis 分区技术(又称 Redis Partition)指的是将 Redis 中的数据进行拆分,然后把拆分后的数据分散到多个不同的 Redis 实例(即服务器)中,每个实例仅存储数据集的某一部分(一个子集),我们把这个过程称之为 Redis 分区操作。

Redis 实例指的是一台安装了 Redis 服务器的计算机。

18.1 分区常用方法

分区技术有两种常用方法,分别是“范围分区”和“哈希分区”

18.1.1 范围分区

范围分区是最简单.最有效的分区方法之一。所谓范围分区指的是将特定范围的 key 映射到指定的 Redis 实例上。key 的命名格式如下:

object_name:<id>

比如:user:1.user:2 …用来表示不同 id 的用户。下面通过一个示例了解范围分区的具体流程:

假设现在共有 3000 个用户,您可以把 id 从 0 到 1000 的用户映射到实例 R0 上,id 从 1001 到 2000 的用户映射到实例 R1 上,以此类推,将 id 从 2001 到 3000 的用户映射到实例 R2 上。

范围分区不仅简单,而且实用,适合许多的特定场景。但当存储的 key 不能按照范围划分时,那么范围分区就不再适用了,比如 key 是一组 uuid(通用唯一识别码)。如下所示:

9eb4d81b-31ec-4c69-a721-c7e1771413dd

此时范围分区就不再适用,就要用到另外一种分区方式——哈希分区。

18.1.2 哈希分区

哈希分区与范围分区相比,它最显著的优势是适合任何形式的 key。哈希分区方法并不复杂比,id 表达式如下所示:

id=hash(key.%N

这里的 id 指的是 Redis 实例的编号,而 N 表示共有多少个 Redis 实例。

首先调用一个 crc32(. 哈希函数,它可以将 key 转换为一个整数。 如下所示:

crc32(key.

假如转换后的整数是 93024922,此时共有 4 个 Redis 实例,对整数与实例的数量进行取模运算,就会得到一个 0 到 3 之间的整数,如下所示:

93024922 % 4 = 2

上述计算结果为 2 ,我们就把这个 key 映射到 R2 实例中,如果为 3 就映射到 R3实例中。以此类推,通过这种方式可以将所有的 key 分散到 4 个不同的 Redis 实例中。

18.2 分区技术的不足

虽然 Redis 分区技术有诸多优势,但是它也存在一些不足之处。下面做简单介绍:

  • 涉及操作多个 key 时,通常不被支持。这是由于批量操作的 key 会被映射到不同的 Redis 实例中,此时无法实现在一个实例中操作分散开的 key;
  • 不支持包含多个 key 的 Redis 事务;
  • 当使用分区的时候,数据的处理变的非常复杂,比如需要处理多个 .rdb 或者 .aof 存储文件,并且还需要从多个 Redis 实例中备份数据;
  • 添加.删除实例变的复杂,比如 Redis 集群支持在运行时增加或减少实例,分区技术不支持这种功能。

18.3 分区技术问题解决

我们知道,应用 Redis 分区技术时存在一些不足之处,比如在增加.删除 Redis 实例时会非常麻烦,但这种情况在实际应用中经常遇到。比如今天需要删除 10 台 Redis 实例,明天又要增加 20 台实例。那么对于这种问题,有没有一种较好的解决办法呢?下面进行简单介绍:

其实 Redis 是一种很轻量级的服务(每个实例仅占用 1 MB),针对它的这种特性,我们提出以下解决办法:

在一台机器上开启多个 Redis 实例,您可以从中选择一定数量的实例作为 Redis 工作集群。当集群中某一台机器存储不足时,您可以将一部分 Redis 实例移动到另外一台机器上,依次类推。这样就保证了 Redis 的实例总数不变,又达到了增加机器的目的。

19 Redis Pipeline管道技术

我们知道, Redis 服务器是以单线程的方式来处理客户端的网络 IO 请求的。如果每执行一次请求都要创建和断开一次连接,就会消耗过多的时间,导致执行效率降低。因此 Redis 提供了 Pipeline(管道技术),使用该技术可以一次性向服务器发送多条命令,并返回多个执行结果。这样就节省了发送命令和创建连接的时间,从而提高了执行效率。

注意:你需要在 Liunx 系统上使用 Pipeline 管道技术。

19.1.执行Pipeline语句

Pipeline 技术有其固定的语法格式,以下是在 Linux 终端执行的语句,具体命令如下:

(echo -en "PING\r\n SET name www.biancheng\r\n GET name\r\n INCR num\r\n INCR num\r\n INCR num\r\n"; sleep 2.|nc localhost 6379

上述语句,首先使用 PING 命令检查 Redis 是否正常工作,然后又分别使用了 SET/GET/INCR 命令,以及 sleep 阻塞 2 秒,最后将这些命令一次性的提交给 Redis 服务器,Redis 服务器在阻塞了 2 秒之后,一次性输出了所有命令的响应信息。

注意: 每个命令字符串必须以 \r\n 结尾。至于语句最后的 nc localhost 6379 是固定格式无需更改。

客户端一次性接收到所有命令的执行结果,如下所示:

$(echo -en "PING\r\n SET name www.biancheng\r\n GET name\r\n INCR num\r\n INCR num\r\n INCR num\r\n"; sleep 2.|nc localhost 6379
+PONG
+OK
www.bianchneg.net
:1
:2
:3 

注意:上述示例需要在 Linux 系统执行,Windows 由于缺少nc命令,无法执行成功。

20 Redis数据备份和还原

Redis SAVE 命令用于创建当前数据库的备份文件,文件名默认为dump.rdb。备份数据库数据可以增强对数据的保护,提升数据的安全性。当数据不小心丢失或者被删除时,我们就可以通过相应的操作进行数据恢复。

20.1 备份数据

SAVE 命令基本语法如下:

redis 127.0.0.1:6379> SAVE

执行备份命令:

redis 127.0.0.1:6379> SAVE
OK

注意:命令执行后,将在 Redis 安装目录中自动创建dump.rdb文件。如下图所示:

20.2 恢复数据

如果您想恢复数据,只需将备份文件 dump.rdb 移动到 Redis 安装目录下,然后重启 Redis 服务器,即可进行数据还原。

下面使用CONFIG命令获取 Redis 安装目录,如下所示:

127.0.0.1:6379> CONFIG GET dir
1. "dir"
2. "D:\\Redis-x64-5.0.10"

从上述命令可以得知 Redis 的安装目录为 D:\Redis-x64-5.0.10。

20.3 后台备份数据命令

Redis 还提供了一个BGSAVE命令,同样也可以创建 Redis 备份文件,它与SAVE命令的不同之处在于,该命令在后台运行。示例演示:

127.0.0.1:6379> BGSAVE
Background saving started

21 Redis RDB持久化

Redis 提供了两种持久化机制:第一种是 RDB,又称快照(snapshot)模式,第二种是 AOF 日志,也就追加模式。本节先讲解 RDB 快照模式

21.1 RDB快照模式原理

RDB 即快照模式,它是 Redis 默认的数据持久化方式,它会将数据库的快照保存在 dump.rdb 这个二进制文件中。

提示:所谓“快照”就是将内存数据以二进制文件的形式保存起来。

我们知道 Redis 是单线程的,也就说一个线程要同时负责多个客户端套接字的并发读写,以及内存数据结构的逻辑读写。

Redis 服务器不仅需要服务线上请求,同时还要备份内存快照。在备份过程中 Redis 必须进行文件 IO 读写,而 IO 操作会严重服务器的性能。那么如何实现既不影响客户端的请求,又实现快照备份操作呢,这时就用到了多进程。

Redis 使用操作系统的多进程 COW(Copy On Write. 机制来实现快照持久化操作。

RDB 实际上是 Redis 内部的一个定时器事件,它每隔一段固定时间就去检查当前数据发生改变的次数和改变的时间频率,看它们是否满足配置文件中规定的持久化触发条件。当满足条件时,Redis 就会通过操作系统调用 fork(. 来创建一个子进程,该子进程与父进程享有相同的地址空间。

Redis 通过子进程遍历整个内存空间来获取存储的数据,从而完成数据持久化操作。注意,此时的主进程则仍然可以对外提供服务,父子进程之间通过操作系统的 COW 机制实现了数据段分离,从而保证了父子进程之间互不影响。

21.2 RDB持久化触发策略

RDB 持久化提供了两种触发策略:一种是手动触发,另一种是自动触发。

21.2.1 手动触发策略

手动触发是通过SAVAE命令或者BGSAVE命令将内存数据保存到磁盘文件中。如下所示:

127.0.0.1:6379> SAVE
OK
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379>  LASTSAVE
(integer. 1611298430

上述命令BGSAVE从后台执行数据保存操作,其可用性要优于执行 SAVE 命令。

SAVE 命令会阻塞 Redis 服务器进程,直到 dump.rdb 文件创建完毕为止,在这个过程中,服务器不能处理任何的命令请求。

BGSAVE命令是非阻塞式的,所谓非阻塞式,指的是在该命令执行的过程中,并不影响 Redis 服务器处理客户端的其他请求。这是因为 Redis 服务器会 fork(. 一个子进程来进行持久化操作(比如创建新的 dunp.rdb 文件),而父进程则继续处理客户端请求。当子进程处理完后会向父进程发送一个信号,通知它已经处理完毕。此时,父进程会用新的 dump.rdb 文件覆盖掉原来的旧文件。

因为SAVE命令无需创建子进程,所以执行速度要略快于BGSAVE命令,但是SAVE命令是阻塞式的,因此其可用性欠佳,如果在数据量较少的情况下,基本上体会不到两个命令的差别,不过仍然建议您使用 BGSAVE命令。

注意:LASTSAVE 命令用于查看 BGSAVE 命令是否执行成功。

21.2.2 自动触发策略

自动触发策略,是指 Redis 在指定的时间内,数据发生了多少次变化时,会自动执行BGSAVE命令。自动触发的条件包含在了 Redis 的配置文件中,

  • save 900 1 表示在 900 秒内,至少更新了 1 条数据,Redis 自动触发 BGSAVE 命令,将数据保存到硬盘。
  • save 300 10 表示在 300 秒内,至少更新了 10 条数据,Redis 自动触 BGSAVE 命令,将数据保存到硬盘。
  • save 60 10000 表示 60 秒内,至少更新了 10000 条数据,Redis 自动触发 BGSAVE 命令,将数据保存到硬盘。

只要上述三个条件任意满足一个,服务器就会自动执行BGSAVE命令。当然您可以根据实际情况自己调整触发策略。

21.3 RDB持久化优劣势

最后我们对 RDB 持久化的优劣势做简单地分析:

我们知道,在 RDB 持久化的过程中,子进程会把 Redis 的所有数据都保存到新建的 dump.rdb 文件中,这是一个既消耗资源又浪费时间的操作。因此 Redis 服务器不能过于频繁地创建 rdb 文件,否则会严重影响服务器的性能。

RDB 持久化的最大不足之处在于,最后一次持久化的数据可能会出现丢失的情况。我们可以这样理解,在 持久化进行过程中,服务器突然宕机了,这时存储的数据可能并不完整,比如子进程已经生成了 rdb 文件,但是主进程还没来得及用它覆盖掉原来的旧 rdb 文件,这样就把最后一次持久化的数据丢失了。

RDB 数据持久化适合于大规模的数据恢复,并且还原速度快,如果对数据的完整性不是特别敏感(可能存在最后一次丢失的情况),那么 RDB 持久化方式非常合适。

22 Redis AOF持久化

AOF 被称为追加模式,或日志模式,是 Redis 提供的另一种持久化策略,它能够存储 Redis 服务器已经执行过的的命令,并且只记录对内存有过修改的命令,这种数据记录方法,被叫做“增量复制”,其默认存储文件为appendonly.aof

22.1 开启AOF持久化

AOF 机制默认处于未开启状态,可以通过修改 Redis 配置文件开启 AOF,如下所示:

22.1.1 Windows系统

执行如下操作:

#修改配置文件,把no改为 yes
appendonly yes
#确定存储文件名是否正确
appendfilename "appendonly.aof"
#重启服务器
redis-server --service-stop
redis-server --service-start
22.1.2 Linux系统

执行如下操作:

#修改配置文件:
vim /etc/redis/redis.conf
appendonly yes # 把 no 改为 yes
#确定存储文件名是否正确
appendfilename "appendonly.aof"
#重启服务:
sudo /etc/init.d/redis-server restart

提示:本节建议在您在 Linux 系统上操作 Redis,否则一些 AOF 的性能无法体现。

22.2 AOF持久化机制

每当有一个修改数据库的命令被执行时,服务器就将命令写入到 appendonly.aof 文件中,该文件存储了服务器执行过的所有修改命令,因此,只要服务器重新执行一次 .aof 文件,就可以实现还原数据的目的,这个过程被形象地称之为“命令重演”。

22.2.1.写入机制

Redis 在收到客户端修改命令后,先进行相应的校验,如果没问题,就立即将该命令存追加到 .aof 文件中,也就是先存到磁盘中,然后服务器再执行命令。这样就算遇到了突发的宕机情况情况,也只需将存储到 .aof 文件中的命令,进行一次“命令重演”就可以恢复到宕机前的状态。

在上述执行过程中,有一个很重要的环节就是命令的写入,这是一个 IO 操作。Redis 为了提升写入效率,它不会将内容直接写入到磁盘中,而是将其放到一个内存缓存区(buffer)中,等到缓存区被填满时才真正将缓存区中的内容写入到磁盘里。

22.2.2.重写机制

Redis 在长期运行的过程中,aof 文件会越变越长。如果机器宕机重启,“重演”整个 aof 文件会非常耗时,导致长时间 Redis 无法对外提供服务。因此就需要对 aof 文件做一下“瘦身”运动。

为了让 aof 文件的大小控制在合理的范围内,Redis 提供了 AOF 重写机制,手动执行BGREWRITEAOF命令,开始重写 aof 文件,如下所示:

127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started

通过上述操作后,服务器会生成一个新的 aof 文件,该文件具有以下特点:

  • 新的 aof 文件记录的数据库数据和原 aof 文件记录的数据库数据完全一致;
  • 新的 aof 文件会使用尽可能少的命令来记录数据库数据,因此新的 aof 文件的体积会小很多;
  • AOF 重写期间,服务器不会被阻塞,它可以正常处理客户端发送的命令。

下表对原有 aof 文件和新生成的 aof 文件做了对比,如下所示:

原有aof文件重写后aof文件
select 0SELECT 0
sadd myset JackSADD myset Jack Helen JJ Lisa
sadd myset HelenSET msg ‘hello tarena’
sadd myset JJRPUSH num 4 6 8
sadd myset Lisa
INCR number
INCR number
DEL number
SET message ‘www.baidu.com’
SET message ‘www.biancheng.net’
RPUSH num 2 4 6
RPUSH num 8
LPOP num

从上表可以看出,新生成的 aof 文件中,它的命令格式做了很大程度的简化。

22.2.3.自动触发AOF重写

Redis 为自动触发 AOF 重写功能,提供了相应的配置策略。如下所示:修改 Redis 配置文件,让服务器自动执行 BGREWRITEAOF 命令。

#默认配置项
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb #表示触发AOF重写的最小文件体积,大于或等于64MB自动触发。

该配置项表示:触发重写所需要的 aof 文件体积百分比,只有当 aof 文件的增量大于 100% 时才进行重写,也就是大一倍。比如,第一次重写时文件大小为 64M,那么第二次触发重写的体积为 128M,第三次重写为 256M,以此类推。如果将百分比值设置为 0 就表示关闭 AOF 自动重写功能。

22.3 AOF策略配置

在上述介绍写入机制的过程中,如果遇到宕机前,缓存内的数据未能写入到磁盘中,那么数据仍然会有丢失的风险。服务器宕机时,丢失命令的数量,取决于命令被写入磁盘的时间,越早地把命令写入到磁盘中,发生意外时丢失的数据就会越少,否则越多。

Redis 为数据的安全性考虑,同样为 AOF 持久化提供了策略配置,打开 Redis 配置文件,如下图所示:

![Redis AOF持久化](http://c.biancheng.net/uploads/allimg/210913/1609113Z8-0.gif.
图1:AOF策略配置

上述配置策略说明如下:

  • Always:服务器每写入一个命令,就调用一次 fsync 函数,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,也不会丢失任何已经成功执行的命令数据,但是其执行速度较慢;
  • Everysec(默认):服务器每一秒调用一次 fsync 函数,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,最多只丢失一秒钟内的执行的命令数据,通常都使用它作为 AOF 配置策略;
  • No:服务器不主动调用 fsync 函数,由操作系统决定何时将缓冲区里面的命令写入到硬盘。这种模式下,服务器遭遇意外停机时,丢失命令的数量是不确定的,所以这种策略,不确定性较大,不安全。

注意:Linux 系统的 fsync(. 函数可以将指定文件的内容从内核缓存刷到硬盘中。

由于是 fsync 是磁盘 IO 操作,所以它很慢!如果 Redis 执行一条指令就要 fsync 一次(Always),那么 Redis 高性能将严重受到影响。

在生产环境的服务器中,Redis 通常是每隔 1s 左右执行一次 fsync 操作( Everysec),这样既保持了高性能,也让数据尽可能的少丢失。最后一种策略(No),让操作系统来决定何时将数据同步到磁盘,这种策略存在许多不确定性,所以不建议使用。

从三种策略的运行速度来看,Always 的速度最慢,而 Everysec 和 No 都很快。

22.4 AOF和RDB对比

RDB持久化AOF持久化
全量备份,一次保存整个数据库。增量备份,一次只保存一个修改数据库的命令。
每次执行持久化操作的间隔时间较长。保存的间隔默认为一秒钟(Everysec)
数据保存为二进制格式,其还原速度快。使用文本格式还原数据,所以数据还原速度一般。
执行 SAVE 命令时会阻塞服务器,但手动或者自动触发的 BGSAVE 不会阻塞服务器AOF持久化无论何时都不会阻塞服务器。

如果进行数据恢复时,既有 dump.rdb文件,又有 appendonly.aof 文件,您应该先通过 appendonly.aof 恢复数据,这能最大程度地保证数据的安全性。

23 Redis Cluster主从模式

在软件的架构中,主从模式(Master-Slave)是使用较多的一种架构。主(Master)和从(Slave)分别部署在不同的服务器上,当主节点服务器写入数据时,同时也会将数据同步至从节点服务器,通常情况下,主节点负责写入数据,而从节点负责读取数据。

23.1 主从模式解析

主从模式的结构图如下:

![Redis主从模式](http://c.biancheng.net/uploads/allimg/210913/16133214H-0.gif.
图1:Redis 主从模式

如图 1 所示,Redis 主机会一直将自己的数据复制给 Redis 从机,从而实现主从同步。在这个过程中,只有 master 主机可执行写命令,其他 salve 从机只能只能执行读命令,这种读写分离的模式可以大大减轻 Redis 主机的数据读取压力,从而提高了Redis 的效率,并同时提供了多个数据备份。主从模式是搭建 Redis Cluster 集群最简单的一种方式。

23.2 主从模式实现

Redis 提供了两种实现主从模式的方法,下面进行逐一介绍。为了方便演示,我们只从一台机器上搭建主从模式。

23.2.1 使用命令实现

使用命令在服务端搭建主从模式,其语法格式如下:

redis-server --port <slave-port> --slaveof <master-ip> <master-port>

执行以下命令:

#开启开启一个port为6300的从机,它依赖的主机port=6379
C:\Users\Administrator> redis-server --port 6300 --slaveof 127.0.0.1 6379

输出结果如下图:

![Redis主从模式](http://c.biancheng.net/uploads/allimg/210913/16133255M-1.gif.
图2:Redis 主从模式

接下来开启客户端,并执行查询命令,如下所示:

C:\Users\Administrator>redis-cli -p 6300
127.0.0.1:6300> get name
"jack"
127.0.0.1:6300> get website
"www.biancheng.net"
#不能执行写命令
127.0.0.1:6300> set myname BangDe
(error. READONLY You can't write against a read only slave.
127.0.0.1:6300> keys *
1. "myset:__rand_int__"
2. "ID"
3. "title"
4. "course2"
5. "website"
6. "age"
7. "user:2"
8. "salary"
9. "mystream"
10. "key:__rand_int__"
11. "user:uv:2021011308"
....

注意:此时 port=6300 的服务端界面不能关闭。从上述命令可以看出,port =6300 的从机,完全备份了主机的数据,它可以执行查询命令,但是不能执行写入命令。

如果你注意观察服务端的话,您会看到以下提示:

[18160] 20 Jan 17:40:34.101 # Server initialized #服务初始化
[18160] 20 Jan 17:40:34.108 * Ready to accept connections #准备连接
[18160] 20 Jan 17:40:34.108 * Connecting to MASTER 127.0.0.1:6379 #连接到主服务器
[18160] 20 Jan 17:40:34.109 * MASTER <-> REPLICA sync started #启动副本同步
[18160] 20 Jan 17:40:34.110 * Non blocking connect for SYNC fired the event.#自动触发SYNC命令,请求同步数据
[18160] 20 Jan 17:40:34.110 * Master replied to PING, replication can continue...
[18160] 20 Jan 17:40:34.112 * Partial resynchronization not possible (no cached master.
[18160] 20 Jan 17:40:34.431 * Full resync from master: 6eb220706f73107990c2b886dbc2c12a8d0d9d05:0
[18160] 20 Jan 17:40:34.857 * MASTER <-> REPLICA sync: receiving 6916 bytes from master #从主机接受了数据,并将其存在于磁盘
[18160] 20 Jan 17:40:34.874 * MASTER <-> REPLICA sync: Flushing old data #清空原有数据
[18160] 20 Jan 17:40:34.874 * MASTER <-> REPLICA sync: Loading DB in memory #将磁盘中数据载入内存
[18160] 20 Jan 17:40:34.879 * MASTER <-> REPLICA sync: Finished with success #同步数据完成

可以看出主从模式下,数据的同步是自动完成的,这个数据同步的过程,又称为全量复制。

您也可以使用下面的命令来创建主从模式。启动一个服务端,并指定端口号:

#指定端口号为63001,不要关闭
redis-server --port 63001

打开一个客户端,连接服务器,如下所示:

#连接port=63001的服务器
C:\Users\Administrator>redis-cli -p 63001
#现在处于主机模式下,所以允许读写数据
127.0.0.1:63001> keys *
1. "FANS"
2. "user:login"
3. "course2"
4. "1"
5. "age"
6. "ID"
7. "title"
8. "counter:__rand_int__"
9. "key:__rand_int__"
10. "user:3"
11. "user:2"
...
127.0.0.1:63001> set myname 123456
OK
#将当前服务器设置成从服务器,从属于6379
127.0.0.1:63001> SLAVEOF 127.0.0.1 6379
OK
#写入命令执行失败
127.0.0.1:63001> SET mywebsite www.biancheng.net
(error. READONLY You can't write against a read only replica.
#再次切换为主机模式,执行下面命令
127.0.0.1:63001> SLAVEOF no one
OK
#写入成功
127.0.0.1:63001> SET mywebsite www.biancheng.net
OK

上述示例中,主要使用了两个命令,如下所示:

slaveof IP PORT #设置从服务器
slaveof no one  #使服务器切换为独立主机
23.2.2 修改配置文件实现

每个 Redis 服务器都有一个与其对应的配置文件,通过修改该配置文件也可以实现主从模式,下面在 Ubuntu 环境下对该方法进行演练。

新建 redis_6302.conf 文件,并添加以下配置信息:

slaveof 127.0.0.1 6379 #指定主机的ip与port
port 6302 #指定从机的端口

启动 Redis 服务器,执行以下命令:

$ redis-server redis_6302.conf

客户端连接服务器,并进行简单测试。执行以下命令:

$ redis-cli -p 6302
127.0.0.1:6300> HSET user:username biangcheng
#写入失败
(error. READONLY You can't write against a read only slave.

提示:通过命令搭建主从模式,简单又快捷,所以不建议您使用修改配置文件的方法。

23.3 主从模式不足

主从模式并不完美,它也存在许多不足之处,下面做了简单地总结:

  • 1. Redis 主从模式不具备自动容错和恢复功能,如果主节点宕机,Redis 集群将无法工作,此时需要人为干预,将从节点提升为主节点。
  • 2. 如果主机宕机前有一部分数据未能及时同步到从机,即使切换主机后也会造成数据不一致的问题,从而降低了系统的可用性。
  • 3. 因为只有一个主节点,所以其写入能力和存储能力都受到一定程度地限制。
  • 4. 在进行数据全量同步时,若同步的数据量较大可能会造卡顿的现象。

24 Redis集群Sentinel哨兵模式

在 Redis 主从复制模式中,因为系统不具备自动恢复的功能,所以当主服务器(master)宕机后,需要手动把一台从服务器(slave)切换为主服务器。在这个过程中,不仅需要人为干预,而且还会造成一段时间内服务器处于不可用状态,同时数据安全性也得不到保障,因此主从模式的可用性较低,不适用于线上生产环境。

Redis 官方推荐一种高可用方案,也就是 Redis Sentinel 哨兵模式,它弥补了主从模式的不足。Sentinel 通过监控的方式获取主机的工作状态是否正常,当主机发生故障时, Sentinel 会自动进行 Failover(即故障转移),并将其监控的从机提升主服务器(master),从而保证了系统的高可用性。

24.1 哨兵模式原理

哨兵模式是一种特殊的模式,Redis 为其提供了专属的哨兵命令,它是一个独立的进程,能够独立运行。下面使用 Sentinel 搭建 Redis 集群,基本结构图如下所示:

![哨兵模式](http://c.biancheng.net/uploads/allimg/210913/1K00M955-0.gif.
图1:哨兵基本模式

在上图过程中,哨兵主要有两个重要作用:

  • 第一:哨兵节点会以每秒一次的频率对每个 Redis 节点发送PING命令,并通过 Redis 节点的回复来判断其运行状态。
  • 第二:当哨兵监测到主服务器发生故障时,会自动在从节点中选择一台将机器,并其提升为主服务器,然后使用 PubSub 发布订阅模式,通知其他的从节点,修改配置文件,跟随新的主服务器。

在实际生产情况中,Redis Sentinel 是集群的高可用的保障,为避免 Sentinel 发生意外,它一般是由 3~5 个节点组成,这样就算挂了个别节点,该集群仍然可以正常运转。其结构图如下所示:

![Redis哨兵模式](http://c.biancheng.net/uploads/allimg/210913/1K00HQ5-1.gif.
图2:多哨兵模式

上图所示,多个哨兵之间也存在互相监控,这就形成了多哨兵模式,现在对该模式的工作过程进行讲解,介绍如下:

24.1.1 主观下线

主观下线,适用于主服务器和从服务器。如果在规定的时间内(配置参数:down-after-milliseconds.,Sentinel 节点没有收到目标服务器的有效回复,则判定该服务器为“主观下线”。比如 Sentinel1 向主服务发送了PING命令,在规定时间内没收到主服务器PONG回复,则 Sentinel1 判定主服务器为“主观下线”。

24.1.2 客观下线

客观下线,只适用于主服务器。 Sentinel1 发现主服务器出现了故障,它会通过相应的命令,询问其它 Sentinel 节点对主服务器的状态判断。如果超过半数以上的 Sentinel 节点认为主服务器 down 掉,则 Sentinel1 节点判定主服务为“客观下线”。

24.1.3 投票选举

投票选举,所有 Sentinel 节点会通过投票机制,按照谁发现谁去处理的原则,选举 Sentinel1 为领头节点去做 Failover(故障转移)操作。Sentinel1 节点则按照一定的规则在所有从节点中选择一个最优的作为主服务器,然后通过发布订功能通知其余的从节点(slave)更改配置文件,跟随新上任的主服务器(master)。至此就完成了主从切换的操作。

对上对述过程做简单总结:

Sentinel 负责监控主从节点的“健康”状态。当主节点挂掉时,自动选择一个最优的从节点切换为主节点。客户端来连接 Redis 集群时,会首先连接 Sentinel,通过 Sentinel 来查询主节点的地址,然后再去连接主节点进行数据交互。当主节点发生故障时,客户端会重新向 Sentinel 要地址,Sentinel 会将最新的主节点地址告诉客户端。因此应用程序无需重启即可自动完成主从节点切换。

24.2 哨兵模式应用

Redis Sentinel 哨兵模式适合于在 Linux 系统中使用,所以下面的应用都基于 Ubuntu 实现。

24.2.1 安装sentinel

Sentinel 需要作为插件单独安装,安装方式如下:

sudo apt install redis-sentinel
24.2.2 搭建主从模式

接下来,在本地环境使用主从模式搭建一个拥有三台服务器的 Redis 集群,命令如下所示:

启动6379的redis服务器作为master主机:
sudo /etc/init.d/redis-server start启动6380的redis服务器,设置为6379的slave:
redis-server --port 6380
$ redis-cli -p 6380
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK启动6381的redis服务器,设置为6379的salve
redis-server --port 6381
$ redis-cli -p 6381
127.0.0.1:6381> slaveof 127.0.0.1 6379
24.2.3 配置sentinel哨兵

首先新建 sentinel.conf 文件,并对其进行配置,如下所示:

port 26379
Sentinel monitor biancheng 127.0.0.1 6379 1

配置文件说明如下:

port 26379 #sentinel监听端口,默认是26379,可以更改
sentinel monitor <master-name> <ip> <redis-port> <quorum>

第二个配置项表示:让 sentinel 去监控一个地址为 ip:port 的主服务器,这里的 master-name 可以自定义; 是一个数字,表示当有多少个 sentinel 认为主服务器宕机时,它才算真正的宕机掉,通常数量为半数或半数以上才会认为主机已经宕机, 需要根据 sentinel 的数量设置。

24.2.4 启动sentienl哨兵
方式一: 
redis-sentinel sentinel.conf
方式二: 
redis-server sentinel.conf --sentinel
24.2.5 停止主服务器服务

下面模拟主服务意外宕机的情况,首先直接将主服务器的 Redis 服务终止,然后查看从服务器是否被提升为了主服务器。执行以下命令:

#终止master的redis服务
sudo /etc/init.d/redis-server stop

执行完上述命令,您会发现 6381 称为了新的 master,而其余节点变成了它的从机,执行命令验证:

127.0.0.1:6381> set webname www.biancheng.net
OK

哨兵的配置文件 sentinel.conf 也发生了变化:

#port 26379
#sentinel myid 4c626b6ff25dca5e757afdae2bd26a881a61a2b2
# Generated by CONFIG REWRITE
dir "/home/biancheng"
maxclients 4064
sentinel myid 4c626b6ff25dca5e757afdae2bd26a881a61a2b2
sentinel monitor biancheng 127.0.0.1 6379 1
sentinel config-epoch biancheng 2
sentinel leader-epoch biancheng 2
sentinel known-slave biancheng 127.0.0.1 6379
sentinel known-slave biancheng 127.0.0.1 6380
sentinel known-slave biancheng 127.0.0.1 6381
port 26379
sentinel current-epoch 2

如果您想开启多个哨兵,只需配置要多个 sentinel.conf 文件即可,一个配置文件开启一个。

24.3 sentinel.conf配置项

下面对 Sentinel 配置文件的其他配置项做简单说明:

配置项参数类型说明
dir文件目录哨兵进程服务的文件存放目录,默认为 /tmp。
port端口号启动哨兵的进程端口号,默认为 26379。
sentinel down-after-milliseconds<服务名称><毫秒数(整数)>在指定的毫秒数内,若主节点没有应答哨兵的 PING 命令,此时哨兵认为服务器主观下线,默认时间为 30 秒。
sentinel parallel-syncs<服务名称><服务器数(整数)>指定可以有多少个 Redis 服务同步新的主机,一般而言,这个数字越小同步时间越长,而越大,则对网络资源要求就越高。
sentinel failover-timeout<服务名称><毫秒数(整数)>指定故障转移允许的毫秒数,若超过这个时间,就认为故障转移执行失败,默认为 3 分钟。
sentinel notification-script<服务名称><脚本路径>脚本通知,配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
sentinel auth-pass <服务器名称><密码>若主服务器设置了密码,则哨兵必须也配置密码,否则哨兵无法对主从服务器进行监控。该密码与主服务器密码相同。

25 Redis分布式锁应用

在分布式系统中,当不同进程或线程一起访问共享资源时,会造成资源争抢,如果不加以控制的话,就会引发程序错乱。此时使用分布式锁能够非常有效的解决这个问题,它采用了一种互斥机制来防止线程或进程间相互干扰,从而保证了数据的一致性。

提示:如果对分布式系统这一概念不清楚,可参考百度百科《[分布式系统](https://baike.baidu.com/item/分布式系统/4905336?fr=aladdin.》,简而言之,它是一种架构.一种模式。

25.1 Redis分布式锁介绍

分布式锁并非是 Redis 独有,比如 MySQL 关系型数据库,以及 Zookeeper 分布式服务应用,它们都实现分布式锁,只不过 Redis 是基于缓存实现的。

Redis 分布式锁有很对应用场景,举个简单的例子,比如春运时,您需要在 12306 上抢购回家火车票,但 Redis 数据库中只剩一张票了,此时有多个用户来预订购买,那么这张票会被谁抢走呢?Redis 服务器又是如何处理这种情景的呢?在这个过程中就需要使用分布式锁。

Redis 分布式锁主要有以下特点:

  • 第一:互斥性是分布式锁的重要特点,在任意时刻,只有一个线程能够持有锁;
  • 第二:锁的超时时间,一个线程在持锁期间挂掉了而没主动释放锁,此时通过超时时间来保证该线程在超时后可以释放锁,这样其他线程才可以继续获取锁;
  • 第三:加锁和解锁必须是由同一个线程来设置;
  • 第四:Redis 是缓存型数据库,拥有很高的性能,因此加锁和释放锁开销较小,并且能够很轻易地实现分布式锁。

注意:一个线程代表一个客户端。

25.2 Redis分布式锁命令

分布式锁的本质其实就是要在 Redis 里面占一个“坑”,当别的进程也要来占时,发现已经有人蹲了,就只好放弃或者稍做等待。这个“坑”同一时刻只允许被一个客户端占据,也就是本着“先来先占”的原则。

25.2.1 常用命令

Redis 分布式锁常用命令如下所示:

  • SETNX key val:仅当key不存在时,设置一个 key 为 value 的字符串,返回1;若 key 存在,设置失败,返回 0;
  • Expire key timeout:为 key 设置一个超时时间,以 second 秒为单位,超过这个时间锁会自动释放,避免死锁;
  • DEL key:删除 key。

上述 SETNX 命令相当于占“坑”操作,EXPIRE 是为避免出现意外用来设置锁的过期时间,也就是说到了指定的过期时间,该客户端必须让出锁,让其他客户端去持有。

但还有一种情况,如果在 SETNX 和 EXPIRE 之间服务器进程突然挂掉,也就是还未设置过期时间,这样就会导致 EXPIRE 执行不了,因此还是会造成“死锁”的问题。为了避免这个问题,Redis 作者在 2.6.12 版本后,对 SET 命令参数做了扩展,使它可以同时执行 SETNX 和 EXPIRE 命令,从而解决了死锁的问题。

直接使用 SET 命令实现,语法格式如下:

SET key value [expiration EX seconds|PX milliseconds] [NX|XX]  
  • EX second:设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
  • PX millisecond:设置键的过期时间为毫秒。SET key value PX millisecond 效果等同于 PSETEX key millisecondvalue 。
  • NX:只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
  • XX:只在键已经存在时,才对键进行设置操作。
25.2.2 命令应用

下面进行简单的命令演示:

127.0.0.1:6379> SETNX WEBNAME www.biancheng.net
(integer. 1
127.0.0.1:6379> EXPIRE WEBNAME 60
(integer. 1
127.0.0.1:6379> GET WEBNAME
"www.biancheng.net"
127.0.0.1:6379> TTL WEBNAME
(integer. 33
127.0.0.1:6379> SET name www.biancheng.net EX 60 NX
OK

26 缓存雪崩击穿

在实际的业务场景中,Redis 一般和其他数据库搭配使用,用来减轻后端数据库的压力,比如和关系型数据库 MySQL 配合使用。

Redis 会把 MySQL 中经常被查询的数据缓存起来,比如热点数据,这样当用户来访问的时候,就不需要到 MySQL 中去查询了,而是直接获取 Redis 中的缓存数据,从而降低了后端数据库的读取压力。如果说用户查询的数据 Redis 没有,此时用户的查询请求就会转到 MySQL 数据库,当 MySQL 将数据返回给客户端时,同时会将数据缓存到 Redis 中,这样用户再次读取时,就可以直接从 Redis 中获取数据。流程图如下所示:

![Redis缓存使用流程图](http://c.biancheng.net/uploads/allimg/210913/1K924O02-0.gif.
图1:缓存使用流程图

在使用 Redis 作为缓存数据库的过程中,有时也会遇到一些棘手问题,比如常见缓存穿透.缓存击穿和缓存雪崩等问题,本节将对这些问题做简单地说明,并且提供有效的解决方案。

26.1 缓存穿透

缓存穿透是指当用户查询某个数据时,Redis 中不存在该数据,也就是缓存没有命中,此时查询请求就会转向持久层数据库 MySQL,结果发现 MySQL 中也不存在该数据,MySQL 只能返回一个空对象,代表此次查询失败。如果这种类请求非常多,或者用户利用这种请求进行恶意攻击,就会给 MySQL 数据库造成很大压力,甚至于崩溃,这种现象就叫缓存穿透。

为了避免缓存穿透问题,下面介绍两种解决方案:

26.1.1 缓存空对象

当 MySQL 返回空对象时, Redis 将该对象缓存起来,同时为其设置一个过期时间。当用户再次发起相同请求时,就会从缓存中拿到一个空对象,用户的请求被阻断在了缓存层,从而保护了后端数据库,但是这种做法也存在一些问题,虽然请求进不了 MSQL,但是这种策略会占用 Redis 的缓存空间。

26.1.2 布隆过滤器

我们知道,布隆过滤器判定不存在的数据,那么该数据一定不存在,利用它的这一特点可以防止缓存穿透。

首先将用户可能会访问的热点数据存储在布隆过滤器中(也称缓存预热),当有一个用户请求到来时会先经过布隆过滤器,如果请求的数据,布隆过滤器中不存在,那么该请求将直接被拒绝,否则将继续执行查询。相较于第一种方法,用布隆过滤器方法更为高效.实用。其流程示意图如下:

![缓存穿透问题](http://c.biancheng.net/uploads/allimg/210913/1K924O21-1.gif.
图2:缓存穿透问题解决

缓存预热:是指系统启动时,提前将相关的数据加载到 Redis 缓存系统中。这样避免了用户请求的时再去加载数据。

26.2 缓存击穿

缓存击穿是指用户查询的数据缓存中不存在,但是后端数据库却存在,这种现象出现原因是一般是由缓存中 key 过期导致的。比如一个热点数据 key,它无时无刻都在接受大量的并发访问,如果某一时刻这个 key 突然失效了,就致使大量的并发请求进入后端数据库,导致其压力瞬间增大。这种现象被称为缓存击穿。

缓存击穿有两种解决方法:

26.2.1 改变过期时间

设置热点数据永不过期。

26.2.2 分布式锁

采用分布式锁的方法,重新设计缓存的使用方式,过程如下:

  • 上锁:当我们通过 key 去查询数据时,首先查询缓存,如果没有,就通过分布式锁进行加锁,第一个获取锁的进程进入后端数据库查询,并将查询结果缓到Redis 中。
  • 解锁:当其他进程发现锁被某个进程占用时,就进入等待状态,直至解锁后,其余进程再依次访问被缓存的 key。

26.3 缓存雪崩

缓存雪崩是指缓存中大批量的 key 同时过期,而此时数据访问量又非常大,从而导致后端数据库压力突然暴增,甚至会挂掉,这种现象被称为缓存雪崩。它和缓存击穿不同,缓存击穿是在并发量特别大时,某一个热点 key 突然过期,而缓存雪崩则是大量的 key 同时过期,因此它们根本不是一个量级。

26.3.1 解决方案

缓存雪崩和缓存击穿有相似之处,所以也可以采用热点数据永不过期的方法,来减少大批量的 key 同时过期。再者就是为 key 设置随机过期时间,避免 key 集中过期。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • LLM之基于llama-index部署本地embedding与GLM-4模型并初步搭建RAG(其他大模型也可,附上ollma方式运行)
  • 【设计模式】模板方法模式和迭代器模式
  • 【Docker】Linux系统以及威联通QNAP部署思源笔记的通用教程
  • css实现闪烁渐变背景,@property自定义属性
  • 一次了解所有功能!超详细【Stable Diffusion界面】大揭秘!
  • 简过网:报个线上公务员培训班大概要多少钱?
  • 警惕!低血糖来袭,这些“隐形信号”你中招了吗?
  • 解决LabVIEW配置文件中文乱码问题
  • 【项目】微服务及时通讯系统:编写核心类
  • 拼车系统开发方案
  • Android about event log
  • 《通义千问AI落地—中》:前端实现
  • C语言程序设计(初识C语言后部分)
  • Compose(7)交互和动画
  • 第二节:Nodify 添加节点到编辑器中
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • Angular2开发踩坑系列-生产环境编译
  • AngularJS指令开发(1)——参数详解
  • avalon2.2的VM生成过程
  • Debian下无root权限使用Python访问Oracle
  • GraphQL学习过程应该是这样的
  • java第三方包学习之lombok
  • MySQL QA
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • Vim 折腾记
  • Webpack4 学习笔记 - 01:webpack的安装和简单配置
  • 工作踩坑系列——https访问遇到“已阻止载入混合活动内容”
  • 技术发展面试
  • 聚簇索引和非聚簇索引
  • 类orAPI - 收藏集 - 掘金
  • 批量截取pdf文件
  • 入口文件开始,分析Vue源码实现
  • 设计模式(12)迭代器模式(讲解+应用)
  • 使用docker-compose进行多节点部署
  • 物联网链路协议
  • #includecmath
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • $.ajax()方法详解
  • (4)事件处理——(7)简单事件(Simple events)
  • (Bean工厂的后处理器入门)学习Spring的第七天
  • (接口自动化)Python3操作MySQL数据库
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (排序详解之 堆排序)
  • (四)stm32之通信协议
  • (学习日记)2024.01.09
  • (一) 初入MySQL 【认识和部署】
  • (一)Kafka 安全之使用 SASL 进行身份验证 —— JAAS 配置、SASL 配置
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • (转载)CentOS查看系统信息|CentOS查看命令
  • .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)...
  • .NET HttpWebRequest、WebClient、HttpClient
  • .NET 设计模式初探
  • .NET/C# 在 64 位进程中读取 32 位进程重定向后的注册表
  • .Net6使用WebSocket与前端进行通信