Redis 介绍

Redis 介绍

Redis的全称是Remote Dictonary Server(远程字典服务器),Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API,Redis有如下优点:

  1. 高性能 - Redis能支持超过100K+每秒的读写频率
  2. 丰富的数据类型 - Redis支持Strings、Lists、Hashes、Sets及Ordered Sets等数据类型
  3. 原子性 - Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子操作
  4. 丰富的特性 - Redis还支持发布/订阅、事务、key过期等特性

Redis 配置

  • Redis 的配置文件位于 Redis 安装目录下,文件名为 redis.conf。
    通过修改 redis.conf 文件或使用 CONFIG set 命令来修改配置。

CONFIG SET命令基本语法:

CONFIG SET CONFIG_SETTING_NAME NEW CONFIG_VALUE

实例:

redis 127.0.0.1:6379> CONFIG SET loglevel “notice”
OK
redis 127.0.0.1:6379> CONFIG GET loglevel
1. “loglevel”
2. “notice”

redis.conf配置项说明如下:

  1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程
daemonize no
  1. 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定
pidfile /var/run/redis.pid
  1. 指定Redis监听端口,默认端口为6379
port 6379
  1. 绑定的主机地址
bind 127.0.0.1
  1. 当 客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
timeout 300
  1. 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
loglevel verbose
  1. 日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null
logfile stdout
  1. 设置数据库的数量,默认数据库为0,可以使用SELECT 命令在连接上指定数据库id
databases 16
  1. 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
save <seconds> <times>

Redis默认配置文件中提供了三个条件:

save 900 1

save 300 10

save 60 10000

分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。
  1. 指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大
    rdbcompression yes

  2. 指定本地数据库文件名,默认值为dump.rdb

dbfilename dump.rdb
  1. 指定本地数据库存放目录
dir ./
  1. 设置当本机为slave服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步
slaveof <masterip> <masterport>
  1. 当master服务设置了密码保护时,slave服务连接master的密码
masterauth <master-password>
  1. 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH 命令提供密码,默认关闭
requirepass foobared
  1. 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息
maxclients 128
  1. 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区
maxmemory <bytes>
  1. 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no
appendonly no
  1. 指定更新日志文件名,默认为appendonly.aof
appendfilename appendonly.aof
  1. 指定更新日志条件,共有3个可选值:
no:表示等操作系统进行数据缓存同步到磁盘(快)

always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全) 

everysec:表示每秒同步一次(折中,默认值)

appendfsync everysec
  1. 指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析Redis的VM机制)
vm-enabled no
  1. 虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享
vm-swap-file /tmp/redis.swap
  1. 将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0
vm-max-memory 0
  1. Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,但一个page上不能被多个对象共享,vm-page-size是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page大小最好设置为32或者64bytes;如果存储很大大对象,则可以使用更大的page,如果不 确定,就使用默认值
vm-page-size 32
  1. 设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是在放在内存中的,在磁盘上每8个pages将消耗1byte的内存。
vm-pages 134217728
  1. 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4
 vm-max-threads 4
  1. 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启
glueoutputbuf yes
  1. 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法
hash-max-zipmap-entries 64

hash-max-zipmap-value 512
  1. 指定是否激活重置哈希,默认为开启(后面在介绍Redis的哈希算法时具体介绍)
activerehashing yes
  1. 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
include /path/to/local.conf

Redis数据类型

redis提供五种数据类型:string,hash,list,set及zset(sorted set)。

string(字符串)

redis中最基本的类型,string类型是二进制安全的,可以包含任何数据。string类型的值最大能存储512MB。

SET key value [EX seconds] [PX milliseconds] [NX|XX]
将字符串值 value 关联到 key 。
如果 key 已经持有其他值, SET 就覆写旧值,无视类型。
对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。
**可选参数**
从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改:
EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
XX :只在键已经存在时,才对键进行设置操作。

GET key
返回 key 所关联的字符串值。
如果 key 不存在那么返回特殊值 nil 。
假如 key 储存的值不是字符串类型,返回一个错误,因为 GET 只能用于处理字符串值。

Hash(哈希)

Redis hash 是一个键值(key=>value)对集合, string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

HSET key field value
将哈希表 key 中的域 field 的值设为 value 。
key 不存在,一个新的哈希表被创建并进行 HSET 操作。
如果域 field 已经存在于哈希表中,旧值将被覆盖。
返回值:
如果 field 是哈希表中的一个新建域,并且值设置成功,返回 1 。
如果哈希表中域 field 已经存在且旧值已被新值覆盖,返回 0 。
	
	redis> HSET website google "www.g.cn"       # 设置一个新域
	(integer) 1
	redis> HSET website google "www.google.com" # 覆盖一个旧域
	(integer) 0

HGET key field
返回哈希表 key 中给定域 field 的值。
返回值:
给定域的值。
当给定域不存在或是给定 key 不存在时,返回 nil 。
	# 域存在
	redis> HSET site redis redis.com
	(integer) 1
	redis> HGET site redis
	"redis.com"

	# 域不存在
	redis> HGET site mysql
	(nil)

List(列表)

双向链表类型,支持push,pop等操作,key即为链表的名字。按照插入顺序排序,可以添加一个元素到列表的头部(左边)或者尾部(右边)。列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)。

LPUSH key value [value ...]
将一个或多个值 value 插入到列表 key 的表头
如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头: 比如说,对空列表 mylist 执行命令 LPUSH mylist a b c ,列表的值将是 c b a ,这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令。
如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。
当 key 存在但不是列表类型时,返回一个错误。
返回值:
	执行 LPUSH 命令后,列表的长度。

	# 加入单个元素
	redis> LPUSH languages python
	(integer) 1

	# 加入重复元素
	redis> LPUSH languages python
	(integer) 2
	redis> LRANGE languages 0 -1     # 列表允许重复元素
	1) "python"
	2) "python"

	# 加入多个元素
	redis> LPUSH mylist a b c
	(integer) 3
	redis> LRANGE mylist 0 -1
	1) "c"
	2) "b"
	3) "a"

LPOP key
移除并返回列表 key 的头元素。
返回值:
	列表的头元素。
	当 key 不存在时,返回 nil 。
	redis> LLEN course
	(integer) 0

	redis> RPUSH course algorithm001
	(integer) 1

	redis> RPUSH course c++101
	(integer) 2

	redis> LPOP course  # 移除头元素
	"algorithm001"

Set(集合)

Redis的Set是string类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
SADD key member [member …]
将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
假如 key 不存在,则创建一个只包含 member 元素作成员的集合。
当 key 不是集合类型时,返回一个错误。
在Redis2.4版本以前, SADD 只接受单个 member 值。
返回值:
被添加到集合中的新元素的数量,不包括被忽略的元素。

	# 添加单个元素
	redis> SADD bbs "discuz.net"
	(integer) 1

	# 添加重复元素
	redis> SADD bbs "discuz.net"
	(integer) 0

	# 添加多个元素
	redis> SADD bbs "tianya.cn" "groups.google.com"
	(integer) 2
	redis> SMEMBERS bbs
	1) "discuz.net"
	2) "groups.google.com"
	3) "tianya.cn"

SREM key member [member ...]
移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。
当 key 不是集合类型,返回一个错误。
返回值:
	被成功移除的元素的数量,不包括被忽略的元素。

	# 测试数据
	redis> SMEMBERS languages
	1) "c"
	2) "lisp"
	3) "python"
	4) "ruby"

	# 移除单个元素
	redis> SREM languages ruby
	(integer) 1

	# 移除不存在元素
	redis> SREM languages non-exists-language
	(integer) 0

	# 移除多个元素
	redis> SREM languages lisp python c
	(integer) 3
	redis> SMEMBERS languages
	(empty list or set)

Zset(sorted set:有序集合)

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。
ZADD key score member [[score member] [score member] …]
将一个或多个 member 元素及其 score 值加入到有序集 key 当中。

如果某个 member 已经是有序集的成员,那么更新这个 member 的 score 值,并通过重新插入这个 member 元素,来保证该 member 在正确的位置上。

score 值可以是整数值或双精度浮点数。

如果 key 不存在,则创建一个空的有序集并执行 ZADD 操作。

当 key 存在但不是有序集类型时,返回一个错误。

返回值:
	被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。

	# 添加单个元素
	redis> ZADD page_rank 10 google.com
	(integer) 1

	# 添加多个元素
	redis> ZADD page_rank 9 baidu.com 8 bing.com
	(integer) 2
	redis> ZRANGE page_rank 0 -1 WITHSCORES
	1) "bing.com"
	2) "8"
	3) "baidu.com"
	4) "9"
	5) "google.com"
	6) "10"

	# 添加已存在元素,且 score 值不变
	redis> ZADD page_rank 10 google.com
	(integer) 0
	redis> ZRANGE page_rank 0 -1 WITHSCORES  # 没有改变
	1) "bing.com"
	2) "8"
	3) "baidu.com"
	4) "9"
	5) "google.com"
	6) "10"

	# 添加已存在元素,但是改变 score 值
	redis> ZADD page_rank 6 bing.com
	(integer) 0
	redis> ZRANGE page_rank 0 -1 WITHSCORES  # bing.com 元素的 score 值被改变
	1) "bing.com"
	2) "6"
	3) "baidu.com"
	4) "9"
	5) "google.com"
	6) "10"

ZREM key member [member ...]
移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。
当 key 存在但不是有序集类型时,返回一个错误。
# 在 Redis 2.4 版本以前, ZREM 每次只能删除一个元素。
返回值:
	被成功移除的成员的数量,不包括被忽略的成员。
	# 测试数据
	redis> ZRANGE page_rank 0 -1 WITHSCORES
	1) "bing.com"
	2) "8"
	3) "baidu.com"
	4) "9"
	5) "google.com"
	6) "10"

	# 移除单个元素
	redis> ZREM page_rank google.com
	(integer) 1
	redis> ZRANGE page_rank 0 -1 WITHSCORES
	1) "bing.com"
	2) "8"
	3) "baidu.com"
	4) "9"

	# 移除多个元素
	redis> ZREM page_rank baidu.com bing.com
	(integer) 2
	redis> ZRANGE page_rank 0 -1 WITHSCORES
	(empty list or set)

	# 移除不存在元素
	redis> ZREM page_rank non-exists-element
	(integer) 0

Redis事务

Redis事务可以一次执行多个命令,并且带有以下两个重要的保证:

• 批量操作在发送 EXEC 命令前被放入队列缓存。

• 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。

• 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
一个事务从开始到执行会经历以下三个阶段:

• 开始事务

• 命令入队

• 执行事务

单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。
事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。

Redis事务命令

1、DISCARD

取消事务,放弃执行事务块内的所有命令。

2、EXEC

执行所有事务块内的命令。

3、MULTI

标记一个事务块的开始

4、UNWATCH

取消WATCH命令对所有key的监视

5、WATCH key[key …]

监视一个(或多个)key, 如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断。

Redis发布订阅

Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。

命令

1、PSUBSCRIBE pattern[pattern …]

订阅一个或多个给定模式的频道

2、PUBSUB subcommand [argument [argument …]]

查看订阅与发布系统状态

3、PUBLISH channel message

将信息发送到指定的频道。

4、PUNSUBSCRIBE [pattern [pattern …]]

退订所有给定模式的频道

5、SUBSCRIBE channel [channel …]

订阅给定的一个或多个频道的信息

6、UNSUBSCRIBE [channel [channel …]]

退订给定的频道

实例

以下实例演示了发布订阅是如何工作的。在我们实例中我们创建了订阅频道名为redisChat:

Redis 127.0.0.1:6379> PUBLISH redisChat “redis is a great caching technique”

(integer) 1

Redis 127.0.0.1:6379> PUBLISH redisChat “Learning redis by runoob.com”

(integer) 1

#订阅的客户端会显示如下消息

1)	“message”

2)	“redisChat”

3)	“Redis is a great caching technique”

4)	“message”

5)	“redisChat”

6)	“Learn redis by runoob.com”

Redis数据备份与恢复

Redis SAVE命令用于创建当前数据库的备份。

语法

Redis SAVE命令基本语法如下:

Redis 127.0.0.1 > SAVE

该命令将在redis安装目录中创建dump.rdb文件

恢复数据

如果需要恢复数据库,只需将备份文件(dump.rdb)移动到redis安装目录并启动服务即可。

获取redis目录可以使用CONFIG命令,如下所示:

Redis 127.0.0.1:6379 > CONFIG GET dir

“dir”

“/usr/local/redis/bin”

以上命令CONFIG GET dir输出的redis安装目录为 /usr/local/redis/bin

Bgsave

创建redis备份文件也可以使用命令BGSAVE,该命令在后台运行。

Redis管道技术

Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。这意味着通常情况下一个请求会遵循以下步骤:

• 客户端向服务端发送一个查询请求,并监听Socket返回,通常是以阻塞模式,等待服务端响应。

• 服务端处理命令,并将结果返回给客户端。
Redis 管道技术可以在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。

管道技术优势

管道技术最显著的优势是提高了 redis 服务的性能。

实例

`$ (echo -en "PING\r\n SET runoobkey redis\r\nGET runoobkey\r\nINCR visitor\r\nINCR visitor\r\nINCR visitor\r\n";sleep 10) | nc localhost 6379`
(输出)
+PONG
+OK
$5
redis
:1
:2
:3

以上实例中我们通过使用 PING 命令查看redis服务是否可用, 之后我们设置了 runoobkey 的值为 redis,然后我们获取 runoobkey 的值并使得 visitor 自增 3 次。

在返回的结果中我们可以看到这些命令一次性向 redis 服务提交,并最终一次性读取所有服务端的响应

Redis分区

  • 分区是分割数据到多个Redis实例的处理过程,因此每个实例只保存key的一个子集。

分区的优势

• 通过利用多台计算机内存的和值,允许我们构造更大的数据库。

• 通过多核和多台计算机,允许我们扩展计算能力;通过多台计算机和网络适配器,允许我们扩展网络带宽。

分区的不足

redis的一些特性在分区方面表现的不是很好:

• 涉及多个key的操作通常是不被支持的。举例来说,当两个set映射到不同的redis实例上时,你就不能对这两个set执行交集操作。

• 涉及多个key的redis事务不能使用。

• 当使用分区时,数据处理较为复杂,比如你需要处理多个rdb/aof文件,并且从多个实例和主机备份持久化文件。

• 增加或删除容量也比较复杂。redis集群大多数支持在运行时增加、删除节点的透明数据平衡的能力,但是类似于客户端分区、代理等其他系统则不支持这项特性。然而,一种叫做presharding的技术对此是有帮助的。

分区类型

Redis 有两种类型分区。 假设有4个Redis实例 R0,R1,R2,R3,和类似user:1,user:2这样的表示用户的多个key,对既定的key有多种不同方式来选择这个key存放在哪个实例中。也就是说,有不同的系统来映射某个key到某个Redis服务。

范围分区

最简单的分区方式是按范围分区,就是映射一定范围的对象到特定的Redis实例。

比如,ID从0到10000的用户会保存到实例R0,ID从10001到 20000的用户会保存到R1,以此类推。

这种方式是可行的,并且在实际中使用,不足就是要有一个区间范围到实例的映射表。这个表要被管理,同时还需要各 种对象的映射表,通常对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集群

集群介绍

Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施。

Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需要在多个 Redis 节点之间移动数据, 并且在高负载的情况下, 这些命令将降低Redis集群的性能, 并导致不可预测的行为。

Redis 集群通过分区partition来提供一定程度的可用性availability: 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。

Redis集群提供了以下两个好处:

• 将数据自动切分split到多个节点的能力。

• 当集群中的一部分节点失效或者无法进行通讯时, 仍然可以继续处理命令请求的能力。

集群架构

架构细节:

(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.

(2)节点的fail是通过集群中超过半数的节点检测失效时才生效.

(3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可

(4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value

集群选举、容错

• 领着选举过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉.

• 整个集群不可用(cluster_state:fail),当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误

a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成进群的slot映射[0-16383]不完成时进入fail状态.
  
b:如果进群超过半数以上master挂掉,无论是否有slave集群进入fail状态.

C++操作redis

  • C++通过hiredis.h接口来操作Redis数据库。

同步接口

  1. redisContext* redisConnect(const char *ip, int port)

    该函数用来连接redis数据库, 两个参数分别是redis数据库的ip和端口,端口号一般为6379。类似
    的还提供了一个函数,供连接超时限定,即
    redisContext* redisConnectWithTimeout(const char *ip, int port, timeval tv)。

  2. void *redisCommand(redisContext *c, const char *format…)

    该函数用于执行redis数据库中的命令,第一个参数为连接数据库返回的redisContext,剩下的参数
    为变参,如同C语言中的prinf()函数。
    此函数的返回值为void*,但是一般会强制转换为redisReply类型,以便做进一步的处理。

  3. void freeReplyObject(void *reply)

    释放redisCommand执行后返回的的redisReply所占用的内存。

  4. void redisFree(redisContext *c)

    释放redisConnect()所产生的连接。

异步接口

  1. redisAsyncContext * redisAsyncConnect(const char *ip, int port);

    函数 redisAsyncConnect 用来建立到redis服务器的非阻塞连接. 返回一个 redisAsyncContext 结构体指针. 因为建立的连接是非阻塞的,无法立即返回目标主机的ip和端口是否可达。所以在建立连接后,我们应该检查 err 成员,来确认连接是否存在错误。

     if (c->err) {
    
     	printf("Error: %s\n", c->errstr);
    
     	// 错误处理
     }
    

    redisAsyncContext包含一个连接断开回调函数(主动断开,或者发生错误都会调用)。此函数原型如下:

     void(const redisAsyncContext *c, int status);
    

    当用户主动断开连接时, 参数 status 被设置为 REDIS_OK ; 当发生错误而导致连接断开时 status 被设置为REDIS_ERR 。此时我们可以根据 err 成员变量判断错误产生的情况。

    当我们需要进行断线重连时,可以在断开连接回调函数处理。

    每个上下文(redisAsyncContext)实例只能设置一次断线回调函数,多次调用会返回REDIS_ERR错误。 使用以下函数设置断线回调函数:

     int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
    
  2. 发送命令并设置回调

    使用redisAsyncContext时,(每帧)发送的命令会自动pipelined(打包发送命令)。所以我们需要设置reply回调函数来进行命令执行后的处理工作。回调函数原型如下:

     void(redisAsyncContext *c, void *reply, void *privdata);
    

    参数 privdata 为用户数据,你可以设置成函数调用时所需要的任意数据。

     int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,const char *format, ...);
    
     int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen);
    

    这两个函数和阻塞版本类似。命令成功添加到输出缓冲区时返回 REDIS_OK ,错误时返回 REDIS_ERR 。 例如:当连接被用户中断时,新命令无法被添加,所有类似 redisAsyncCommand 的函数调用都返回 REDIS_ERR错误码。

    如果将回调函数设置成 NULL (? privdata,还是reply?需要实验一下 ?)内存被立即释放。当回调函数非空,则内存在调用后释放内存。reply参数只能在回调函数体中使用。

    当上下文(redisAsyncContext)发生错误时所有未执行的命令所设置的回调函数都会被调用,回调函数中reply指针为空。

  3. 断开连接
    异步连接可以使用以下函数终止:
    void redisAsyncDisconnect(redisAsyncContext *ac);

    当函数被调用时连接并不是立即被断开,而是新的命令不在被接受。(调用函数后)当所有未执行的指令都被写入到socket中,并且命令回调函数都被执行以后,连接才被中断(连接中断回调函数被调用,status为 REDIS_OK )、上下文对象被释放。

  4. 绑定到事件库
    There are a few hooks that need to be set on the context object after it is created. See the adapters/ directory for bindings to libev and libevent.

参考文献:

  • http://doc.redisfans.com/index.html
  • http://www.runoob.com/redis/redis-tutorial.html
  • https://blog.csdn.net/lhl_blog/article/details/78665285
  • https://blog.csdn.net/shudaqi2010/article/details/53895772
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员之光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值