1.0.0 • Published 10 months ago

kigo-dubbo2-client v1.0.0

Weekly downloads
-
License
ISC
Repository
-
Last release
10 months ago

@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
  • registryService(Service) 注册服务
    • Service {Dubbo.Service}
  • registerServiceByPath(path) 递归注册目录下所有 service
    • path {String} 全路径
  • getService(name) 获取服务对象
    • name {String} 默认类名首字母小写
  • configure(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) 添加前置过滤器
  • after(filter) 添加后置过滤器