0
点赞
收藏
分享

微信扫一扫

Node ZooKeeper 服务发现获取服务节点信息并发送请求


公司服务治理需通过 ZK 来做服务发现,Java都被集成,有封装好的包,直接注释器调用即可。Node还需自己手搓。

1. node-zookeeper-client 包连接 ZK

官方文档:​​https://www.npmjs.com/package/node-zookeeper-client​​

安装

npm i node-zookeeper-client

2. 连接ZK

const Zookeeper = require('node-zookeeper-client');
const CONNECTION_STRING = "127.0.0.1:2181"; // 要连接的ZK地址
const OPTIONS = {
sessionTimeout: 5000
}
const zk = Zookeeper.createClient(CONNECTION_STRING, OPTIONS);
zk.on('connected', function(){
console.log("zk=====", zk);
});
//获取根节点下的子节点
zk.getChildren('/', function(error, children, stat){
if(error){
console.log(error.stack);
return;
}
console.log(children);
})
zk.connect();

3. 其他API

// 判断节点是否已存在
zk.exists('/phpnode',function(error,stat){
if(stat){
console.log("节点存在");
}else{
console.log("节点不存在");
}
})

// 创建/注册节点
zk.create('/phpnode',new Buffer('hello'),function(error,path){
console.log(path);
})

// 获取节点数据
zk.getData('/phpnode',function(error,data,stat){
console.log(data.toString());
});

//节点删除
zk.remove('/phpnode',function(error){
if(!error){
console.log('node 节点删除成功');
}
})

4. DEMO(获取服务ip+port,发起请求)

  • 因为我的Node服务只需调用其他服务,无需其他服务调用我,所以无需注册ZK,直接获取服务地址即可。
  • 还可以通过 js-to-java 、调用 dubbo 等方式进行更优雅的调用,可自行扩展研究

封装 zk.ts 文件,方便调用

// ZK基础信息,可改为配置或传入
export const ZK = {
clientAddress: 'localhost:2181/zk/test', // ZK地址
servicePath: '/test-service', // 服务路径
};
const zookeeper = require('node-zookeeper-client');
let zkClient: any = null;

// 获取服务ip+port
export const getZKServiceBaseUrl = (servicePath: string) => {
return new Promise((resolve, reject) => {
try {
// 防止重复连接
if (zkClient) {
disconnectZKService();
}
// 新建连接
zkClient = zookeeper.createClient(ZK.clientAddress);
// 连接后执行一次
zkClient.once('connected', async function () {
// 获取服务节点信息
const res: any = await listChildren(zkClient, servicePath);
res.msgText ? reject(res) : resolve(res);
});

zkClient.connect();
} catch (error) {
reject(error);
}
});
};

// 断开链接
export const disconnectZKService = () => {
if (zkClient) {
zkClient.close();
}
};

// 获取节点信息,取出ip+port
function listChildren(client, path) {
return new Promise((resolve, reject) => {
client.getChildren(
path,
function () {},
function (error, children) {
if (error) {
reject({ ...error, msgText: `获取ZK节点error,Path: ${path}` });
}
try {
let addressPath = path + '/';
if (children.length > 1) {
//若存在多个地址,则随机获取一个地址
addressPath += children[Math.floor(Math.random() * children.length)];
} else {
//若只有唯一地址,则获取该地址
addressPath += children[0];
}
//获取服务地址
client.getData(addressPath, function (err, serviceAddress) {
if (err) {
reject({ ...error, msgText: `获取ZK服务地址error,Stack: ${err.stack}` });
}
if (!serviceAddress) {
reject({ ...error, msgText: `ZK serviceAddress is not exist` });
}
const serviceInfo = JSON.parse(serviceAddress);

const url = serviceInfo.address + ':' + serviceInfo.port;
resolve(url);
});
} catch (error) {
reject({ ...error, msgText: `list ZK children error` });
}
}
);
});
}

使用

import { getZKServiceBaseUrl, disconnectZKService, ZK } from '../../utils/zk';

const requestBaseUrl = await getZKServiceBaseUrl(ZK.servicePath);
// 用后及时断联
disconnectZKService();
// 发起请求,这里是 egg 的请求方式
this.ctx.curl(requestBaseUrl + '/v3/list/save', {
method: 'POST',
data: {},
dataType: 'json',
headers: { 'Content-Type': 'application/json' },
})
.then((res) => {})
.catch((err) => {});

  • 因为我的Node服务只需调用其他服务,无需其他服务调用我,所以无需注册ZK,直接获取服务地址即可。
  • 还可以通过 js-to-java 、调用 dubbo 等方式进行更优雅的调用,可自行扩展研究。


举报

相关推荐

0 条评论