设为首页 收藏本站
查看: 2377|回复: 0

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

[复制链接]

尚未签到

发表于 2017-4-19 09:04:40 | 显示全部楼层 |阅读模式
  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通信的核心类,单独进行分析

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-366154-1-1.html 上篇帖子: zookeeper的应用场景 下篇帖子: zookeeper 启动出错问题排查
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表