tag | dce38dff8bb142d24bd575414e59b9b13868aebb | |
---|---|---|
tagger | hufeng <hufeng@qianmi.com> | Mon May 07 14:05:59 2018 +0800 |
object | 73f6c4e88ac20e6796e0756bf18fdaeff30556fc |
dubbo-invoker@1.0.1
commit | 73f6c4e88ac20e6796e0756bf18fdaeff30556fc | [log] [tgz] |
---|---|---|
author | hufeng <hufeng@qianmi.com> | Mon May 07 14:05:59 2018 +0800 |
committer | hufeng <hufeng@qianmi.com> | Mon May 07 14:05:59 2018 +0800 |
tree | eb1d2e052349f67574cc9e1044010cae728b2eda | |
parent | 5e3ad957835dca4a67a0575e59ae3ef9877f08e2 [diff] |
Publish - dubbo-invoker@1.0.1
多年期盼,一朝梦圆! We love dubbo 👏
感谢 js-to-java,hessian.js 两大核心模块, 感谢fengmk2和dead-horse老师。
nodejs 使用原生的 dubbo (dubbo head + hessian body) 协议打通了 dubbo 的 rpc 方法调用 .
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
yarn add dubbo2.js # or npm install dubbo2.js --save
import {Dubbo, java, TDubboCallResult} from 'dubbo2.js'; //定义dubbo方法类型接口 //方便代码自动提示 interface IDemoService { sayHello(name: string): TDubboCallResult<string>; echo(): TDubboCallResult<string>; test(): TDubboCallResult<void>; getUserInfo(): TDubboCallResult<{ status: string; info: {id: number; name: string}; }>; } //创建dubbo对象 const dubbo = new Dubbo({ application: {name: 'node-dubbo'}, //zookeeper address register: 'localhost:2181', dubboVersion: '2.0.0', interfaces: ['com.alibaba.dubbo.demo.DemoService'], }); //代理本地对象->dubbo对象 const demoService = dubbo.proxyService<IDemoService>({ dubboInterface: 'com.alibaba.dubbo.demo.DemoService', version: '1.0.0', methods: { sayHello(name) { //仅仅做参数hessian化转换 return [java.String(name)]; }, echo() {}, test() {}, getUserInfo() { //仅仅做参数hessian化转换 return [ java.combine('com.alibaba.dubbo.demo.UserRequest', { id: 1, name: 'nodejs', email: 'node@qianmi.com', }), ]; }, }, }); //main method (async () => { const result1 = await demoService.sayHello('node'); //print {err: null, res:'hello node from dubbo service'} const res = await demoService.echo(); //print {err: null, res: 'pang'} const res = await demoService.getUserInfo(); //status: 'ok', info: { id: '1', name: 'test' } })();
brew install zookeeper brew services start zookeeper #运行java/dubbo-simple下面的例子 yarn run test # 全链路日志跟踪 DEBUG=dubbo* yarn run test
const dubbo = new Dubbo({ dubboVersion //当前dubbo的版本 (string类型); 必传 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> 必填 }); // Or const dubbo = Dubbo.from({ dubboVersion //当前dubbo的版本 (string类型); 必传 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> 必填 }) //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 xx(params) { return [ params ] } }, })
const dubbo = Dubbo.from(/*...*/); (async () => { await dubbo.ready(); //TODO dubbo was ready })(); //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
import {dubboInvoker, matcher} from 'dubbo-invoker'; //init const dubbo = Dubbo.from(/*....*/); //set params dubbo.use( dubboInvoke( matcher //精确匹配接口 .match('com.alibaba.demo.UserProvider', { version: '1.0.0', group: 'user', }) //正则匹配 .match(/$com.alibaba.dubbo/, { version: '2.0.0', group: '', }) //match thunk match((ctx) => { //computed.... return true }, { version: '3.0.0' }) ., ), );
我们坚定的认为开发体验同用户的体验同等重要,我们做了一些创新,一些很酷的实践。
为了使node和dubbo之间的调用像java调用dubbo一样简单透明,我们设计和实现了translator.
通过分析java的jar包中的bytecode提取dubbo调用的接口信息,自动生成typescript类型定义文件 以及调用的代码。
在packages/dubbo/src/tests/provider就是根据java目录下的demo翻译而来。
我们希望整个dubbo调用的代码都可以无缝生成。
Seamlessly connect to dubbo2.js to enhance the development experience!
remarks are not synchronized;
npm install interpret-dubbo2js -g
interpret -c dubbo.json
dubbo.json:
{ "output": "./src", "dubboVersion": "1.0", "entry":"com.qianmi", "entryJarPath":"${jarPath}", "libDirPath":"${denpendJarDir}" }
Tip 生成的代码可以发npm包供其他业务线使用或直接在项目中引用
import {D2pMarketingQueryProvider} from '@qianmi/d2p-cart-api/lib/com/qianmi/cloudshop/api/marketing/d2p/D2pMarketingQueryProvider'; const dubbo = new Dubbo({ application: {name: 'd2p-visitor-bff'}, dubboInvokeTimeout: 10, //zookeeper address register: app.config.zookeeper, dubboVersion: '2.4.13', logger: app.logger as ILogger, interfaces: [ 'com.qianmi.cloudshop.api.marketing.d2p.D2pMarketingQueryProvider' ], }); let D2pMarketingQuery = D2pMarketingQueryProvider(dubbo);
Tip npm install interpret-util dubbo2.js
;
loadtest -c 100 -n 10000 -k http://localhost:3000/hello [Mon Feb 12 2018 17:30:28 GMT+0800 (CST)] INFO Requests: 0 (0%), requests per second: 0, mean latency: 0 ms [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO Target URL: http://localhost:3000/hello [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO Max requests: 10000 [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO Concurrency level: 100 [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO Agent: keepalive [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO Completed requests: 10000 [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO Total errors: 0 [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO Total time: 2.3191059540000003 s [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO Requests per second: 4312 [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO Mean latency: 22.9 ms [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO Percentage of the requests served within a certain time [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO 50% 20 ms [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO 90% 31 ms [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO 95% 38 ms [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO 99% 73 ms [Mon Feb 12 2018 17:30:30 GMT+0800 (CST)] INFO 100% 116 ms (longest request)
import {Dubbo} from 'dubbo2.js';
默认导入的 dubbo2.js 是按照 es2017 进行编译的,支持 node7.10 以上。
如果更低的 node 版本,可以使用
import {Dubbo} from 'dubbo2.js/es6';
1.欢迎 pr
2.欢迎 issue