[Zookeeper学习笔记九]Zookeeper源代码分析之Zookeeper构造过程

编程技术  /  houtizong 发布于 3年前   88

   Zookeeper重载了几个构造函数,其中构造者可以提供参数最多,可定制性最多的构造函数是  

 

public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly)

 

 

    /**     * To create a ZooKeeper client object, the application needs to pass a     * connection string containing a comma separated list of host:port pairs,     * each corresponding to a ZooKeeper server.     * <p>     * Session establishment is asynchronous. This constructor will initiate     * connection to the server and return immediately - potentially (usually)     * before the session is fully established. The watcher argument specifies     * the watcher that will be notified of any changes in state. This     * notification can come at any point before or after the constructor call     * has returned.     * <p>     * The instantiated ZooKeeper client object will pick an arbitrary server     * from the connectString and attempt to connect to it. If establishment of     * the connection fails, another server in the connect string will be tried     * (the order is non-deterministic, as we random shuffle the list), until a     * connection is established. The client will continue attempts until the     * session is explicitly closed (or the session is expired by the server).     * <p>     * Added in 3.2.0: An optional "chroot" suffix may also be appended to the     * connection string. This will run the client commands while interpreting     * all paths relative to this root (similar to the unix chroot command).     * <p>     * Use {@link #getSessionId} and {@link #getSessionPasswd} on an established     * client connection, these values must be passed as sessionId and     * sessionPasswd respectively if reconnecting. Otherwise, if not     * reconnecting, use the other constructor which does not require these     * parameters.     *     * @param connectString     *            comma separated host:port pairs, each corresponding to a zk     *            server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002"     *            If the optional chroot suffix is used the example would look     *            like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a"     *            where the client would be rooted at "/app/a" and all paths     *            would be relative to this root - ie getting/setting/etc...     *            "/foo/bar" would result in operations being run on     *            "/app/a/foo/bar" (from the server perspective).     * @param sessionTimeout     *            session timeout in milliseconds     * @param watcher     *            a watcher object which will be notified of state changes, may     *            also be notified for node events     * @param sessionId     *            specific session id to use if reconnecting     * @param sessionPasswd     *            password for this session     * @param canBeReadOnly     *            (added in 3.4) whether the created client is allowed to go to     *            read-only mode in case of partitioning. Read-only mode     *            basically means that if the client can't find any majority     *            servers but there's partitioned server it could reach, it     *            connects to one in read-only mode, i.e. read requests are     *            allowed while write requests are not. It continues seeking for     *            majority in the background.     *     * @throws IOException in cases of network failure     * @throws IllegalArgumentException if an invalid chroot path is specified     */    //sessionId和sessionPasswd用于重连,    public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher,            long sessionId, byte[] sessionPasswd, boolean canBeReadOnly)        throws IOException    {        LOG.info("Initiating client connection, connectString=" + connectString                + " sessionTimeout=" + sessionTimeout                + " watcher=" + watcher                + " sessionId=" + Long.toHexString(sessionId)                + " sessionPasswd="                + (sessionPasswd == null ? "<null>" : "<hidden>"));        //设置作为Zookeeper的默认Watcher        watchManager.defaultWatcher = watcher;                //解析链接串,链接是IP:Port,用逗号分割的串        ConnectStringParser connectStringParser = new ConnectStringParser(                connectString);                HostProvider hostProvider = new StaticHostProvider(                connectStringParser.getServerAddresses());        //封装IO和Event相关的线程        cnxn = new ClientCnxn(connectStringParser.getChrootPath(),                hostProvider, sessionTimeout, this, watchManager,                getClientCnxnSocket(), sessionId, sessionPasswd, canBeReadOnly);        cnxn.seenRwServerBefore = true; // since user has provided sessionId        cnxn.start();    }

 

 ConnectionStringParser类

  public ConnectStringParser(String connectString) {        // parse out chroot, if any        int off = connectString.indexOf('/');        if (off >= 0) {            String chrootPath = connectString.substring(off);            // ignore "/" chroot spec, same as null            if (chrootPath.length() == 1) {                this.chrootPath = null;            } else {                PathUtils.validatePath(chrootPath);                this.chrootPath = chrootPath;            }            connectString = connectString.substring(0, off);        } else {            this.chrootPath = null;        }        String hostsList[] = connectString.split(",");        for (String host : hostsList) {            int port = DEFAULT_PORT;            int pidx = host.lastIndexOf(':');            if (pidx >= 0) {                // otherwise : is at the end of the string, ignore                if (pidx < host.length() - 1) {                    port = Integer.parseInt(host.substring(pidx + 1));                }                host = host.substring(0, pidx);            }            serverAddresses.add(InetSocketAddress.createUnresolved(host, port));        }    }

 ConnectionStringParser类主要是构造函数,构造函数包括两个功能,1.从connectString中解析出chrootPath 2.从connectString解析出Zookeeper服务器列表,解析成InetSocketAddress列表

chrootPath的语法同znode的path一样,以/开头,chrootPath有什么功能呢?

 

HostProvider和StaticHostProvider类

/** * A set of hosts a ZooKeeper client should connect to.//Zookeeper客户端尝试建立Zookeeper服务器的服务器列表 *  * Classes implementing this interface must guarantee the following://HostProvider类实现规范 *  * * Every call to next() returns an InetSocketAddress. So the iterator never //next是循环或者随即选取,但是不能返回null * ends. *  * * The size() of a HostProvider may never be zero.//HostProvider的服务器列表不能为空 *  * A HostProvider must return resolved InetSocketAddress instances on next(), * but it's up to the HostProvider, when it wants to do the resolving. //HostProvider的next返回resolved InetSocketAddress实例,HostProvider的实现者负责解析InetSocketAddress *  * Different HostProvider could be imagined: //HostProvider的可能实现 *  * * A HostProvider that loads the list of Hosts from an URL or from DNS //域名或者IP列表 * * A HostProvider that re-resolves the InetSocketAddress after a timeout.  * * A HostProvider that prefers nearby hosts. */public interface HostProvider {    public int size();    /**     * The next host to try to connect to.     *      * For a spinDelay of 0 there should be no wait.     *      * @param spinDelay     *            Milliseconds to wait if all hosts have been tried once.     */    public InetSocketAddress next(long spinDelay);    /**     * Notify the HostProvider of a successful connection.     *      * The HostProvider may use this notification to reset it's inner state.     */    public void onConnected();}

 

 StaticHostProivder类的看点是它的构造方法,构造方法实现Resolved Address和Unresolved Address之间的转换,什么是解析了的地址(Resolved Address),什么是未解析的地址(Unresolved Address)呢?

 

/**     * Constructs a SimpleHostSet.     *      * @param serverAddresses     *            possibly unresolved ZooKeeper server addresses //传入的参数有可能是没有解析的Zookeeper服务器地址     * @throws UnknownHostException     * @throws IllegalArgumentException     *             if serverAddresses is empty or resolves to an empty list     */    public StaticHostProvider(Collection<InetSocketAddress> serverAddresses)            throws UnknownHostException {        //对传入的InetSocketAddress进行解析        for (InetSocketAddress address : serverAddresses) {            InetAddress ia = address.getAddress();            InetAddress resolvedAddresses[] = InetAddress.getAllByName((ia!=null) ? ia.getHostAddress():                address.getHostName());            for (InetAddress resolvedAddress : resolvedAddresses) {                // If hostName is null but the address is not, we can tell that                // the hostName is an literal IP address. Then we can set the host string as the hostname                // safely to avoid reverse DNS lookup.                // As far as i know, the only way to check if the hostName is null is use toString().                // Both the two implementations of InetAddress are final class, so we can trust the return value of                // the toString() method.                if (resolvedAddress.toString().startsWith("/")                         && resolvedAddress.getAddress() != null) {                    this.serverAddresses.add(                            new InetSocketAddress(InetAddress.getByAddress(                                    address.getHostName(),                                    resolvedAddress.getAddress()),                                     address.getPort()));                } else {                    this.serverAddresses.add(new InetSocketAddress(resolvedAddress.getHostAddress(), address.getPort()));                }              }        }                if (this.serverAddresses.isEmpty()) {            throw new IllegalArgumentException(                    "A HostProvider may not be empty!");        }        //对服务器列表进行洗牌打乱次序,传说中可以提升可靠性,这里的原因我猜想是在写服务器列表的时候,往往是把按机房一个一个的写,A机房3个Zookeeper,B机房4个Zookeeper,这7个可能是先写完A这里的3个,然后写B的4个        //打乱次序可以使得A挂了,找到B的可能性大点        Collections.shuffle(this.serverAddresses);    }

 

ClientCnxn是客户端跟Zookeeper通信的核心类,单独进行分析

 

 

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

留言需要登陆哦

技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成

网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];

      订阅博客周刊 去订阅

文章归档

文章标签

友情链接

Auther ·HouTiZong
侯体宗的博客
© 2020 zongscan.com
版权所有ICP证 : 粤ICP备20027696号
PHP交流群 也可以扫右边的二维码
侯体宗的博客