这一小节主要讨论两个问题,一是描述Datastax Cassandra Driver为请求和响应定义的的数据结构;二是在收发数据都经过了哪些编解码。
一、数据结构:
driver发送/接收数据的结构分为两种版本:V1和V2共用的版本和V3使用的版本(如下图):
(1)version, 不解释,V3还是V1/V2
(2)flags, 分两种,使用序列化方式压缩进数据帧内
1 | (header.writeByte(Header.Flag.serialize(frame.header.flags));) |
a) TRACING: Returns whether tracing is enabled for this query or not.
b) COMPRESSED 是否压缩
(3)stream :很关键,标示数据帧的id. 收发一致以保持数据的发送和接收以一个对应起来。
(4)opcode: 编解码方式,例如对于请求,Query类型的opcode是7,从而服务器在接收到Driver发送的请求后,根据7的Requests.Query.coder进行解码,因为明显不同类型的请求的编解码方式是不同的。
1 2 3 4 5 6 7 8 9 | STARTUP ( 1 , Requests.Startup.coder), CREDENTIALS ( 4 , Requests.Credentials.coder), OPTIONS ( 5 , Requests.Options.coder), QUERY ( 7 , Requests.Query.coder), PREPARE ( 9 , Requests.Prepare.coder), EXECUTE ( 10 , Requests.Execute.coder), REGISTER ( 11 , Requests.Register.coder), BATCH ( 13 , Requests.Batch.coder), AUTH_RESPONSE ( 15 , Requests.AuthResponse.coder); |
(5) length: 数据帧Body内容的总长度;
(6)body: 例如对于仅有HashMap属性的Credentials请求类型:
body分为2部分:第一部分为:总的长度(值为下图中x,区别于5);第二部分:数据内容(如下)
总体代码如下:
1 2 3 4 5 6 | header.writeByte(frame.header.version.toInt()); header.writeByte(Header.Flag.serialize(frame.header.flags)); writeStreamId(frame.header.streamId, header, protocolVersion); header.writeByte(frame.header.opcode); header.writeInt(frame.body.readableBytes()); return ChannelBuffers.wrappedBuffer(header, frame.body); |
二、编解码Codec
了解完数据帧的编码后,我们来了解下netty对收发数据的编解码,首先可以从以下代码可以看出收发数据编解码的过程和顺序:
1 2 3 4 5 6 7 8 9 10 11 12 13 | pipeline.addLast( "frameDecoder" , new Frame.Decoder()); pipeline.addLast( "frameEncoder" , frameEncoder); if (compressor != null ) { pipeline.addLast( "frameDecompressor" , new Frame.Decompressor(compressor)); pipeline.addLast( "frameCompressor" , new Frame.Compressor(compressor)); } pipeline.addLast( "messageDecoder" , messageDecoder); pipeline.addLast( "messageEncoder" , messageEncoderFor(protocolVersion)); pipeline.addLast( "dispatcher" , connection.dispatcher); |
根据netty对收发数据处理的流程(如下图)可知:
datastax的转化流程图如下:
其中Frame.Decoder()为LengthFieldBasedFrameDecoder;dispatcher为SimpleChannelUpstreamHandler,其他都为OneToOneDecoder
总结:Driver 对于数据帧的定义方式非常典型:有identify的标记位,有影响后面body处理的压缩等flag,有长度字段和编解码方式字段;同时编解码也挺齐全:有压缩,也有不同请求的封装。
从driver对netty的使用来看,netty确实是强大的网络程序构架框架,相比较自己去一步一步码nio的server/client程序要高效的多。