commit | a9d9d5c090ed79f48d7741c9f0791f7f410d015d | [log] [tgz] |
---|---|---|
author | hufeng <hufeng@qianmi.com> | Thu Jun 28 14:39:35 2018 +0800 |
committer | hufeng <hufeng@qianmi.com> | Thu Jun 28 14:39:35 2018 +0800 |
tree | 5dbe3cb1a45f6bcfb2c60b32b204e927423e3683 | |
parent | aadb4454a367d6286d245987e9ae7fd33908690f [diff] |
release dubbo2.js@2.1.5
dubbo2.js = Nodejs connected Java Dubbo service by dubbo protocol (dubbo head + hessian body)
多年期盼,一朝梦圆! We love dubbo 👏
感谢 js-to-java,hessian.js 两大核心模块, 感谢fengmk2和dead-horse老师。
Keep it Simple
Support zookeeper as register center
TCP Dubbo Native protocol (Dubbo Header + Hessian Body)
Socket Pool (ServerAgent -> SocketPool -> SocketWorker)
Support Directly Dubbo (const Dubbo = DirectlyDubbo({..}))
Middleware, Easy to extend.
Tracing
Supported Dubbox
Typescript type definition
Convert java dubbo interface to typescript module
socket-worker auto retry
yarn add dubbo2.js
//=====================service.ts================== //generated by interpret tools import {BasicTypeProvider} from './providers/com/alibaba/dubbo/demo/BasicTypeProvider'; import {DemoProvider} from './providers/com/alibaba/dubbo/demo/DemoProvider'; import {ErrorProvider} from './providers/com/alibaba/dubbo/demo/ErrorProvider'; export default { BasicTypeProvider, DemoProvider, ErrorProvider, }; //===============dubbo.ts======================== import {Dubbo} from 'dubbo2.js'; import service from './service'; //创建dubbo对象 const dubbo = new Dubbo<typeof service>({ application: {name: 'node-dubbo'}, //zookeeper address register: 'localhost:2181', service, }); //main method (async () => { const result1 = await dubbo.service.DemoProvider.sayHello('node'); //print {err: null, res:'hello node from dubbo service'} const res = await dubbo.service.DemoProvider.echo(); //print {err: null, res: 'pang'} const res = await dubbo.service.DemoProvider.getUserInfo(); //status: 'ok', info: { id: '1', name: 'test' } })();
//创建要注入的service import {Dubbo} from 'dubbo2.js'; const demoProvider = dubbo => dubbo.proxyService({ dubboInterface: 'com.alibaba.dubbo.demo.DemoProvider', version: '1.0.0', methods: { sayHello(name) { return [java.String(name)]; }, echo() {}, test() {}, getUserInfo() { return [ java.combine('com.alibaba.dubbo.demo.UserRequest', { id: 1, name: 'nodejs', email: 'node@qianmi.com', }), ]; }, }, }); //将该service合入dubbo对象构造函数的service对象中 const service = { demoProvider, }; const dubbo = new Dubbo<typeof service>({ // ....other parameters service, });
import {Dubbo, java, TDubboCallResult} from 'dubbo2.js'; //generated by interpret tools import {BasicTypeProvider} from './providers/com/alibaba/dubbo/demo/BasicTypeProvider'; import {DemoProvider} from './providers/com/alibaba/dubbo/demo/DemoProvider'; import {ErrorProvider} from './providers/com/alibaba/dubbo/demo/ErrorProvider'; //创建dubbo对象 const dubbo = new Dubbo({ application: {name: 'node-dubbo'}, //zookeeper address register: 'localhost:2181', interfaces: [ 'com.alibaba.dubbo.demo.DemoProvider', 'com.alibaba.dubbo.demo.BasicTypeProvider', 'com.alibaba.dubbo.demo.ErrorProvider', ], }); const basicTypeProvider = BasicTypeProvider(dubbo); const demoProvider = DemoProvider(dubbo); const errorProvider = ErrorProvider(dubbo); //main method (async () => { const result1 = await demoProvider.sayHello('node'); //print {err: null, res:'hello node from dubbo service'} const res = await demoProvider.echo(); //print {err: null, res: 'pang'} const res = await demoProvider.getUserInfo(); //status: 'ok', info: { id: '1', name: 'test' } })();
//创建要注入的service import {Dubbo} from 'dubbo2.js'; const demoProvider = dubbo => dubbo.proxyService({ dubboInterface: 'com.alibaba.dubbo.demo.DemoProvider', version: '1.0.0', methods: { sayHello(name) { return [java.String(name)]; }, echo() {}, test() {}, getUserInfo() { return [ java.combine('com.alibaba.dubbo.demo.UserRequest', { id: 1, name: 'nodejs', email: 'node@qianmi.com', }), ]; }, }, }); //将该service合入dubbo对象构造函数的service对象中 const service = { demoProvider, }; const dubbo = new Dubbo({ // ....other parameters interfaces: [ //.... 'com.alibaba.dubbo.demo.DemoProvider', ], }); const demoProvider = demoProvider(dubbo);
brew install zookeeper brew services start zookeeper #运行java/dubbo-demo-provider下面的例子 yarn run test # 全链路日志跟踪 DEBUG=dubbo* yarn run test
const dubbo = new Dubbo({ isSupportedDubbox //是不是支持dubbox (boolean类型); 可选,默认false application //记录应用的名称,zookeeper的调用时候写入consumer 类型:({name: string};) 可选 dubboInvokeTimeout //设置dubbo调用超时时间默认10s 可选 类型number dubboSocketPool //设置dubbo创建socket的pool大小,默认4 可选 类型number register //设置zookeeper注册中心地址 必填 类型string zkRoot //zk的默认根路径,默认/dubbo 类型string interfaces //设置zk监听的接口名称 类型 Array<string> 必填, 在dubbo2.js@2.0.4+版本中不在使用这个参数 service //注入到dubbo容器的dubbo服务,类型Object, 在dubbo2.js@2.0.4+使用 }); // Or const dubbo = Dubbo.from({ isSupportedDubbox //是不是支持dubbox (boolean类型); 可选,默认false application //记录应用的名称,zookeeper的调用时候写入consumer 类型:({name: string};) 可选 dubboInvokeTimeout //设置dubbo调用超时时间默认10s 可选 类型number dubboSocketPool //设置dubbo创建socket的pool大小,默认4 可选 类型number register //设置zookeeper注册中心地址 必填 类型string zkRoot //zk的默认根路径,默认/dubbo 类型string interfaces //设置zk监听的接口名称 类型 Array<string> 必填, 在dubbo2.js@2.0.4+版本中不在使用这个参数 service //注入到dubbo容器的dubbo服务,类型Object, 在dubbo2.js@2.0.4+使用 }) //dubbo的代理服务 const demoSerivce = dubbo.proxService({ //代理的服务接口 - string 必传 dubboInterface: 'com.alibaba.dubbo.demo.DemoService', //服务接口的版本 - string 可选 version: '1.0.0', //超时时间 number 可选 timeout: 10 //所属组 string 可选 group: 'qianmi', //接口内的方法 - Array<Function> 必传 methods: { //method name sayHello(name) { //仅仅做参数hessian化转换 return [java.String(name)]; }, //method name getUserInfo() { //仅仅做参数hessian化转换 return [ java.combine('com.alibaba.dubbo.demo.UserRequest', { id: 1, name: 'nodejs', email: 'node@qianmi.com', }), ]; }, }, })
import {DirectlyDubbo, java} from 'dubbo2.js'; import { DemoProvider, DemoProviderWrapper, IDemoProvider, } from './providers/com/alibaba/dubbo/demo/DemoProvider'; import {UserRequest} from './providers/com/alibaba/dubbo/demo/UserRequest'; const dubbo = DirectlyDubbo.from({ dubboAddress: 'localhost:20880', dubboVersion: '2.0.0', dubboInvokeTimeout: 10, }); const demoService = dubbo.proxyService<IDemoProvider>({ dubboInterface: 'com.alibaba.dubbo.demo.DemoProvider', methods: DemoProviderWrapper, version: '1.0.0', });
const dubbo = Dubbo.from(/*...*/); (async () => { await dubbo.ready(); //TODO dubbo was ready })(); //for example, in egg.js app.beforeStart(async () => { await dubbo.ready(); app.logger.info('dubbo was ready...'); });
const dubbo = Dubbo.from(/*...*/); dubbo.subcribe({ onReady: () => { //dubbo was ready. //TODO for example logger }, onSysError: err => { //dubbo occur error //TODO dingTalkRobot.send('error') }, onStatistics: stat => { //get invoke time statistics info //in order to know load whether balance }, });
通过对调用链路的抽象使用和 koa 相同的 middleware 机制,方便自定义拦截器,比如 logger,
//cost-time middleware dubbo.use(async (ctx, next) => { const startTime = Date.now(); await next(); const endTime = Date.now(); console.log('invoke cost time->', endTime - startTime); });
在 dubbo 的接口调用中,需要设置一些动态的参数如,version, group, timeout, retry 等常常
这些参数需要在 consumer 调用方才精确设定值,之前是在 interpret 翻译生成 ts 的代码里面进行设置这个不够灵活,所以这里面我就抽象一个 dubbo-invoker 作为设置参数的 middleware,这样可以很方便的动态设置各种 runtime 参数
import {dubboInvoker, matcher} from 'dubbo-invoker'; //init const dubbo = Dubbo.from(/*....*/); const matchRuler = matcher //精确匹配接口 .match('com.alibaba.demo.UserProvider', { version: '1.0.0', group: 'user', }) //match thunk .match(ctx => { if (ctx.dubboInterface === 'com.alibaba.demo.ProductProvider') { ctx.version = '2.0.0'; ctx.group = 'product-center'; //通知dubboInvoker匹配成功 return true; } }) //正则匹配 .match(/^com.alibaba.dubbo/, { version: '2.0.0', group: '', }); dubbo.use(dubboInvoke(matchRuler));
我们坚定的认为开发体验同用户的体验同等重要,我们做了一些创新,一些很酷的实践。
为了使 node 和 dubbo 之间的调用像 java 调用 dubbo 一样简单透明,我们设计和实现了 translator.
通过分析 java 的 jar 包中的 bytecode 提取 dubbo 调用的接口信息,自动生成 typescript 类型定义文件以及调用的代码。
在 packages/dubbo/src/tests/provider 就是根据 java 目录下的 demo 翻译而来。
我们希望整个 dubbo 调用的代码都可以无缝生成。
职责
❯ loadtest -t 20 -c 200 http://localhost:3000/dubbo -k [Wed Jun 20 2018 15:10:16 GMT+0800 (CST)] INFO Requests: 0, requests per second: 0, mean latency: 0 ms [Wed Jun 20 2018 15:10:21 GMT+0800 (CST)] INFO Requests: 37305, requests per second: 7484, mean latency: 26.9 ms [Wed Jun 20 2018 15:10:26 GMT+0800 (CST)] INFO Requests: 79187, requests per second: 8371, mean latency: 23.9 ms [Wed Jun 20 2018 15:10:31 GMT+0800 (CST)] INFO Requests: 120374, requests per second: 8247, mean latency: 24.2 ms [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO Target URL: http://localhost:3000/dubbo [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO Max time (s): 20 [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO Concurrency level: 200 [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO Agent: keepalive [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO Completed requests: 161828 [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO Total errors: 0 [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO Total time: 20.000902374000002 s [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO Requests per second: 8091 [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO Mean latency: 24.7 ms [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO Percentage of the requests served within a certain time [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO 50% 22 ms [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO 90% 30 ms [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO 95% 34 ms [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO 99% 49 ms [Wed Jun 20 2018 15:10:36 GMT+0800 (CST)] INFO 100% 134 ms (longest request)
import {Dubbo} from 'dubbo2.js';
默认导入的 dubbo2.js 是按照 es2017 进行编译的,支持 node7.10 以上。
如果更低的 node 版本,可以使用
import {Dubbo} from 'dubbo2.js/es6';
1.欢迎 pr
2.欢迎 issue