Zookeeper 配置中心服務治理實現
阿新 • • 發佈:2019-02-14
Zookeeper配置中心服務治理實現
背景
上一篇部落格詳細講解了為什麼我們要選擇Zookeeper作為服務發現框架而不是使用Eureka。
參考 這篇部落格將繼續講解怎麼實現的,裡面會有大量的程式碼的拷貝,具體的架構可以參考上一篇部落格的架構演進圖。本篇主要講解實現過程。
準備工作
- Spring Maven專案新增Zookeeper的依賴包,這樣就可以使用Zookeeper的SDK了。
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.3.6</version>
</dependency>
football-server實現服務註冊功能
建立Zookeeper.properties在resources目錄下,並寫入引數。
server.parent.name = football (註冊服務的父路徑)
server.instance.name = football-server (註冊服務的名字)
server.port = 8081 (註冊服務的埠號)
zookeeper.host = Your zookeeper address
zookeeper.port = Your zookeeper port
建立Zookeeper.properties讀取檔案的類。
@Component
public class ZookeeperProperties {
@Value("${zookeeper.host}")
private String host;
@Value("${zookeeper.port}")
private String zkPort;
@Value ("${server.parent.name}")
private String parentName;
@Value("${server.port}")
private String serverPort;
@Value("${server.instance.name}")
private String instanceName;
public String getZookeeperAddress(){
return String.format("%s:%s",host,zkPort);
}
public String getParentName() {
parentName=parentName.replace("/","");
return parentName;
}
public String getServerPort() {
return serverPort;
}
public String getInstanceName() {
parentName=parentName.replace("/","");
return instanceName;
}
}
在服務啟動成功後,呼叫Zookeeper的JavaSDK向Zookeeper註冊自己。
@Service
public class ZookeeperRegistrar implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
ZookeeperProperties zookeeperProperties;
private static Logger log = LoggerFactory.getLogger(ZookeeperRegistrar.class);
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
if(contextRefreshedEvent.getApplicationContext().getParent()==null){
try {
registry();
} catch (IOException e) {
log.error("fooball-server registry to zookeeper fault ,{}",e.getMessage());
e.printStackTrace();
} catch (InterruptedException e) {
log.error("fooball-server registry to zookeeper fault ,{}",e.getMessage());
e.printStackTrace();
} catch (KeeperException e) {
log.error("fooball-server registry to zookeeper fault ,{}",e.getMessage());
e.printStackTrace();
}
}
}
public void registry() throws IOException, KeeperException, InterruptedException {
Watcher watcher=new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
log.info("zookeeper watcher ,{}",watchedEvent.toString());
}
};
ZooKeeper zooKeeper = new ZooKeeper(zookeeperProperties.getZookeeperAddress(),200000,watcher);
initParentPath(zooKeeper,watcher);
createInstancePath(zooKeeper,watcher);
}
public void initParentPath(ZooKeeper zookeeper,Watcher watcher) throws KeeperException, InterruptedException, UnknownHostException {
String parentPath = String.format("/%s",zookeeperProperties.getParentName());
log.info("fooball-server parentPath:{}",parentPath);
if(zookeeper.exists(parentPath,watcher)==null){
zookeeper.create(parentPath,null,ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
log.info("create parentPath {} success.",parentPath);
}
}
public void createInstancePath(ZooKeeper zooKeeper,Watcher watcher) throws KeeperException, InterruptedException, UnknownHostException {
String instancePath = String.format("/%s/%s",zookeeperProperties.getParentName(),zookeeperProperties.getInstanceName());
zooKeeper.create(instancePath,instanceInfoToByte(),ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
log.info("create path {} success.",zookeeperProperties.getInstanceName());
}
public String getHost() throws UnknownHostException {
InetAddress address = InetAddress.getLocalHost();
return address.getHostAddress();
}
public InstanceInfo createInstanceInfo() throws UnknownHostException {
String host = String.format("%s:%s",getHost(),zookeeperProperties.getServerPort());
log.info("current instance host {}",host);
return new InstanceInfo(zookeeperProperties.getInstanceName(),host);
}
public byte[] instanceInfoToByte() throws UnknownHostException {
Gson gson=new Gson();
InstanceInfo instanceInfo = createInstanceInfo();
return gson.toJson(instanceInfo).getBytes();
}
}
fooball-meta實現服務發現功能
建立Zookeeper.properties和建立讀取.properties檔案的類和football-server一致。
從Zookeeper獲取註冊服務的引數
@Service
public class MetaService implements IMetaService {
@Autowired
ZooKeeper zooKeeper;
@Autowired
ZookeeperProperties zookeeperProperties;
@Autowired
Watcher watcher;
private static Logger log = LoggerFactory.getLogger(MetaService.class);
@Override
public List<InstanceInfo> getServiceInfo() {
try {
String parentPath = String.format("/%s",zookeeperProperties.getParentName());
List<String> childs = zooKeeper.getChildren(parentPath,false);
return getInstancesByName(childs);
} catch (KeeperException e) {
log.error("Zookeeper getChildren error!");
e.printStackTrace();
} catch (InterruptedException e) {
log.error("Zookeeper getChildren error!");
e.printStackTrace();
}
return Collections.emptyList();
}
public List<InstanceInfo> getInstancesByName(List<String> childs) throws KeeperException, InterruptedException {
List<InstanceInfo> instanceInfos =new ArrayList<InstanceInfo>();
for(String childName:childs){
String childPath = String.format("/%s/%s",zookeeperProperties.getParentName(),childName);
instanceInfos.add(getInstanceFromZK(childPath));
}
return instanceInfos;
}
public InstanceInfo getInstanceFromZK(String path) throws KeeperException, InterruptedException {
byte[] data = zooKeeper.getData(path,watcher,null);
String instanceJson = new String(data);
return new Gson().fromJson(instanceJson,InstanceInfo.class);
}
}