利用Transaction提交創建節點
/**
* <p>創建zNode節點, String create(path<節點路徑>, data[]<節點內容>, List(ACL訪問控制列表), CreateMode<zNode創建類型>) </p><br/>
* <pre>
* 節點創建類型(CreateMode)
* 1、PERSISTENT:持久化節點
* 2、PERSISTENT_SEQUENTIAL:順序自動編號持久化節點,這種節點會根據當前已存在的節點數自動加 1
* 3、EPHEMERAL:臨時節點客戶端,session超時這類節點就會被自動刪除
* 4、EPHEMERAL_SEQUENTIAL:臨時自動編號節點
* </pre>
* @param path zNode節點路徑
* @param data zNode數據內容
* @return 創建成功返回true, 反之返回false.
*/
public boolean createZNode(String path,String data){
try {
String zkPath = MyZooKeeper.zooKeeper.create(path, data.getBytes(),
acls, CreateMode.PERSISTENT);
logger.info("ZooKeeper創建節點成功,節點地址:" + zkPath);
return true;
} catch (KeeperException e) {
logger.error("創建節點失敗:" + e.getMessage() + ",path:" + path ,e);
} catch (InterruptedException e) {
logger.error("創建節點失敗:" + e.getMessage() + ",path:" + path ,e);
}
return false;
}
批量創建多個時,可以引入事物來進行對創建的控制:public boolean createZNode(List<String> path,List<String> data){
try {
Transaction tx = MyZooKeeper.zooKeeper.transaction();
for (int i = 0,len = path.size(); i < len; i++) {
createZNode(path.get(i), data.get(i));
}
tx.commit();
return true;
} catch (InterruptedException e) {
logger.error("創建節點失敗:" + e.getMessage() + ",path:" + path ,e);
} catch (KeeperException e) {
logger.error("創建節點失敗:" + e.getMessage() + ",path:" + path ,e);
}
return false;
}
Zookeeper對於事務性的支持
它對於事務性的支持主要依賴於四個函數支持主要依賴於四個函數,zoo_create_op_initzoo_delete_op_initzoo_set_op_init以及zoo_check_op_init。每一個函數都會在客戶端初始化一個operation,客戶端程序有義務保留這些operations。當準備好一個事務中的所有操作後,可以使用zoo_multi來提交所有的操作,由zookeeper服務來保證這一系列操作的原子性。也就是說只要其中有一個操作失敗了,相當於此次提交的任何一個操作都沒有對服務端的數據造成影響。Zoo_multi的返回值是第一個失敗操作的狀態信號。
Zookeeper通過版本號來保證操作的實效性。zoo_set的最後一個形參就是version number。如果提交的數和服務端在該節點的版本號對不上,那麼此次設值操作就失敗了。這可以解決這樣的情況:client1.get, client2.get, client2.set, client1.set。從client1的角度出發,set和get之前操作的變量值已經發生改變了,zookeeper非常負責的保證的最後一次set將不會成功,客戶端可以重新get, set一次。
Zookeeper查看事物日誌
zookeeper的事務日誌通過zoo.cfg文件中的dataLogDir配置項配置,文件如下:
zookeeper提供了查看事務日誌的工具類LogFormatter ,運行:
java -classpath .:slf4j-api-1.6.1.jar:zookeeper-3.4.5.jar org.apache.zookeeper.server.LogFormatter /export1/zookeeper/logs/version-2/log.1000003d2
ZooKeeper Transactional Log File with dbid 0 txnlog format version 2
5/12/14 7:06:31 PM CST session 0x145ef610b530000 cxid 0x229e zxid 0x1000003e8 delete '/hbase/region-in-transition/e3d18e83988febe321e563f085210127
5/12/14 7:06:31 PM CST session 0x245ef610b52004c cxid 0x0 zxid 0x1000003e9 createSession 40000
5/12/14 7:06:31 PM CST session 0x245ef610b52004c cxid 0x3 zxid 0x1000003ea closeSession null
5/12/14 7:06:31 PM CST session 0x545f01346c60001 cxid 0x0 zxid 0x1000003eb createSession 40000
5/12/14 7:06:31 PM CST session 0x545f01346c60001 cxid 0x3 zxid 0x1000003ec closeSession null
5/12/14 7:06:32 PM CST session 0x445f018d5e00002 cxid 0x0 zxid 0x1000003ed createSession 40000
5/12/14 7:06:32 PM CST session 0x445f018d5e00002 cxid 0x3 zxid 0x1000003ee closeSession null
5/12/14 7:06:32 PM CST session 0x145ef610b530000 cxid 0x22a1 zxid 0x1000003ef setData '/hbase/table/wyp,#ffffffff000146d61737465723a36303030303b36ffffffc765ffffffb0ffffffa5ffffffa3745042554681,5
5/12/14 7:06:32 PM CST session 0x145ef610b530000 cxid 0x22a3 zxid 0x1000003f0 delete '/hbase/table-lock/wyp/write-master:600000000000002
5/12/14 7:06:32 PM CST session 0x145ef610b530033 cxid 0x0 zxid 0x1000003f1 createSession 40000
5/12/14 7:06:32 PM CST session 0x145ef610b530033 cxid 0x3 zxid 0x1000003f2 closeSession null
LogFormatter 類代碼如下:/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zookeeper.server;
import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;
import java.util.zip.Adler32;
import java.util.zip.Checksum;
import org.apache.jute.BinaryInputArchive;
import org.apache.jute.InputArchive;
import org.apache.jute.Record;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.zookeeper.server.persistence.FileHeader;
import org.apache.zookeeper.server.persistence.FileTxnLog;
import org.apache.zookeeper.server.util.SerializeUtils;
import org.apache.zookeeper.txn.TxnHeader;
public class LogFormatter {
private static final Logger LOG = LoggerFactory.getLogger(LogFormatter.class);
/**
* @param args
*/
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("USAGE: LogFormatter log_file");
System.exit(2);
}
FileInputStream fis = new FileInputStream(args[0]);
BinaryInputArchive logStream = BinaryInputArchive.getArchive(fis);
FileHeader fhdr = new FileHeader();
fhdr.deserialize(logStream, "fileheader");
if (fhdr.getMagic() != FileTxnLog.TXNLOG_MAGIC) {
System.err.println("Invalid magic number for " + args[0]);
System.exit(2);
}
System.out.println("ZooKeeper Transactional Log File with dbid "
+ fhdr.getDbid() + " txnlog format version "
+ fhdr.getVersion());
int count = 0;
while (true) {
long crcValue;
byte[] bytes;
try {
crcValue = logStream.readLong("crcvalue");
bytes = logStream.readBuffer("txnEntry");
} catch (EOFException e) {
System.out.println("EOF reached after " + count + " txns.");
return;
}
if (bytes.length == 0) {
// Since we preallocate, we define EOF to be an
// empty transaction
System.out.println("EOF reached after " + count + " txns.");
return;
}
Checksum crc = new Adler32();
crc.update(bytes, 0, bytes.length);
if (crcValue != crc.getValue()) {
throw new IOException("CRC doesn't match " + crcValue +
" vs " + crc.getValue());
}
TxnHeader hdr = new TxnHeader();
Record txn = SerializeUtils.deserializeTxn(bytes, hdr);
System.out.println(DateFormat.getDateTimeInstance(DateFormat.SHORT,
DateFormat.LONG).format(new Date(hdr.getTime()))
+ " session 0x"
+ Long.toHexString(hdr.getClientId())
+ " cxid 0x"
+ Long.toHexString(hdr.getCxid())
+ " zxid 0x"
+ Long.toHexString(hdr.getZxid())
+ " " + TraceFormatter.op2String(hdr.getType()) + " " + txn);
if (logStream.readByte("EOR") != 'B') {
LOG.error("Last transaction was partial.");
throw new EOFException("Last transaction was partial.");
}
count++;
}
}
}