kigo-dubbo2-client
v1.0.0
Published
node dubbo client
Downloads
2
Readme
@melot/dubbo-client
dubbo 客户端
Log4js category:
Dubbo
Install with:
$ cnpm install @melot/dubbo-client
Usage
package com.melot.dubbo.service;
import com.melot.dubbo.entry.User;
import org.apache.dubbo.config.annotation.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloServiceImpl implements HelloService {
static Logger logger = LoggerFactory.getLogger(HelloServiceImpl.class);
public String hello(String name) {
return "hello " + name;
}
}
假设有这么一个 dubbo 接口, 我们如何使用 dubbo-client 对其进行 rpc 调用呢
编写相对应的 Service
'use strict'
const util = require('util');
const dubbo = require('@melot/dubbo-client');
const java = dubbo.java;
const Service = dubbo.Service;
// Service 函数签名参数必须是 dubbo application 对象
/**
* @param {Dubbo} [cxt] dubbo 对象
*/
function HelloService(app) {
Service.call(this, app);
// 注册到 nacos 的服务名称
this.serviceName = 'provider-service';
// 服务接口名
this.interfaceName = 'com.melot.dubbo.service.HelloService';
// 服务版本
this.version = '1.0.0';
}
// 继承自 dubbo 的 Service
util.inherits(HelloService, Service);
module.exports = HelloService;
HelloService.prototype.hello = function(name, cb) {
const methodName = 'hello';
const args = [name];
// 没有 return 的话不支持 async/await 调用
return this.invoke(methodName, args, cb);
}
注册到 dubbo application
'use strict'
const dubbo = require('@melot/dubbo-client');
const Application = dubbo.Dubbo;
const java = dubbo.java;
const app = new Application({
// 应用名称
name: 'dubbo-js',
// dubbo 版本
version: '2.0.2',
// 注册中心配置
register: {
protocol: 'nacos',
serverList: '127.0.0.1:8848',
namespace: 'public'
}
})
// 假设我们编写的 HelloService 放在 service/ 目录下
// 注册到 dubbo 容器
const HelloService = require('./service/HelloService');
app.registerService(HelloService);
// 从 dubbo 容器中获取 service 对象
// 默认名称为 service 名称首字母小写, 也可以在 Service 中显示声明
const helloService = app.getService('helloService');
// callback 方式调用
helloService.hello('world', function(err, res) {
});
// async/await 方式调用
(async function() {
let res = null;
try {
res = await helloService.hello('world');
} catch(e) {
}
})()
泛化调用
'use strict'
const dubbo = require('@melot/dubbo-client');
const Application = dubbo.Dubbo;
const app = new Application({
// 应用名称
name: 'dubbo-js',
// dubbo 版本
version: '2.0.2',
// 注册中心配置
register: {
protocol: 'nacos',
serverList: '127.0.0.1:8848',
namespace: 'public'
}
})
app.$invoke({
serviceName: 'provider-service',
interfaceName: 'com.melot.dubbo.service.HelloService',
version: '1.0.0',
methodName: 'hello',
args: ['world'],
}, function(err, res) {
})
(async function main() {
let res = null;
try {
res = await app.$invoke({
serviceName: 'provider-service',
interfaceName: 'com.melot.dubbo.service.HelloService',
version: '1.0.0',
methodName: 'hello',
args: ['world'],
})
} catch(e) {
}
})()
配置
负载均衡
缺省是随机 random, 可配置
- random 加权随机
- roundrobin 轮询
- weightroundrobin 加权轮询
- leastactive 最不活跃优先
- consistenthash 一致性哈希
接口级别配置
app.configure('com.melot.dubbo.service.HelloService', 'loadbalance', 'roundrobin');
方法级别配置
app.configure('com.melot.dubbo.service.HelloService', 'hello', 'loadbalance', 'roundrobin');
超时
缺省请求超时时间为 5s
接口级别配置
app.configure('com.melot.dubbo.service.HelloService', 'timeout', 3000);
方法级别配置
app.configure('com.melot.dubbo.service.HelloService', 'hello', 'timeout', 3000);
服务治理(只支持方法级别)
缓存
app.configure('com.melot.dubbo.service.HelloService', 'hello', 'cache', {
capacity: 500, // 容量
ttl: 60000 // 缓存时间
});
降级
app.configure('com.melot.dubbo.service.HelloService', 'hello', 'degrader', true);
熔断器
app.configure('com.melot.dubbo.service.HelloService', 'hello', 'circuitbreaker', {
failWindowTime: 60000, // 滑动窗口时间
requestVolumeThreshold: 10, // 滑动窗口时间内的请求数阈值
failThresholdPercentage: 60, // 失败率阈值
sleepWindowTime: 5000 // 自动恢复时间间隔
});
直连提供者(服务级别配置)
为了避免复杂化线上环境,不要在线上使用这个功能,只应在测试阶段使用
app.setUrl('provider-service', 'dubbo://127.0.0.1:3050');
app.setUrl('provider-service', {
host: '127.0.0.1',
port: 3050
});
Filter
过滤器有前置和后置过滤器, 前置后置是相对于内置的过滤器, 而不是请求, 请求永远在最后执行。
内置过滤器依次为缓存过滤器, 降级过滤器, 熔断过滤器
过滤器函数签名为
async function(app, rpcRequest, next) {
}
过滤器必须返回 await next() 的结果
前置过滤器
app.before(async function(app, rpcRequest, next) {
const start = Date.now();
const res = await next();
console.log(`do ${rpcRequest.getDubboInterface()}.${rpcRequest.getMethodName()} use ${Date.now() - start}`);
return res;
})
后置过滤器
app.after(async function(app, rpcRequest, next) {
if (Math.random() > 0.5) {
throw new Error('server error');
}
return await next();
})
APIs
new Dubbo(opts)
- opts {Object}
- [name] {String} application name, default is dubbo-node
- version {String} dubbo version
- [naming] {NamingClient} registry naming client
- [register] {Object}
- [protocol] {String} register protocol, default is nacos
- [namespace] {String} 命名空间 default is public
- serverList {String|Array} server list, if type is string, split by ','
- [timeout] {Number} rpc request timeout, default is 5000
- [retryMax] {Number} socket retry max, default is 20
- [retryDelay] {Number} socket retry delay, default is 1000
- [retryDelayMax] {Number} socket retry delay max, default is 60000
- [heartInterval] {Number} socket heart interval, default is 60000
- opts {Object}
registryService(Service)
注册服务- Service {Dubbo.Service}
registerServiceByPath(path)
递归注册目录下所有 service- path {String} 全路径
getService(name)
获取服务对象- name {String} 默认类名首字母小写
configure(interfaceName, [methodName], key, value)
配置- interfaceName
- [methodName]
- key
- value
setUrl(serviceName, url)
配置直连模式- serviceName {String}
- url {String|Object} if type is string, pattern is 'dubbo://host:port'
- host {String}
- port {Number}
before(filter)
添加前置过滤器- filter [Function|Array]
after(filter)
添加后置过滤器- filter [Function|Array]