Redis和MongoDB通讯协议简介
2016-11-22 00:00
106 查看
Redis
Redis的通讯协议可以说大集汇了……消息头标识,消息行还有就行里可能还有个数据块大小描述.首先Redis是以行来划分,每行以\r\n行结束。每一行都有一个消息头,消息头共分为5种分别如下:(+) 表示一个正确的状态信息,具体信息是当前行+后面的字符。
(-) 表示一个错误信息,具体信息是当前行-后面的字符。
(*) 表示消息体总共有多少行,不包括当前行,*后面是具体的行数。
($) 表示下一行数据长度,不包括换行符长度\r\n,$后面则是对应的长度的数据。
(:) 表示返回一个数值,:后面是相应的数字节符。
以上就是Redis协议的基础组成部分,下面来分析几个指令了解一下具体相关指令和返回情况.
SET
SET HENRY HENRYFAN
以上命令是设置HENRY 的值为HENRYFAN.在Redis的通讯协议上会以空格把命令拆分成三行;得到最终的命令如下:
*3\r\n $3\r\n SET\r\n $5\r\n HENRY\r\n $8\r\n HENRYFAN\r\n
服务端操作成功
+OK\r\n
如果出现错误服务端会返回
-错误信息\r\n
GET
客户端GET HENRY
产生的通讯指令是:
*2\r\n $3\r\n GET\r\n $5\r\n HENRY\r\n
服务端:
如果存在这个Key则返回
$8\r\n HENRYFAN\r\n
不存在返回
$-1\r\n
HKEYS
客户端HKEYS HENRY
以上命令是获取对应HENRY有多少个field成员
*2\r\n $5\r\n HKEYS\r\n $5\r\n HENRY\r\n
服务端
如果不存在任何字段信息
*0\r\n
如果存在QQ字段信息
*1\r\n $2\r\n QQ\r\n
HMGET
客户端HMGET HENRY QQ
以上命令是获取HENRY的QQ信息。
*3\r\n $5\r\n HMGET\r\n $5\r\n HENRY\r\n $2\r\n QQ\r\n
服务端
如果不存在字段值
*1\r\n $-1\r\n
存在字段值
*1\r\n $8\r\n 28304340\r\n
MongDB
总结性的说MongoDB通讯基于TCP之上,数据采用BSON封装CP具有良好的拥塞控制,可靠传输等特性,比较适合数据库产品的通讯协议。一些对数据一致性,可靠性要求不高的产品也有采用UDP协议实现。如Redis,Memcached都支持UDP访问,但从实际的生产上来说,TCP来的更可靠,UDP的“不可靠”性质,反而会带来更多的运维负担,增加了排查问题的复杂性。
关于BSON
BSON作为JSON的一种扩展,支持了Binary的数据类型,日期数据等。相比较于Protocol Buffers而言,数据是Humman Readable。MongoDB经常提及的Documents,实际上就是BSON格式数据。同样的,支持嵌套的机制,BSON可以很好的映射成Object,这相对于表结构,在灵活性上提高了一大截。数据不在是扁平的,可以是树形的组织结构,比如:{ "_id" : 1, "name" : { "first" : "John", "last" : "Backus" }, "contribs" : [ "Fortran", "ALGOL", "Backus-Naur Form", "FP" ], "awards" : [ { "award" : "W.W. McDowell Award", "year" : 1967, "by" : "IEEE Computer Society" }, { "award" : "Draper Prize", "year" : 1993, "by" : "National Academy of Engineering" } ] }
当然BSON也有非常讨厌的一些地方,比如编码后的数据过大,引入了过的括号,符号等。
Wire Protocol
TCP是一种Stream的通讯方式,每次请求之间没有间隔,数据源源不断的发来,那如何才能识别出一个完整的请求块?一般的解决方法是加上一个Header,Header的长度固定,用来描述余下的信息量,包括携带的信息长度。额外说明:MongoDB的网络协议都是little-endian。参考util/net/message.h的代码:
struct Layout { int32_t messageLength; // total message size, including this int32_t requestID; // identifier for this message int32_t responseTo; // requestID from the original request // (used in responses from db) int32_t opCode; };
messageLength表示整个协议的长度,因为是头部,所以Client每次发送命令时都要先将数据写到Buffer里,得到完整的长度后才能通过TCP发送整个请求。MongoDB规定,messageLength不能大于48MB(1000计算),过大的请求包一般意味着过于复杂的请求类型,或者过大的Document,这与NoSQL的设计原则也是违背的。
requestID/responseTo每个请求都有一个ID标识,同一时刻不应该出现相同的requestID,Driver和Server通过这个字段来确认是否是同一个请求的上下文
opCode操作代码,支持的类型:request-opcodes
相关的解析代码在MessagingPort::recv(Message& m)函数内,首先读取固定长度的Header(Layout),读取到Header后,根据messageLength数值做个预判是否是其他的协议类型,预判全部通过后等待读取余下的协议(messageLength-4),如果SocketBuffer中数据不足,就会阻塞在这里,等待数据包完整到达。
从网络上获得了完整的数据后交给MyMessageHandler::process来处理接下来的命令,这时opCode开始发挥作用,assembleResponse函数会根据opcode的不同,按照不同的协议去解析出相应的对象,然后执行命令。最后按照同样的协议格式发送给Client响应。发给Client的responseTo设置为与请求命令的requestID相同,以便Driver对应到相应的上下文。
相关文章推荐
- MongoDB & Redis资料汇总
- redis 入门书
- php操作redis中的hash类型数据的方法和代码例子
- 【redis】常见JedisConnectionException异常分析
- [转]优化Redis内存的9个要点
- windows7系统的java访问VM中的ubuntu下的redis
- SpringMVC 整合Redis
- Redis的安装和部署
- Redis安全规范----check list
- java工程中如何连接redis数据库?
- mongodb,redis,hbase 三者都是nosql数据库,他们的最大区别和不同定位
- redis配置
- Redis 5.0 正式发布!一网打尽所有新特性!
- redis学习笔记
- redis数据丢失及解决
- Redis 缓存服务器
- 初学Redis(1)——认识Redis
- Nopcommerce 3.7 增加了Redis 作为缓存啦
- spring集成 JedisCluster 连接 redis3.0 集群
- Redis源码解析——有序整数集