欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

nodeJs直连Java服务化dubbo协议长连接实现

程序员文章站 2024-02-26 15:40:04
...

需求背景

这个需求的出现来源于我们的某业务接口优化中遇到的一个瓶颈:

初期接口在调用php提供的第三方接口时,遇到访问高峰的情况会出现该接口timeout的情况(如下图 平常时接口时延75ms,高峰时到达368ms ),同时服务器上会出现及大量的TIME_WAIT连接数(高峰时 2W左右)。

nodeJs直连Java服务化dubbo协议长连接实现

分析是由于大流量时, 每次接口调用都会调用一次rest api,继而产生大量的tcp短连接导致的。这种不稳定的因素对我们的集群产生了极大的压力,同时接口时延也不稳定的上升。当务之急是减少短连接数,取而代之使用长连接的方式去请求。

同时我也了解到,异构系统间采用http长连接的做法在公司内部php集群并不支持(现阶段公司内部只有少数业务有成熟的长连接方案),而又了解到java服务化方可以提供dubbo协议的接口请求。

因此就决定尝试使用dubbo协议跨过php这一层直接和java服务化做直连,这样既可以减少短连接数,同时也将调用链路变短了一层。

nodeJs直连dubbo的做法

调用dubbo服务的过程主要分以下几步:

首先需要连接上dubbo的zk配置中心(从java服务化那边得到地址),获取你需要的服务的dubbo节点连接信息(包括dubbo服务的host:port,服务名等等)

然后 使用sockets-pool(我们维护的)库 与获得的dubbo节点建立起起socket长连接,并维护在一个连接池队列中
在需要查询对应服务时,从连接池中获取可用连接,执行查询,然后释放该次连接到连接池。

demo代码如下:

        var ZD = require('node-zoodubbo');
        var zd = new ZD({
                // config the addresses of zookeeper
                conn: '127.0.0.1:2181',
                dubbo: '2.8.0.2',
                root: 'dubbo'
        });

        // connect to zookeeperzd.connect();
        //zd.getProvider('com.member.query', '1.0.0', function(res, data){//      console.log(res, data);//});// get a invoker with a service path
        var invoker = zd.getInvoker('com.member.query', {
                version: '1.0.0',
                timeout: 2000,
                pool: {
                        max: 100,
                        min: 10,
                        maxWaitingClients: 500       
                }   
        });

        // excute a method with parametersvar method = 'memberInfo';
        var arg1 = {
                $class: 'com.member.memberRequestTO',
                $: {
                        uid: {
                                $class: 'java.lang.String',
                                $: '34625433'
                        }
                }
        };

        invoker.excute(method, [arg1])
        .then(res => console.log(res))
        .catch(e => console.log(e));

node-zoodubbo 连接包实现

nodeJs直连Java服务化dubbo协议长连接实现

查看包地址

关于整个包及连接实现点击这里

带来的效果

采用restapi方式调用黑名单接口时,该接口平常访问时延在27ms左右,高峰时接口时延159ms。

采用dubbo长连接后,黑名单接口请求时延平均在3ms左右,高峰时任然不变。同时由于我们把ip的接口请求也自己本地化实现了一套,接口时延从(平常时75ms,高峰时368ms)降到如下情况

nodeJs直连Java服务化dubbo协议长连接实现

平常时 25ms 提升 300%,高峰时 56ms 提升 660%

结合某业务接口优化谈一谈QPS的提升

优化前对某接口做了差不多5组压测,每波大概20min,集群当时是9台机器,每台机器4个接口进程,集群qps测到 1200就上不去了(单机 130)。当时与运维讨论了很久未果, 甚至怀疑是测试工具的问题。

在压测过程中,我的服务打点时间始终是正常的且只维持在30ms左右,开始怀疑是不是我们node框架koa2的问题,第二天我在单机使用ab测试了空koa框架发现单机可以到达3000qps,因此框架的qps是不成问题的。

然后对接口的ab结果最终单机真实qps为 240.

再次与运维讨论怀疑是负载均衡而非框架的问题。然后又去了解了我们的进程管理工具PM2其实也承担了对请求的负载分发的工作,虽然其底层采用RollIng算法并不是问题,但是 pm2对请求队列的消耗过程并非是 epoll 类似的做法。

之后为了验证这个猜想使用了nginx反向代理到本机的4个端口,每个端口只跑一个进程,这样等于绕开了pm2分发,只由nginx来做负载均衡,发现QPS可以到达

nodeJs直连Java服务化dubbo协议长连接实现
(最终单机真实qps为 437)

至此我们初步确定QPS的部分瓶颈在pm2的请求转发,采用直接走nginx的方式 直接带来了性能 182%的提升