http://www.bubuko.com/infodetail-615044.html
標簽:class style 代碼 com log 使用 java 文件 http
Zookeeper開發過程中一些常見問題
一、 關於zookeeper_init函數的使用
問題描述:
開發人員在調用zookeeper_init函數時,若返回一個非空句柄zhandle_t *zh,則認為初始化成功,這樣可能會導致后續操作失敗。
問題分析:
zhandle_t *zookeeper_init(const char *host, watcher_fn fn, int recv_timeout,const clientid_t *clientid, void *context, int flags) 函 數 返回一個zookeeper客戶端與服務器通信的句柄,通常我們僅僅根據返回句柄情況來判斷zookeeper 客戶端與zookeeper服務器是否 建立連接。如果句柄為空則認為是失敗,非空則成功。其實不然,zookeeper_init創建與ZooKeeper服務端通信的句柄以及對應於此句柄的會話,而會話的創建是一個異步的過程,僅當會話建立成功,zookeeper_init才返回一個可用句柄。
問題解決:
如何正確判斷zookeepr_init初始化成功,可通過以下三種方式
1、判斷句柄的state是否為ZOO_CONNECTED_STATE狀態,通過zoo_state(zh)判斷狀態值是否為ZOO_CONNECTED_STATE。
1
2
3
4
5
6
7
8
9
|
void ensureConnected()
{
pthread_mutex_lock(&lock);
while (zoo_state(zh)!=ZOO_CONNECTED_STATE)
{
pthread_cond_wait(&cond, &lock);
}
pthread_mutex_unlock(&lock);
}
|
2、 在zookeeper_init中設置watcher,當zookeeper client與server會話建立后,觸發watcher,當 watcher 的state = 3 (ZOO_CONNECTED_STATE), type = -1(ZOO_SESSION_EVENT)時,確認 會話成功建立,此時zookeeper client 初始化成功,可進行后續操作。
3、業務上可以做保證,調用zookeeper_init返回句柄zh,通過該句柄嘗試做zoo_exists()或zoo_get_data()等操作,根據操作結果來判斷是否初始化成功。
二、 如何解決session失效問題
問題描述:
session失效,導致注冊的watcher全部丟失。
問題分析:
如果zookeeper client與server在協商的超時時間內仍沒有建立連接,當client與server再次建立連接時,由於session失效了,所有watcher已經被服務器端刪除,從而導致所有的watcher需要重新注冊。
session 失效,zookeeper client與server重連后所有watcher都會收到兩次觸發,第一次 wathetr state = 1,type = -1(state = 1表示正在連接中,type = -1 表示session事件);第二次 watcher state = -112,type = -1(state = -112表示session失效)。
問題解決:
可以通過以下兩種方法解決session失效問題
1、獲取觸發session失效watcher后,業務重新注冊所有的watcher。
2、不能根本解決,但是可以減小session失效的概率。通過zookeeper client 與server設置更長的session超時時間。(參考下一問題)
三、 為什么zookeeper_init設置recv_timeout較長卻沒有效果
問題描述:
zookeeper_init設置recv_timeout 100000ms,但客戶端與服務端斷開連接30s就session失效了。
問題分析:
關於session超時時間的確定:zookeeper_init中設置的超時時間並非真正的session超時時間,session超時時間需要 server與client協商,業務通過zoo_recv_timeout(zhandle_t* zh)獲取server與client協商后的超時時間。服務端: minSessionTimeout (默認值為:tickTime * 2) , maxSessionTimeout(默認值為:tickTime * 20), ticktime的默認值為2000ms。所以session范圍為4s ~ 40s 。客戶端: sessionTimeout, 無默認值,創建實例時設置recv_timeout 值。經常會認為創建zookeeper客戶端時設置了sessionTimeout為100s,而沒有改變server端的配置,默認值是 不會生效的。 原因: 客戶端的zookeeper實例在創建連接時,將sessionTimeout參數發送給了服務端,服務端會根據對應的 minSession/maxSession Timeout的設置,強制修改sessionTimeout參數,也就是修改為4s~40s 返回的參數。所以服務端不一定會以客戶端的sessionTImeout做為session expire管理的時間。
問題解決:
增加zookeeper_init recv_timeout大小的同時,需要配置tickTime的值。
tickTime設置是在 conf/zoo.cfg 文件中
# The number of milliseconds of each ticktickTime=2000 (默認) 注: tickTime 心跳基本時間單位毫秒,ZK基本上所有的時間都是這個時間的整數倍。 |
四、 zoo_get_children內存泄露問題
問題描述:
調用zoo_get_children函數出現內存泄露問題。
問題分析:
通過查看代碼發現問題在於 ZOOAPI int zoo_get_children(zhandle_t *zh, const char *path, int watch,struct String_vector *strings), 該API中String_vector *strings結構體定義如下:
1
2
3
4
5
|
struct String_vector
{
int32_t count;
char * *data;
};
|
Zookeeper API將getchildren結果通過String_vector結構體返回時,malloc分配內存,將子節點所有目錄存放在data中,而釋放內存需要有客戶端來做處理。
問題解決:
調用zoo_get_children(zh, path, watch, strings);需要通過調用zookeper提供的釋放內存的方法:deallocate_String_vector(strings)。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
int deallocate_String_vector(struct String_vector *v){
if (v->data)
{
int32_t i;
for(i = 0; i < v->count; i++)
{
deallocate_String(&v->data[i]);
}
free(v->data);
v->data = 0;
}
return 0;
}
|
五、 如何正確設置和獲取watcher
Watcher 設置是開發中最常見的,需要搞清楚watcher的一些基本特征,對於exists、getdata、getchild對於節點的不同操作會收到不同的 watcher信息。對父節點的變更以及孫節點的變更都不會觸發watcher,而對watcher本身節點以及子節點的變更會觸發watcher,具體參照下表。
操作 | 方法 | 觸發watcher | watcher state | watcher type | watcher path |
Create當前節點 | getdata | × | × | × | × |
getchildren | √ | 3 | 4 | √ | |
exists | × | × | × | × | |
set當前節點 | getdata | √ | 3 | 3 | √ |
getchildren | × | × | × | × | |
exists | √ | 3 | 3 | √ | |
delete當前節點 | getdata | √ | 3 | 2 | √ |
getchildren | √ | 3 | 2 | √ | |
exists | √ | 3 | 2 | √ | |
create子節點 | getdata | × | × | × | × |
getchildren | √ | 3 | 4 | √ | |
exists | × | × | × | × | |
set子節點 | getdata | × | × | × | × |
getchildren | × | × | × | × | |
exists | × | × | × | × | |
delete子節點 | getdata | × | × | × | × |
getchildren | √ | 3 | 4 | √ | |
exists | × | × | × | × | |
恢復連接 | getdata | √ | 1 | -1 | × |
getchildren | √ | 1 | -1 | × | |
exists | √ | 1 | -1 | × | |
恢復連接session未超時 | getdata | √ | -112 | -1 | × |
getchildren | √ | -112 | -1 | × | |
exists | √ | -112 | -1 | × | |
恢復連接session超時 | getdata | √ | 3 | -1 | × |
getchildren | √ | 3 | -1 | × | |
exists | √ | 3 | -1 | × |
注: state = 2 表示刪除事件;state = 3表示節點數據變更;state =4表示子節點事件;state = -1表示session事件。 type = -112表示session失效;type = 1表示session建立中;tpye = = 3表示session建立成功。×表示否,√表示是。
六、 zookeeper連接數問題
問題描述:
zookeeper服務器都運行正常,而客戶端連接異常。
問題分析:
這是由於zookeeper client連接數已經超過了zookeeper server獲取的配置最大連接數。所以導致zookeeper client連接失敗。
解決方法:
修改zookeeper安裝目錄下 conf/zoo.cfg文件。將maxClientCnxns參數改成更大的值。
七、 zookeeper服務器安裝相關問題
問題一:是否可以只裝一個zookeeper服務器。
問題解答:
可以安裝,此時沒有leader,follow,此時zookeeper server狀態為standalone。
./zkServer.sh status JMX enabled by default Using config: /home/bbs/zookeeper-3.4.5/bin/../conf/zoo.cfg Mode: standalone |
關於zoo.cfg配置:
tickTime=2000initLimit=10 syncLimit=5 dataDir=../data clientPort=4181 |
問題二:開發沒有足夠機器,一台機子上是否裝三個zookeeper服務器集群。
問題解答:
這種安裝模式只能說是一種偽集群模式。三個zookeeper服務器都安裝在同一個服務器(platform)上,需保證clientPort不相同。
將zookeeper安裝包分別解壓在三個目錄server1,server2,server3下,配置文件zoo.cfg
Server1配置文件 zoo.cfg,server1在data目錄下增加文件myid內容為1。
dataDir=../datadata LogDir=../dataLog clientPort=5181 server.1=platform:5888:6888 server.2= platform:5889:6889 server.3= platform:5890:6890 |
Server2配置文件 zoo.cfg,server1在data目錄下增加文件myid內容為2。
dataDir=../datadata LogDir=../dataLog clientPort=6181 server.1=platform:5888:6888 server.2= platform:5889:6889 server.3= platform:5890:6890 |
Server3配置文件 zoo.cfg,server1在data目錄下增加文件myid內容為3。
dataDir=../datadata LogDir=../dataLog clientPort=7181 server.1=platform:5888:6888 server.2= platform:5889:6889 server.3= platform:5890:6890 |
以上出處“UC技術博客” http://tech.uc.cn/?p=1189
啟動zookeeper中的常見問題
1. 啟動zookeeper后出現noClassFound等等錯誤,例如:
Exception in thread "main" java.lang.NoSuchMethodError: method java.lang.management.ManagementFactory.getPlatformMBeanServer with signature ()Ljavax.management.MBeanServer; was not found.
at org.apache.zookeeper.jmx.ManagedUtil.registerLog4jMBeans(ManagedUtil.java:48)
at org.apache.zookeeper.server.quorum.QuorumPeerMain.runFromConfig(QuorumPeerMain.java:114)
at org.apache.zookeeper.server.quorum.QuorumPeerMain.initializeAndRun(QuorumPeerMain.java:103)
at org.apache.zookeeper.server.quorum.QuorumPeerMain.main(QuorumPeerMain.java:7
可能原因是該服務器的jdk版本不正確,或是環境變量未設置好。
例如,原來的linux下已經裝有jdk-1.4,然后又安裝了新版本的jdk-1.6,我們按照網上教程的步驟安裝好zookeeper並設置環境變量后,
echo $JAVA_HOME顯示java-1.6,
但是用java -version命令發現,仍然顯示java-1.4,說明環境變量未配好。zookeeper讀取的jdk版本仍然是舊版本的jdk-1.4。
解決方法是在/etc/bashrc文件的末尾,
export JAVA_HOME=/usr/java/jdk1.6.0_23
export JRE_HOME=$JAVA_HOME/jre
export PATH=$JAVA_HOME/bin:$PATH
//這里要注意,應該將$PATH放在尾部而不是放在頭部,網上有安裝教程寫的是$PATH :$JAVA_HOME/bin,這樣zookeeper讀取的將是$PATH中的jdk舊版本而出錯。
export CLASSPATH=.:$JAVA_HOME/lib/*.jar
2. 當一台或某台機器反復出現cannot open channel to xxxx:2888/3888,報錯(例如無法與leader進行同步等等錯誤),無法完成選舉(這個錯誤以前一直有出現,但是時有時無,不知道為什么)。
可能原因是防火牆開啟,導致某台機器的端口不能開啟,一般是2888不能開啟。linux下的很多分布式應用會要求關閉防火牆。。。所以還是干脆關閉算了。今天把防火牆直接關閉后zookeeper啟動正常。
用命令service iptables status查看,顯示一系列消息,表示防火牆處於開啟狀態;可以用service iptables stop關閉防火牆。但是這個只是臨時關閉防火牆。
要使系統啟動時不自動啟動防火牆,則可以使用命令chkconfig –list iptables查看防火牆信息,chkconfig iptables off關閉防火牆。以后若要打開,用chkconfig iptables on命令。
3.Zookeeper能夠正常啟動,但是顯示如下錯誤:
Starting zookeeper…
./zkServer.sh: line 80: /home /sysdata/zookeeper/zookeeper-data/zookeeper_server.pid: No such file or directory
STARTED
在配置文件zoo.cfg文件中指定了zookeeper啟動的pid文件的生成位置:dataDir=/home /sysdata/zookeeper/zookeeper-data,但是我們發現該pid並沒有生成。而且想要停止zookeeper顯然也不能成功:
Stopping zookeeper ...
error: could not find file /zookeeper_server.pid。
zoo.cfg文件中的給dataDir路徑賦值前多了一個空格!zookeeper在讀取此配置文件時會把空格也讀進文件名,將此空格刪去后zookeeper啟動、關閉就正常了!
摘自 http://hi.baidu.com/luhao8415/item/23c6e7f075aa18b730c1993a
標簽:class style 代碼 com log 使用 java 文件 http
原文:http://www.cnblogs.com/binyue/p/4270150.html