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客户端: ...
随机推荐
- pgsql中的行锁
pgsql中的行锁 前言 用户可见的锁 regular Lock 行级别 FOR UPDATE FOR NO KEY UPDATE FOR SHARE FOR KEY SHARE 测试下加锁之后的数据 ...
- tf.nn.max_pool 池化
tf.nn.max_pool( value, ksize, strides, padding, data_format='NHWC', name=None ) 参数: value:由data_form ...
- 360众测考试,weblogic题(CVE-2018-2894)文件上传漏洞
0x01 漏洞简介 Weblogic管理端未授权的两个页面存在任意上传jsp文件漏洞,进而获取服务器权限. Oracle 7月更新中,修复了Weblogic Web Service Test Page ...
- AJ学IOS 之微博项目实战(12)发送微博自定义工具条代理实现点击事件
AJ分享,必须精品 一:效果 二:封装好的工具条 NYComposeToolbar.h 带代理方法 #import <UIKit/UIKit.h> typedef enum { NYCom ...
- c++ string类的一些使用
初始化: string类的初始化是不可以用字符进行的,如; string str='c'; string str('c');必须传递字符串字面量作为参数:string本身是用模板类进行实例化的类. s ...
- mysql定期任务
进来开发项目时遇到一个问题,就是每一周需要清理服务器数据库数据.现在我就来记录一下用Navicat for MySQL 来实现定时任务. 1.启动Navicat for MySQL,新建数据库连接,打 ...
- Python3使用 pytesseract 进行图片识别
一.安装Tesseract-OCR软件 参考我的前一篇文章:Windows安装Tesseract-OCR 4.00并配置环境变量 二.Python中使用 需要使用 pytesseract 库,官方使用 ...
- Python 【面试强化宝典】
四大数据类型的常用方法 列表常用方法 #1. append 用于在列表末尾追加新的对象 a = [1,2,3] a.append(4) #the result : [1, 2, 3, 4] #2. c ...
- [PHP] excel 的导入导出
其实excel导入导出挺简单的,导出最简单! 其原理都是把数据读出来,导出是从数据库中读出数据,导入是从文件读出数据! 导出写入文件,导入写入数据库! 但是在导入表的时候,用的是PHPExcel, 不 ...
- 电脑Win10晚上让它更新,为何第二天开机蓝屏?
大家好,欢迎来到<电脑讲堂>,我是主持人高帅帅.PS:没错,就是那个人见人爱,花见花开的高帅帅. 话说,在一个月黑风高的夜晚,我晚上离开实验室,离开前看到了电脑的系统更新提醒,就顺手点了一 ...