查看PDF版本 java
轉載請用註明:@ni掌櫃nileader@gmail.comgit
在以前一個文章《ZooKeeper Java API 使用樣例》中提到,客戶端使用ZooKeeper的時候,首先會創建與ZooKeeper的鏈接,方法是經過調用下面這個構造方法來實現的。 github
- public ZooKeeper(String connectString, //
- int sessionTimeout, //
- Watcher watcher,//
- boolean canBeReadOnly )
- throws IOException
在這個構造方法中,首先要配置的是ZK服務器的地址列表,即connectString 這個參數,這個參數一般是這樣一個格式的字符串:服務器
- 192.168.1.1:2181,192.168.1.2:2181,192.168.1.3:2181
很明顯,咱們能夠看到,ZK客戶端容許咱們將ZK服務器的全部地址都配置在這裏,因而一個問題就來了,ZK在鏈接服務器過程當中,是如何選擇服務器的呢?下面首先來看看ZK客戶端是如何處理這個connectString的:session
- new ZooKeeper(「192.168.1.1:2181,192.168.1.2:2181,192.168.1.3:2181」,...)
實例一個ZooKeeper對象的時候,會要求傳入一個地址列表的字符串,這個字符串就是ZK服務器的地址列表,用英文狀態「,「隔開。ide
new ConnectStringParser(「192.168.1.1:2181,192.168.1.2:2181,192.168.1.3:2181」);
- ConnectStringParser connectStringParser =
以後,這個地址列表會被封裝到一個ConnectStringParser 對象中去,這個類主要就是解析傳入地址列表字符串,將其它保存在一個ArrayList中。這個對象基本結構以下,這裏咱們主要關注serverAddresses這個成員。this
- public final class ConnectStringParser {
- private final String chrootPath;
- private final ArrayList<InetSocketAddress> serverAddresses = new ArrayList<InetSocketAddress>();
- }
接下去,這個地址列表會被進一步封裝成StaticHostProvider對象,而且在運行過程當中,一直是這個對象來維護整個地址列表。關於這個對象,咱們主要關注兩點:地址列表的隨機和地址獲取這兩個過程。首先來看地址列表的隨機:spa
- public StaticHostProvider(Collection<InetSocketAddress> serverAddresses)
- throws UnknownHostException {
- ……
- ……
- Collections.shuffle(this.serverAddresses);
- }
這裏能夠看到,對於傳入地址列表,ZK使用java.util.Collections.shuffle(List list) 來對地址列表隨機打亂順序,注意,這個隨機過程是一次性的,也就是說,以後使用過程當中一直是按照這樣的順序。再來看看地址列表被隨機打亂後,又是怎麼使用地址的:server
- public InetSocketAddress next(long spinDelay) {
- ++currentIndex;
- if (currentIndex == serverAddresses.size()) {
- currentIndex = 0;
- }
- ……
- ……
- return serverAddresses.get(currentIndex);
- }
看一下StaticHostProvider.next(long spinDelay) 方法就明白了。next方法的實現, 沒錯,就是「Round Robin」。簡單的說,ZK客戶端將全部Server保存在一個List中,而後隨機打亂,而且造成一個環,具體使用的時候,從0號位開始一個一個使用。xml
另外兩個注意點:
1.經過代碼,能夠發現ZK本質上是經過一個List來維護地址列表的,所以,Server地址可以重複配置,這樣可以彌補客戶端沒法設置Server權重的缺陷,可是也會加大風險。 好比: 192.168.1.1:2181,192.168.1.1:2181,192.168.1.2:2181
2.若是客戶端在進行Server切換過程當中耗時過長,那麼將會收到SESSION_EXPIRED. 這也是上面第1點中的加大風險之處。