传入格式
- 都是以字节流形式传输;
- 都是以NIO方式最终放到ByteBuffer里面通过socket 传输;
客户端创建连接
文字描述
所有的请求都包含RequestHeader和requestData两部分。第一部分是表示什么样的操作,如增加、修改等等,第二部分是表示具体的数据内容;
客户端时序图
sequenceDiagram
client->>zookeeper: setData()
zookeeper->>ClientCnxn: queuePacket()
ClientCnxn->>ClientCnxnSocketNIO: doIO()
- setData():包含requestheader和requestData;
- queuePacket():组装成Packet放入outgoingQueue;然后ClientCnxn里面会有个异步消费线程来消费outgoingQueue数据;
- doIo()函数最终会调用p.createBB()最终拿到ByteBuffer,然后通过NIO的socket对象传入到服务器;传输字节流也就是key为header和request;
服务器接收请求
文字描述
服务器接收到客户端的请求之后,会反序列化,分别以header和request为key取出相应的数据,然后拼接成Request,然后在后面的requestProcessor责任链里面流转;
服务器时序图
sequenceDiagram
QuorumPeer->>NIOServerCnxnFactory: start()
NIOServerCnxnFactory-->>NIOServerCnxnFactory:run()
NIOServerCnxnFactory-->>NIOServerCnxn:doIO()
NIOServerCnxn-->>NIOServerCnxn:readPayload()
NIOServerCnxn-->>NIOServerCnxn:readRequest()
NIOServerCnxn-->>ZooKeeperServer:processPacket():组装request
ZooKeeperServer-->>ZooKeeperServer:submitRequest()
ZooKeeperServer-->>RequestProcessor:processRequest()
- NIOServerCnxnFactory开启工作线程;
- 启动工作线程监听2181客户端连接;
- 一旦监听到连接则创建NIOServerCnxn对象,调用NIOServerCnxn的doIO逻辑,所以,一个连接对应一个serverCnxn;
- NIOServerCnxn会最终调用到ZooKeeperServer的processPacket函数,这个函数是所以不同类型zookeeperserver的父类,需要注意的是ZooKeeperServer有多个子类如FollowerZooKeeperServer、LeaderZooKeeperServer等,他们会依据节点不同的节点类型,创建不同的server对象。具体是在leader类或者follower类里面调用ServerCnxnFactory的setZooKeeperServer函数,把相应的zookeeperserver对象注入进去;不同的zookeeperserver创建不同个requestProcessor责任链;
- ZooKeeperServe的processPacket依据传输的数据其实就是requestheader和requestdata组装成request对象,需要注意的是此时组装request对象里面会把操作类型type设为不同的值,具体的请求内容会存放在request的buffer里面,最终在不同的requestProcessor中传递处理;但是需要注意的是在request对象里面还有个属性是TxnHeader,这个属性暂时比作为事务header,也就是只有对数据发生修改的时候这个字段才会被设置成相应的值,换句话说,查询逻辑request的这个字段值应该是空的,因为他没有什么事务。具体的实现逻辑在PrepRequestProcessor里面