带你走进Redis的世界 - Redis的客户端服务端交互

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 带你走进Redis的世界 - Redis的客户端服务端交互

前言

Redis实例运行于单独的进程之中,应用系统和Redis通过Redis协议进行交互。在协议允许的范围内,客户端与服务器可以实现多种典型的交互模式:串行的请求/响应模式、双工的请求/响应模式(Pipeline)、原子化的批量请求/响应模式(事务)、发布/订阅模式、脚本化的批量执行(脚本模式)

双工模式,包括半双工、全双工

半双工:在同一时刻,A 、B通讯双方只能单方向传输信息,A -> B 或者 B -> A

全双工:在任意时刻,A、B通讯双方都能互传信息,支持任意时刻的A -> B ,B -> A

客户端/服务器协议

Redis的交互协议包括:

  • 网络模型 数据交互的组织方式
  • 序列化协议 数据本身序列化
1. 网络交互

Redis协议位于TCP层之上,即客户端和Redis实例保持双工的连接。客户端与服务端交互的内容,是序列化后的相应类型的协议数据,服务器端为每个客户端建立对应的连接,在应用层维护一系列的状态保存到连接中。连接之间没有相互关联性。在Redis中,连接通过redisClient结构体实现。

2. 序列化协议

在Redis中,协议数据分为不同的类型,每种类型的数据均以CRLF(\r\n)结束,通过数据首字符区分类型。

  • inline command

这类数据表示Redis命令,首字符为Redis命令名的字符,格式为command str

如,keys * ,首字符为k,表示Redis查找所有的匹配的key

  • simple string

首字符为+,后续字符为string的内容,且该string不能包含\r \n 两个字符;最后仍以\r\n结束

如,+OK\r\n 表示新增OK这个string数据

  • bulk string

对于string类型本身内容中包含了\r \n的情况,simple string不再适用

解决方案可以包括两种,转义字符和长度自描述。Redis采用的是长度自描述,称为Bulk string

bulk string 首字符为$ ,紧随之后是string数据长度,\r\n之后紧跟着string的内容本身,可以允许包含\r或者\n特殊字符,最后仍以\r\n结束

如 $12\r\nhello\r\nworld\r\n

对于“”字符串和null通过$之后数字长度区分

  • “$0\r\n\r\n”,代表空字符串
  • "$-1\r\n"代表null
  • error

对于服务端返回内容,客户端需要识别是正确内容还是异常响应。异常信息即error类型数据,在Redis中首字符“-”表示

如“-ERR unknown command'foobar'\r\n“ 表示一个错误,和一个错误信息

  • integer

首字符“:”开头,紧跟着整型数字本身,最后\r\n结尾

  • array

数组以首字符“*”开头,紧跟着数组的长度,\r\n之后为数组中每个元素的序列化数据。

如,*2\r\n+abc\r\n:9\r\n 代表长度为2的数组,["abc",9]

数组长度为0或-1代表空数组或者null

  • C/S两端使用的协议数据类型

客户端发送给服务器端的类型为:inline command 有bulk string组成的array

由服务器端发送给客户端的类型为除了inline command 之外的所有类型,根据客户端命令或者交互模型不同进行确定,如:

  • 请求/响应模式下,对客户端发送的EXISTS KEY1 返回integer型数据
  • 发布/订阅模式下,为channel 订阅者推送的消息,采用array型数据

请求/响应模式

同一连接,请求/响应模式如下:

交互方向:客户端发送请求数据,服务器发送响应数据

对应关系:每一个请求数据其且仅有一个对应的响应数据

时序:响应数据的发送发生在“服务器完全接收到其对应的请求数据”之后

1.串行化实现

Redis对单个请求的处理时间通常比局域网延迟小一个数量级,因此串行化模式下,单连接的大部分时间都处于网络等待,没有充分利用服务器的处理能力。

2.pipeline实现

pipeline的实现取决于客户端,需要考虑:

  • 通过批量请求发送还是异步化请求发送实现
  • 非异步化的批量发送需要考虑每个批次的数据量,避免连接的buffer满后死锁
  • 对使用者如何封装接口,使得使用pipeline简单

事务模式

当需要将批量执行的语句原子化,需要引入redis的事务模式

图片

一次事务中多条命令以原子化方式执行,不同事务的命令相互时序不再交叉\

1.入队/执行分离的事务原子性

入队阶段:客户端将请求发送到服务端之后,暂存在连接对象对应的请求队列中

执行阶段:发送完一个批次的所有请求后,redis服务器一次执行连接对象队列中的所有请求

执行过程,redis不再执行其余连接请求。

2.事务一致性

当入队阶段出现错误,不执行后续的执行exec,不会对数据实际产生影响

当执行阶段已经开始,其中一条请求执行失败,后续请求会继续执行,返回客户端的array型响应中标记出错的结果,redis本身不包含回滚机制

3.事务的只读操作

入队模式下,所有的操作都没有真正执行,仅返回是否入队成功。此时,以A账号向B账号转账说明:

100 <= get a

100 <= get b

ok <= multi

queued <= set b 110

queued <= set a 90

如果客户端2,中间对a或者b有所改变,那么最终一致性就会被破坏

4.乐观所得可串行化事务隔离

正如上述所说,不同事务的命令相互时序不再交叉,Redis通过watch机制实现乐观锁,解决事务一致性问题

  • 将本次事务涉及的所有key注册为观察模式,假设此时逻辑时间为tstart
  • 执行只读操作
  • 根据只读操作结果组装写操作命令并发送到服务器端入队
  • 发送原子化的批量执行命令,试图执行连接的请求队列中的命令,此时逻辑时间为tcommit

存在两种情况:

假设注册的key有一个或多个,在tstart和tcommit之间被修改,则原子化批量执行命令,拒绝执行;

否则执行所有队列中请求

5.事务实现

事务实现通过redisObject对象进行相关设置

6.事务交互模式

通过watch机制,保证了不存在数据不一致问题,执行器是单线程,保证所有的写操作都是通过串行方式实现串行化

脚本模式

事务模式,会有一定的局限,redis允许客户端向服务器提交一个脚本,来编排业务事务多个redis操作,

1.脚本交互模式
  • 客户端发送eval lua_script_string 2 key1 key2 first second 给服务端
  • 服务端解析lua_script_string 根据string内容通过sha1计算出sha值,存放到redisServer对象的lua_script 成员变量中
  • 服务器端原子化通过内置lua执行脚本
  • 执行完成后,将lua结果转为redis类型返回给客户端
2.script特性

脚本包含以下特性:

  • 每一个提交的脚本,常驻不会消失,除非显式通过flush命令清理
  • script在实例的主备间可以通过script重放和cmd重放实现复制
  • 执行过的script之后,可以通过sha指定,不用重复发内容到服务端

发布/订阅模式

redis提供一种模式,一个客户端触发,多个客户端被动接受,称为发布/订阅模式

1.发布/订阅交互模式

该模式如下所述:

1)角色关系

  • 客户端分为发布者和订阅者两种角色
  • 发布端和订阅者通过channel关联

2)交互方向

  • 发布者和redis服务器的交互认为请求/响应模式
  • 服务端向订阅者发送数据,推送
  • 时序:服务器收到发布者消息之后
2.两类channel

普通channel:明确定义的channel

pattern channel:模糊匹配的channle

3.订阅实现
typedef struct redisServer {
...
dict *pubsub_channels;
list *pubsub_patterns;
...
}

通过维护指针链表来实现。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
17天前
|
JSON NoSQL Java
Redis入门到通关之Java客户端SpringDataRedis(RedisTemplate)
Redis入门到通关之Java客户端SpringDataRedis(RedisTemplate)
33 0
|
1月前
|
编解码 NoSQL 数据可视化
一个现代化轻量级的跨平台Redis桌面客户端
一个现代化轻量级的跨平台Redis桌面客户端
|
4月前
|
NoSQL Redis C++
VS2017的redis客户端实现
VS2017的redis客户端实现
|
2月前
|
JSON NoSQL Java
【Redis】2、Redis 的 Java 客户端(Jedis 和 SpringDataRedis)
【Redis】2、Redis 的 Java 客户端(Jedis 和 SpringDataRedis)
51 0
|
4天前
|
JSON NoSQL Java
深入浅出Redis(十三):SpringBoot整合Redis客户端
深入浅出Redis(十三):SpringBoot整合Redis客户端
|
5天前
|
NoSQL 网络协议 Java
Redis客户端Lettuce深度分析介绍(上)
Spring Boot自2.0版本开始默认使用Lettuce作为Redis的客户端(注1)。Lettuce客户端基于Netty的NIO框架实现,对于大多数的Redis操作,只需要维持单一的连接即可高效支持业务端的并发请求 —— 这点与Jedis的连接池模式有很大不同。同时,Lettuce支持的特性更加全面,且其性能表现并不逊于,甚至优于Jedis。本文通过分析Lettuce的特性和内部实现(基于6.0版本),及其与Jedis的对照比较,对这两种客户端,以及Redis服务端进行深度探讨。
|
2月前
|
NoSQL Linux 网络安全
Redis 客户端工具
Redis 客户端工具
26 0
|
2月前
|
NoSQL Redis
Netty实战:模拟Redis的客户端
Netty实战:模拟Redis的客户端
18 0
|
2月前
|
存储 缓存 Dragonfly
微软开抢年收入上亿美元的 Redis 饭碗?开源性能遥遥领先的 Garnet:无需修改,Redis 客户端可直接接入
微软开源了高性能缓存系统Garnet,旨在挑战 Redis 和 Dragonfly。Garnet 基于 .NET8,提供高吞吐量、低延迟和跨平台支持。它支持 RESP 协议,允许大部分 Redis 客户端无缝迁移。Garnet 的特性包括多连接批量处理以提升扩展性和吞吐量,以及更好的延迟稳定性。适合于需要高性能缓存层来降低成本和提高应用性能的场景。Garnet 的集群模式允许动态键迁移和分片管理,且支持 TLS 和自定义扩展。其网络层设计减少了线程切换开销,存储层则具备丰富的 API 和事务支持。在基准测试中,Garnet 在吞吐量和延迟上优于 Redis 和 KeyDB,展现出优秀的扩展性。
337 0
微软开抢年收入上亿美元的 Redis 饭碗?开源性能遥遥领先的 Garnet:无需修改,Redis 客户端可直接接入
|
2月前
|
存储 NoSQL Redis
Star 3.1k!Tiny RDM 刚上线就收获一众好评的Redis桌面客户端!现代化、轻量级、跨平台!
Star 3.1k!Tiny RDM 刚上线就收获一众好评的Redis桌面客户端!现代化、轻量级、跨平台!