zookeeper源码分析--序列化篇

其实很多时候我们都在使用zkclient这款jar包对zk进行相关的操作,但是在zkclient里面到底发生了什么,我们却并不是很清楚。对zk的了解出了简单的节点创建,删除,监听以外,我们还可以加深对它的思想理解。
下边我们来深入探讨一下zk的内部机制:
其实我们清楚一点,zk是采用了java语言进行编写的,因此关于zk这部分的内容对于java程序员来说是比较好接受的。
现在让我们来看下zk里面序列化部分:
在这里插入图片描述
在jute里面有一个叫做record的接口,专门用于定义序列化和反序列化操作:

package org.apache.jute;
import java.io.IOException;
/**
 * Interface that is implemented by generated classes.
 * 
 */
public interface Record {
    public void serialize(OutputArchive archive, String tag)
        throws IOException;
    public void deserialize(InputArchive archive, String tag)
        throws IOException;
}

zk内部的jute是自己研发的一款用于处理序列化和反序列化操作的工具。核心的序列化和反序列化器有以下几种:
BinaryInputArchive 处理二进制数据
BinaryOutputArchive

CsvInputArchive 处理csv格式数据
CsvOutputArchive

XmlInputArchive处理xml格式数据
XmlOutputArchive

下边我们结合一段代码案例来深入了解jute的序列化器工作使用方式:

package 源码分析.jute包;
import lombok.Data;
import org.apache.jute.InputArchive;
import org.apache.jute.OutputArchive;
import org.apache.jute.Record;
import java.io.IOException;
/**
 * @author idea
 * @data 2019/10/27
 */
@Data
public class TestBean implements Record {
    private int number;
    private String name;
    public TestBean(int number, String name) {
        this.number = number;
        this.name = name;
    }
    public TestBean(){}
    @Override
    public void serialize(OutputArchive archive, String tag) throws IOException {
        System.out.println("tag output:"+tag);
        archive.startRecord(this,tag);
        archive.writeInt(this.number,"number");
        archive.writeString(this.name,"name");
        archive.endRecord(this,tag);
    }
    @Override
    public void deserialize(InputArchive archive, String tag) throws IOException {
        System.out.println("tag:"+tag);
        archive.startRecord(tag);
        this.number=archive.readInt("number");
        this.name=archive.readString("name");
        archive.endRecord(tag);
    }
}


接下来是我们的测试类

package 源码分析.jute包;
import org.apache.jute.BinaryInputArchive;
import org.apache.jute.BinaryOutputArchive;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
 * @author idea
 * @data 2019/10/27
 */
public class TestDemo {
    public static void main(String[] args) throws IOException {
        //先序列化操作
        ByteArrayOutputStream baos=new ByteArrayOutputStream();
        BinaryOutputArchive boa= BinaryOutputArchive.getArchive(baos);
        new TestBean(1,"idea").serialize(boa,"tag1");
        byte[] array=baos.toByteArray();
        ByteArrayInputStream bins=new ByteArrayInputStream(array);
        BinaryInputArchive bia=BinaryInputArchive.getArchive(bins);
        TestBean testBean=new TestBean();
        testBean.deserialize(bia,"tag1");
        System.out.println("int="+testBean.getNumber()+"--string="+testBean.getName());
        bins.close();
        baos.close();
    }
}

处理完毕之后,便是我们的数据展示环节了。
看完之后你可能会觉得,怎么zk里面的数据类型进行序列化和反序列化需要提前对bean做如此复杂的操作啊?是的,在zk源码的
包org.apache.zookeeper.data下边,会看到相应的类都做了非常复杂的操作,举个案例来说,例如说Stat这个对象,在它的源码里面可以看到这样的内容描述:

// File generated by hadoop record compiler. Do not edit.
package org.apache.zookeeper.data;
import org.apache.jute.*;
public class Stat implements Record {
  private long czxid;
  private long mzxid;
  private long ctime;
  private long mtime;
  private int version;
  private int cversion;
  private int aversion;
  private long ephemeralOwner;
  private int dataLength;
  private int numChildren;
  private long pzxid;
  public Stat() {
  }
  public Stat(
        long czxid,
        long mzxid,
        long ctime,
        long mtime,
        int version,
        int cversion,
        int aversion,
        long ephemeralOwner,
        int dataLength,
        int numChildren,
        long pzxid) {
    this.czxid=czxid;
    this.mzxid=mzxid;
    this.ctime=ctime;
    this.mtime=mtime;
    this.version=version;
    this.cversion=cversion;
    this.aversion=aversion;
    this.ephemeralOwner=ephemeralOwner;
    this.dataLength=dataLength;
    this.numChildren=numChildren;
    this.pzxid=pzxid;
  }
  public long getCzxid() {
    return czxid;
  }
  public void setCzxid(long m_) {
    czxid=m_;
  }
  public long getMzxid() {
    return mzxid;
  }
  public void setMzxid(long m_) {
    mzxid=m_;
  }
  public long getCtime() {
    return ctime;
  }
  public void setCtime(long m_) {
    ctime=m_;
  }
  public long getMtime() {
    return mtime;
  }
  public void setMtime(long m_) {
    mtime=m_;
  }
  public int getVersion() {
    return version;
  }
  public void setVersion(int m_) {
    version=m_;
  }
  public int getCversion() {
    return cversion;
  }
  public void setCversion(int m_) {
    cversion=m_;
  }
  public int getAversion() {
    return aversion;
  }
  public void setAversion(int m_) {
    aversion=m_;
  }
  public long getEphemeralOwner() {
    return ephemeralOwner;
  }
  public void setEphemeralOwner(long m_) {
    ephemeralOwner=m_;
  }
  public int getDataLength() {
    return dataLength;
  }
  public void setDataLength(int m_) {
    dataLength=m_;
  }
  public int getNumChildren() {
    return numChildren;
  }
  public void setNumChildren(int m_) {
    numChildren=m_;
  }
  public long getPzxid() {
    return pzxid;
  }
  public void setPzxid(long m_) {
    pzxid=m_;
  }
  public void serialize(OutputArchive a_, String tag) throws java.io.IOException {
    a_.startRecord(this,tag);
    a_.writeLong(czxid,"czxid");
    a_.writeLong(mzxid,"mzxid");
    a_.writeLong(ctime,"ctime");
    a_.writeLong(mtime,"mtime");
    a_.writeInt(version,"version");
    a_.writeInt(cversion,"cversion");
    a_.writeInt(aversion,"aversion");
    a_.writeLong(ephemeralOwner,"ephemeralOwner");
    a_.writeInt(dataLength,"dataLength");
    a_.writeInt(numChildren,"numChildren");
    a_.writeLong(pzxid,"pzxid");
    a_.endRecord(this,tag);
  }
  public void deserialize(InputArchive a_, String tag) throws java.io.IOException {
    a_.startRecord(tag);
    czxid=a_.readLong("czxid");
    mzxid=a_.readLong("mzxid");
    ctime=a_.readLong("ctime");
    mtime=a_.readLong("mtime");
    version=a_.readInt("version");
    cversion=a_.readInt("cversion");
    aversion=a_.readInt("aversion");
    ephemeralOwner=a_.readLong("ephemeralOwner");
    dataLength=a_.readInt("dataLength");
    numChildren=a_.readInt("numChildren");
    pzxid=a_.readLong("pzxid");
    a_.endRecord(tag);
}
  public String toString() {
    try {
      java.io.ByteArrayOutputStream s =
        new java.io.ByteArrayOutputStream();
      CsvOutputArchive a_ = 
        new CsvOutputArchive(s);
      a_.startRecord(this,"");
    a_.writeLong(czxid,"czxid");
    a_.writeLong(mzxid,"mzxid");
    a_.writeLong(ctime,"ctime");
    a_.writeLong(mtime,"mtime");
    a_.writeInt(version,"version");
    a_.writeInt(cversion,"cversion");
    a_.writeInt(aversion,"aversion");
    a_.writeLong(ephemeralOwner,"ephemeralOwner");
    a_.writeInt(dataLength,"dataLength");
    a_.writeInt(numChildren,"numChildren");
    a_.writeLong(pzxid,"pzxid");
      a_.endRecord(this,"");
      return new String(s.toByteArray(), "UTF-8");
    } catch (Throwable ex) {
      ex.printStackTrace();
    }
    return "ERROR";
  }
  public void write(java.io.DataOutput out) throws java.io.IOException {
    BinaryOutputArchive archive = new BinaryOutputArchive(out);
    serialize(archive, "");
  }
  public void readFields(java.io.DataInput in) throws java.io.IOException {
    BinaryInputArchive archive = new BinaryInputArchive(in);
    deserialize(archive, "");
  }
  public int compareTo (Object peer_) throws ClassCastException {
    if (!(peer_ instanceof Stat)) {
      throw new ClassCastException("Comparing different types of records.");
    }
    Stat peer = (Stat) peer_;
    int ret = 0;
    ret = (czxid == peer.czxid)? 0 :((czxid<peer.czxid)?-1:1);
    if (ret != 0) return ret;
    ret = (mzxid == peer.mzxid)? 0 :((mzxid<peer.mzxid)?-1:1);
    if (ret != 0) return ret;
    ret = (ctime == peer.ctime)? 0 :((ctime<peer.ctime)?-1:1);
    if (ret != 0) return ret;
    ret = (mtime == peer.mtime)? 0 :((mtime<peer.mtime)?-1:1);
    if (ret != 0) return ret;
    ret = (version == peer.version)? 0 :((version<peer.version)?-1:1);
    if (ret != 0) return ret;
    ret = (cversion == peer.cversion)? 0 :((cversion<peer.cversion)?-1:1);
    if (ret != 0) return ret;
    ret = (aversion == peer.aversion)? 0 :((aversion<peer.aversion)?-1:1);
    if (ret != 0) return ret;
    ret = (ephemeralOwner == peer.ephemeralOwner)? 0 :((ephemeralOwner<peer.ephemeralOwner)?-1:1);
    if (ret != 0) return ret;
    ret = (dataLength == peer.dataLength)? 0 :((dataLength<peer.dataLength)?-1:1);
    if (ret != 0) return ret;
    ret = (numChildren == peer.numChildren)? 0 :((numChildren<peer.numChildren)?-1:1);
    if (ret != 0) return ret;
    ret = (pzxid == peer.pzxid)? 0 :((pzxid<peer.pzxid)?-1:1);
    if (ret != 0) return ret;
     return ret;
  }
  public boolean equals(Object peer_) {
    if (!(peer_ instanceof Stat)) {
      return false;
    }
    if (peer_ == this) {
      return true;
    }
    Stat peer = (Stat) peer_;
    boolean ret = false;
    ret = (czxid==peer.czxid);
    if (!ret) return ret;
    ret = (mzxid==peer.mzxid);
    if (!ret) return ret;
    ret = (ctime==peer.ctime);
    if (!ret) return ret;
    ret = (mtime==peer.mtime);
    if (!ret) return ret;
    ret = (version==peer.version);
    if (!ret) return ret;
    ret = (cversion==peer.cversion);
    if (!ret) return ret;
    ret = (aversion==peer.aversion);
    if (!ret) return ret;
    ret = (ephemeralOwner==peer.ephemeralOwner);
    if (!ret) return ret;
    ret = (dataLength==peer.dataLength);
    if (!ret) return ret;
    ret = (numChildren==peer.numChildren);
    if (!ret) return ret;
    ret = (pzxid==peer.pzxid);
    if (!ret) return ret;
     return ret;
  }
  public int hashCode() {
    int result = 17;
    int ret;
    ret = (int) (czxid^(czxid>>>32));
    result = 37*result + ret;
    ret = (int) (mzxid^(mzxid>>>32));
    result = 37*result + ret;
    ret = (int) (ctime^(ctime>>>32));
    result = 37*result + ret;
    ret = (int) (mtime^(mtime>>>32));
    result = 37*result + ret;
    ret = (int)version;
    result = 37*result + ret;
    ret = (int)cversion;
    result = 37*result + ret;
    ret = (int)aversion;
    result = 37*result + ret;
    ret = (int) (ephemeralOwner^(ephemeralOwner>>>32));
    result = 37*result + ret;
    ret = (int)dataLength;
    result = 37*result + ret;
    ret = (int)numChildren;
    result = 37*result + ret;
    ret = (int) (pzxid^(pzxid>>>32));
    result = 37*result + ret;
    return result;
  }
  public static String signature() {
    return "LStat(lllliiiliil)";
  }
}

这段代码非常的长,通过一些晚上的性能比对测试,会发现在速度方便jute的序列化性能要比protobuf好一些,但是码流方面后者更佳。
本文讲解了关于zk内部的序列化机制,认真观看之后会发现,zk并没有对jdk本身的序列化方式做什么优化的手段,因此并没有什么过多的特别之处。更多的就是在DataInputStream那个位置加入了一些数据的接受和处理。

让我们回顾一下以前写过的一篇序列化文章,或许两篇文章对比之后你会有不同的收获和体会。
https://blog.csdn.net/Danny_idea/article/details/99620144

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章