简单的zoo.cfg配置如下
tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
initLimit=5
syncLimit=2
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
这里重点分析server.x配置项的解析
/**
* Parse a ZooKeeper configuration file
* @param path the patch of the configuration file
* @throws ConfigException error processing configuration
*/
public void parse(String path) throws ConfigException {
LOG.info("Reading configuration from: " + path);
try {
File configFile = (new VerifyingFileFactory.Builder(LOG)
.warnForRelativePath()
.failForNonExistingPath()
.build()).create(path); // 根据配置文件路径实例化File对象
Properties cfg = new Properties();
FileInputStream in = new FileInputStream(configFile);
try {
cfg.load(in); // 读取配置文件
configFileStr = path;
} finally {
in.close();
}
/* Read entire config file as initial configuration */
initialConfig = new String(Files.readAllBytes(configFile.toPath()));
parseProperties(cfg); // 解析配置文件
} ...
...
}
/**
* Parse config from a Properties.
* @param zkProp Properties to parse from.
* @throws IOException
* @throws ConfigException
*/
public void parseProperties(Properties zkProp) throws IOException, ConfigException {
...
for (Entry<Object, Object> entry : zkProp.entrySet()) {
... // 具体的配置项解析
}
...
// backward compatibility - dynamic configuration in the same file as
// static configuration params see writeDynamicConfig()
if (dynamicConfigFileStr == null) { // 上面的for循环中会对dynamicConfigFileStr进行赋值,但是配置文件中没有dynamicConfigFile项,同静态配置文件
setupQuorumPeerConfig(zkProp, true);
if (isDistributed() && isReconfigEnabled()) {
// we don't backup static config for standalone mode.
// we also don't backup if reconfig feature is disabled.
backupOldConfig();
}
}
}
void setupQuorumPeerConfig(Properties prop, boolean configBackwardCompatibilityMode) throws IOException, ConfigException {
quorumVerifier = parseDynamicConfig(prop, electionAlg, true, configBackwardCompatibilityMode);
setupMyId(); // 设置sid(myid)
setupClientPort();
setupPeerType();
checkValidity();
}
/**
* Parse dynamic configuration file and return
* quorumVerifier for new configuration.
* @param dynamicConfigProp Properties to parse from.
* @throws IOException
* @throws ConfigException
*/
public static QuorumVerifier parseDynamicConfig(Properties dynamicConfigProp, int eAlg, boolean warnings, boolean configBackwardCompatibilityMode) throws IOException, ConfigException {
boolean isHierarchical = false;
for (Entry<Object, Object> entry : dynamicConfigProp.entrySet()) {
String key = entry.getKey().toString().trim();
if (key.startsWith("group") || key.startsWith("weight")) {
isHierarchical = true;
} else if (!configBackwardCompatibilityMode && !key.startsWith("server.") && !key.equals("version")) {
LOG.info(dynamicConfigProp.toString());
throw new ConfigException("Unrecognised parameter: " + key);
}
}
QuorumVerifier qv = createQuorumVerifier(dynamicConfigProp, isHierarchical); // 由于没有配置group或者weight,isHierarchical为false
...
return qv;
}
private static QuorumVerifier createQuorumVerifier(Properties dynamicConfigProp, boolean isHierarchical) throws ConfigException {
if (isHierarchical) {
return new QuorumHierarchical(dynamicConfigProp);
} else {
/*
* The default QuorumVerifier is QuorumMaj
*/
//LOG.info("Defaulting to majority quorums");
return new QuorumMaj(dynamicConfigProp);
}
}
public QuorumMaj(Properties props) throws ConfigException {
for (Entry<Object, Object> entry : props.entrySet()) {
String key = entry.getKey().toString();
String value = entry.getValue().toString();
if (key.startsWith("server.")) { // 解析server.x
int dot = key.indexOf('.');
long sid = Long.parseLong(key.substring(dot + 1)); // sid or myid
QuorumServer qs = new QuorumServer(sid, value);
allMembers.put(Long.valueOf(sid), qs);
if (qs.type == LearnerType.PARTICIPANT) {
votingMembers.put(Long.valueOf(sid), qs); // leader or follower
} else {
observingMembers.put(Long.valueOf(sid), qs); // observer
}
} else if (key.equals("version")) {
version = Long.parseLong(value, 16);
}
}
half = votingMembers.size() / 2;
}
public QuorumServer(long sid, String addressStr) throws ConfigException {
this.id = sid;
LearnerType newType = null;
String[] serverClientParts = addressStr.split(";"); // 长度为1
String[] serverAddresses = serverClientParts[0].split("\\|"); // 长度为1
...
for (String serverAddress : serverAddresses) {
String serverParts[] = ConfigUtils.getHostAndPort(serverAddress); // 通过冒号分割
...
// server_config should be either host:port:port or host:port:port:type
InetSocketAddress tempAddress;
InetSocketAddress tempElectionAddress;
try {
tempAddress = new InetSocketAddress(serverParts[0], Integer.parseInt(serverParts[1]));
addr.addAddress(tempAddress); // 数据同步使用的ip+port
} ...
try {
tempElectionAddress = new InetSocketAddress(serverParts[0], Integer.parseInt(serverParts[2]));
electionAddr.addAddress(tempElectionAddress); // 选举使用的ip+port
} ...
...
this.hostname = serverParts[0]; // 表示的host
}
...
setMyAddrs();
}