Redis服务器和客户端的通信
Redis客户端使用RESP(Redis序列化协议)与Redis服务器进行通信,RESP在位于TCP之上,而网络模型上客户端和服务器是保持的双工的连接。如图1
而一个简单的请求/响应的串行通信模型如下图:
串行化通信
串行化通信比较简单,上面那张图就很表面的反应出来这种通信方式,同一个Connction需要在等上一个命令执行完成之后在执行下一个命令,我们在前面文章讲Redis各种类型的时候做的测试,就是用这种方式。客户端发送一个指令到Redis实例,Redis实例处理完成之后将结果返回给客户端。
前面文章说Redis为什么要用多线程中有说过,Redis处理请求的速度特别快,我们一个请求的瓶颈主要是在I/O上面,而对于串行化通信,每一个请求的发送都要等到上一个请求的响应介绍,因此在串行模式下,单连接的大部分时间都浪费在网络等待上,没有充分的利用服务器的处理能力。
管道技术
Redis在很早的时候就支持管道技术了,简单来说,就是可以完全无需等待服务端应答地发送多条指令给服务端,并最终一次性读取所有应答。管道技术最显著的优势是提高了redis服务的性能,通过管道技术来进行大批量的操作的时候,可以节省很多在网络延迟上的时间。
在.net core 的Redis客户端StackExchange.Redis则是基于Task来实现管道技术,而StackExchangeRedis本身的异步也都是通过管道技术来实现。
事务
在菜鸟教程中是这么介绍的
Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:
- 批量操作在发送 EXEC 命令前被放入队列缓存。
- 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
- 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
一个事务从开始到执行会经历以下三个阶段:
- 开始事务。
- 命令入队。
- 执行事务
- 放弃事务
原理很简单,客户端发送命令MULTI,服务器会将后续的命令都放入队列缓存,直到收到EXEC命令才会依次执行命令。单个Redis的命令是原子性的,但是Redis并没有在事务上增加任何的维持原子性的机制,当中间某条命令失败并不会导致其他命令的回滚,这个跟我们在关系型数据库的理解不一样,更多的像一个打包的批处理脚本。
菜鸟中有这么一句话
在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
粗略一看我还理解为事务开启会阻塞其他客户端的命令,吓得我马上做了一下测试
在客户端1中开启事务multi,并发送一个set 和 get 的命令,能看到都是QUEUED的状态,表明是正确的入队了
接着在客户端2中获取key1发现值是null,说明客户端1的命令还没有真正执行,接着设置key1的值为value2,接着取得key1的值,在客户端1中开启事务后,在客户端2是可以顺利执行命令的,菜鸟中的话的意思其实客户端的命令不会进入开启事务那个客户端的命令队列中。
我们接着在客户端1提交命令,key1的值变为value1,客户端2中设置的value2被更改为value1了。
我们将Redis事务与数据库事务的四大特征对比下
原子性 | 不支持 | Redis单个指令是具有原子性的,但是事务没有 |
一致性 | 不支持 | 在上面的例子就可以看见,在客户端1的事务开启的时候,我仍然能修改key1的值,在关系型数据库中我们有悲观锁和乐观锁来解决这种并发问题,Redis也通过Watch可以实现乐观锁的效果,但是我还是没有体会出来有什么用处。在关系型数据中的事务,我们可能会先取出来值,在进行修改,最后提交事务,如果没有锁来保证,那么我们最后的数据就没有一致性了,但是对于Redis我还是没想出来什么场景下会需要用乐观锁来控制并发,知道的小伙伴麻烦告知一声。 |
隔离性 | 支持 | Redis本身是没有隔离性这个说法的,之所以我觉得是支持隔离性,因为我觉得Redis的事务都是在最后才执行,而本身命令又是原子性的,所以隔离性对Redis是无意义的。 |
持久性 | 不支持 | Redis有持久化方案,但是最高数据安全性的方式-AOF中的修改同步,仍然会在异常情况下导致数据丢失。 |
其实这个对比不太恰当,Redis的事务只是顶着事务这个名字,做的还是批量处理的事情,它的关注点不应该在正真的事务上
脚本
在说事务的时候有说事务更像是批处理的感觉,而脚本也是批处理,不同的是,我们可以根据上一个指令的结果作为我们下个指令的参数,这是处理逻辑问题的时候特别有用。
Redis脚本是通过Eval命令实现,当客户都安使用Eval命令的时候,Redis实例会通过lua解释器来执行脚本,我们这里的脚本也是lua脚本,用Abp中清除缓存的的源码作为示例
EVAL "local keys = redis.call('keys', ARGV[1])
for i=1,#keys,5000
do
redis.call('del', unpack(keys, i, math.min(i+4999, #keys)))
end"
0 'Test_*'
这个脚本第一步将以Test做为前缀的key全部取出来存入变量keys,接着从1开始,以keys的长度为最大值,步长为5000进行遍历,每一步都是删除5000个key。为什么要用每次5000遍历来执行呢?因为unpack函数在数量太多的时候会出现 'too many results to unpack' 的错误,我们来实际操作下,往实例中添加10个用Test_为前缀的值,然后执行上面的脚本
可以看到我们以Test_做为前缀的Key都被删除了
发布/订阅模式
前面有讲到过,Redis实例和客户都之间是双工连接的,但是前面所说的不管是简单的命令还是事务脚本都是客户端主动发起请求,Redis实例被动回应的,而发布/订阅模式则是可以由Redis实例主动给客户端发送消息,在下一节会详细说这种模式。
Redis服务器和客户端的通信的更多相关文章
- 基于 HTML5 WebGL 的 3D 服务器与客户端的通信
这个例子的初衷是模拟服务器与客户端的通信,我把整个需求简化变成了今天的这个例子.3D 机房方面的模拟一般都是需要鹰眼来辅助的,这样找产品以及整个空间的概括会比较明确,在这个例子中我也加了,这篇文章就算 ...
- Socket通信——服务器和客户端相互通信
所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过"套接字"向网络发出请求或者应答网络请求. Socket和S ...
- C#利用服务器实现客户端之间通信
这两天在学习C#,C#高级编程真的是厚厚的一本书QAQ. 昨天看了一下里面的通信部分(其实还没怎么看),看了网上一些人的博客,自己在他们的博客基础上写了一个通信. 先来讲述下我自己对于整个Socket ...
- nodejs+expressjs+ws实现了websocket即时通讯,服务器和客户端互相通信
nodejs代码 // 导入WebSocket模块: const WebSocket = require('ws'); // 引用Server类: const WebSocketServer = We ...
- [转]redis服务器与客户端保活参数(tcp-keepalive)设置
最近使用redis的list做跨进程的消息队列,客户端使用的是redis-cplusplus-client.这个client库还是蛮好用的,提供了和redis命令行一致的接口,很方便. 使用过程中发现 ...
- ajax利用json进行服务器与客户端的通信
1.JQuery中$.ajax()方法参数详解 http://blog.sina.com.cn/s/blog_4f925fc30100la36.html 2.服务器端获取String que=requ ...
- Redis源码解析:14Redis服务器与客户端间的交互
Redis服务器是典型的一对多服务器程序,通过使用由IO多路复用技术实现的文件事件处理器,Redis服务器使用单线程单进程的方式来处理命令请求,并与多个客户端进行网络通信. Redis客户端与服务器之 ...
- GATT两个角色 服务器与客户端
两个设备应用数据的通信是通过协议栈的GATT层实现的. 从GATT角度来看,当两个设备建立连接后,他们处于以下两种角色之一: GATT服务器: 它是为GATT客户端提供数据服务的设备 GATT客户端: ...
- GATT 服务器与客户端角色
两个设备应用数据的通信是通过协议栈的GATT层实现的.从GATT角度来看,当两个设备建立连接后,他们处于以下两种角色之一: GATT服务器: 它是为GATT客户端提供数据服务的设备 GATT客户端: ...
随机推荐
- std::string构造函数
string(); string (const string& str); string (const string& str, size_t pos, size_t len = np ...
- 【Java】Operator 运算符/操作符
Operator 运算符/操作符 什么是操作符? 一个表示特定的数学或逻辑操作的符号 算术运算符 加 + 减 - 乘 * 除 / 取模 % 前置自运算 ++ a .--b 后置自运算 a++ .b-- ...
- 用网线连接Windows和Linux台式机,并实现Linux共享Windows的WiFi网络
前言 由于工作需要,需要利用网线将自己的笔记本和Linux台式机进行连接,实现Windows可以远程登录Linux机器,并实现Linux共享Windows的WiFi网络. 网上的很多方法可以实现两台机 ...
- Python生成一维码
参考页面 https://pypi.org/project/python-barcode/ 利用python-barcode的库 一.安装python-barcode库 #安装前提条件库 pip in ...
- Spark SQL源码解析(二)Antlr4解析Sql并生成树
Spark SQL原理解析前言: Spark SQL源码剖析(一)SQL解析框架Catalyst流程概述 这一次要开始真正介绍Spark解析SQL的流程,首先是从Sql Parse阶段开始,简单点说, ...
- Spring Cloud Gateway+Nacos,yml+properties两种配置文件方式搭建网关服务
写在前面 网关的作用不在此赘述,举个最常用的例子,我们搭建了微服务,前端调用各服务接口时,由于各服务接口不一样,如果让前端同事分别调用,前端同事会疯的.而网关就可以解决这个问题,网关屏蔽了各业务服务的 ...
- JUC并发编程基石AQS之主流程源码解析
前言 由于AQS的源码太过凝练,而且有很多分支比如取消排队.等待条件等,如果把所有的分支在一篇文章的写完可能会看懵,所以这篇文章主要是从正常流程先走一遍,重点不在取消排队等分支,之后会专门写一篇取消排 ...
- tp5.1部署到IIS服务器404
本人小白一枚,本地用的apache环境,公司让做了一个小项目,在本地写好之后,一切调试好,就直接交给了主管,之后别人负责上线. 就这样平淡的度过了两天,今天突然和我说,除了首页其他链接都是404,我想 ...
- thinkphp5--多文件入口设置
来源:http://www.cnblogs.com/walblog/p/8035426.html 今天在用tp5做项目的时候发现,前台是可以绑定默认到index模块的,但是后台不好弄,于是查了一下手册 ...
- webpack4 图片加载
图片处理(file-loader) 引用时出现的问题 在js中引入图片并添加到页面 let img = new Image(); img.src = './logo.png' document.bod ...