Redis学习----服务器(上)

10 篇文章 0 订阅

你未必出类拔萃,但一定与众不同

Redis 服务器

命令请求的执行过程

一个命令请求从发送到获得回复的完整过程

127.0.0.1:6379> set userId 9527
OK

1.客户端发送命令set userId 9527 给服务器

2.服务器接收并且处理客户端命令请求set userId 9527,在数据库中进行操作,并且成功后产生命令回复OK

3.服务器将命令回复OK发送给客户端

4.客户端接收服务器命令回复OK,并且将回复打印给用户看

图解
在这里插入图片描述

发送命令请求

当用户输入一个命令请求时,客户端会将命令转化为协议格式,通过连接到服务器的套接字,将协议格式的命令发送给服务器
在这里插入图片描述

读取命令请求

客户端与服务器之间因为客户端的写入而可读时,服务器将调用命令请求处理器来执行以下操作

1.读取套接字中协议格式的命令请求,并且将命令请求保存到客户端状态的输入缓冲区

2.对输入缓冲区中的命令进行分析,提取出命令请求中的命令参数,以及参数个数,然后保存到客户端状态的argv属性(数组中的每个元素都是一个字符串对象)和argc属性(数组的长度)

3.调用命令执行器。执行客户端的命令

图解

在这里插入图片描述

然后分析程序就会对输入缓冲区中的协议进行分析,然后保存到客户端状态的argv属性(数组中的每个元素都是一个字符串对象)和argc属性(数组的长度)

命令执行器

(1):查找命令实现

第一件事就是根据客户端状态的argv[0]参数,在命令表里查找参数所指定的命令,并且将找到的命令保存到客户端状态的cmd属性里面

命令表是一个字典,字典的键就是一个一个命令名字

字典的值就是一个个redisCommand结构,每个redisCommand都记录一个redis命令的实现消息

redisCommand结构主要属性

属性名类型作用
namechar *命令的名字
procredisCommandProc *函数指针,指向命令的实现函数,比如setCommand
arityint命令参数的个数,用于检查命令请求的格式是否正确。如果值为-N,表示参数的数量大于等于N(命令的名字本身也是一个参数)
sflagschar *字符串形式的标识值。这个值记录了命令的属性,如读命令、写命令、是否允许在载入时或Lua脚本中使用
flagsint对sflags标识进行分析得出的二进制标识,由程序自动生成。服务器对命令标识进行检查使用该属性而不是sflags属性,因为对二进制标识的检查可以方便地通过& ^ ~ 等操作来完成
callslong long服务器总共执行的命令个数
millisecondslong long执行命令的总耗时

sflags标识

标识意义带有这个标识的命令
w写入命令SET RPUSH DEL等
r只读命令GET STRLEN EXISTS等
m执行前检查服务器内存使用情况,内存紧缺就不执行SET APPEND RPUSH LPUSH SADD SINTERSTORE等
a管理命令SAVE BGSAVE SHUTDOWN等
p发布与订阅命令PUBLISH SUBSCRIBE PUBSUB等
s不可在lua脚本使用BRPOP BLPOP BRPOPLPUSH SPOP等
R随机命令SPOP SRANDMEMBER SSCAN RANDOMKEY等
S对结果执行排序SINTER SUNION SDIFF SMEMBERS KEYS等
l服务器载入数据时使用INFO SHUTDOWN PUBLISH等
t允许从服务器在带有过期数据时使用的命令SLAVEEOF PING INFO等
M在监视器模式下不会被自动传播EXEC

以SET、GET命令示例redisCommand结构:

SET
实现函数为setCommand,命令参数为-3:表示命令接受3个或以上的参数,命令标识为wm:表示SET命令是一个写入命令,并且在执行这个命令之前,服务器应该对内存占用状况进行检查,因为这个命令可能会占用大量内存
GET
实现函数为getCommand,命令参数为2:表示该命令只接受2个参数,命令标识为r:标识是一个只读命令

命令执行器(2):执行预备操作

在真正执行命令之前,还需要一些准备操作

1.检查客户端状态的cmd指针是否指向NULL,是则说明用户输入的命令名字找不到相应的命令实现,剩下的步骤服务器就不执行

2.根据客户端的cmd属性指向的redisCommand结构的arity属性,检查命令请求所给定的参数个数是否正确,当参数个数不正确就不执行后续步骤

3.检查客户端是否通过身份验证,未通过的只能执行AUTH命令

4.如果服务器打开了maxmemory功能,就需要执行命令之前检查服务器的内存。

5.如果服务器上一次执行BGSAVE命令时出错,且服务器打开了stop-writes-on-bgsave-error功能,而服务器要执行的是一个写命令,那么服务器拒绝执行这个命令,并返回一个错误。
6.如果客户端正在用SUBSCRIBE命令订阅频道,或正在用PSUBSCRIBE命令订阅模式,那么服务器只会执行客户端发来的SUBSCRIB、PSUBSCRIBE、UNSUBSCRIB、PUNSUBSCRIBE四个命令,其他命令会被服务器拒绝。
7.如果服务器正在进行数据载入,那么客户端发送的命令必须带有 l 标识(比如INFO、SHUTDOWN、PUBLISH等)才会被服务器执行,其他命令都会被服务器拒绝。
8.如果服务器因为执行Lua脚本而超时并进入阻塞状态,那么服务器只会执行客户端发来的SHUTDOWN nosave命令和SCRIPT KILL命令,其他命令都会被服务器拒绝。
9.如果客户端正在执行事务,那么服务器只会执行客户端发来的EXEC、DISCARD、MULTI、WATCH四个命令,其他命令都会被放进事务队列中。
10.如果服务器打开了监视器功能,那么服务器会将要执行的命令和参数等信息发送给监视器。

命令执行器(3):调用命令的实现函数

将要执行的命令会被保存到客户端状态的cmd属性里,执行命令时只要执行喜爱语句

client->cmd->proc(client)

被调用的命令实现函数会执行指定的操作,并且产生相应的命令回复,这些回复被保存在客户端状态的输出缓冲区里,之后实现函数会为客户端的套接字关联命令回复处理器,这个处理器负责将命令回复返回给客户端。

命令执行器(4):执行后续工作
  • 如果服务器执行了慢查询日志功能,那么慢查询日志模块会检查是否需要为刚刚执行完的命令请求添加一条新的慢查询日志
  • 根据刚刚执行命令所耗费的时长,更新被执行命令的redisCommand结构的milliseconds属性,并且将命令的redisCommand结构的calls计数器的值加一
  • 如果服务器开启了AOF持久化功能,那么AOF持久化模块会将刚刚执行的命令请求加入到AOF缓冲区中
  • 如果有其他从服务器正在复制当前这个服务器,那么服务器会将刚刚执行的命令传播给其他所有服务器

以上操作执行完以后,服务器就会开始执行下一个命令

将命令回复发送给客户端

命令实现函数会将命令回复保存到客户端的输出缓冲区中,并且为客户端的套接字关联命令回复处理器,当客户端套接字变为可写状态,服务器就会执行命令回复处理器,将保存在客户端的输出缓冲区中的命令回复给客户端

当命令回复发送完毕用户,回复处理器会清空客户端状态的输出缓冲区,准备处理下一个请求

客户端接收并打印命令回复

当客户端接收到协议格式的命令会转化为人类可读的格式然后打印在客户端给用户看。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

鱼爱吃柚子

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

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

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

打赏作者

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

抵扣说明:

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

余额充值