关于dubbo:Spring-Cloud-和-Dubbo到底用哪个好

公众号:MarkerHub,网站:https://markerhub.comCat哥领读:Spring Cloud,Spring体系一站式解决方案,我更喜爱,你们呢? 作者:Crazy 晓枫https://blog.csdn.net/u010664... Spring Cloud 是 http 协定传输,带宽会比拟多,同时应用 http 协定个别会应用 JSON 报文,耗费会更大 dubbo 的开发难度较大,起因是 dubbo 的 jar 包依赖问题很多大型工程无奈解决 springcloud 的接口协议约定比拟自在且涣散,须要有强有力的行政措施来限度接口无序降级 dubbo 的注册核心能够抉择 zk,redis 等多种,springcloud 的注册核心只能用 eureka 或者自研 但如果我选,我会用 Spring Cloud 从公司整体规划: 我不会抉择很久没人保护的 dubbo,重启之后也未必是原班人马 从程序员招聘难度 :招 springcloud 的程序员会更好招,因为更新更炫 从系统结构简易程序: springcloud 的系统结构更简略、“注册 + springmvc=springcloud”,而 dubbo 各种简单的 Url,protocol,register,invocation,dubbofilter,dubboSPI,dubbo 序列化.......... 炫技的成分更多一些 从性能: dubbo 的网络耗费小于 springcloud,然而在国内 95% 的公司内,网络耗费不是什么太大问题,如果真的成了问题,通过压缩、二进制、高速缓存、分段降级等办法,很容易解 从开发难易度: dubbo 的神坑是 jar 包依赖,开发阶段难度极大,我已经带一个三十人的团队,因为 jar 包降级问题,把每个人的电脑都操作过,尤其每个人电脑的库门路、命令、快捷键、键盘,鼠标快慢都不一样,那会儿我默默的在心中艹了 dubbo 发明者全家老小一百二十遍。 springcloud 比拟自在,但带来的问题是无奈 “强力束缚接口标准”,倡议用行政形式解决,且咱们团队的强力行政束缚做的还是比拟好的,在接口管控层面比拟强效,一个没有行政组织能力的 IT 团队真的是个废渣,用什么框架都不好使。 从后续改良: dubbo 的改良是通过 dubbofilter,很多货色没有,须要本人继承,如监控,如日志,如限流,如追踪。springcloud 本人带了很多监控、限流措施,然而性能可能和欧美习惯雷同,国内须要进行适当革新,但更简略,就是 ServletFilter 而已,然而总归比 dubbo 多一些货色是好的 ...

March 8, 2021 · 2 min · jiezi

关于dubbo:冰河开始对Dubbo下手了

写在后面对冰河有肯定理解的读者都晓得,冰河经验了一个高并发电商零碎用户从零到上亿的整个研发过程,前期也由此衍生出电商零碎(商城+秒杀)和基于海量数据的实时精准商品举荐平台。局部外围常识已总结到我出版的两本书籍——《海量数据处理与大数据技术实战》和《MySQL技术大全:开发、优化与运维实战》中。随着电商零碎业务的一直倒退,咱们须要对系统一直的迭代降级,这期间,Dubbo功不可没。 在微服务畛域有两个比拟闻名的技术栈:SpringCloud / SpringCloud Alibaba(目前SpringCloud Alibaba有超过SpringCloud的势头)和Dubbo。而Dubbo作为一个服务治理的RPC框架,在大厂面试的过程中,简直是一个必问的技术。所以,我打算写一个深度解析Dubbo的系列专题,揭开Dubbo的神秘面纱,让更多的小伙伴彻底把握Dubbo。 这篇就作为Dubbo源码系列的开篇吧!! 注:写完Dubbo再写SpringCloud Alibaba系列。 文章已收录到: https://github.com/sunshinelyz/technology-binghe https://gitee.com/binghe001/technology-binghe Dubbo的外围能力总体来说,Apache Dubbo是一款高性能,轻量级的开源RPC框架,提供了六大外围能力: 面向接口代理的高性能RPC调用。智能容错和负载平衡。服务主动注册和发现。高度可扩大能力。运行期流量调度。可视化的服务治理与运维。具体细节小伙伴们能够参见Dubbo官网文档。 为何学Dubbo为何要深度学习Dubbo,那必定是要解决某种业务场景啊。接下来,咱们就聊一聊为何学习Dubbo。不过在介绍为何学习Dubbo前,咱们先来看看随着业务的一直倒退,咱们的零碎在架构上会有哪些变动。 单体利用架构在企业倒退的初期,个别公司的网站流量都比拟小,只须要一个利用,将所有的性能代码打包成一个服务,部署到服务器上就能撑持公司的业务。这样也可能缩小开发、部署和保护的老本。 比方,大家都很相熟的电商零碎,外面波及的业务次要有:用户治理、商品治理、订单治理、领取治理、库存治理、物流治理等等模块,初期咱们会将所有模块写到一个Web我的项目中,而后对立部署到一个Web服务器中。 这种架构特点有其长处: 架构简略,我的项目开发和保护成本低。所有我的项目模块部署到一起,对于小型我的项目来说,保护不便。然而,其毛病也是比拟显著的: 所有模块耦合在一起,尽管对于小型我的项目来说,保护不便。然而,对于大型项目来说,却是不易开发和保护的。我的项目的各模块之前过于耦合,如果一旦有一个模块呈现问题,则整个我的项目将不可用。无奈针对某个具体模块来晋升性能。无奈对我的项目进行程度扩大。正是因为单体利用架构存在着诸多的毛病,才逐步演变为垂直利用架构。接下来,咱们就来看看垂直利用架构。 垂直利用架构随着企业业务的一直倒退,发现单节点的单体利用不足以撑持业务的倒退,于是企业会将单体利用部署多份,别离放在不同的服务器上。然而,此时会发现不是所有的模块都会有比拟大的访问量。如果想针对我的项目中的某些模块进行优化和性能晋升,此时对于单体利用来说,是做不到的。于是乎,垂直利用架构诞生了。 垂直利用架构,就是将原来一个我的项目利用进行拆分,将其拆分为互不想干的几个利用,以此来晋升零碎的整体性能。 这里,咱们同样以电商零碎为例,在垂直利用架构下,咱们能够将整个电商我的项目拆分为:电商交易系统、后盾管理系统、CMS管理系统等。 咱们将单体利用架构拆分为垂直利用架构之后,一旦访问量变大,咱们只须要针对访问量大的业务减少服务器节点即可,无需针对整个我的项目减少服务器节点了。 这种架构的长处: 零碎进行了拆分,可依据不同零碎的拜访状况,有针对性的进行优化。可能实现利用的程度扩大。各零碎可能分担整体拜访的流量,解决了并发问题。一个零碎产生了故障,不利用其余零碎的运行状况,进步了整体的容错率。这种架构的毛病: 拆分后的各零碎之间绝对比拟独立,无奈进行相互调用。各零碎不免存在重叠的业务,会存在反复开发的业务,前期保护比拟艰难。分布式架构咱们将零碎演变为垂直利用架构之后,当垂直利用越来越多,反复编写的业务代码就会越来越多。此时,咱们须要将反复的代码形象进去,造成对立的服务供其余零碎或者业务模块来进行调用。此时,零碎就会演变为分布式架构。 在分布式架构中,咱们会将零碎整体拆分为服务层和体现层。服务层封装了具体的业务逻辑供体现层调用,体现层则负责解决与页面的交互操作。 这种架构的长处: 将反复的业务代码形象进去,造成公共的拜访服务,进步了代码的复用性。能够有针对性的对系统和服务进行性能优化,以晋升整体的拜访性能。这种架构的毛病: 零碎之间的耦合度变高,调用关系变得复杂,难以保护。 SOA架构在分布式架构下,当部署的服务越来越多,反复的代码就会越来越多,对于容量的评估,小服务资源的节约等问题比较严重。此时,咱们就须要减少一个对立的调度核心来对集群进行实时治理。此时,零碎就会演变为SOA(面向服务)的架构。 这种架构的长处: 应用注册核心解决了各个服务之间的服务依赖和调用关系的主动注册与发现。 这种架构的毛病: 各服务之间存在依赖关系,如果某个服务呈现故障可能会造成服务的雪崩(对于穿透、击穿和雪崩的问题,小伙伴们能够参见我之前写的《【高并发】面试官:讲讲什么是缓存穿透?击穿?雪崩?如何解决?》一文)。服务之间的依赖与调用关系简单,测试部署的艰难比拟大。微服务架构随着业务的倒退,咱们在SOA架构的根底上进一步扩大,将其彻底拆分为微服务架构。在微服务架构下,咱们将一个大的我的项目拆分为一个个小的能够独立部署的微服务,每个微服务都有本人的数据库。 这种架构的长处: 服务彻底拆分,各服务独立打包、独立部署和独立降级。每个微服务负责的业务比拟清晰,利于前期扩大和保护。微服务之间能够采纳REST和RPC协定进行通信。这种架构的毛病: 开发的老本比拟高。波及到各服务的容错性问题。波及到数据的一致性问题。波及到分布式事务问题(小伙伴们能够参见我后续会继续更新的【分布式事务】专题)。为何学习Dubbo?(1)系统升级过程中须要应用dubbo解决问题。 在零碎架构降级和微服务落地的过程中,咱们须要解决很多的问题,比方: 将一个我的项目拆分为多个服务之后,服务于服务之间如何高效的通信?服务的调用如何做到负载平衡和高可用?服务的调用如何做到限流?又如何疾速的感知到依赖服务宕机?服务的边界如何定义?当零碎中存在的服务越来越多时,如何进行服务治理等等。这些问题,咱们都能够应用Dubbo来解决。 (2)互联网大厂须要把握Dubbo技术。 很明确,很多互联网大厂都须要深度把握Dubbo这项技术。这里说的深度把握,并不只是停留在简略的应用层面,而是对Dubbo的外围原理和源码有肯定的了解。换句话说:就是你要对Dubbo的外围原理和源码很熟,在高并发、大流量场景下要可能联合Dubbo的原理和源码剖析出问题所在,并可能进行相应的性能调优。 所以说,如果你想进互联网大厂,最好是把握Dubbo的外围原理和源码。 Dubbo的应用场景在分布式架构、SOA架构和微服务架构下,Dubbo有其充沛的用武之地。有些小伙伴可能会说:咱们零碎中应用的是SpringCloud技术栈,不须要应用Dubbo呀!其实,应用SpringCloud和Dubbo是不抵触的,甚至二者也能够联合应用。例如,我所经验的我的项目,有些独立的模块应用了Dubbo作为RPC框架,有些模块则应用了SpringCloud,二者并不是抵触的,能够做到互相促进的作用。 总体来说,Dubbo的应用场景如下: RPC分布式服务当网站变大后,不可避免的须要拆分利用进行服务化,以进步开发效率,调优性能,节俭要害竞争资源等。 比方:为了实用一直变动的市场需求,以及多个垂直利用之间数据交互不便,咱们把公共的业务抽取进去作为独立的模块,为其余的利用提供服务,零碎逐步依赖于形象和rpc近程服务调用。 配置管理当服务越来越多时,服务的URL地址信息就会爆炸式增长,配置管理变得十分艰难,F5硬件负载均衡器的单点压力也越来越大。 服务依赖当进一步倒退,服务间依赖关系变得错踪简单,甚至分不清哪个利用要在哪个利用之前启动,架构师都不能残缺的形容利用的架构关系。 服务扩容接着,服务的调用量越来越大,服务的容量问题就裸露进去,这个服务须要多少机器撑持?什么时候该加机器?等等…… Dubbo总结总之,用官网的话说:Apache Dubbo 是一款高性能、轻量级的开源 Java 服务框架,提供了六大外围能力:面向接口代理的高性能RPC调用,智能容错和负载平衡,服务主动注册和发现,高度可扩大能力,运行期流量调度,可视化的服务治理与运维。 Dubbo的六大外围能力可能为咱们在疾速迭代微服务项目时,更好的提供RPC和服务治理能力。如果你想进大厂,就最好把握Dubbo。 好了,明天就到这儿吧,我是冰河,大家有啥问题能够在下方留言,也能够加我微信:sun_shine_lyz,一起交换技术,一起进阶,一起牛逼~~

January 5, 2021 · 1 min · jiezi

关于dubbo:Arthas-定位-Dubbo-手动注册-Eureka-异常

作者 | java_keith起源|阿里巴巴云原生公众号 很久没有写技术分享博客,因为发现一个好的工具的确有点忍不住分享一下,毕竟独乐乐不如众乐乐。> 这里须要说的配角就是 Artahs。> Arthas 应用文档很具体,我这里次要记录一下应用 Arthas 的一点总结。应用背景在一个大的团队外面,会因为很多历史起因或客观因素导致技术栈并不对立,咱们就遇到这么一个问题。老我的项目是应用 Dubbo 框架的 Dubbo 协定进行服务交互,有新的我的项目是应用 Springcloud 体系的 Feignclient 框架的 Http 协定进行交互。那么就须要解决两个问题。 问题 1 是 Dubbo 服务须要反对 Dubbo 协定又须要撑持 Http 协定。问题 2 是 Feignclient 框架可能无损调用 Dubbo 服务的 Http 协定(无损指的是 Dubbo 对 Feignclient 调用方可能做到服务动静感知,负载平衡不须要做二次开发)。解决思路有了以上的指标,咱们就须要想方法解决问题。解决第一个问题倒是比拟容易,Dubbo 自身就提供的 Http 协定暴漏。也就是将老工程 Dubbo 降级、配置两种协定问题一就这么解决了。 然而针对问题 2,咱们能够列举一下遇到的问题。Dubbo 注册应用的是 zk 注册核心,Springcloud 工程应用 Eureka 注册核心。这里顺带也要赞美一下 Feignclient 框架,Feignclient 接入服务的门槛很低,这样兼容了很多语言、环境等带来的差别,也就是说只有是 http 协定的接口 Feignclient 就能调用。到这里实际上通过 Feignclient 间接调用 Dubbo 服务暴漏的 Http 协定接口是可能走的通,只不过没法做到负载平衡,失败转移等能力。说了这么多总结一下吧。 ...

January 4, 2021 · 2 min · jiezi

关于dubbo:dubbogo-30牵手-gRPC-走向云原生时代

作者 | 李志信  于雨起源|阿里巴巴云原生公众号 自从 2011 年 Dubbo 开源之后,被大量中小公司采纳,始终是国内最受欢迎的 RPC 框架。2014 年,因为阿里外部组织架构调整,Dubbo 暂停保护了一段时间,之后随着 Spring Cloud 的面世,两个体系在交融中一起助推了微服务的炽热。 不过这世界变动快,自从以 docker 为代表的的容器技术和以 K8s 为代表的容器编排技术登上舞台之后,云原生时代到来了。在云原生时代,不可变的基础设施给原有的中间件带来了不可变的中间件基础设施:gRPC 对立了底层通信层;protobuf 对立了序列化协定;以 envoy + istio 为代表的 service mesh 逐步对立了服务的管制面与数据面。 dubbogo 的人造使命是:Bridging the gap between Java and Go。放弃 Go 利用与 Java 利用互联互通的同时,借助 Go 语言(事实上的第一云原生语言)的劣势拥抱云原生时代。dubbogo 社区 2020 年勠力打造三支箭: 曾经公布的对齐 dubbo 2.7 的 dubbogo v1.5 版本;近期将要公布的 sidecar 状态的 dubbo-go-proxy 我的项目;以及处于进行时的 dubbogo 3.0。用一句话概括 dubbogo 3.0 即是:新通信协议、新序列化协定、新利用注册模型以及新的服务治理能力!本文次要着重探讨 dubbogo 3.0 的新通信协议和利用级服务注册发现模型。 ...

December 16, 2020 · 3 min · jiezi

关于dubbo:dubbogo-白话文-go-和-java-互通有无

本文从一个 BUG 动手,手把手教你 dubbogo 调用 dubbogo 或 dubbo 服务 一、前言昨天邹部长在群里@我让看一个对于 dubbogo 调用 dubbo 报错的问题,<u>问题issue地址</u>,于是我跑了 dubbogo + dubbbo 的测试代码来定位这个问题,因为之前也没跨语言调用,从零开始搭建,踩到了一些新人应用 dubbogo 的坑,把这个过程记录下供大家参考。 二、解决问题2.1 筹备 dubbo 服务提供者2.1.1 根本定义定义 DemoService 接口: public interface DemoService { String sayHello(String name); String sayHello(User user); String sayHello(User user, String name);}定义 User 对象: public class User implements Serializable { private String name; private int age; ......}2.1.2 启动 dubbo 服务提供者用的 dubbo 官网示例代码: public static void main(String[] args) throws IOException { // 服务实现 DemoService demoService = new DemoServiceImpl(); // 以后利用配置 ApplicationConfig application = new ApplicationConfig(); application.setName("demoProvider"); // 连贯注册核心配置 RegistryConfig registry = new RegistryConfig(); registry.setAddress("127.0.0.1:2181"); registry.setProtocol("zookeeper"); registry.setUsername(""); registry.setPassword(""); // 服务提供者协定配置 ProtocolConfig protocol = new ProtocolConfig(); protocol.setName("dubbo"); protocol.setPort(12345); protocol.setThreads(200); // 留神:ServiceConfig为重对象,外部封装了与注册核心的连贯,以及开启服务端口 // 服务提供者裸露服务配置 ServiceConfig<DemoService> service = new ServiceConfig<>(); // 此实例很重,封装了与注册核心的连贯,请自行缓存,否则可能造成内存和连贯透露 service.setApplication(application); service.setRegistry(registry); // 多个注册核心能够用setRegistries() service.setProtocol(protocol); // 多个协定能够用setProtocols() service.setInterface(DemoService.class); service.setRef(demoService); service.setVersion("1.0.0"); service.setGroup("tc"); service.setTimeout(60 * 1000); // 裸露及注册服务 service.export(); System.in.read();}查看 zookeeper 看是否注册胜利: ...

December 11, 2020 · 7 min · jiezi

关于dubbo:万字长文Dubbo-入门总结-一款高性能的-Java-RPC-框架

这篇文章是我学习整顿 Dubbo 的一篇文章,首先大部分内容参考了官网 + 某硅谷的视频,内容解说进行了从新编排,40多张图片,也都是我批改重制的,尽管一万多字,然而其实也能够看进去,更多的内容集中在了概念或性能的介绍,具体环境的搭建,以及如何配置,疾速上手下面,然而对于这样一款优良的框架,文章中提到的每一个点其实开展来讲都能写这样篇幅的一篇文章,仅仅入门来看也没必要,总得学会走,才能够去试着跑 文章提及了 SSM 和 Springboot 下的不同配置形式,然而 Zookeeper 环境搭在了 Windows 下,前面筹备重新整理的 Redis 我思考在 Linux 中来跑,会更贴近理论一些说句题外话,设计模式也没停,还有一篇存稿,不过想整顿的货色太多,还有学校等等的事件,真有点自闭了有什么倡议和意见欢送在评论区和我交换哈,感激各位大佬的反对~早安,学习人 & 打工人 ~ ~ ~ 一 必备基础知识(一) 分布式基础理论在百度以及维基中的定义都绝对业余且艰涩,大部分博客或者教程常常会应用《分布式系统原理和范型》中的定义,即:“分布式系统是若干独立计算机的汇合,这些计算机对于用户来说就像是单个相干零碎” 上面咱们用一些篇幅来艰深的解释一下什么叫做分布式 (1) 什么是集中式零碎提到分布式,不得不提的就是 “集中式零碎”,这个概念最好了解了,它就是将性能,程序等装置在同一台设施上,就由这一台主机设施向外提供服务 举个最简略的例子:你拿一台PC主机,将其改装成了一台简略的服务器,配置好各种内容后,你将MySQL,Web服务器,FTP,Nginx 等等,全副装置在其中,打包部署我的项目后,就能够对外提供服务了,然而一旦这台机器无论是软件还是硬件呈现了问题,整个零碎都会受到重大的株连谬误,鸡蛋放在一个篮子里,要打就全打了 (2) 什么是分布式系统既然集中式零碎有这样一种牵一发而动全身的问题,那么分布式的其中一个作用,天然是来解决这样的问题了,正如定义中所知,分布式系统在用户的体验感官里,就像传统的单零碎一样,一些变动都是这个零碎自身外部进行的,对于用户并没有什么太大的感觉 例如:淘宝,京东这种大型电商平台,它们的主机都是数以万计的,否则基本没法解决大量的数据和申请,具体其中有什么划分,以及操作,咱们上面会说到,然而对于用户的咱们,咱们不须要也不想关怀这些,咱们仍能够单纯的认为,咱们面对的就是 “淘宝” 这一台 “主机” 所以分布式的一个绝对业余一些的说法是这样的(过程粒度)两个或者多个程序,别离运行在不同的主机过程上,它们互相配合协调,实现独特的性能,那么这几个程序之间形成的零碎就能够叫做分布式系统 这几者都是雷同的程序 —— 分布式这几者都是不同的程序 —— 集群 (3) 倒退过程 A:繁多利用架构当网站流量很小时,只需一个利用,将所有性能都部署在一起,以缩小部署节点和老本。此时,用于简化增删改查工作量的数据拜访框架(ORM)是要害 长处: 所有性能集中在一起,开发以及前期保护均绝对简略对于小型网站及管理系统,简略易用毛病: 对于大型项目,降级保护艰难无奈对于一个模块进行程度扩大或优化模块之间耦合严密,容错率低B:垂直利用架构当访问量逐步增大,繁多利用减少机器带来的加速度越来越小,晋升效率的办法之一是将利用拆成互不相干的几个利用,以晋升效率。此时,用于减速前端页面开发的Web框架(MVC)是要害 长处: 通过切分业务达到各模块独立部署,保护和部署更加简略能够对一个模块进行程度扩大或优化毛病: 零碎之间无奈互相调用具备反复代码,且专用模块无奈反复利用C:分布式服务架构当垂直利用越来越多,利用之间交互不可避免,将外围业务抽取进去,作为独立的服务,逐步造成稳固的服务中心,使前端利用能更疾速的响应多变的市场需求。此时,用于进步业务复用及整合的分布式服务框架(RPC)是要害 长处: 抽取公共代码,代码复用性进步毛病: 调用关系简单,保护很麻烦D:流动计算架构当服务越来越多,容量的评估,小服务资源的节约等问题逐步浮现,此时需减少一个调度核心基于拜访压力实时治理集群容量,进步集群利用率。此时,用于进步机器利用率的资源调度和治理核心(SOA)是要害 长处: 简单的调用关系不再须要自行保护毛病: 服务具备依赖性,一个服务呈现问题或者会导致其余零碎不可用(4) RPC 介绍RPC(Remote Procedure Call)是指近程过程调用,是一种过程间通信形式,他是一种技术的思维,而不是标准。它容许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不必程序员显式编码这个近程调用的细节 ...

December 7, 2020 · 8 min · jiezi

关于dubbo:1112

Docker是轻量级的虚拟机,相似于VMware虚拟机,但占用资源更少,启动速度更快开发运维一体化(DevOps)的外围工具,进步了开发-测试-上线部署的工作效率 DubboApache Dubbo |db| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大外围能力:面向接口的近程办法调用,智能容错和负载平衡,以及服务主动注册和发现。 xml配置 如果其中一个服务器宕机 用户拜访是否受限?答:因为zk的帮忙,使得程序永远能够拜访正确的服务器.并且当服务重启时,duboo有服务的主动发现性能,消费者不须要重启即能够拜访新的服务. 如果ZK集群短时间宕机,用户拜访是否受限?答: 用户的拜访不受影响,因为消费者在本地存储服务列表信息,当拜访故障机时,主动的将标识信息改为down属性. Dubbo负载平衡策略 形容HTTP协定的作用及具体内容(申请和响应的构造)网络通信中存在不同的主机、网络、设施,须要遵循一套对立的通信协议才能够无效的进行通信。HTTP协定就是一套基于tcp/ip协定的应用层协定 它规定了客户端(通常是浏览器)和服务器之间的通信形式。 一个典型的HTTP申请分为 一个申请行 若干申请头 一个空行 实体内容

November 12, 2020 · 1 min · jiezi

关于dubbo:第三阶段-Day18-Dubbo-完成用户注册单点登录

Dubbo========= 1.1 Dubbo介绍Apache Dubbo |db| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大外围能力:面向接口的近程办法调用,智能容错和负载平衡,以及服务主动注册和发现。 1.2 Dubbo特点 2 Dubbo入门案例2.1 定义公共接口我的项目阐明:接口我的项目个别定义公共的局部,并且被第三方依赖. 2.2 服务提供者介绍2.2.1 提供者代码构造 2.2.2 编辑实现类`package com.jt.dubbo.service;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import com.alibaba.dubbo.config.annotation.Service;import com.jt.dubbo.mapper.UserMapper;import com.jt.dubbo.pojo.User;@Service(timeout=3000) //3秒超时 外部实现了rpc//@org.springframework.stereotype.Service//将对象交给spring容器治理public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public List<User> findAll() { System.out.println("我是第一个服务的提供者"); return userMapper.selectList(null); } @Override public void saveUser(User user) { userMapper.insert(user); }}` 2.2.3 编辑提供者配置文件`server: port: 9000 #定义端口spring: datasource: #引入druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true username: root password: root#对于Dubbo配置 dubbo: scan: basePackages: com.jt #指定dubbo的包门路 扫描dubbo注解 application: #利用名称 name: provider-user #一个接口对应一个服务名称 一个接口能够有多个实现 registry: #注册核心 用户获取数据从机中获取 主机只负责监控整个集群 实现数据同步 address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183 protocol: #指定协定 name: dubbo #应用dubbo协定(tcp-ip) web-controller间接调用sso-Service port: 20880 #每一个服务都有本人特定的端口 不能反复. mybatis-plus: type-aliases-package: com.jt.dubbo.pojo #配置别名包门路 mapper-locations: classpath:/mybatis/mappers/*.xml #增加mapper映射文件 configuration: map-underscore-to-camel-case: true #开启驼峰映射规定` 2.3 服务消费者介绍2.3.1 编辑Controller`package com.jt.dubbo.controller;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import com.alibaba.dubbo.config.annotation.Reference;import com.jt.dubbo.pojo.User;import com.jt.dubbo.service.UserService;@RestControllerpublic class UserController { //利用dubbo的形式为接口创立代理对象 利用rpc调用 @Reference private UserService userService; /** * Dubbo框架调用特点:近程RPC调用就像调用本人本地服务一样简略 * @return */ @RequestMapping("/findAll") public List<User> findAll(){ //近程调用时传递的对象数据必须序列化. return userService.findAll(); } @RequestMapping("/saveUser/{name}/{age}/{sex}") public String saveUser(User user) { userService.saveUser(user); return "用户入库胜利!!!"; }}` 2.3.2 编辑YML配置文件`server: port: 9001dubbo: scan: basePackages: com.jt application: name: consumer-user #定义消费者名称 registry: #注册核心地址 address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183` 2.3.3 Dubbo入门案例测试 ...

November 9, 2020 · 3 min · jiezi

关于dubbo:Dubbogo-Server端开启服务过程

导读导读:随着微服务架构的风行,许多高性能 rpc 框架应运而生,由阿里开源的 dubbo 框架 go 语言版本的 dubbo-go 也成为了泛滥开发者不错的抉择。本文将介绍 dubbo-go 框架的根本应用办法,以及从 export 调用链的角度进行 server 端源码导读,心愿能疏导读者进一步意识这款框架。下周将发表本文的姊妹篇:《从 client 端源码导读 dubbo-go 框架》。序言近日浏览了局部dubbo-go源码https://github.com/dubbogo/dubbo-go 当拿到一款框架之后,一种不错的源码浏览形式大抵如下:从运行最根底的helloworld demo 源码开始,再查看配置文件,开启各种依赖服务(比方zk、consul),开启服务端,再到通过client调用服务端,打印残缺申请日志和回包。调用胜利之后,再依据框架的设计模型,从配置文件解析开始,自顶向下递浏览整个框架的调用栈。对于C/S模式的rpc申请来说,整个调用栈被拆成了client和server两局部,所以能够别离从server端的配置文件解析浏览到server端的监听启动,从client端的配置文件解析浏览到一次invoker Call 调用。这样一次残缺申请就清晰了起来。 1. 运行官网提供的helloworld-demo官网demo 1.1 dubbo-go 2.7版本 QuickStart1. 开启一个go-server服务将仓库clone 到本地$ git clone https://github.com/dubbogo/dubbo-samples.git进入dubbo目录$ cd dubbo-samples/golang/helloworld/dubbo进入目录后可看到四个文件夹,别离反对go和java的client以及server,咱们尝试运行一个go的server进入app子文件夹内,能够看到外面保留了go文件。 $ cd go-server/appsample文件构造:可在go-server外面看到三个文件夹:app、assembly、profiles其中app文件夹下保留go源码,assembly文件夹下保留可选的针对特定环境的build脚本,profiles下保留配置文件。对于dubbo-go框架,配置文件十分重要,没有文件将导致服务无奈启动。 设置指向配置文件的环境变量因为dubbo-go框架依赖配置文件启动,让框架定位到配置文件的形式就是通过环境变量来找。对于server端须要两个必须配置的环境变量:CONF_PROVIDER_FILE_PATH、APP_LOG_CONF_FILE,别离应该指向服务端配置文件、日志配置文件。在sample外面,咱们能够应用dev环境,即profiles/dev/log.yml profiles/dev/server.yml 两个文件。在app/下,通过命令行中指定好这两个文件: $ export CONF_PROVIDER_FILE_PATH="../profiles/dev/server.yml"$ export APP_LOG_CONF_FILE="../profiles/dev/log.yml"设置go代理并运行服务$ go run .如果提醒timeout,则须要设置goproxy代理 $ export GOPROXY="http://goproxy.io"再运行go run 即可开启服务 2. 运行zookeeper装置zookeeper,并运行zkServer, 默认为2181端口 3. 运行go-client调用server服务进入go-client的源码目录$ cd go-client/app同理,在/app下配置环境变量$ export CONF_CONSUMER_FILE_PATH="../profiles/dev/client.yml"$ export APP_LOG_CONF_FILE="../profiles/dev/log.yml"配置go代理 ...

November 7, 2020 · 3 min · jiezi

关于dubbo:1020

1.Dubbo1.1Dubbo介绍Apache Dubbo |db| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大外围能力:面向接口的近程办法调用,智能容错和负载平衡,以及服务主动注册和发现。 1.2Dubbo特点 2 Dubbo入门案例2.1 定义公共接口我的项目阐明:接口我的项目个别定义公共的局部,并且被第三方依赖 2.2服务提供者介绍2.2.1提供者代码构造 2.2.2编辑实现类 2.2.3编辑提供者配置文件 2.3服务者生产介绍2.3.1编辑controller 2.3.2编辑YML配置文件 2.4对于Dubbo框架知识点2.4.1问题1:### 如果其中一个服务器宕机 用户拜访是否受限?答:因为zk的帮忙,使得程序永远能够拜访正确的服务器.并且当服务重启时,duboo有服务的主动发现性能,消费者不须要重启即能够拜访新的服务. 问题2:如果ZK集群短时间宕机,用户拜访是否受限?答: 用户的拜访不受影响,因为消费者在本地存储服务列表信息,当拜访故障机时,主动的将标识信息改为down属性. 2.5Dubbo负载平衡策略2.5.1负载平衡品种1.客户端负载平衡Dubbo/SpringCloud等微服务框架 2.服务端负载平衡阐明:客户端发动申请之后,必须由对立的服务器进行负载平衡,所有的压力都在服务器中.NGINX 2.5.2Dubbo负载平衡形式 对于ZK数据存储构造阐明:在zk中数据的存储采纳树形构造的形式保留命令: [root@localhost bin]# sh zkCli.sh查问命令: ls /… 用户单点登录原理介绍4.3.1传统形式登录存在的问题阐明:如果采纳SESSION的形式实现用户的登录操作,因为nginx负载平衡的策略,用户能够拜访不同的服务器.然而Session不能共享,所以导致用户频繁的登录. 用户的体验不好. SSO单点登录(SingleSignOn,SSO),就是通过用户的一次性甄别登录。当用户在身份认证服务器上登录一次当前,即可取得拜访单点登录零碎中其余关联系统和应用软件的权限,同时这种实现是不须要管理员对用户的登录状态或其余信息进行批改的,这意味着在多个利用零碎中,用户只需一次登录就能够拜访所有相互信任的利用零碎。这种形式缩小了由登录产生的工夫耗费,辅助了用户治理,是目前比拟风行的 京淘我的项目单点登录设计实现步骤:1.当用户输出用户名和明码点击登录时,将申请发送给JT-WEB消费者服务器.2.JT-WEB服务器将用户信息传递给JT-SSO单点登录零碎实现数据校验.3.如果登录胜利,则动静生成密钥信息,将user数据转化为json.保留到redis中. 留神超时工夫的设定.4.JT-SSO将登录的凭证 传给JT-WEB服务器.5.JT-WEB服务器将用户密钥TICKET信息保留到用户的cookie中 留神超时工夫设定.6.如果登录不胜利,则间接返回错误信息即可.

October 20, 2020 · 1 min · jiezi

关于dubbo:解构-Dubbogo-的核心注册引擎-Nacos

近几年,随着Go语言社区逐步倒退和壮大,越来越多的公司开始尝试采纳Go搭建微服务体系,也涌现了一批Go的微服务框架,如go-micro、go-kit、Dubbo-go等,跟微服务治理相干的组件也逐步开始在Go生态发力,如Sentinel、Hystrix等都推出了Go语言版本,而作为微服务框架的外围引擎--注册核心,也是必不可缺少的组件,市面曾经有多款注册核心反对Go语言,应该如何抉择呢?咱们能够对目前支流的反对Go语言的注册核心做个比照。 图1依据上表的比照咱们能够从以下几个维度得出结论: 生态:各注册核心对Go语言都有反对,然而Nacos、 Consul、Etcd 社区沉闷,zookeeper和Eureka社区活跃度较低;易用性:Nacos、Eureka、Consul都有现成的管控平台,Etcd、zookeeper自身作为kv存储,没有相应的管控平台,Nacos反对中文界面,比拟合乎国人应用习惯;场景反对:CP模型次要针对强统一场景,如金融类,AP模型实用于高可用场景,Nacos能够同时满足两种场景,Eureka次要满足高可用场景,Consul、Zookeepr、Etcd次要满足强统一场景,此外Nacos反对从其它注册核心同步数据,不便用户注册核心迁徙;性能完整性:所有注册核心都反对健康检查,Nacos、Consul反对的查看形式较多,满足不同利用场景,Zookeeper通过keep alive形式,能实时感知实例变动;Nacos、Consul和Eureka都反对负载平衡策略,Nacos通过Metadata selector反对更灵便的策略;此外,Nacos、Eureka都反对雪崩爱护,防止因为过多的实例不衰弱对衰弱的实例造成雪崩效应。综合下面各维度的比照,能够理解到Nacos作为注册核心有肯定的劣势,那么它对Go微服务生态的集成做得如何?接下来咱们首先摸索下Nacos是如何与Dubbo-go集成。 引言Dubbo-go目前是Dubbo多语言生态中最炽热的一个我的项目,从2016年公布至今,曾经走过5个年头。最近,Dubbo-go公布了v1.5版本,全面兼容Dubbo 2.7.x版本,反对了利用维度的服务注册与发现,和支流的注册模型保持一致,标记着Dubbo-go向云原生迈出了要害的一步。作为驱动服务运行的外围引擎--注册核心,在切换到利用维度的注册模型后,也须要做相应的适配,本文将解析如何以Nacos为外围引擎实现利用维度的服务注册与发现,并且给出相应的实际案例。此外,本文代码基于Dubbo-go v1.5.1,Nacos-SDK-go v1.0.0和Nacos v1.3.2。 服务注册与发现架构从架构中,咱们能够看到,与接口级别的服务注册发现不同的是,Dubbo-go的provider启动后会调用Nacos-go-sdk的RegisterInstance接口向Nacos注册服务实例,注册的服务名即为利用名称,而不是接口名称。Conusmer启动后则会调用Subscribe接口订阅该利用的服务实例变动,并对的实例发动服务调用。 图2服务模型图3是咱们Dubbo-go的利用维度服务发现模型,次要有服务和实例两个层级关系,服务实例的属性次要蕴含实例Id、主机地址、服务端口、激活状态和元数据。图4为Nacos的服务分级存储模型,蕴含服务、集群和实例三个档次。两者比照,多了一个集群维度的层级,而且实例属性信息可能齐全匹配。所以在Dubbo-go将应用服务实例注册到Nacos时,咱们只须要将集群设置为默认集群,再填充服务和实例的相干属性,即可实现服务模型上的匹配。此外Nacos能够将服务注册到不同的Namespace下,实现多租户的隔离。 图3 图4服务实例心跳维持Dubbo-go的Provider在向Nacos注册应用服务实例信息后,须要被动上报心跳,让Nacos服务端感知实例的存活与否,以判断是否将该节点从实例列表中移除。保护心跳的工作是在Nacos-SDK-go实现的,从图5代码中能够看到,当Dubbo-go调用RegisterInstance注册一个服务实例时,SDK除了调用Nacos的Register API之外,还会调用AddBeatInfo,将服务实例信息增加到本地缓存,通过后盾协程定期向Nacos发送服务实例信息,放弃心跳。当服务下线时,能够通过调用DeRegisterInstance执行反注册,并移除本地的心跳放弃工作,Nacos实例列表中也会将该实例移除。 图5订阅服务实例变动Dubbo-go的Consumer在启动的时候会调用Nacos-SDK-go的Subscribe接口,该接口入参如图6,订阅的时候只须要传递ServiceName即利用名和回调函数SubscribeCallback,Nacos在服务实例发生变化的时候即可通过回调函数告诉Dubbo-go。Nacos-SDK-go是如何感知Nacos的服务实例变动的呢?次要有两种形式: Nacos服务端被动推送,Nacos-SDK-go在启动的时候会监听一个UDP端口,该端口在调用Nacos Register API的时候作为参数传递,Nacos会记录Ip和端口,当服务实例发生变化时,Nacos会对所有监听该服务的Ip和端口发送UDP申请,推送变动后的服务实例信息。Nacos-SDK-go定期查问,SDK会对订阅的服务实例定时调用查问接口,如果查问有变动则通过回调接口告诉Dubbo-go。作为兜底策略保障Nacos服务端推送失败后,仍能感知到变动。 图6此外Nacos-SDK-go还反对推空爱护,当Nacos推送的实例列表为空时,不更新本地缓存,也不告诉Dubbo-go变更,防止Consumer无可用实例调用,造成故障。同时,SDK还反对服务实例信息本地长久化存储,能够保障在Nacos服务故障过程中,Consumer重启也能获取到可用实例,具备容灾成果。 范例实际环境筹备dubbo-go samples代码下载:https://github.com/apache/dub...,基于Nacos注册核心的利用级服务发现的hello world代码目录在 registry/servicediscovery/nacos。 图7Nacos服务端搭建,参考官网文档:https://nacos.io/zh-cn/docs/q...,或者应用官网提供的公共Nacos服务:http://console.nacos.io/nacos...:nacos,仅供测试),或者购买阿里云服务:https://help.aliyun.com/docum... Server端搭建进入registry/servicediscovery/nacos/go-server/profiles文件,能够看到有dev、release和test三个文件夹,别离对应开发、测试和生产配置。咱们应用dev配置来搭建开发环境,dev文件下有log.yml和server.yml文件,上面对server.yml配置进行批改。 remote配置,这里应用公共的Nacos服务,address反对配置多个地址,用逗号宰割。params参数配置nacos-sdk的日志目录。 remote: nacos: address: "console.nacos.io:80" timeout: "5s" params: logDir: "/data/nacos-sdk/log"configCenter配置config_center: protocol: "nacos" address: "console.nacos.io:80"配置server端环境变量 export CONF_PROVIDER_FILE_PATH=server端的server.yml文件门路export APP_LOG_CONF_FILE=server端的log.yml文件门路进入registry/servicediscovery/nacos/go-server/app,运行server.go的main办法,能够从Nacos的控制台(http://console.nacos.io/nacos...) 看到,利用user-info-server曾经注册胜利。 Client端搭建client的配置文件在registry/servicediscovery/nacos/go-server/profiles目录下,须要批改的中央跟server端一样,这里不赘述。 配置client端环境变量 export CONF_CONSUMER_FILE_PATH=client端的server.yml文件门路export APP_LOG_CONF_FILE=client端的log.yml文件门路进入registry/servicediscovery/nacos/go-client/app,运行client.go的main办法,看到如下日志输入,示意调用server端胜利。 ...

September 19, 2020 · 1 min · jiezi

关于dubbo:Dubbo框架pojo类转化异常

对于POJO转化异样阐明在Dubbo框架应用时,启动服务器运行程序时总会报pojo转化的异样: 报错阐明: 因为SpringBoot配置了热部署的工具,当代码进行批改之后,程序就会重新启动. 在重启的过程中程序又会再次链接zookeeper注册核心.因为zk的心跳检测机制存在超时工夫,可能在zk中会呈现2条截然不同的服务的提供者的信息. 解决方案: 须要手动的重启服务器即可.(因为手动开关服务器过程较长,工夫足够zookeeper中进行判断,只留下一条信息) 报错信息:com.xx.pojo.User cannot be cast to com.xx.pojo.User

September 17, 2020 · 1 min · jiezi

关于dubbo:写在-Dubbo-go-的第五年

简介: dubbogo 我的项目已进入第五个年头。与社区同学们齐心合力之下,现在全面兼容 Dubbo v2.7.x 的 Dubbo-go v1.5.1 曾经公布。 作者 | 于雨 阿里巴巴云原生公众号后盾回复“915”即可查看 dubbogo v1.5.1 项目管理图清晰大图! 引语dubbogo 我的项目已进入第五个年头。 我的项目倒退的前两年,咱们把 hessian2 协定库、网络库和整体根底框架搭建一番。从 2018 年我的项目被 Dubbo 官网接收开始,依靠阿里平台,社区开始造成并疾速倒退。与社区同学们齐心合力之下,现在全面兼容 Dubbo v2.7.x 的 Dubbo-go v1.5.1 曾经公布。 立项一个我的项目整体必须提炼出外围指标,指明其存在的意义和价值。有了初心,我的项目倒退过程中产生困惑时,能力明确回答 “我是谁?从哪里来?到哪里去”。 dubbogodubbogo 我的项目有其本身的 milestone 要求,大抵布局了每个阶段的要害里程碑,在我的项目倒退初期仅仅是实现 Dubbo 的某个性能,但在倒退过程中会一直联合当下的技术倒退潮流,一直修改其将来倒退方向。 其发版打算是通过“开发以后版本、布局新版本、依据反馈修改新版本”的模式定义以后版本的开发内容和下一个版本的倒退方向。每次发版后会依据社区应用反馈对下一代的倒退指标进行修改。 站在吃瓜人的角度,或者能够说出 “dubbogo 不就是 dubbo 的 Go 语言版本嘛,照着抄就是了” 之类的论调。而参加过 dubbogo 我的项目跟着社区一路走来的人,就晓得 dubbogo 并不简略定位于 Dubbo 我的项目的 Go 语言版本。 dubbogo 初心不变,不同工夫对本身定位均有降级。我认为以后 dubbogo 的定位是: 全面兼容 Dubbo;一个 Go 语言利用通信框架,充分利用作为云原生时代第一语言---Go 语言的劣势,扩大 dubbo 的能力。dubbo-go-proxydubbogo 我的项目初期目标是依附 Dubbo 实现 "bridge the gap between Java and Go" ,目前 dubbogo 正与 Dubbo 齐头并进,曾经达到我的项目立项的指标。有长期生命的通信框架,大略有 5 年的成长期和 5 年的稳固成熟期。目前的 dubbogo 处在成长期和稳固成熟期的过渡期,这意味着社区如果想放弃倒退态势,就必须开始走多元化路线,倒退本人的生态了。 ...

September 17, 2020 · 2 min · jiezi

关于dubbo:Dubbo的SPI机制

前言上一篇 Dubbo 文章敖丙曾经带了大家过了一遍整体的架构,也提到了 Dubbo 的胜利离不开它采纳微内核设计+SPI扩大,使得有非凡需要的接入方能够自定义扩大,做定制的二次开发。 良好的扩展性对于一个框架而言尤其重要,框架顾名思义就是搭好外围架子,给予用户简略便捷的应用,同时也须要满足他们定制化的需要。 Dubbo 就依附 SPI 机制实现了插件化性能,简直将所有的性能组件做成基于 SPI 实现,并且默认提供了很多能够间接应用的扩大点,实现了面向性能进行拆分的对扩大凋谢的架构。 什么是 SPI首先咱们得先晓得什么叫 SPI。 SPI (Service Provider Interface),次要是用来在框架中应用的,最常见和莫过于咱们在拜访数据库时候用到的java.sql.Driver接口了。 你想一下首先市面上的数据库形形色色,不同的数据库底层协定的大不相同,所以首先须要定制一个接口,来束缚一下这些数据库,使得 Java 语言的使用者在调用数据库的时候能够不便、对立的面向接口编程。 数据库厂商们须要依据接口来开发他们对应的实现,那么问题来了,真正应用的时候到底用哪个实现呢?从哪里找到实现类呢? 这时候 Java SPI 机制就派上用场了,不晓得到底用哪个实现类和找不到实现类,咱们通知它不就完事了呗。 大家都约定好将实现类的配置写在一个中央,而后到时候都去哪个中央查一下不就晓得了吗? Java SPI 就是这样做的,约定在 Classpath 下的 META-INF/services/ 目录里创立一个以服务接口命名的文件,而后文件外面记录的是此 jar 包提供的具体实现类的全限定名。 这样当咱们援用了某个 jar 包的时候就能够去找这个 jar 包的 META-INF/services/ 目录,再依据接口名找到文件,而后读取文件外面的内容去进行实现类的加载与实例化。 比方咱们看下 MySQL 是怎么做的。 再来看一下文件外面的内容。 MySQL 就是这样做的,为了让大家更加粗浅的了解我再简略的写一个示例。 Java SPI 示例 而后我在 META-INF/services/ 目录下建了个以接口全限定名命名的文件,内容如下 com.demo.spi.NuanNanAobingcom.demo.spi.ShuaiAobing运行之后的后果如下 Java SPI 源码剖析之前的文章我也提到了 Dubbo 并没有用 Java 实现的 SPI,而是自定义 SPI,那必定是 Java SPI 有什么不不便的中央或者劣势。 ...

September 14, 2020 · 2 min · jiezi

关于dubbo:Whats-new-in-Dubbogo-v151

近期咱们公布了 dubbo-go v1.5.1,尽管是 v1.5 的一个子版本,但相比于 v1.5.0, 社区还是投入了很大人力增加了如下重大改良。 1 利用维度注册模型在新模型 release 后,咱们发现 Provider 每个 URL 公布元数据都会注册 ServiceInstance,影响性能须要优化。咱们的优化计划是:去除 ServiceDiscoveryRegistry 中注册 ServiceInstance 的代码,在 config_loader 中的loadProviderConfig 办法的最初注册 ServiceInstance具体步骤:1、获取所有注册的 Registry,过滤出 ServiceDiscoveryRegistry,拿取所有 ServiceDiscovery。2、创立 ServiceInstance。3、每个 ServiceDiscovery 注册 ServiceInstance。保障 Provider 在注册胜利之后,才裸露元数据信息。 2 反对基于 Seata 的事务基于 Seata 扩大实现。通过减少过滤器,在服务端接管  xid 并联合 seata-golang 达到反对分布式事务的目标。 从而使 Dubbo-go 在分布式场景下,让用户有更多的抉择,能适应更多的个性化场景。咱们在 dubbo-samples 中给出了 事务测试用例 。 3 多注册核心集群负载平衡对于多注册核心订阅的场景,选址时的多了一层注册核心集群间的负载平衡:在 Cluster Invoker 这一级,咱们反对的选址策略有: 指定优先级同 zone 优先权重轮询 3 传输链路安全性该版本在传输链路的安全性上做了尝试,对于内置的 Dubbo getty Server 提供了基于 TLS 的平安链路传输机制。为尽可能保障利用启动的灵活性,TLS Cert 的指定通过配置文件形式,具体请参见 Dubbo-go 配置读取规定与 TLS 示例: ...

September 12, 2020 · 2 min · jiezi

关于dubbo:Dubbogo应用维度注册模型

本文作者: 白泽(蒋超),Github ID @Patrick0308,开源爱好者。 Dubbo 3.0 将至。其最重要的一点就是服务自省,其根底即是利用维度的注册模型,作为目前与 Dubbo 在性能上齐全对齐的 Dubbo-go,已于 本年【2020 年】7 月份公布了其 v1.5.0 版本,实现了该模型,为年底实现与 Dubbo 3.0 对齐的新版本奠定了根底。Dubbo-go 作为 Dubbo 的 Go 语言版本,因跨语言之故,二者针对同一模型的实现必然有较大差别,故本文重视探讨 Dubbo-go 社区本身对该模型的了解和实现,以及其与 Dubbo 之间的差别。 1 引语在 v1.5 以前,Dubbo-go 注册模型都是以服务为维度的,直观的了解可认为其是接口维度。譬如注册信息,依照服务维度模型其示例如下: "com.xxx.User":[ {"name":"instance1", "ip":"127.0.0.1", "metadata":{"timeout":1000}}, {"name":"instance2", "ip":"127.0.0.2", "metadata":{"timeout":2000}}, {"name":"instance3", "ip":"127.0.0.3", "metadata":{"timeout":3000}}, ]这种模式的益处是显而易见的,简略直观,提供了细粒度的服务管制伎俩。而近两年,随着云时代的到来,这种模式就裸露了有余: 支流的注册模型都是利用维度的;以服务维度来注册,那么规模与服务数量成正比,大规模集群之下,注册核心压力十分大; 2 Dubbo-go v1.5.0 的新注册模型这次 Dubbo-go 反对了新的注册模型,也就是利用维度的注册模型。简略而言,在利用维度注册下,其注册信息相似: "application1": [ {"name":"instance1", "ip":"127.0.0.1", "metadata":{}}, {"name":"instance2", "ip":"127.0.0.2", "metadata":{}}, {"name":"instanceN", "ip":"127.0.0.3", "metadata":{}}]在此模式之下,能够看到注册信息将会大幅度缩小,集群规模只与实例数量相干。与此同时,在实现这一个性能的时候,Dubbo-go 还心愿放弃两个指标: 对用户齐全兼容,用户迁徙无感知;放弃住本来服务粒度上精密管制的能力——即保留现有的服务维度的元数据;因而 Dubbo-go 要着力解决以下几点: ...

September 12, 2020 · 2 min · jiezi

关于dubbo:没想到吧关于Dubbo的『消费端线程池模型』官网也写错了

[ 文件](https://www.mdnice.com/#)格局性能查看主题代码主题设置帮忙 这是why的第 **63** 篇原创文章 ![](https://p6-juejin.byteimg.com... # 荒腔走板 大家好,我是 why,欢送来到我间断周更优质原创文章的第 63 篇。老规矩,先荒腔走板聊聊其余的。 下面这张图片是我前几天整顿相册的时候看到的。拍摄于 2016 年 8 月 20日,北京。 那个时候我刚刚去北京没多久,住在公司的提供的宿舍外面。宿舍位于北京二环内的一个叫做东廊下的胡同里。 地位极佳,条件极差。 我刚刚进入宿舍的时候,房间外面只有一张大床、一个矮矮的电视柜、一个不能点头的风扇。我的房间也没有空调,到处都是灰蒙蒙的,用卫生间都是去楼下的公共卫生间。 有一次北京下暴雨,我才发现窗户那边有一个缺口,雨下的太大,能够顺着那个缺口流下来,把我的鞋都打湿了。 宿舍外面没有冰箱,所以节假日我在宿舍只煮面条或者用电饭煲做干饭,而后就着各种酱吃。记得有一次周五领导请咱们吃饭,最初菜点多了,有几个羊蹄动都没动,领导就叫我打包带回家。我带回去,挂在墙上挂钩,筹备第二天中午吃。第二天一闻,坏了,也就没有吃。 宿舍外面也没有洗衣机,所以我在超市买了一个微小的盆子,每周末的时候我会拿出一个下午的工夫,边看电视,边手搓衣服,四季如此。 刚刚去北京的前一年,过的真的还是很艰巨的。然而宿舍的益处是离公司近,所以我基本上也不怎么在宿舍呆着,工作日在公司学习到很晚,周末也去公司学习。 艰辛的环境更能激发人的斗志。 然而我还是简略的装璜了一下简陋的出租屋,买了贴画和绿植,因为我深信房子是租来的,然而生存是本人的。 而且每周洗完衣服后我会用洗衣服的水再拖一下地。我的房间很小,摆上一张 1.5 米的大床之后基本上就没有什么空间了,所以我用不上拖把,一张帕子就够了。 我能够蹲在地上,把房间外面的每一块地砖的边边角角都仔仔细细的擦拭一遍,而后跳到床上去,静静的坐着,开始放空本人。 过后并没感觉有什么艰难,然而和当初的生存再比照一下,真的是天壤之别。当初回想起,才真真正正的感觉:我已经也在北京使劲的生存过,来到的时候回顾满满,风华正茂。 就像我之前写过的:北漂就像在黑屋子里洗衣服,你不晓得洗洁净了没有,只能一遍又一遍地去洗。等到来到北京的那一刻,灯光亮了,你发现,如果你认真洗过了,那件衣服光洁如新。让你当前每次穿这件衣服都会想起那段岁月。 所以你呢,有没有在使劲的生存? 好了,说回文章。 # 大佬指导,纠正错误 前段时间一位大佬指出了我之前文章中的一处谬误: ![](https://p6-juejin.byteimg.com... 文章是这篇文章[《Dubbo 2.7.5在线程模型上的优化》](https://mp.weixin.qq.com/s/tD...。 谬误具体是指上面红框框起来的这句话的形容: ...

September 1, 2020 · 3 min · jiezi

关于dubbo:dubbo路由规则

问题我的项目有分库的需要,测试的时候,不同分支在同时进行,为了防止相互影响,分库分支做了路由规定配置,使得指定服务消费者调用指定服务生产者。 解决办法搜服务名字 1.提供者有多个提供者,比方利用名字1、利用名字2,是同一个利用的集群。2.消费者有多个消费者,比方利用名字1、利用名字2,是同一个利用的集群。 增加 失效已路由就示意曾经失效 点击已路由

August 31, 2020 · 1 min · jiezi

关于dubbo:Dubbo-30-开启下一代云原生微服务

简介: 本文整顿自作者于 2020 年云原生微服务大会上的分享《Dubbo3.0 - 开启下一代云原生微服务》,次要介绍了对于思考 rpc 框架层面,性能演进的方向是什么?以及怎么更好地反对云上的多语言开发的新思考。 作者 | 郭浩(项升)  阿里巴巴经济体 RPC 框架负责人 导读:本文整顿自作者于 2020 年云原生微服务大会上的分享《Dubbo3.0 - 开启下一代云原生微服务》,次要介绍了对于思考 rpc 框架层面,性能演进的方向是什么?以及怎么更好地反对云上的多语言开发的新思考。关注阿里巴巴云原生公众号,后盾回复 【818】 即可获取直播回看地址和大会 PPT 合集。 看到这个题目,大家可能会有几个问题,比方,什么是云原生微服务?Dubbo3.0 是什么?和目前的 Dubbo2.0 有什么区别?用了 Dubbo3.0 会带来哪些业务视角的益处?前面的分享会对这些问题逐个解答。 这次分享分为以下几个环节: Dubbo 的演进历史Dubbo 的开源现状定义 Dubbo3.0 分享 Dubbo 3.0 目前获得的一些成绩思考到有些同学对 Dubbo 可能不太熟悉,在介绍背景之前,我先简略介绍一下 Dubbo 是什么。简略地说,Dubbo 是基于 Java 的 RPC 框架。一个 RPC 框架至多由数据格式、传输协定和连贯治理组成,这三点也是形成外围。Dubbo 可能被广泛应用次要有两个起因: 一方面是较好的插件机制撑持了多种扩大,这些扩大在不同业务场景和基础架构中能别离施展最大劣势;另一方面不同于一般的 RPC 框架,Dubbo 的服务治理性能让其在易用性方面怀才不遇,比方路由规定可能反对灵活多样的运行时动静路由,能够基于此性能实现灰度、ABTest、流量回放等性能。Dubbo 倒退历程简略介绍完 Dubbo,当初让咱们一起回顾一下 Dubbo 的历史。 在 2008 年,Dubbo 作为阿里巴巴外部 SOA 解决方案横空出世。业务的急速倒退带来了强烈的服务化需要,只用了两年的工夫 dubbo 就在外部大面积落地,日均调用量超过了 30 亿。通过落地过程中一直的打磨,Dubbo 无论是在性能上还是在扩展性方面,都成为了过后遥遥领先的 RPC 框架。为了更好地回馈开发用户和其余有服务化需要的公司,在 2011 年 Dubbo 抉择了开源,并公布了 2.0.7 版本作为开源的第一个正式版本。 ...

August 26, 2020 · 3 min · jiezi

关于dubbo:dubbo-ip错误导致-message-can-not-send-because-channel-is-closed

dubbo报错org.apache.dubbo.remoting.RemotingException: message can not send, because channel is closed 认真一看,ip的确不是本机ifconfig查看到的ip。解决方案是ifconfig查看本人本机的内网ip。将dubbo的配置批改为内网ip 其实你去GitHub的dubbo我的项目中,ip谬误的issue有很多,大家很多人都遇到过。那么为什么会有ip乱入的状况呢?以及dubbo是如何抉择机器ip的呢。下篇文章咱们来剖析一下。

August 26, 2020 · 1 min · jiezi

关于dubbo:Dubbo27试用

一、Dubbo介绍 Java开发的同学置信对Dubbo都有理解,Dubbo是阿里开源的RPC/服务治理框架,以下是百度的解释: Dubbo(读音[db])是阿里巴巴公司开源的一个高性能优良的服务框架,使得利用可通过高性能的 RPC 实现服务的输入和输出性能,能够和 [1]  Spring框架无缝集成。Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大外围能力:面向接口的近程办法调用,智能容错和负载平衡,以及服务主动注册和发现。https://baike.baidu.com/item/... 首先Dubbo是一个RPC框架,如果零碎是微服务架构,服务之间能够通过Dubbo来调用,解耦调用者(Consumer)和服务提供者(Provider)的依赖问题,为了对立概念,前面都以Consumer称说服务调用者,以Provider称说服务提供者; 没有RPC框架,可能要在配置文件中硬编码很多服务地址,有了Dubbo之后,Consumer不必关怀有多少服务提供者,打个比方我想调用用户服务,你只有把服务名通知Dubbo,Dubbo会主动寻找相应的Provider,而不必在配置文件中写死,真正解放了运维。 Dubbo具体的性能就不在这里解释了,能够参考官网手册: http://dubbo.apache.org/zh-cn... 二、Dubbo2.7介绍 Dubbo最新版本为2.7.6,2.7当前有大的变动,次要个性有: 1、Tag路由 标签路由通过将某一个或多个服务的提供者划分到同一个分组,束缚流量只在指定分组中流转,从而实现流量隔离的目标,能够作为蓝绿公布、灰度公布等场景的能力根底。 这是1个理论的例子: force: false假如以后tradecenter服务有2台机器,1台是172.21.107.21,另1台是172.21.107.22; 下面将tradecenter这个服务其中1台172.21.107.21,打了标签pre,后续Consumer调用时,只有带了pre的tag,就肯定会调用到这台机;而没带tag的会调用到另1台机172.21.107.22,这样就能够实现灰度公布了。 这个上面再重点讲述。 2、新增元数据中心 这块以前是全在注册核心,之所以独自分进去,也是思考性能、带宽的问题,因为有的配置Consumer基本不必关怀,当集群调用方增多的时候,如果还按以前的形式,将大大将减少网络的耗费。  元数据中心负责存储包含服务动态化配置、服务定义(如办法签名)等数据,默认提供Zookeeper, Redis反对。 3、动静配置核心 次要承当2个性能:     A、内部化配置。启动配置的集中式存储 (简略了解为dubbo.properties的内部化存储)。     B、服务治理。服务治理规定的存储与告诉。 启用动静配置,以Zookeeper为例 <dubbo:config-center address="zookeeper://127.0.0.1:2181"/>理论反对Redis、Zookeeper,还有阿波罗等第三方配置核心;能够看到,这些也是不便运维的操作,以前这些操作可能须要重启利用,有了动静配置核心后只有在后盾配置就能够了。 三、灰度公布 咱们来看下如何通过tag路由做灰度,假如咱们的利用架构是这样的: 在接入层,即用户浏览器能够拜访到的是商城的接口,而后商城会依赖订单核心服务,订单又会依赖商品核心服务,举1个理论的例子,以下单接口为例: 1、用户调用接口下单接口; 2、商城调用订单核心保留订单接口; 3、订单调用商品核心查问接口接口; 以下面的场景来说须要做灰度首先在调用层须要将tag传递过去,通过以下代码传递tag: RpcContext.getContext().setAttachment(TAG_KEY, "pre");如何对利用中无侵入呢,官网倡议通过Filter或SPI的形式实现,具体形式是放在动静配置中,或环境配置中,而后在过滤器初始化的时候读取这个配置,而后每次调用前将tag传递到调用链中。 对于非Java利用,比方PHP,如果通过Hessian协定调用,通过http头传递就能够了,看下Hessian的实现: RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort());即在http头中这样传参数,Hessian Php客户端的实现,github上曾经有了,原仓库地址我曾经不记得了,我在github上曾经clone,并做了些优化,地址: https://github.com/programwit... function getStream($url, $data, $options)即在http头中加上参数 headerdubbo.tag,下面tag内容是写死的,能够依据状况本人读取动静配置或环境配置。 四、Dubbo环境搭建 1、从github下载代码:https://github.com/apache/dubbo 2、切到相应分支,我用的是2.7.4.1的; 3、mvn编译就行了,mvn clean:compile 官网自带了一些样例代码,即demo模块,上面是demo的代码,实现形式有注解、api、xml的形式,我用xml的形式进行测试,其中dubbo-demo-xml-provider-service是我另外加的模块 这是consumer的xml配置,次要是多了 metadata-report和config-center的标签配置: <dubbo:application name="demo-consumer"/>记得在pom文件援用zookeeper的依赖: <dependency>provider的xml配置: <dubbo:application name="demo-provider"/>下面加了hessian协定,是为了不便PHP调用而测试的。 ...

August 15, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的roundRobinLoadBalance

序本文次要钻研一下dubbo-go的roundRobinLoadBalance roundRobinLoadBalancedubbo-go-v1.4.2/cluster/loadbalance/round_robin.go const ( // RoundRobin ... RoundRobin = "roundrobin" // COMPLETE ... COMPLETE = 0 // UPDATING ... UPDATING = 1)var ( methodWeightMap sync.Map // [string]invokers state = int32(COMPLETE) // update lock acquired ? recyclePeriod = 60 * time.Second.Nanoseconds())func init() { extension.SetLoadbalance(RoundRobin, NewRoundRobinLoadBalance)}type roundRobinLoadBalance struct{}// NewRoundRobinLoadBalance ...func NewRoundRobinLoadBalance() cluster.LoadBalance { return &roundRobinLoadBalance{}}roundRobinLoadBalance的NewRoundRobinLoadBalance办法创立了roundRobinLoadBalanceSelectdubbo-go-v1.4.2/cluster/loadbalance/round_robin.go func (lb *roundRobinLoadBalance) Select(invokers []protocol.Invoker, invocation protocol.Invocation) protocol.Invoker { count := len(invokers) if count == 0 { return nil } if count == 1 { return invokers[0] } key := invokers[0].GetUrl().Path + "." + invocation.MethodName() cache, _ := methodWeightMap.LoadOrStore(key, &cachedInvokers{}) cachedInvokers := cache.(*cachedInvokers) var ( clean = false totalWeight = int64(0) maxCurrentWeight = int64(math.MinInt64) now = time.Now() selectedInvoker protocol.Invoker selectedWeightRobin *weightedRoundRobin ) for _, invoker := range invokers { var weight = GetWeight(invoker, invocation) if weight < 0 { weight = 0 } identifier := invoker.GetUrl().Key() loaded, found := cachedInvokers.LoadOrStore(identifier, &weightedRoundRobin{weight: weight}) weightRobin := loaded.(*weightedRoundRobin) if !found { clean = true } if weightRobin.Weight() != weight { weightRobin.setWeight(weight) } currentWeight := weightRobin.increaseCurrent() weightRobin.lastUpdate = &now if currentWeight > maxCurrentWeight { maxCurrentWeight = currentWeight selectedInvoker = invoker selectedWeightRobin = weightRobin } totalWeight += weight } cleanIfRequired(clean, cachedInvokers, &now) if selectedWeightRobin != nil { selectedWeightRobin.Current(totalWeight) return selectedInvoker } // should never happen return invokers[0]}Select办法遍历invokers,通过weightRobin.increaseCurrent()作为currentWeight,若currentWeight大于maxCurrentWeight则更新maxCurrentWeight,设置selectedInvoker为以后invoker,设置selectedWeightRobin为以后weightRobin;之后对于selectedWeightRobin不为nil的执行selectedWeightRobin.Current(totalWeight),返回selectedInvoker小结roundRobinLoadBalance的NewRoundRobinLoadBalance办法创立了roundRobinLoadBalance;其Select办法遍历invokers,通过weightRobin.increaseCurrent()作为currentWeight,若currentWeight大于maxCurrentWeight则更新maxCurrentWeight,设置selectedInvoker为以后invoker,设置selectedWeightRobin为以后weightRobin ...

August 13, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的randomLoadBalance

序本文次要钻研一下dubbo-go的randomLoadBalance randomLoadBalancedubbo-go-v1.4.2/cluster/loadbalance/random.go const ( name = "random")func init() { extension.SetLoadbalance(name, NewRandomLoadBalance)}type randomLoadBalance struct {}// NewRandomLoadBalance ...func NewRandomLoadBalance() cluster.LoadBalance { return &randomLoadBalance{}}randomLoadBalance的NewRandomLoadBalance办法创立randomLoadBalanceSelectdubbo-go-v1.4.2/cluster/loadbalance/random.go func (lb *randomLoadBalance) Select(invokers []protocol.Invoker, invocation protocol.Invocation) protocol.Invoker { var length int if length = len(invokers); length == 1 { return invokers[0] } sameWeight := true weights := make([]int64, length) firstWeight := GetWeight(invokers[0], invocation) totalWeight := firstWeight weights[0] = firstWeight for i := 1; i < length; i++ { weight := GetWeight(invokers[i], invocation) weights[i] = weight totalWeight += weight if sameWeight && weight != firstWeight { sameWeight = false } } if totalWeight > 0 && !sameWeight { // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on totalWeight. offset := rand.Int63n(totalWeight) for i := 0; i < length; i++ { offset -= weights[i] if offset < 0 { return invokers[i] } } } // If all invokers have the same weight value or totalWeight=0, return evenly. return invokers[rand.Intn(length)]}Select办法先判断invokers数量,若只有一个则返回invokers[0];之后遍历invokers计算totalWeight及sameWeight,若totalWeight大于0且sameWeight为false则应用rand.Int63n(totalWeight)随机一个offset,之后遍历weights,用offset挨个去减weights[i],若offset小于0,则返回invokers[i];若都没有选中,则返回invokers[rand.Intn(length)]小结randomLoadBalance的NewRandomLoadBalance办法创立randomLoadBalance;其Select办法应用了带weight的办法,具体就是应用rand.Int63n(totalWeight)随机一个offset,之后遍历weights,用offset挨个去减weights[i],若offset小于0,则返回invokers[i] ...

August 12, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的leastActiveLoadBalance

序本文次要钻研一下dubbo-go的leastActiveLoadBalance leastActiveLoadBalancedubbo-go-v1.4.2/cluster/loadbalance/least_active.go const ( // LeastActive ... LeastActive = "leastactive")func init() { extension.SetLoadbalance(LeastActive, NewLeastActiveLoadBalance)}type leastActiveLoadBalance struct {}// NewLeastActiveLoadBalance ...func NewLeastActiveLoadBalance() cluster.LoadBalance { return &leastActiveLoadBalance{}}leastActiveLoadBalance的NewLeastActiveLoadBalance办法创立leastActiveLoadBalanceSelectdubbo-go-v1.4.2/cluster/loadbalance/least_active.go func (lb *leastActiveLoadBalance) Select(invokers []protocol.Invoker, invocation protocol.Invocation) protocol.Invoker { count := len(invokers) if count == 0 { return nil } if count == 1 { return invokers[0] } var ( leastActive int32 = -1 // The least active value of all invokers totalWeight int64 // The number of invokers having the same least active value (LEAST_ACTIVE) firstWeight int64 // Initial value, used for comparison leastCount int // The number of invokers having the same least active value (LEAST_ACTIVE) leastIndexes = make([]int, count) // The index of invokers having the same least active value (LEAST_ACTIVE) sameWeight = true // Every invoker has the same weight value? ) for i := 0; i < count; i++ { invoker := invokers[i] // Active number active := protocol.GetMethodStatus(invoker.GetUrl(), invocation.MethodName()).GetActive() // current weight (maybe in warmUp) weight := GetWeight(invoker, invocation) // There are smaller active services if leastActive == -1 || active < leastActive { leastActive = active leastIndexes[0] = i leastCount = 1 // next available leastIndex offset totalWeight = weight firstWeight = weight sameWeight = true } else if active == leastActive { leastIndexes[leastCount] = i totalWeight += weight leastCount++ if sameWeight && (i > 0) && weight != firstWeight { sameWeight = false } } } if leastCount == 1 { return invokers[0] } if !sameWeight && totalWeight > 0 { offsetWeight := rand.Int63n(totalWeight) + 1 for i := 0; i < leastCount; i++ { leastIndex := leastIndexes[i] offsetWeight -= GetWeight(invokers[i], invocation) if offsetWeight <= 0 { return invokers[leastIndex] } } } index := leastIndexes[rand.Intn(leastCount)] return invokers[index]}Select办法遍历invokers,挨个通过protocol.GetMethodStatus(invoker.GetUrl(), invocation.MethodName()).GetActive()获取active信息,并通过GetWeight(invoker, invocation)获取weight,而后计算leastCount、totalWeight、sameWeight;对于leastCount为1的返回invokers[0],对于sameWeight为false且totalWeight大于0的,遍历leastIndexes,计算offsetWeight,若offsetWeight小于等于0,则返回invokers[leastIndex],否则通过leastIndexes[rand.Intn(leastCount)]计算index,返回invokers[index]GetWeightdubbo-go-v1.4.2/cluster/loadbalance/util.go ...

August 11, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的ConsistentHashLoadBalance

序本文次要钻研一下dubbo-go的ConsistentHashLoadBalance ConsistentHashLoadBalancedubbo-go-v1.4.2/cluster/loadbalance/consistent_hash.go const ( // ConsistentHash ... ConsistentHash = "consistenthash" // HashNodes ... HashNodes = "hash.nodes" // HashArguments ... HashArguments = "hash.arguments")var ( selectors = make(map[string]*ConsistentHashSelector) re = regexp.MustCompile(constant.COMMA_SPLIT_PATTERN))func init() { extension.SetLoadbalance(ConsistentHash, NewConsistentHashLoadBalance)}// ConsistentHashLoadBalance ...type ConsistentHashLoadBalance struct {}// NewConsistentHashLoadBalance ...func NewConsistentHashLoadBalance() cluster.LoadBalance { return &ConsistentHashLoadBalance{}}ConsistentHashLoadBalance的init办法设置了名为consistenthash的ConsistentHashLoadBalance到extension中Selectdubbo-go-v1.4.2/cluster/loadbalance/consistent_hash.go // Select ...func (lb *ConsistentHashLoadBalance) Select(invokers []protocol.Invoker, invocation protocol.Invocation) protocol.Invoker { methodName := invocation.MethodName() key := invokers[0].GetUrl().ServiceKey() + "." + methodName // hash the invokers bs := make([]byte, 0) for _, invoker := range invokers { b, err := json.Marshal(invoker) if err != nil { return nil } bs = append(bs, b...) } hashCode := crc32.ChecksumIEEE(bs) selector, ok := selectors[key] if !ok || selector.hashCode != hashCode { selectors[key] = newConsistentHashSelector(invokers, methodName, hashCode) selector = selectors[key] } return selector.Select(invocation)}Select办法遍历invokers挨个执行json.Marshal(invoker),将bytes[]增加到bs中,之后通过crc32.ChecksumIEEE(bs)计算hashCode,而后比照selectors[key]的hashCode与计算出来的hashCode是否统一,不统一则通过newConsistentHashSelector从新设置一个,最初执行selector.Select(invocation)ConsistentHashSelectordubbo-go-v1.4.2/cluster/loadbalance/consistent_hash.go ...

August 10, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的ConsistentHashLoadBalance

序本文次要钻研一下dubbo-go的ConsistentHashLoadBalance ConsistentHashLoadBalancedubbo-go-v1.4.2/cluster/loadbalance/consistent_hash.go const ( // ConsistentHash ... ConsistentHash = "consistenthash" // HashNodes ... HashNodes = "hash.nodes" // HashArguments ... HashArguments = "hash.arguments")var ( selectors = make(map[string]*ConsistentHashSelector) re = regexp.MustCompile(constant.COMMA_SPLIT_PATTERN))func init() { extension.SetLoadbalance(ConsistentHash, NewConsistentHashLoadBalance)}// ConsistentHashLoadBalance ...type ConsistentHashLoadBalance struct {}// NewConsistentHashLoadBalance ...func NewConsistentHashLoadBalance() cluster.LoadBalance { return &ConsistentHashLoadBalance{}}ConsistentHashLoadBalance的init办法设置了名为consistenthash的ConsistentHashLoadBalance到extension中Selectdubbo-go-v1.4.2/cluster/loadbalance/consistent_hash.go // Select ...func (lb *ConsistentHashLoadBalance) Select(invokers []protocol.Invoker, invocation protocol.Invocation) protocol.Invoker { methodName := invocation.MethodName() key := invokers[0].GetUrl().ServiceKey() + "." + methodName // hash the invokers bs := make([]byte, 0) for _, invoker := range invokers { b, err := json.Marshal(invoker) if err != nil { return nil } bs = append(bs, b...) } hashCode := crc32.ChecksumIEEE(bs) selector, ok := selectors[key] if !ok || selector.hashCode != hashCode { selectors[key] = newConsistentHashSelector(invokers, methodName, hashCode) selector = selectors[key] } return selector.Select(invocation)}Select办法遍历invokers挨个执行json.Marshal(invoker),将bytes[]增加到bs中,之后通过crc32.ChecksumIEEE(bs)计算hashCode,而后比照selectors[key]的hashCode与计算出来的hashCode是否统一,不统一则通过newConsistentHashSelector从新设置一个,最初执行selector.Select(invocation)ConsistentHashSelectordubbo-go-v1.4.2/cluster/loadbalance/consistent_hash.go ...

August 10, 2020 · 2 min · jiezi

关于dubbo:Dubbo协议解析与OPPO自研ESA-RPC框架实践

本文来自OPPO互联网根底技术团队,转载请注名作者。同时欢送关注咱们的公众号:OPPO_tech,与你分享OPPO前沿互联网技术及流动。1. 背景Dubbo是一款高性能、轻量级的开源Java RPC框架,诞生于2012年,2015年进行研发,起初重启并公布了2.7及间断多个版本。Dubbo自开源以来,许多大公司都以此为微服务架构基石,甚至在官网进行保护的几年中,热度仍然不减。 但最近几年云原生技术开始成为支流,与Dubbo框架的外围设计理念有不相容之处,再加上公司平安治理的需要,OPPO互联网技术团队开发了面向云原生、 Mesh敌对的ESA RPC框架。 2.Dubbo协定解析协定是两个网络实体进行通信的根底,数据在网络上从一个实体传输到另一个实体,以字节流的模式传递到对端。Dubbo协定由服务提供者与消费者双端约定,须要确定的是一次有意义的传输内容在读到何时完结,因为一个一个byte传输过去,须要有一个完结。而且数据在网络上的传输,存在粘包和半包的状况,可能应答这个问题的方法就是协定可能精确的辨认,当粘包产生时不会多读,当半包产生时会持续读取。 2.1 Dubbo Header内容Dubbo header的长度总共16字节,128位,如下图所示: Magic(16 bits) : 协定魔数,标识Dubbo 数据包。Req/Res(1 bit) : 标识申请或者相应。申请:1,相应:0。Two Way(1 bit) : 仅在 Req/Res 为1(申请)时才有用,标记是否冀望从服务器返回值。如果须要来自服务器的返回值,则设置为1。Event(1 bit) : 标识是否是事件音讯,例如,心跳事件。如果这是一个事件,则设置为1。SerializationId(5 bits) : 序列化id。Status(8 bits) : 仅在 Req/Res 为0(响应)时有用,用于标识响应的状态。RequstId(64 bits) : 标识惟一申请。类型为long。Data length(32 bits) : 序列化后的内容长度(变长局部,即不蕴含header),按字节计数。通过payload参数指定,默认为8M。2.2 Dubbo body内容Dubbo 数据包的body 局部内容,分为申请包与响应包。 如果是申请包,则蕴含的局部有: dubbo协定版本号(2.0.2);接口名;接口版本号;办法名;办法参数类型;办法参数;附件(Attachment): 接口分组(group);接口版本号(version);接口名;自定义附件参数;如果是响应包,则蕴含的内容有: 返回值类型(byte): 返回空值(2);失常返回值(1);异样(0);返回值;通过对dubbo协定的解析,咱们能够晓得,dubbo协定是一个Header定长的变长协定。这也在咱们ESA RPC实际过程中提供了一些思路。 2.3 Dubbo协定优缺点2.3.1 长处Dubbo协定的设计十分紧凑、简略,尽可能的缩小传输包大小,能用一个bit示意的字段,不会用一个byte。 2.3.2 有余申请body中某些字段反复传递(如接口名,接口版本号),即body内容与附件attachment 中存在反复字段,增大传输数据包大小;对于ServiceMesh 场景很不敌对。在ServiceMesh 场景中,会将原sdk中的大部分性能迁徙至SideCar 中实现,这里以服务发现为例。Dubbo 中的服务发现,是通过接口名(interfaceName)、接口分组(group)、接口版本号(version)三者定位一个惟一服务,也是服务发现的要害因素,然而咱们从dubbo body内容可知,必须要将残缺的数据包全副解析(attachment位于body末),能力获取到这三个因素,这是齐全没必要的。没有预留字段,扩展性有余。3. Dubbo的现状Dubbo自开源以来,在业内造成了微小的影响,许多公司甚至大厂都以此为微服务架构基石,甚至在Dubbo官网进行保护的几年中,热度仍然不减,足以证实其自身的优良。 ...

August 10, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的registryAwareCluster

序本文次要钻研一下dubbo-go的registryAwareCluster registryAwareClusterdubbo-go-v1.4.2/cluster/cluster_impl/registry_aware_cluster.go type registryAwareCluster struct{}func init() { extension.SetCluster("registryAware", NewRegistryAwareCluster)}// NewRegistryAwareCluster ...func NewRegistryAwareCluster() cluster.Cluster { return &registryAwareCluster{}}func (cluster *registryAwareCluster) Join(directory cluster.Directory) protocol.Invoker { return newRegistryAwareClusterInvoker(directory)}registryAwareCluster的Join办法执行newRegistryAwareClusterInvoker(directory)newRegistryAwareClusterInvokerdubbo-go-v1.4.2/cluster/cluster_impl/registry_aware_cluster_invoker.go type registryAwareClusterInvoker struct { baseClusterInvoker}func newRegistryAwareClusterInvoker(directory cluster.Directory) protocol.Invoker { return &registryAwareClusterInvoker{ baseClusterInvoker: newBaseClusterInvoker(directory), }}newRegistryAwareClusterInvoker办法创立registryAwareClusterInvokerInvokedubbo-go-v1.4.2/cluster/cluster_impl/registry_aware_cluster_invoker.go func (invoker *registryAwareClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result { invokers := invoker.directory.List(invocation) //First, pick the invoker (XXXClusterInvoker) that comes from the local registry, distinguish by a 'default' key. for _, invoker := range invokers { if invoker.IsAvailable() && invoker.GetUrl().GetParam(constant.REGISTRY_DEFAULT_KEY, "false") == "true" { return invoker.Invoke(ctx, invocation) } } //If none of the invokers has a local signal, pick the first one available. for _, invoker := range invokers { if invoker.IsAvailable() { return invoker.Invoke(ctx, invocation) } } return nil}Invoke办法先通过invoker.directory.List(invocation)获取invokers,而后遍历invokers判断是否有来自local registry的invoker, 如果有则执行invoker.Invoke(ctx, invocation);否则再次遍历invokers,找到第一个available的执行invoker.Invoke(ctx, invocation)小结registryAwareCluster的Join办法执行newRegistryAwareClusterInvoker(directory);registryAwareClusterInvoker的Invoke办法先通过invoker.directory.List(invocation)获取invokers,而后遍历invokers判断是否有来自local registry的invoker, 如果有则执行invoker.Invoke(ctx, invocation),没有local的则遍历invokers,找到第一个available的执行invoker.Invoke(ctx, invocation) ...

August 9, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的registryAwareCluster

序本文次要钻研一下dubbo-go的registryAwareCluster registryAwareClusterdubbo-go-v1.4.2/cluster/cluster_impl/registry_aware_cluster.go type registryAwareCluster struct{}func init() { extension.SetCluster("registryAware", NewRegistryAwareCluster)}// NewRegistryAwareCluster ...func NewRegistryAwareCluster() cluster.Cluster { return &registryAwareCluster{}}func (cluster *registryAwareCluster) Join(directory cluster.Directory) protocol.Invoker { return newRegistryAwareClusterInvoker(directory)}registryAwareCluster的Join办法执行newRegistryAwareClusterInvoker(directory)newRegistryAwareClusterInvokerdubbo-go-v1.4.2/cluster/cluster_impl/registry_aware_cluster_invoker.go type registryAwareClusterInvoker struct { baseClusterInvoker}func newRegistryAwareClusterInvoker(directory cluster.Directory) protocol.Invoker { return &registryAwareClusterInvoker{ baseClusterInvoker: newBaseClusterInvoker(directory), }}newRegistryAwareClusterInvoker办法创立registryAwareClusterInvokerInvokedubbo-go-v1.4.2/cluster/cluster_impl/registry_aware_cluster_invoker.go func (invoker *registryAwareClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result { invokers := invoker.directory.List(invocation) //First, pick the invoker (XXXClusterInvoker) that comes from the local registry, distinguish by a 'default' key. for _, invoker := range invokers { if invoker.IsAvailable() && invoker.GetUrl().GetParam(constant.REGISTRY_DEFAULT_KEY, "false") == "true" { return invoker.Invoke(ctx, invocation) } } //If none of the invokers has a local signal, pick the first one available. for _, invoker := range invokers { if invoker.IsAvailable() { return invoker.Invoke(ctx, invocation) } } return nil}Invoke办法先通过invoker.directory.List(invocation)获取invokers,而后遍历invokers判断是否有来自local registry的invoker, 如果有则执行invoker.Invoke(ctx, invocation);否则再次遍历invokers,找到第一个available的执行invoker.Invoke(ctx, invocation)小结registryAwareCluster的Join办法执行newRegistryAwareClusterInvoker(directory);registryAwareClusterInvoker的Invoke办法先通过invoker.directory.List(invocation)获取invokers,而后遍历invokers判断是否有来自local registry的invoker, 如果有则执行invoker.Invoke(ctx, invocation),没有local的则遍历invokers,找到第一个available的执行invoker.Invoke(ctx, invocation) ...

August 9, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的failsafeCluster

序本文次要钻研一下dubbo-go的failsafeCluster failsafeClusterdubbo-go-v1.4.2/cluster/cluster_impl/failsafe_cluster.go type failsafeCluster struct{}const failsafe = "failsafe"func init() { extension.SetCluster(failsafe, NewFailsafeCluster)}// NewFailsafeCluster ...func NewFailsafeCluster() cluster.Cluster { return &failsafeCluster{}}func (cluster *failsafeCluster) Join(directory cluster.Directory) protocol.Invoker { return newFailsafeClusterInvoker(directory)}failsafeCluster的join办法执行newFailsafeClusterInvokernewFailsafeClusterInvokerdubbo-go-v1.4.2/cluster/cluster_impl/failsafe_cluster_invoker.go type failsafeClusterInvoker struct { baseClusterInvoker}func newFailsafeClusterInvoker(directory cluster.Directory) protocol.Invoker { return &failsafeClusterInvoker{ baseClusterInvoker: newBaseClusterInvoker(directory), }}newFailsafeClusterInvoker办法创立failsafeClusterInvokerInvokedubbo-go-v1.4.2/cluster/cluster_impl/failsafe_cluster_invoker.go func (invoker *failsafeClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result { invokers := invoker.directory.List(invocation) err := invoker.checkInvokers(invokers, invocation) if err != nil { return &protocol.RPCResult{} } url := invokers[0].GetUrl() methodName := invocation.MethodName() //Get the service loadbalance config lb := url.GetParam(constant.LOADBALANCE_KEY, constant.DEFAULT_LOADBALANCE) //Get the service method loadbalance config if have if v := url.GetMethodParam(methodName, constant.LOADBALANCE_KEY, ""); v != "" { lb = v } loadbalance := extension.GetLoadbalance(lb) invoked := make([]protocol.Invoker, 0) var result protocol.Result ivk := invoker.doSelect(loadbalance, invocation, invokers, invoked) //DO INVOKE result = ivk.Invoke(ctx, invocation) if result.Error() != nil { // ignore logger.Errorf("Failsafe ignore exception: %v.\n", result.Error().Error()) return &protocol.RPCResult{} } return result}Invoke办法先通过invoker.directory.List(invocation)获取invokers,之后通过invoker.doSelect(loadbalance, invocation, invokers, invoked)抉择ivk,最初执行ivk.Invoke(ctx, invocation),如果有error,则打印error,返回空后果GetLoadbalancedubbo-go-v1.4.2/common/extension/loadbalance.go ...

August 8, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的failsafeCluster

序本文次要钻研一下dubbo-go的failsafeCluster failsafeClusterdubbo-go-v1.4.2/cluster/cluster_impl/failsafe_cluster.go type failsafeCluster struct{}const failsafe = "failsafe"func init() { extension.SetCluster(failsafe, NewFailsafeCluster)}// NewFailsafeCluster ...func NewFailsafeCluster() cluster.Cluster { return &failsafeCluster{}}func (cluster *failsafeCluster) Join(directory cluster.Directory) protocol.Invoker { return newFailsafeClusterInvoker(directory)}failsafeCluster的join办法执行newFailsafeClusterInvokernewFailsafeClusterInvokerdubbo-go-v1.4.2/cluster/cluster_impl/failsafe_cluster_invoker.go type failsafeClusterInvoker struct { baseClusterInvoker}func newFailsafeClusterInvoker(directory cluster.Directory) protocol.Invoker { return &failsafeClusterInvoker{ baseClusterInvoker: newBaseClusterInvoker(directory), }}newFailsafeClusterInvoker办法创立failsafeClusterInvokerInvokedubbo-go-v1.4.2/cluster/cluster_impl/failsafe_cluster_invoker.go func (invoker *failsafeClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result { invokers := invoker.directory.List(invocation) err := invoker.checkInvokers(invokers, invocation) if err != nil { return &protocol.RPCResult{} } url := invokers[0].GetUrl() methodName := invocation.MethodName() //Get the service loadbalance config lb := url.GetParam(constant.LOADBALANCE_KEY, constant.DEFAULT_LOADBALANCE) //Get the service method loadbalance config if have if v := url.GetMethodParam(methodName, constant.LOADBALANCE_KEY, ""); v != "" { lb = v } loadbalance := extension.GetLoadbalance(lb) invoked := make([]protocol.Invoker, 0) var result protocol.Result ivk := invoker.doSelect(loadbalance, invocation, invokers, invoked) //DO INVOKE result = ivk.Invoke(ctx, invocation) if result.Error() != nil { // ignore logger.Errorf("Failsafe ignore exception: %v.\n", result.Error().Error()) return &protocol.RPCResult{} } return result}Invoke办法先通过invoker.directory.List(invocation)获取invokers,之后通过invoker.doSelect(loadbalance, invocation, invokers, invoked)抉择ivk,最初执行ivk.Invoke(ctx, invocation),如果有error,则打印error,返回空后果GetLoadbalancedubbo-go-v1.4.2/common/extension/loadbalance.go ...

August 8, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的forkingCluster

序本文次要钻研一下dubbo-go的forkingCluster forkingClusterdubbo-go-v1.4.2/cluster/cluster_impl/forking_cluster.go type forkingCluster struct{}const forking = "forking"func init() { extension.SetCluster(forking, NewForkingCluster)}// NewForkingCluster ...func NewForkingCluster() cluster.Cluster { return &forkingCluster{}}func (cluster *forkingCluster) Join(directory cluster.Directory) protocol.Invoker { return newForkingClusterInvoker(directory)}forkingCluster的Join办法执行newForkingClusterInvokernewForkingClusterInvokerdubbo-go-v1.4.2/cluster/cluster_impl/forking_cluster_invoker.go type forkingClusterInvoker struct { baseClusterInvoker}func newForkingClusterInvoker(directory cluster.Directory) protocol.Invoker { return &forkingClusterInvoker{ baseClusterInvoker: newBaseClusterInvoker(directory), }}newForkingClusterInvoker创立了forkingClusterInvokerInvokedubbo-go-v1.4.2/cluster/cluster_impl/forking_cluster_invoker.go // Invoke ...func (invoker *forkingClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result { err := invoker.checkWhetherDestroyed() if err != nil { return &protocol.RPCResult{Err: err} } invokers := invoker.directory.List(invocation) err = invoker.checkInvokers(invokers, invocation) if err != nil { return &protocol.RPCResult{Err: err} } var selected []protocol.Invoker forks := int(invoker.GetUrl().GetParamInt(constant.FORKS_KEY, constant.DEFAULT_FORKS)) timeouts := invoker.GetUrl().GetParamInt(constant.TIMEOUT_KEY, constant.DEFAULT_TIMEOUT) if forks < 0 || forks > len(invokers) { selected = invokers } else { selected = make([]protocol.Invoker, 0) loadbalance := getLoadBalance(invokers[0], invocation) for i := 0; i < forks; i++ { ivk := invoker.doSelect(loadbalance, invocation, invokers, selected) if ivk != nil { selected = append(selected, ivk) } } } resultQ := queue.New(1) for _, ivk := range selected { go func(k protocol.Invoker) { result := k.Invoke(ctx, invocation) err := resultQ.Put(result) if err != nil { logger.Errorf("resultQ put failed with exception: %v.\n", err) } }(ivk) } rsps, err := resultQ.Poll(1, time.Millisecond*time.Duration(timeouts)) if err != nil { return &protocol.RPCResult{ Err: fmt.Errorf("failed to forking invoke provider %v, "+ "but no luck to perform the invocation. Last error is: %v", selected, err), } } if len(rsps) == 0 { return &protocol.RPCResult{Err: fmt.Errorf("failed to forking invoke provider %v, but no resp", selected)} } result, ok := rsps[0].(protocol.Result) if !ok { return &protocol.RPCResult{Err: fmt.Errorf("failed to forking invoke provider %v, but not legal resp", selected)} } return result}Invoke办法先通过invoker.directory.List(invocation)获取invokers,之后从invoker.GetUrl()获取forks及timeouts参数,而后循环forks次通过invoker.doSelect(loadbalance, invocation, invokers, selected)选出selected的invokers;之后遍历selected异步执行其Invoke办法,并将后果放到resultQ中;最初通过resultQ.Poll(1, time.Millisecond*time.Duration(timeouts))拉取最先返回的后果返回小结forkingCluster的Join办法执行newForkingClusterInvoker;其Invoke办法循环forks次通过invoker.doSelect(loadbalance, invocation, invokers, selected)选出selected的invokers;之后遍历selected异步执行其Invoke办法,并将后果放到resultQ中;最初通过resultQ.Poll(1, time.Millisecond*time.Duration(timeouts))拉取最先返回的后果返回 ...

August 7, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的forkingCluster

序本文次要钻研一下dubbo-go的forkingCluster forkingClusterdubbo-go-v1.4.2/cluster/cluster_impl/forking_cluster.go type forkingCluster struct{}const forking = "forking"func init() { extension.SetCluster(forking, NewForkingCluster)}// NewForkingCluster ...func NewForkingCluster() cluster.Cluster { return &forkingCluster{}}func (cluster *forkingCluster) Join(directory cluster.Directory) protocol.Invoker { return newForkingClusterInvoker(directory)}forkingCluster的Join办法执行newForkingClusterInvokernewForkingClusterInvokerdubbo-go-v1.4.2/cluster/cluster_impl/forking_cluster_invoker.go type forkingClusterInvoker struct { baseClusterInvoker}func newForkingClusterInvoker(directory cluster.Directory) protocol.Invoker { return &forkingClusterInvoker{ baseClusterInvoker: newBaseClusterInvoker(directory), }}newForkingClusterInvoker创立了forkingClusterInvokerInvokedubbo-go-v1.4.2/cluster/cluster_impl/forking_cluster_invoker.go // Invoke ...func (invoker *forkingClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result { err := invoker.checkWhetherDestroyed() if err != nil { return &protocol.RPCResult{Err: err} } invokers := invoker.directory.List(invocation) err = invoker.checkInvokers(invokers, invocation) if err != nil { return &protocol.RPCResult{Err: err} } var selected []protocol.Invoker forks := int(invoker.GetUrl().GetParamInt(constant.FORKS_KEY, constant.DEFAULT_FORKS)) timeouts := invoker.GetUrl().GetParamInt(constant.TIMEOUT_KEY, constant.DEFAULT_TIMEOUT) if forks < 0 || forks > len(invokers) { selected = invokers } else { selected = make([]protocol.Invoker, 0) loadbalance := getLoadBalance(invokers[0], invocation) for i := 0; i < forks; i++ { ivk := invoker.doSelect(loadbalance, invocation, invokers, selected) if ivk != nil { selected = append(selected, ivk) } } } resultQ := queue.New(1) for _, ivk := range selected { go func(k protocol.Invoker) { result := k.Invoke(ctx, invocation) err := resultQ.Put(result) if err != nil { logger.Errorf("resultQ put failed with exception: %v.\n", err) } }(ivk) } rsps, err := resultQ.Poll(1, time.Millisecond*time.Duration(timeouts)) if err != nil { return &protocol.RPCResult{ Err: fmt.Errorf("failed to forking invoke provider %v, "+ "but no luck to perform the invocation. Last error is: %v", selected, err), } } if len(rsps) == 0 { return &protocol.RPCResult{Err: fmt.Errorf("failed to forking invoke provider %v, but no resp", selected)} } result, ok := rsps[0].(protocol.Result) if !ok { return &protocol.RPCResult{Err: fmt.Errorf("failed to forking invoke provider %v, but not legal resp", selected)} } return result}Invoke办法先通过invoker.directory.List(invocation)获取invokers,之后从invoker.GetUrl()获取forks及timeouts参数,而后循环forks次通过invoker.doSelect(loadbalance, invocation, invokers, selected)选出selected的invokers;之后遍历selected异步执行其Invoke办法,并将后果放到resultQ中;最初通过resultQ.Poll(1, time.Millisecond*time.Duration(timeouts))拉取最先返回的后果返回小结forkingCluster的Join办法执行newForkingClusterInvoker;其Invoke办法循环forks次通过invoker.doSelect(loadbalance, invocation, invokers, selected)选出selected的invokers;之后遍历selected异步执行其Invoke办法,并将后果放到resultQ中;最初通过resultQ.Poll(1, time.Millisecond*time.Duration(timeouts))拉取最先返回的后果返回 ...

August 7, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的failfastCluster

序本文次要钻研一下dubbo-go的failfastCluster failfastClusterdubbo-go-v1.4.2/cluster/cluster_impl/failfast_cluster.go type failfastCluster struct{}const failfast = "failfast"func init() { extension.SetCluster(failfast, NewFailFastCluster)}// NewFailFastCluster ...func NewFailFastCluster() cluster.Cluster { return &failfastCluster{}}func (cluster *failfastCluster) Join(directory cluster.Directory) protocol.Invoker { return newFailFastClusterInvoker(directory)}failfastCluster的Join办法执行newFailFastClusterInvoker(directory)newFailFastClusterInvokerdubbo-go-v1.4.2/cluster/cluster_impl/failfast_cluster_invoker.go type failfastClusterInvoker struct { baseClusterInvoker}func newFailFastClusterInvoker(directory cluster.Directory) protocol.Invoker { return &failfastClusterInvoker{ baseClusterInvoker: newBaseClusterInvoker(directory), }}newFailFastClusterInvoker办法创立了failfastClusterInvokerInvokedubbo-go-v1.4.2/cluster/cluster_impl/failfast_cluster_invoker.go func (invoker *failfastClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result { invokers := invoker.directory.List(invocation) err := invoker.checkInvokers(invokers, invocation) if err != nil { return &protocol.RPCResult{Err: err} } loadbalance := getLoadBalance(invokers[0], invocation) err = invoker.checkWhetherDestroyed() if err != nil { return &protocol.RPCResult{Err: err} } ivk := invoker.doSelect(loadbalance, invocation, invokers, nil) return ivk.Invoke(ctx, invocation)}Invoke办法先通过invoker.directory.List(invocation)获取invokers,之后通过getLoadBalance(invokers[0], invocation)获取loadbalance,再通过invoker.doSelect(loadbalance, invocation, invokers, nil)抉择ivk,最初执行ivk.Invoke(ctx, invocation)getLoadBalancedubbo-go-v1.4.2/cluster/cluster_impl/base_cluster_invoker.go ...

August 6, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的failbackCluster

序本文次要钻研一下dubbo-go的failbackCluster failbackClusterdubbo-go-v1.4.2/cluster/cluster_impl/failback_cluster.go type failbackCluster struct{}const failback = "failback"func init() { extension.SetCluster(failback, NewFailbackCluster)}// NewFailbackCluster ...func NewFailbackCluster() cluster.Cluster { return &failbackCluster{}}func (cluster *failbackCluster) Join(directory cluster.Directory) protocol.Invoker { return newFailbackClusterInvoker(directory)}failbackCluster的join办法执行newFailbackClusterInvokernewFailbackClusterInvokerdubbo-go-v1.4.2/cluster/cluster_impl/failback_cluster_invoker.go type failbackClusterInvoker struct { baseClusterInvoker once sync.Once ticker *time.Ticker maxRetries int64 failbackTasks int64 taskList *queue.Queue}func newFailbackClusterInvoker(directory cluster.Directory) protocol.Invoker { invoker := &failbackClusterInvoker{ baseClusterInvoker: newBaseClusterInvoker(directory), } retriesConfig := invoker.GetUrl().GetParam(constant.RETRIES_KEY, constant.DEFAULT_FAILBACK_TIMES) retries, err := strconv.Atoi(retriesConfig) if err != nil || retries < 0 { logger.Error("Your retries config is invalid,pls do a check. And will use the default fail back times configuration instead.") retries = constant.DEFAULT_FAILBACK_TIMES_INT } failbackTasksConfig := invoker.GetUrl().GetParamInt(constant.FAIL_BACK_TASKS_KEY, constant.DEFAULT_FAILBACK_TASKS) if failbackTasksConfig <= 0 { failbackTasksConfig = constant.DEFAULT_FAILBACK_TASKS } invoker.maxRetries = int64(retries) invoker.failbackTasks = failbackTasksConfig return invoker}newFailbackClusterInvoker办法创立failbackClusterInvoker,并设置其maxRetries、failbackTasks属性Invokedubbo-go-v1.4.2/cluster/cluster_impl/failback_cluster_invoker.go ...

August 5, 2020 · 3 min · jiezi

关于dubbo:聊聊dubbogo的failbackCluster

序本文次要钻研一下dubbo-go的failbackCluster failbackClusterdubbo-go-v1.4.2/cluster/cluster_impl/failback_cluster.go type failbackCluster struct{}const failback = "failback"func init() { extension.SetCluster(failback, NewFailbackCluster)}// NewFailbackCluster ...func NewFailbackCluster() cluster.Cluster { return &failbackCluster{}}func (cluster *failbackCluster) Join(directory cluster.Directory) protocol.Invoker { return newFailbackClusterInvoker(directory)}failbackCluster的join办法执行newFailbackClusterInvokernewFailbackClusterInvokerdubbo-go-v1.4.2/cluster/cluster_impl/failback_cluster_invoker.go type failbackClusterInvoker struct { baseClusterInvoker once sync.Once ticker *time.Ticker maxRetries int64 failbackTasks int64 taskList *queue.Queue}func newFailbackClusterInvoker(directory cluster.Directory) protocol.Invoker { invoker := &failbackClusterInvoker{ baseClusterInvoker: newBaseClusterInvoker(directory), } retriesConfig := invoker.GetUrl().GetParam(constant.RETRIES_KEY, constant.DEFAULT_FAILBACK_TIMES) retries, err := strconv.Atoi(retriesConfig) if err != nil || retries < 0 { logger.Error("Your retries config is invalid,pls do a check. And will use the default fail back times configuration instead.") retries = constant.DEFAULT_FAILBACK_TIMES_INT } failbackTasksConfig := invoker.GetUrl().GetParamInt(constant.FAIL_BACK_TASKS_KEY, constant.DEFAULT_FAILBACK_TASKS) if failbackTasksConfig <= 0 { failbackTasksConfig = constant.DEFAULT_FAILBACK_TASKS } invoker.maxRetries = int64(retries) invoker.failbackTasks = failbackTasksConfig return invoker}newFailbackClusterInvoker办法创立failbackClusterInvoker,并设置其maxRetries、failbackTasks属性Invokedubbo-go-v1.4.2/cluster/cluster_impl/failback_cluster_invoker.go ...

August 5, 2020 · 3 min · jiezi

关于dubbo:聊聊dubbogo的broadcastCluster

序本文次要钻研一下dubbo-go的broadcastCluster broadcastClusterdubbo-go-v1.4.2/cluster/cluster_impl/broadcast_cluster.go type broadcastCluster struct{}const broadcast = "broadcast"func init() { extension.SetCluster(broadcast, NewBroadcastCluster)}// NewBroadcastCluster ...func NewBroadcastCluster() cluster.Cluster { return &broadcastCluster{}}func (cluster *broadcastCluster) Join(directory cluster.Directory) protocol.Invoker { return newBroadcastClusterInvoker(directory)}broadcastCluster的join办法执行newBroadcastClusterInvokernewBroadcastClusterInvokerdubbo-go-v1.4.2/cluster/cluster_impl/broadcast_cluster_invoker.go type broadcastClusterInvoker struct { baseClusterInvoker}func newBroadcastClusterInvoker(directory cluster.Directory) protocol.Invoker { return &broadcastClusterInvoker{ baseClusterInvoker: newBaseClusterInvoker(directory), }}newBroadcastClusterInvoker办法实例化broadcastClusterInvokerInvokedubbo-go-v1.4.2/cluster/cluster_impl/broadcast_cluster_invoker.go func (invoker *broadcastClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result { invokers := invoker.directory.List(invocation) err := invoker.checkInvokers(invokers, invocation) if err != nil { return &protocol.RPCResult{Err: err} } err = invoker.checkWhetherDestroyed() if err != nil { return &protocol.RPCResult{Err: err} } var result protocol.Result for _, ivk := range invokers { result = ivk.Invoke(ctx, invocation) if result.Error() != nil { logger.Warnf("broadcast invoker invoke err: %v when use invoker: %v\n", result.Error(), ivk) err = result.Error() } } if err != nil { return &protocol.RPCResult{Err: err} } return result}Invoke办法首先通过invoker.directory.List(invocation)获取invokers,之后遍历invokers,挨个执行result = ivk.Invoke(ctx, invocation),如果最初err不为nil,则返回err,否则返回最初的result小结broadcastCluster的join办法执行newBroadcastClusterInvoker;其Invoke办法首先通过invoker.directory.List(invocation)获取invokers,之后遍历invokers,挨个执行result = ivk.Invoke(ctx, invocation),如果最初err不为nil,则返回err,否则返回最初的result ...

August 4, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的availableCluster

序本文次要钻研一下dubbo-go的availableCluster NewAvailableClusterdubbo-go-v1.4.2/cluster/cluster_impl/available_cluster.go type availableCluster struct{}const available = "available"func init() { extension.SetCluster(available, NewAvailableCluster)}// NewAvailableCluster ...func NewAvailableCluster() cluster.Cluster { return &availableCluster{}}NewAvailableCluster办法实例化availableClusterJoindubbo-go-v1.4.2/cluster/cluster_impl/available_cluster.go func (cluser *availableCluster) Join(directory cluster.Directory) protocol.Invoker { return NewAvailableClusterInvoker(directory)}Join办法执行NewAvailableClusterInvokerNewAvailableClusterInvokerdubbo-go-v1.4.2/cluster/cluster_impl/available_cluster_invoker.go type availableClusterInvoker struct { baseClusterInvoker}// NewAvailableClusterInvoker ...func NewAvailableClusterInvoker(directory cluster.Directory) protocol.Invoker { return &availableClusterInvoker{ baseClusterInvoker: newBaseClusterInvoker(directory), }}NewAvailableClusterInvoker办法实例化availableClusterInvokerInvokedubbo-go-v1.4.2/cluster/cluster_impl/available_cluster_invoker.go func (invoker *availableClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result { invokers := invoker.directory.List(invocation) err := invoker.checkInvokers(invokers, invocation) if err != nil { return &protocol.RPCResult{Err: err} } err = invoker.checkWhetherDestroyed() if err != nil { return &protocol.RPCResult{Err: err} } for _, ivk := range invokers { if ivk.IsAvailable() { return ivk.Invoke(ctx, invocation) } } return &protocol.RPCResult{Err: errors.New(fmt.Sprintf("no provider available in %v", invokers))}}Invoke办法先通过invoker.directory.List(invocation)获取invokers,之后遍历invokers,对于ivk.IsAvailable()为true的执行ivk.Invoke(ctx, invocation)小结availableCluster的Join办法执行NewAvailableClusterInvoker,而availableClusterInvoker的Invoke办法先通过invoker.directory.List(invocation)获取invokers,之后遍历invokers,对于ivk.IsAvailable()为true的执行ivk.Invoke(ctx, invocation) ...

August 3, 2020 · 1 min · jiezi

关于dubbo:Dubbo基础

1.架构dubbo架构波及的角色: 节点 角色阐明 Provider 裸露服务的服务提供方 Consumer 调用近程服务的服务生产方 Registry 服务注册与发现的注册核心 Monitor 统计服务的调用次数和调用工夫的监控核心 Container 服务运行容器 2.配置加载流程Dubbo配置形式有XML配置、注解配置、API配置。反对多层级配置,依照优先级配置笼罩。 3.dubbo相干重要点3.1 负载平衡负载平衡策略有: 按权随机按权轮询起码沉闷调用数:沉闷数指调用前后技术差始终性hash:缺省,对第一个参数做hash,缺省用160分虚构节点3.2 线程模型3.3 服务分组一个接口有多种实现时,应用group辨别。 3.4 接口测试留神点(1) 直连提供者 在开发测试环境下,可能存在绕过注册核心的状况下,测试某个服务提供者,这时须要点对点直连。能够有如下形式: xml 配置:<dubbo:reference id="xxxService" interface="com.alibaba.xxx.XxxService"url="dubbo://localhost:8080" /> 指定-D参数:java -Dcom.alibaba.xxx.XxxService=dubbo://localhost:8080文件映射:用 -Ddubbo.resolve.file 指定映射文件门路(2) 只订阅 不便开发测试,可能存在共用注册核心的状况,防止正开发的服务提供者影响服务消费者,能够让服务提供这只订阅服务(开发的服务可能依赖其余的服务),通过直连形式测试。 3.5 异步调用v2.7.0起,dubbo的异步编程接口以CompletableFuture为根底,基于NIO的非阻塞实现,不须要启动多线程,绝对多线程开销小。 3.6 多协定dubbo反对在不同服务上反对多个协定或者同一个服务上同时反对多个协定。 反对的协定有dubbo、rmi、hessian、http、webservice、thrift、memcached、redis、rest 3.7 本地存根近程服务调用后,客户端个别是接口,实现在服务端,提供方想在客户端提供局部执行逻辑如ThreadLocal缓存,提前验证参数,嗲用失败后伪造容错数据,须要在api带上stub。 3.8 并发管制能够限度每个办法服务端并发执行的个数,设置executes属性 3.9 连贯管制限度服务端的连贯个数,设置accepts属性值 3.10 提早连贯提早连贯用户缩小长连接数。有调用的时候才创立,设置lazy属性。 3.11 粘滞连贯个别用户有状态的服务,使客户端总是向调用同一个服务提供者,设置sticky属性。 3.12 令牌验证令牌验证注册核心受权权限,可避免消费者绕过注册核心拜访提供者,设置token属性。 3.13 集群容错在集群调用失败时,Dubbo 提供了多种容错机制,缺省为 failover 重试。容错机制有: failover: 失败主动切换,重试其余服务器,通过设置retries属性(不蕴含第一次)failfast: 疾速失败,只发动一次调用。failsafe:失败平安,出现异常间接疏忽。failback:失败主动复原,后盾记录失败申请,定时重发。forking:并行调用多服务器,一个胜利即返回,通过设置forks属性。4.dubbo我的项目搭建4.1 应用idea创立一个spring boot kotlin我的项目(1) 点击菜单File->new Project->Spring Initializr->next(2) 抉择kotlin依照提醒流程创立集体我的项目(3) 依照下面流程创立一个父我的项目,保留pom文件、.idea 文件,删除无关文件,而后new module 增加模块以上步骤就创立一个基于dubbo的spring boot kotlin多模块我的项目。 ...

August 2, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的DefaultHealthChecker

序本文次要钻研一下dubbo-go的DefaultHealthChecker DefaultHealthCheckerdubbo-go-v1.4.2/cluster/router/healthcheck/default_health_check.go func init() { extension.SethealthChecker(constant.DEFAULT_HEALTH_CHECKER, NewDefaultHealthChecker)}// DefaultHealthChecker is the default implementation of HealthChecker, which determines the health status of// the invoker based on the number of successive bad request and the current active request.type DefaultHealthChecker struct { // the limit of outstanding request outStandingRequestConutLimit int32 // the threshold of successive-failure-request requestSuccessiveFailureThreshold int32 // value of circuit-tripped timeout factor circuitTrippedTimeoutFactor int32}DefaultHealthChecker定义了outStandingRequestConutLimit、requestSuccessiveFailureThreshold、circuitTrippedTimeoutFactor属性NewDefaultHealthCheckerdubbo-go-v1.4.2/cluster/router/healthcheck/default_health_check.go // NewDefaultHealthChecker constructs a new DefaultHealthChecker based on the urlfunc NewDefaultHealthChecker(url *common.URL) router.HealthChecker { return &DefaultHealthChecker{ outStandingRequestConutLimit: int32(url.GetParamInt(constant.OUTSTANDING_REQUEST_COUNT_LIMIT_KEY, math.MaxInt32)), requestSuccessiveFailureThreshold: int32(url.GetParamInt(constant.SUCCESSIVE_FAILED_REQUEST_THRESHOLD_KEY, constant.DEFAULT_SUCCESSIVE_FAILED_REQUEST_MAX_DIFF)), circuitTrippedTimeoutFactor: int32(url.GetParamInt(constant.CIRCUIT_TRIPPED_TIMEOUT_FACTOR_KEY, constant.DEFAULT_CIRCUIT_TRIPPED_TIMEOUT_FACTOR)), }}NewDefaultHealthChecker实例化DefaultHealthCheckerIsHealthydubbo-go-v1.4.2/cluster/router/healthcheck/default_health_check.go ...

August 2, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的apolloConfiguration

序本文次要钻研一下dubbo-go的apolloConfiguration apolloConfigurationdubbo-go-v1.4.2/config_center/apollo/impl.go const ( apolloProtocolPrefix = "http://" apolloConfigFormat = "%s.%s")type apolloConfiguration struct { url *common.URL listeners sync.Map appConf *agollo.AppConfig parser parser.ConfigurationParser}apolloConfiguration定义了url、listeners、appConf、parser属性newApolloConfigurationdubbo-go-v1.4.2/config_center/apollo/impl.go func newApolloConfiguration(url *common.URL) (*apolloConfiguration, error) { c := &apolloConfiguration{ url: url, } configAddr := c.getAddressWithProtocolPrefix(url) configCluster := url.GetParam(constant.CONFIG_CLUSTER_KEY, "") appId := url.GetParam(constant.CONFIG_APP_ID_KEY, "") namespaces := getProperties(url.GetParam(constant.CONFIG_NAMESPACE_KEY, cc.DEFAULT_GROUP)) c.appConf = &agollo.AppConfig{ AppId: appId, Cluster: configCluster, NamespaceName: namespaces, Ip: configAddr, } agollo.InitCustomConfig(func() (*agollo.AppConfig, error) { return c.appConf, nil }) return c, agollo.Start()}newApolloConfiguration办法创立AppConfig,而后执行agollo.InitCustomConfig,最初执行agollo.Start()GetPropertiesdubbo-go-v1.4.2/config_center/apollo/impl.go ...

August 1, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的PrometheusReporter

序本文次要钻研一下dubbo-go的PrometheusReporter PrometheusReporterdubbo-go-v1.4.2/metrics/prometheus/reporter.go const ( reporterName = "prometheus" serviceKey = constant.SERVICE_KEY groupKey = constant.GROUP_KEY versionKey = constant.VERSION_KEY methodKey = constant.METHOD_KEY timeoutKey = constant.TIMEOUT_KEY providerKey = "provider" consumerKey = "consumer" // to identify the metric's type histogramSuffix = "_histogram" // to identify the metric's type summarySuffix = "_summary")var ( labelNames = []string{serviceKey, groupKey, versionKey, methodKey, timeoutKey} namespace = config.GetApplicationConfig().Name reporterInstance *PrometheusReporter reporterInitOnce sync.Once)// should initialize after loading configurationfunc init() { extension.SetMetricReporter(reporterName, newPrometheusReporter)}// PrometheusReporter// it will collect the data for Prometheus// if you want to use this, you should initialize your prometheus.// https://prometheus.io/docs/guides/go-application/type PrometheusReporter struct { // report the consumer-side's summary data consumerSummaryVec *prometheus.SummaryVec // report the provider-side's summary data providerSummaryVec *prometheus.SummaryVec // report the provider-side's histogram data providerHistogramVec *prometheus.HistogramVec // report the consumer-side's histogram data consumerHistogramVec *prometheus.HistogramVec}PrometheusReporter定义了consumerSummaryVec、providerSummaryVec、providerHistogramVec、consumerHistogramVecnewPrometheusReporterdubbo-go-v1.4.2/metrics/prometheus/reporter.go ...

July 31, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的PrometheusReporter

序本文次要钻研一下dubbo-go的PrometheusReporter PrometheusReporterdubbo-go-v1.4.2/metrics/prometheus/reporter.go const ( reporterName = "prometheus" serviceKey = constant.SERVICE_KEY groupKey = constant.GROUP_KEY versionKey = constant.VERSION_KEY methodKey = constant.METHOD_KEY timeoutKey = constant.TIMEOUT_KEY providerKey = "provider" consumerKey = "consumer" // to identify the metric's type histogramSuffix = "_histogram" // to identify the metric's type summarySuffix = "_summary")var ( labelNames = []string{serviceKey, groupKey, versionKey, methodKey, timeoutKey} namespace = config.GetApplicationConfig().Name reporterInstance *PrometheusReporter reporterInitOnce sync.Once)// should initialize after loading configurationfunc init() { extension.SetMetricReporter(reporterName, newPrometheusReporter)}// PrometheusReporter// it will collect the data for Prometheus// if you want to use this, you should initialize your prometheus.// https://prometheus.io/docs/guides/go-application/type PrometheusReporter struct { // report the consumer-side's summary data consumerSummaryVec *prometheus.SummaryVec // report the provider-side's summary data providerSummaryVec *prometheus.SummaryVec // report the provider-side's histogram data providerHistogramVec *prometheus.HistogramVec // report the consumer-side's histogram data consumerHistogramVec *prometheus.HistogramVec}PrometheusReporter定义了consumerSummaryVec、providerSummaryVec、providerHistogramVec、consumerHistogramVecnewPrometheusReporterdubbo-go-v1.4.2/metrics/prometheus/reporter.go ...

July 31, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的kubernetesRegistry

序本文次要钻研一下dubbo-go的kubernetesRegistry kubernetesRegistrydubbo-go-v1.4.2/registry/kubernetes/registry.go var ( processID = "" localIP = "")const ( Name = "kubernetes" ConnDelay = 3 MaxFailTimes = 15)func init() { processID = fmt.Sprintf("%d", os.Getpid()) localIP, _ = gxnet.GetLocalIP() extension.SetRegistry(Name, newKubernetesRegistry)}type kubernetesRegistry struct { registry.BaseRegistry cltLock sync.RWMutex client *kubernetes.Client listenerLock sync.Mutex listener *kubernetes.EventListener dataListener *dataListener configListener *configurationListener}kubernetesRegistry定义了cltLock、client、listenerLock、listener、dataListener、configListener属性newKubernetesRegistrydubbo-go-v1.4.2/registry/kubernetes/registry.go func newKubernetesRegistry(url *common.URL) (registry.Registry, error) { // actually, kubernetes use in-cluster config, r := &kubernetesRegistry{} r.InitBaseRegistry(url, r) if err := kubernetes.ValidateClient(r); err != nil { return nil, perrors.WithStack(err) } r.WaitGroup().Add(1) go r.HandleClientRestart() r.InitListeners() logger.Debugf("the kubernetes registry started") return r, nil}newKubernetesRegistry办法实例化kubernetesRegistry,而后执行InitBaseRegistry、InitListenersInitListenersdubbo-go-v1.4.2/registry/kubernetes/registry.go ...

July 30, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的kubernetesRegistry

序本文次要钻研一下dubbo-go的kubernetesRegistry kubernetesRegistrydubbo-go-v1.4.2/registry/kubernetes/registry.go var ( processID = "" localIP = "")const ( Name = "kubernetes" ConnDelay = 3 MaxFailTimes = 15)func init() { processID = fmt.Sprintf("%d", os.Getpid()) localIP, _ = gxnet.GetLocalIP() extension.SetRegistry(Name, newKubernetesRegistry)}type kubernetesRegistry struct { registry.BaseRegistry cltLock sync.RWMutex client *kubernetes.Client listenerLock sync.Mutex listener *kubernetes.EventListener dataListener *dataListener configListener *configurationListener}kubernetesRegistry定义了cltLock、client、listenerLock、listener、dataListener、configListener属性newKubernetesRegistrydubbo-go-v1.4.2/registry/kubernetes/registry.go func newKubernetesRegistry(url *common.URL) (registry.Registry, error) { // actually, kubernetes use in-cluster config, r := &kubernetesRegistry{} r.InitBaseRegistry(url, r) if err := kubernetes.ValidateClient(r); err != nil { return nil, perrors.WithStack(err) } r.WaitGroup().Add(1) go r.HandleClientRestart() r.InitListeners() logger.Debugf("the kubernetes registry started") return r, nil}newKubernetesRegistry办法实例化kubernetesRegistry,而后执行InitBaseRegistry、InitListenersInitListenersdubbo-go-v1.4.2/registry/kubernetes/registry.go ...

July 30, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的kubernetesRegistry

序本文次要钻研一下dubbo-go的kubernetesRegistry kubernetesRegistrydubbo-go-v1.4.2/registry/kubernetes/registry.go var ( processID = "" localIP = "")const ( Name = "kubernetes" ConnDelay = 3 MaxFailTimes = 15)func init() { processID = fmt.Sprintf("%d", os.Getpid()) localIP, _ = gxnet.GetLocalIP() extension.SetRegistry(Name, newKubernetesRegistry)}type kubernetesRegistry struct { registry.BaseRegistry cltLock sync.RWMutex client *kubernetes.Client listenerLock sync.Mutex listener *kubernetes.EventListener dataListener *dataListener configListener *configurationListener}kubernetesRegistry定义了cltLock、client、listenerLock、listener、dataListener、configListener属性newKubernetesRegistrydubbo-go-v1.4.2/registry/kubernetes/registry.go func newKubernetesRegistry(url *common.URL) (registry.Registry, error) { // actually, kubernetes use in-cluster config, r := &kubernetesRegistry{} r.InitBaseRegistry(url, r) if err := kubernetes.ValidateClient(r); err != nil { return nil, perrors.WithStack(err) } r.WaitGroup().Add(1) go r.HandleClientRestart() r.InitListeners() logger.Debugf("the kubernetes registry started") return r, nil}newKubernetesRegistry办法实例化kubernetesRegistry,而后执行InitBaseRegistry、InitListenersInitListenersdubbo-go-v1.4.2/registry/kubernetes/registry.go ...

July 30, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的nacosRegistry

序本文次要钻研一下dubbo-go的nacosRegistry nacosRegistrydubbo-go-v1.4.2/registry/nacos/registry.go var ( localIP = "")const ( //RegistryConnDelay registry connection delay RegistryConnDelay = 3)func init() { localIP, _ = gxnet.GetLocalIP() extension.SetRegistry(constant.NACOS_KEY, newNacosRegistry)}type nacosRegistry struct { *common.URL namingClient naming_client.INamingClient}nacosRegistry定义了common.URL、namingClient属性newNacosRegistrydubbo-go-v1.4.2/registry/nacos/registry.go func newNacosRegistry(url *common.URL) (registry.Registry, error) { nacosConfig, err := getNacosConfig(url) if err != nil { return nil, err } client, err := clients.CreateNamingClient(nacosConfig) if err != nil { return nil, err } registry := nacosRegistry{ URL: url, namingClient: client, } return &registry, nil}newNacosRegistry办法先通过getNacosConfig获取nacosConfig,之后通过clients.CreateNamingClient(nacosConfig)创立client,最初实例化nacosRegistrygetNacosConfigdubbo-go-v1.4.2/registry/nacos/registry.go ...

July 29, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的nacosRegistry

序本文次要钻研一下dubbo-go的nacosRegistry nacosRegistrydubbo-go-v1.4.2/registry/nacos/registry.go var ( localIP = "")const ( //RegistryConnDelay registry connection delay RegistryConnDelay = 3)func init() { localIP, _ = gxnet.GetLocalIP() extension.SetRegistry(constant.NACOS_KEY, newNacosRegistry)}type nacosRegistry struct { *common.URL namingClient naming_client.INamingClient}nacosRegistry定义了common.URL、namingClient属性newNacosRegistrydubbo-go-v1.4.2/registry/nacos/registry.go func newNacosRegistry(url *common.URL) (registry.Registry, error) { nacosConfig, err := getNacosConfig(url) if err != nil { return nil, err } client, err := clients.CreateNamingClient(nacosConfig) if err != nil { return nil, err } registry := nacosRegistry{ URL: url, namingClient: client, } return &registry, nil}newNacosRegistry办法先通过getNacosConfig获取nacosConfig,之后通过clients.CreateNamingClient(nacosConfig)创立client,最初实例化nacosRegistrygetNacosConfigdubbo-go-v1.4.2/registry/nacos/registry.go ...

July 29, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的DubboPackage

序本文只有钻研一下dubbo-go的DubboPackage DubboPackagedubbo-go-v1.4.2/protocol/dubbo/codec.go //CallType call typetype CallType int32const ( // CT_UNKNOWN unknown call type CT_UNKNOWN CallType = 0 // CT_OneWay call one way CT_OneWay CallType = 1 // CT_TwoWay call in request/response CT_TwoWay CallType = 2)// SequenceType ...type SequenceType int64// DubboPackage ...type DubboPackage struct { Header hessian.DubboHeader Service hessian.Service Body interface{} Err error}DubboPackage定义了Header、Service、Body、Err属性Marshaldubbo-go-v1.4.2/protocol/dubbo/codec.go // Marshal ...func (p *DubboPackage) Marshal() (*bytes.Buffer, error) { codec := hessian.NewHessianCodec(nil) pkg, err := codec.Write(p.Service, p.Header, p.Body) if err != nil { return nil, perrors.WithStack(err) } return bytes.NewBuffer(pkg), nil}Marshal办法通过hessian.NewHessianCodec(nil)创立codec,之后执行bytes.NewBuffer(pkg)Unmarshaldubbo-go-v1.4.2/protocol/dubbo/codec.go ...

July 28, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的DubboProtocol

序本文次要钻研一下dubbo-go的DubboProtocol DubboProtocoldubbo-go-v1.4.2/protocol/dubbo/dubbo_protocol.go // dubbo protocol constantconst ( // DUBBO ... DUBBO = "dubbo")func init() { extension.SetProtocol(DUBBO, GetProtocol)}var ( dubboProtocol *DubboProtocol)// DubboProtocol ...type DubboProtocol struct { protocol.BaseProtocol serverMap map[string]*Server serverLock sync.Mutex}DubboProtocol嵌套了protocol.BaseProtocol,定义了serverMap、serverLock属性GetProtocoldubbo-go-v1.4.2/protocol/dubbo/dubbo_protocol.go // GetProtocol ...func GetProtocol() protocol.Protocol { if dubboProtocol == nil { dubboProtocol = NewDubboProtocol() } return dubboProtocol}GetProtocol办法通过NewDubboProtocol创立dubboProtocolNewDubboProtocoldubbo-go-v1.4.2/protocol/dubbo/dubbo_protocol.go // NewDubboProtocol ...func NewDubboProtocol() *DubboProtocol { return &DubboProtocol{ BaseProtocol: protocol.NewBaseProtocol(), serverMap: make(map[string]*Server), }}NewDubboProtocol办法实例化了DubboProtocolExportdubbo-go-v1.4.2/protocol/dubbo/dubbo_protocol.go // Export ...func (dp *DubboProtocol) Export(invoker protocol.Invoker) protocol.Exporter { url := invoker.GetUrl() serviceKey := url.ServiceKey() exporter := NewDubboExporter(serviceKey, invoker, dp.ExporterMap()) dp.SetExporterMap(serviceKey, exporter) logger.Infof("Export service: %s", url.String()) // start server dp.openServer(url) return exporter}Export办法通过NewDubboExporter创立exporter,而后更新到DubboProtocol的exporterMap中,之后执行DubboProtocol的openServeropenServerdubbo-go-v1.4.2/protocol/dubbo/dubbo_protocol.go ...

July 27, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的DubboProtocol

序本文次要钻研一下dubbo-go的DubboProtocol DubboProtocoldubbo-go-v1.4.2/protocol/dubbo/dubbo_protocol.go // dubbo protocol constantconst ( // DUBBO ... DUBBO = "dubbo")func init() { extension.SetProtocol(DUBBO, GetProtocol)}var ( dubboProtocol *DubboProtocol)// DubboProtocol ...type DubboProtocol struct { protocol.BaseProtocol serverMap map[string]*Server serverLock sync.Mutex}DubboProtocol嵌套了protocol.BaseProtocol,定义了serverMap、serverLock属性GetProtocoldubbo-go-v1.4.2/protocol/dubbo/dubbo_protocol.go // GetProtocol ...func GetProtocol() protocol.Protocol { if dubboProtocol == nil { dubboProtocol = NewDubboProtocol() } return dubboProtocol}GetProtocol办法通过NewDubboProtocol创立dubboProtocolNewDubboProtocoldubbo-go-v1.4.2/protocol/dubbo/dubbo_protocol.go // NewDubboProtocol ...func NewDubboProtocol() *DubboProtocol { return &DubboProtocol{ BaseProtocol: protocol.NewBaseProtocol(), serverMap: make(map[string]*Server), }}NewDubboProtocol办法实例化了DubboProtocolExportdubbo-go-v1.4.2/protocol/dubbo/dubbo_protocol.go // Export ...func (dp *DubboProtocol) Export(invoker protocol.Invoker) protocol.Exporter { url := invoker.GetUrl() serviceKey := url.ServiceKey() exporter := NewDubboExporter(serviceKey, invoker, dp.ExporterMap()) dp.SetExporterMap(serviceKey, exporter) logger.Infof("Export service: %s", url.String()) // start server dp.openServer(url) return exporter}Export办法通过NewDubboExporter创立exporter,而后更新到DubboProtocol的exporterMap中,之后执行DubboProtocol的openServeropenServerdubbo-go-v1.4.2/protocol/dubbo/dubbo_protocol.go ...

July 27, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的DubboInvoker

序本文次要钻研一下dubbo-go的DubboInvoker Invokerdubbo-go-v1.4.2/protocol/invoker.go // Extension - Invokertype Invoker interface { common.Node Invoke(context.Context, Invocation) Result}/////////////////////////////// base invoker/////////////////////////////// BaseInvoker ...type BaseInvoker struct { url common.URL available bool destroyed bool}// NewBaseInvoker ...func NewBaseInvoker(url common.URL) *BaseInvoker { return &BaseInvoker{ url: url, available: true, destroyed: false, }}// GetUrl ...func (bi *BaseInvoker) GetUrl() common.URL { return bi.url}// IsAvailable ...func (bi *BaseInvoker) IsAvailable() bool { return bi.available}// IsDestroyed ...func (bi *BaseInvoker) IsDestroyed() bool { return bi.destroyed}// Invoke ...func (bi *BaseInvoker) Invoke(context context.Context, invocation Invocation) Result { return &RPCResult{}}// Destroy ...func (bi *BaseInvoker) Destroy() { logger.Infof("Destroy invoker: %s", bi.GetUrl().String()) bi.destroyed = true bi.available = false}Invoker定义了Invoke办法;BaseInvoker定义了url、available、destroyed属性;NewBaseInvoker办法实例化了BaseInvoker,其available为true,destroyed为false;Destroy办法设置available为false,destroyed为trueDubboInvokerdubbo-go-v1.4.2/protocol/dubbo/dubbo_invoker.go ...

July 26, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的DubboInvoker

序本文次要钻研一下dubbo-go的DubboInvoker Invokerdubbo-go-v1.4.2/protocol/invoker.go // Extension - Invokertype Invoker interface { common.Node Invoke(context.Context, Invocation) Result}/////////////////////////////// base invoker/////////////////////////////// BaseInvoker ...type BaseInvoker struct { url common.URL available bool destroyed bool}// NewBaseInvoker ...func NewBaseInvoker(url common.URL) *BaseInvoker { return &BaseInvoker{ url: url, available: true, destroyed: false, }}// GetUrl ...func (bi *BaseInvoker) GetUrl() common.URL { return bi.url}// IsAvailable ...func (bi *BaseInvoker) IsAvailable() bool { return bi.available}// IsDestroyed ...func (bi *BaseInvoker) IsDestroyed() bool { return bi.destroyed}// Invoke ...func (bi *BaseInvoker) Invoke(context context.Context, invocation Invocation) Result { return &RPCResult{}}// Destroy ...func (bi *BaseInvoker) Destroy() { logger.Infof("Destroy invoker: %s", bi.GetUrl().String()) bi.destroyed = true bi.available = false}Invoker定义了Invoke办法;BaseInvoker定义了url、available、destroyed属性;NewBaseInvoker办法实例化了BaseInvoker,其available为true,destroyed为false;Destroy办法设置available为false,destroyed为trueDubboInvokerdubbo-go-v1.4.2/protocol/dubbo/dubbo_invoker.go ...

July 26, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的RPCInvocation

序本文次要钻研一下dubbo-go的RPCInvocation Invocationdubbo-go-v1.4.2/protocol/invocation.go // Invocation ...type Invocation interface { MethodName() string ParameterTypes() []reflect.Type ParameterValues() []reflect.Value Arguments() []interface{} Reply() interface{} Attachments() map[string]string AttachmentsByKey(string, string) string Invoker() Invoker}Invocation定义了MethodName、ParameterTypes、ParameterValues、Arguments、Reply、Attachments、AttachmentsByKey、Invoker办法RPCInvocationdubbo-go-v1.4.2/protocol/invocation/rpcinvocation.go type RPCInvocation struct { methodName string parameterTypes []reflect.Type parameterValues []reflect.Value arguments []interface{} reply interface{} callBack interface{} attachments map[string]string invoker protocol.Invoker lock sync.RWMutex}RPCInvocation定义了methodName、parameterTypes、parameterValues、arguments、reply、callBack、attachments、invoker、lock属性NewRPCInvocationdubbo-go-v1.4.2/protocol/invocation/rpcinvocation.go // NewRPCInvocation ...func NewRPCInvocation(methodName string, arguments []interface{}, attachments map[string]string) *RPCInvocation { return &RPCInvocation{ methodName: methodName, arguments: arguments, attachments: attachments, }}NewRPCInvocation办法实例化RPCInvocationNewRPCInvocationWithOptionsdubbo-go-v1.4.2/protocol/invocation/rpcinvocation.go ...

July 25, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的ProviderAuthFilter

序本文次要钻研一下dubbo-go的ProviderAuthFilter ProviderAuthFilterdubbo-go-v1.4.2/filter/filter_impl/auth/provider_auth.go type ProviderAuthFilter struct {}func init() { extension.SetFilter(constant.PROVIDER_AUTH_FILTER, getProviderAuthFilter)}ProviderAuthFilter的init办法设置了getProviderAuthFiltergetProviderAuthFilterdubbo-go-v1.4.2/filter/filter_impl/auth/provider_auth.go func getProviderAuthFilter() filter.Filter { return &ProviderAuthFilter{}}getProviderAuthFilter实例化了ProviderAuthFilterInvokedubbo-go-v1.4.2/filter/filter_impl/auth/provider_auth.go func (paf *ProviderAuthFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { logger.Infof("invoking providerAuth filter.") url := invoker.GetUrl() err := doAuthWork(&url, func(authenticator filter.Authenticator) error { return authenticator.Authenticate(invocation, &url) }) if err != nil { logger.Infof("auth the request: %v occur exception, cause: %s", invocation, err.Error()) return &protocol.RPCResult{ Err: err, } } return invoker.Invoke(ctx, invocation)}Invoke办法通过doAuthWork来进行auth,其传递的func执行authenticator.Authenticate(invocation, &url)OnResponsedubbo-go-v1.4.2/filter/filter_impl/auth/default_authenticator.go ...

July 24, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的ProviderAuthFilter

序本文次要钻研一下dubbo-go的ProviderAuthFilter ProviderAuthFilterdubbo-go-v1.4.2/filter/filter_impl/auth/provider_auth.go type ProviderAuthFilter struct {}func init() { extension.SetFilter(constant.PROVIDER_AUTH_FILTER, getProviderAuthFilter)}ProviderAuthFilter的init办法设置了getProviderAuthFiltergetProviderAuthFilterdubbo-go-v1.4.2/filter/filter_impl/auth/provider_auth.go func getProviderAuthFilter() filter.Filter { return &ProviderAuthFilter{}}getProviderAuthFilter实例化了ProviderAuthFilterInvokedubbo-go-v1.4.2/filter/filter_impl/auth/provider_auth.go func (paf *ProviderAuthFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { logger.Infof("invoking providerAuth filter.") url := invoker.GetUrl() err := doAuthWork(&url, func(authenticator filter.Authenticator) error { return authenticator.Authenticate(invocation, &url) }) if err != nil { logger.Infof("auth the request: %v occur exception, cause: %s", invocation, err.Error()) return &protocol.RPCResult{ Err: err, } } return invoker.Invoke(ctx, invocation)}Invoke办法通过doAuthWork来进行auth,其传递的func执行authenticator.Authenticate(invocation, &url)OnResponsedubbo-go-v1.4.2/filter/filter_impl/auth/default_authenticator.go ...

July 24, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的ConsumerSignFilter

序本文次要钻研一下dubbo-go的ConsumerSignFilter ConsumerSignFilterdubbo-go-v1.4.2/filter/filter_impl/auth/consumer_sign.go type ConsumerSignFilter struct {}func init() { extension.SetFilter(constant.CONSUMER_SIGN_FILTER, getConsumerSignFilter)}ConsumerSignFilter的init办法设置了getConsumerSignFiltergetConsumerSignFilterdubbo-go-v1.4.2/filter/filter_impl/auth/consumer_sign.go func getConsumerSignFilter() filter.Filter { return &ConsumerSignFilter{}}getConsumerSignFilter创立了ConsumerSignFilterInvokedubbo-go-v1.4.2/filter/filter_impl/auth/consumer_sign.go func (csf *ConsumerSignFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { logger.Infof("invoking ConsumerSign filter.") url := invoker.GetUrl() err := doAuthWork(&url, func(authenticator filter.Authenticator) error { return authenticator.Sign(invocation, &url) }) if err != nil { panic(fmt.Sprintf("Sign for invocation %s # %s failed", url.ServiceKey(), invocation.MethodName())) } return invoker.Invoke(ctx, invocation)}Invoke办法会先执行doAuthWork办法,其传递的func执行authenticator.Sign(invocation, &url)OnResponsedubbo-go-v1.4.2/filter/filter_impl/auth/consumer_sign.go func (csf *ConsumerSignFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { return result}OnResponse办法间接返回resultdoAuthWorkfilter/filter_impl/auth/default_authenticator.go ...

July 23, 2020 · 1 min · jiezi

关于dubbo:Dubbo同时支持多种协议以dubbo和rest为例

一. 背景常识有时候微服务须要提供给多个消费者, 而不通过的消费者可能心愿根据本身状况应用不同的协定. 另一方面, 有时候如果本来服务以 dubbo 协定提供服务, 然而为了调试或者监控不便, 咱们也提供 rest 协定. 本文示例服务者同时提供 dubbo 和 rest 协定. 应用的 dubbo 版本为 2.7.1, springboot 版本为 2.1.5. 为了实在地模仿不同微服务之间的调用, 本文将服务者和生产离开. 对应的我的项目有两个, 别离为dubboshop-inventory(服务者)和dubboshop-order(消费者). 其构造如下: dubboshop-inventory (库存微服务. 这个我的项目次要演示服务提供者角色) |- dubbo-api: 蕴含服务接口和 DTO 对象. 打包成 `dubboshop-inventory:1.0.0-snapshot.jar`, 通过 `mvn install`到本地或者`mvn deploy`部署到私服, 在上面`dubboshop-order`我的项目中援用依赖. |- fun.faceless.dubboshop.comms.entity.Result.java |- fun.faceless.dubboshop.comms.entity.CommRetCode.java |- dubbo-provider: 服务接口具体实现类 |- fun.faceless.dubboshop.inventory.dubboprovider.DubboApplication.java |- fun.faceless.dubboshop.inventory.dubboprovider.impl.InventoryProviderImpl.java dubboshop-order (订单微服务) |- dubbo-provider: 订单服务的提供者, 同时是dubboshop-inventory服务的消费者. 这里次要演示其作为消费者的角色. |- fun.faceless.dubboshop.order.dubboprovider.impl.OrderProviderImpl.java二. 通用dubbo配置本文两个我的项目都作为服务者, 也都反对dubbo和rest协定, 所以两者dubbo相干的依赖都蕴含以下几局部. ...

July 23, 2020 · 4 min · jiezi

关于dubbo:聊聊dubbogo的tracingFilter

序本文次要钻研一下dubbo-go的tracingFilter tracingFilterdubbo-go-v1.4.2/filter/filter_impl/tracing_filter.go const ( tracingFilterName = "tracing")// this should be executed before users set their own Tracerfunc init() { extension.SetFilter(tracingFilterName, newTracingFilter) opentracing.SetGlobalTracer(opentracing.NoopTracer{})}var ( errorKey = "ErrorMsg" successKey = "Success")// if you wish to using opentracing, please add the this filter into your filter attribute in your configure file.// notice that this could be used in both client-side and server-side.type tracingFilter struct {}tracingFilter的init办法设置了newTracingFilternewTracingFilterdubbo-go-v1.4.2/filter/filter_impl/tracing_filter.go func newTracingFilter() filter.Filter { if tracingFilterInstance == nil { tracingFilterInstance = &tracingFilter{} } return tracingFilterInstance}newTracingFilter办法实例化tracingFilterInvokedubbo-go-v1.4.2/filter/filter_impl/tracing_filter.go ...

July 22, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的metricsFilter

序本文次要钻研一下dubbo-go的metricsFilter metricsFilterdubbo-go-v1.4.2/filter/filter_impl/metrics_filter.go const ( metricFilterName = "metrics")var ( metricFilterInstance filter.Filter)// must initialized before using the filter and after loading configurationfunc init() { extension.SetFilter(metricFilterName, newMetricsFilter)}// metricFilter will calculate the invocation's duration and the report to the reporters// If you want to use this filter to collect the metrics,// Adding this into your configuration file, like:// filter: "metrics"// metrics:// reporter:// - "your reporter" # here you should specify the reporter, for example 'prometheus'// more info please take a look at dubbo-samples projectstype metricsFilter struct { reporters []metrics.Reporter}metricsFilter定义了reporters属性newMetricsFilterdubbo-go-v1.4.2/filter/filter_impl/metrics_filter.go ...

July 21, 2020 · 1 min · jiezi

关于dubbo:如何生成dubbo-rpc接口文档

在国内dubbo成为很多互联网公司高并发分布式场景下rpc框架的首选,dubbo从开源至今经验过蛮多的过程,从开源到两头的进行保护,通过三年的寂静,2017年9月,阿里巴巴发表重启dubbo我的项目。到2018年2月,阿里将dubbo募捐给Apache基金会,随后dubbo通过孵化后顺利成为apache的顶级我的项目。 当然本文的重点不是介绍dubbo的应用,而是介绍如何利用smart-doc工具来生成dubbo的rpc外部接口文档。smart-doc因为其基于正文和java接口定义主动推导的理念,开源以来受到国内很多开发者的青睐。在开源之初,smart-doc仅仅反对restful api文档的生成,然而在倒退的过程中,一直有开发者询问smart-doc是否反对dubbo rpc接口文档的生成。通过一直致力,在smart-doc 1.8.7版本中咱们减少了dubbo rpc接口的反对,上面来看看真正的操作。 一、集成smart-docsmart-doc本着应用简略的准则开发了maven插件和gradle,通过插件来升高smart-doc的集成难度和去除依赖侵入性。您能够依据本人应用的依赖构建管理工具来抉择相干的插件,上面以应用smart-doc-maven-plugin插件集成smart-doc生成dubbo为例。当然集成smart-doc来生成dubbo rpc接口文档你有两种可选形式: 应用smart-doc扫描dubbo api模块应用smart-doc扫描dubbo provider模块上面来看下集成形式。 1.1 增加插件在你的dubbo api或者或者是dubbo provider模块中增加smart-doc-maven-plugin。当然你只须要选中一种形式即可 <plugin> <groupId>com.github.shalousun</groupId> <artifactId>smart-doc-maven-plugin</artifactId> <version>[最新版本]</version> <configuration> <!--指定生成文档的应用的配置文件,配置文件放在本人的我的项目中--> <configFile>./src/main/resources/smart-doc.json</configFile> <!--指定项目名称--> <projectName>测试</projectName> <!--smart-doc实现主动剖析依赖树加载第三方依赖的源码,如果一些框架依赖库加载不到导致报错,这时请应用excludes排除掉--> <excludes> <!--格局为:groupId:artifactId;参考如下--> <!--1.0.7版本开始你还能够用正则匹配排除,如:poi.* --> <exclude>com.alibaba:fastjson</exclude> </excludes> <!--自1.0.8版本开始,插件提供includes反对--> <!--smart-doc能主动剖析依赖树加载所有依赖源码,原则上会影响文档构建效率,因而你能够应用includes来让插件加载你配置的组件--> <includes> <!--格局为:groupId:artifactId;参考如下--> <include>com.alibaba:fastjson</include> </includes> </configuration> <executions> <execution> <!--如果不须要在执行编译时启动smart-doc,则将phase正文掉--> <phase>compile</phase> <goals> <goal>html</goal> </goals> </execution> </executions></plugin>增加smart-doc所需配置文件在你的dubbo api或者或者是dubbo provider模块reources中增加smart-doc.json配置文件 { "isStrict": false, //是否开启严格模式 "allInOne": true, //是否将文档合并到一个文件中,个别举荐为true "outPath": "D://md2", //指定文档的输入门路 "projectName": "smart-doc",//配置本人的项目名称 "rpcApiDependencies":[{ // 我的项目凋谢的dubbo api接口模块依赖,配置后输入到文档不便使用者集成 "artifactId":"SpringBoot2-Dubbo-Api", "groupId":"com.demo", "version":"1.0.0" }], "rpcConsumerConfig":"src/main/resources/consumer-example.conf"//文档中增加dubbo consumer集成配置,用于不便集成方能够疾速集成}对于smart-doc如果你生成文档须要更具体的配置请常看官网我的项目wiki文档官网wiki文档 ...

July 20, 2020 · 2 min · jiezi

关于dubbo:聊聊dubbogo的TokenFilter

序本文次要钻研一下dubbo-go的TokenFilter TokenFilterdubbo-go-v1.4.2/filter/filter_impl/token_filter.go const ( // TOKEN ... TOKEN = "token")func init() { extension.SetFilter(TOKEN, GetTokenFilter)}// TokenFilter ...type TokenFilter struct{}TokenFilter的init办法设置了GetTokenFilterGetTokenFilterdubbo-go-v1.4.2/filter/filter_impl/token_filter.go // GetTokenFilter ...func GetTokenFilter() filter.Filter { return &TokenFilter{}}GetTokenFilter创立了TokenFilterInvokedubbo-go-v1.4.2/filter/filter_impl/token_filter.go // Invoke ...func (tf *TokenFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { invokerTkn := invoker.GetUrl().GetParam(constant.TOKEN_KEY, "") if len(invokerTkn) > 0 { attachs := invocation.Attachments() remoteTkn, exist := attachs[constant.TOKEN_KEY] if exist && strings.EqualFold(invokerTkn, remoteTkn) { return invoker.Invoke(ctx, invocation) } return &protocol.RPCResult{Err: perrors.Errorf("Invalid token! Forbid invoke remote service %v method %s ", invoker, invocation.MethodName())} } return invoker.Invoke(ctx, invocation)}Invoke办法读取constant.TOKEN_KEY的值invokerTkn,在该值有配置的前提下,从invocation.Attachments()获取对应的remoteTkn,之后比照invokerTkn与remoteTkn,相等则执行invoker.Invoke(ctx, invocation),否则返回谬误后果OnResponsedubbo-go-v1.4.2/filter/filter_impl/token_filter.go ...

July 19, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的TpsLimitFilter

序本文次要钻研一下dubbo-go的TpsLimitFilter TpsLimitFilterdubbo-go-v1.4.2/filter/filter_impl/tps_limit_filter.go const ( // TpsLimitFilterKey key TpsLimitFilterKey = "tps")func init() { extension.SetFilter(TpsLimitFilterKey, GetTpsLimitFilter)}type TpsLimitFilter struct {}TpsLimitFilter的init设置了GetTpsLimitFilterGetTpsLimitFilterdubbo-go-v1.4.2/filter/filter_impl/tps_limit_filter.go // GetTpsLimitFilter ...func GetTpsLimitFilter() filter.Filter { return &TpsLimitFilter{}}GetTpsLimitFilter实例化TpsLimitFilterInvokedubbo-go-v1.4.2/filter/filter_impl/tps_limit_filter.go // Invoke ...func (t TpsLimitFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { url := invoker.GetUrl() tpsLimiter := url.GetParam(constant.TPS_LIMITER_KEY, "") rejectedExeHandler := url.GetParam(constant.TPS_REJECTED_EXECUTION_HANDLER_KEY, constant.DEFAULT_KEY) if len(tpsLimiter) > 0 { allow := extension.GetTpsLimiter(tpsLimiter).IsAllowable(invoker.GetUrl(), invocation) if allow { return invoker.Invoke(ctx, invocation) } logger.Errorf("The invocation was rejected due to over the tps limitation, url: %s ", url.String()) return extension.GetRejectedExecutionHandler(rejectedExeHandler).RejectedExecution(url, invocation) } return invoker.Invoke(ctx, invocation)}Invoke办法读取constant.TPS_LIMITER_KEY及constant.TPS_REJECTED_EXECUTION_HANDLER_KEY;对于有配置tpsLimiter的执行extension.GetTpsLimiter(tpsLimiter).IsAllowable(invoker.GetUrl(), invocation),对于allow的执行invoker.Invoke(ctx, invocation),非allow的执行extension.GetRejectedExecutionHandler(rejectedExeHandler).RejectedExecution(url, invocation)OnResponsedubbo-go-v1.4.2/filter/filter_impl/tps_limit_filter.go ...

July 18, 2020 · 1 min · jiezi

关于dubbo:聊聊dubbogo的GenericFilter

序本文次要钻研一下dubbo-go的GenericFilter GenericFilterdubbo-go-v1.4.2/filter/filter_impl/generic_filter.go const ( // GENERIC //generic module name GENERIC = "generic")func init() { extension.SetFilter(GENERIC, GetGenericFilter)}// when do a generic invoke, struct need to be map// GenericFilter ...type GenericFilter struct{}GenericFilter的init办法设置了GetGenericFilterGetGenericFilterdubbo-go-v1.4.2/filter/filter_impl/generic_filter.go // GetGenericFilter ...func GetGenericFilter() filter.Filter { return &GenericFilter{}}GetGenericFilter办法创立了GenericFilterInvokedubbo-go-v1.4.2/filter/filter_impl/generic_filter.go // Invoke ...func (ef *GenericFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { if invocation.MethodName() == constant.GENERIC && len(invocation.Arguments()) == 3 { oldArguments := invocation.Arguments() if oldParams, ok := oldArguments[2].([]interface{}); ok { newParams := make([]hessian.Object, 0, len(oldParams)) for i := range oldParams { newParams = append(newParams, hessian.Object(struct2MapAll(oldParams[i]))) } newArguments := []interface{}{ oldArguments[0], oldArguments[1], newParams, } newInvocation := invocation2.NewRPCInvocation(invocation.MethodName(), newArguments, invocation.Attachments()) newInvocation.SetReply(invocation.Reply()) return invoker.Invoke(ctx, newInvocation) } } return invoker.Invoke(ctx, invocation)}Invoke办法在methodName为generic,且参数长度为3时,通过struct2MapAll办法将oldParams转换为newParams,发动newInvocationstruct2MapAlldubbo-go-v1.4.2/filter/filter_impl/generic_filter.go ...

July 17, 2020 · 2 min · jiezi

聊聊dubbogo的gracefulShutdownFilter

序本文次要钻研一下dubbo-go的gracefulShutdownFilter gracefulShutdownFilterdubbo-go-v1.4.2/filter/filter_impl/graceful_shutdown_filter.go type gracefulShutdownFilter struct { activeCount int32 shutdownConfig *config.ShutdownConfig}gracefulShutdownFilter定义了activeCount、shutdownConfig属性initdubbo-go-v1.4.2/filter/filter_impl/graceful_shutdown_filter.go func init() { var consumerFiler = &gracefulShutdownFilter{ shutdownConfig: config.GetConsumerConfig().ShutdownConfig, } var providerFilter = &gracefulShutdownFilter{ shutdownConfig: config.GetProviderConfig().ShutdownConfig, } extension.SetFilter(constant.CONSUMER_SHUTDOWN_FILTER, func() filter.Filter { return consumerFiler }) extension.SetFilter(constant.PROVIDER_SHUTDOWN_FILTER, func() filter.Filter { return providerFilter })}init办法别离创立并设置了CONSUMER_SHUTDOWN_FILTER、PROVIDER_SHUTDOWN_FILTERInvokedubbo-go-v1.4.2/filter/filter_impl/graceful_shutdown_filter.go func (gf *gracefulShutdownFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { if gf.rejectNewRequest() { logger.Info("The application is closing, new request will be rejected.") return gf.getRejectHandler().RejectedExecution(invoker.GetUrl(), invocation) } atomic.AddInt32(&gf.activeCount, 1) return invoker.Invoke(ctx, invocation)}Invoke办法先判断gracefulShutdownFilter的rejectNewRequest是否为true,若为true则执行getRejectHandler().RejectedExecution,否则执行atomic.AddInt32及invoker.Invoke(ctx, invocation)OnResponsedubbo-go-v1.4.2/filter/filter_impl/graceful_shutdown_filter.go ...

July 16, 2020 · 1 min · jiezi

聊聊dubbogo的EchoFilter

序本文次要钻研一下dubbo-go的EchoFilter EchoFilterdubbo-go-v1.4.2/filter/filter_impl/echo_filter.go const ( // ECHO echo module name ECHO = "echo")func init() { extension.SetFilter(ECHO, GetFilter)}// EchoFilter// RPCService need a Echo method in consumer, if you want to use EchoFilter// eg:// Echo func(ctx context.Context, arg interface{}, rsp *Xxx) errortype EchoFilter struct{}EchoFilter没有定义属性Invokedubbo-go-v1.4.2/filter/filter_impl/echo_filter.go // Invoke ...func (ef *EchoFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { logger.Infof("invoking echo filter.") logger.Debugf("%v,%v", invocation.MethodName(), len(invocation.Arguments())) if invocation.MethodName() == constant.ECHO && len(invocation.Arguments()) == 1 { return &protocol.RPCResult{ Rest: invocation.Arguments()[0], Attrs: invocation.Attachments(), } } return invoker.Invoke(ctx, invocation)}Invoke办法判断invocation.MethodName是否是echo,且有一个参数,是的话则返回protocol.RPCResultOnResponsedubbo-go-v1.4.2/filter/filter_impl/echo_filter.go ...

July 15, 2020 · 1 min · jiezi

聊聊dubbogo的AccessLogFilter

序本文次要钻研一下dubbo-go的AccessLogFilter AccessLogFilterdubbo-go-v1.4.2/filter/filter_impl/access_log_filter.go type AccessLogFilter struct { logChan chan AccessLogData}AccessLogFilter定义了AccessLogData类型的chanInvokedubbo-go-v1.4.2/filter/filter_impl/access_log_filter.go func (ef *AccessLogFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { accessLog := invoker.GetUrl().GetParam(constant.ACCESS_LOG_KEY, "") if len(accessLog) > 0 { accessLogData := AccessLogData{data: ef.buildAccessLogData(invoker, invocation), accessLog: accessLog} ef.logIntoChannel(accessLogData) } return invoker.Invoke(ctx, invocation)}Invoke办法首先通过invoker.GetUrl().GetParam获取constant.ACCESS_LOG_KEY配置,若accessLog有值,则通过ef.buildAccessLogData构建accessLogData,而后执行ef.logIntoChannel(accessLogData),最初执行invoker.Invoke(ctx, invocation)logIntoChanneldubbo-go-v1.4.2/filter/filter_impl/access_log_filter.go func (ef *AccessLogFilter) logIntoChannel(accessLogData AccessLogData) { select { case ef.logChan <- accessLogData: return default: logger.Warn("The channel is full and the access logIntoChannel data will be dropped") return }}logIntoChannel办法通过select办法将accessLogData写入ef.logChanbuildAccessLogDatadubbo-go-v1.4.2/filter/filter_impl/access_log_filter.go ...

July 14, 2020 · 2 min · jiezi

dubbo客户端请求连接并发数量监控

实现步骤 1.配置 开启监控性能 2.代码 dubbo提供了RpcStatus类,读监控数据。咱们能够自定义dubbo拦截器,而后在拦截器里打印监控数据。 配置为什么要配置? 因为dubbo自带了监控,咱们要做的只是应用,很多框架都是自带了监控(比方阿里的druid数据库连接池),一般来说就是应用即可。 如何配置? ### dubbo线程池调优 #### 作为提供者,单个办法接管的最大并发申请数量(所有消费者)dubbo.provider.executes=200# 作为提供者,单个办法接管的最大并发申请数量(单个消费者)dubbo.provider.actives=200# 作为消费者,调用近程办法的最大并发申请数量dubbo.consumer.actives=200阐明 这几个参数原本是调优的作用,因为个别状况下只须要配置线程池的数量即可,然而如果想要限度单个办法或单个客户端的并发申请数量,从而防止单个服务或单个客户端把零碎拖垮,就能够配置以上的几个参数。配置了之后,就主动开启了监控性能。 代码自定义dubbo拦截器类 if ("provider".equals(side)) { //只在提供者打印监控数据,因为监控个别都是在服务器端//dubbo申请连贯数量监控 RpcStatus status = RpcStatus.getStatus(invoker.getUrl(), inv.getMethodName()); URL url = invoker.getUrl(); String methodName = inv.getMethodName(); int max = url.getMethodParameter(methodName, "executes", 0); if (max <= 0) { max = url.getMethodParameter(methodName, "default.executes", 0); } int left = max - status.getActive(); logger.info("dubbo status:[method:{},status:{},max:{},left:{}]", new Object[]{methodName, JSONObject.toJSONString(status), max, left});字段阐明测试数据 2020-07-09 16:52:22.286|INFO |dw4Vq9rvpwaA-61-0|xxx.common.filter.dubbo.AccessLogExtFilter.invoke:167||dubbo status:[method:getQrcodeInfoById,status:{"active":9,"averageElapsed":1252,"averageTps":0,"failed":0,"failedAverageElapsed":0,"failedElapsed":0,"failedMaxElapsed":0,"maxElapsed":1258,"succeeded":42,"succeededAverageElapsed":1252,"succeededElapsed":52611,"succeededMaxElapsed":1258,"total":42,"totalElapsed":52611},max:200,left:191]2020-07-09 16:52:22.287|INFO |xypAIqCmPDQ4-22-11|xxx.common.filter.dubbo.AccessLogExtFilter.invoke:167||dubbo status:[method:getQrcodeInfoById,status:{"active":2, //以后沉闷的申请连贯数量"averageElapsed":1252, //均匀耗时"averageTps":0, //每秒申请数量"failed":0, //失败数量"failedAverageElapsed":0, //失败均匀耗时"failedElapsed":0, //失败申请总耗时"failedMaxElapsed":0, //失败申请的最大耗时"maxElapsed":1258, //最大耗时 "succeeded":49, //胜利申请数量"succeededAverageElapsed":1252, //胜利均匀耗时"succeededElapsed":61388, //申请胜利总耗时"succeededMaxElapsed":1258, //胜利申请的最大耗时"total":49 //总的申请次数(以后统计数据不蕴含以后申请,是之前的申请之和)"totalElapsed":61388 //总耗时},max:200, //execute拦截器的数量left:198 //残余可应用的连贯数量 = max - activce]阐明 监控后果示例(监控数据是在以后申请之前的数据,不包含本次的,沉闷连接数,胜利数都要少一个)。 ...

July 13, 2020 · 1 min · jiezi

dubbo线程池监控

代码//dubbo线程池数量监控 Class<?> clazz = Class.forName("com.alibaba.dubbo.rpc.protocol.dubbo.status.ThreadPoolStatusChecker"); Method check = clazz.getMethod("check"); Object result = check.invoke(clazz.newInstance()); logger.info(JSONObject.toJSONString(result));原理 1.获取dubbo提供的类的对象 2.读数据即可 dubbo提供的类 /** * ThreadPoolStatusChecker */@Activatepublic class ThreadPoolStatusChecker implements StatusChecker { @Override public Status check() { DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension(); Map<String, Object> executors = dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY); StringBuilder msg = new StringBuilder(); Status.Level level = Status.Level.OK; for (Map.Entry<String, Object> entry : executors.entrySet()) { String port = entry.getKey(); ExecutorService executor = (ExecutorService) entry.getValue(); if (executor != null && executor instanceof ThreadPoolExecutor) { //校验是否是线程池 ThreadPoolExecutor tp = (ThreadPoolExecutor) executor; boolean ok = tp.getActiveCount() < tp.getMaximumPoolSize() - 1; Status.Level lvl = Status.Level.OK; if (!ok) { level = Status.Level.WARN; lvl = Status.Level.WARN; } if (msg.length() > 0) { msg.append(";"); } msg.append("Pool status:" + lvl + ", max:" + tp.getMaximumPoolSize() + ", core:" + tp.getCorePoolSize() + ", largest:" + tp.getLargestPoolSize() + ", active:" + tp.getActiveCount() + ", task:" + tp.getTaskCount() + ", service port: " + port); } } return msg.length() == 0 ? new Status(Status.Level.UNKNOWN) : new Status(level, msg.toString()); }}字段阐明测试数据 ...

July 12, 2020 · 2 min · jiezi

都已经十岁的-Apache-Dubbo还能再乘风破浪吗

简介: 纵观中国开源历史,你真的没法找到第二个像 Dubbo 一样自带争议和讨论热度的开源项目。 纵观中国开源历史,你真的没法找到第二个像 Dubbo 一样自带争议和讨论热度的开源项目。 一方面,2011 年,它的开源填补了当时生产环境使用的 RPC 框架的空白,一发布就被广泛采用;另一方面,它经历了停止维护、重启维护后捐献给 Apache 基金会、接着又以顶级项目的身份毕业。 面对多疑的开发者,在云原生时代,Apache Dubbo 将如何延续当前光芒? 今年是 Dubbo 从 Apache 基金会毕业的一周年,同时也是推进 Dubbo 3.0,即全面拥抱云原生的重要一年。开源中国与 Apaceh Dubbo 共同策划【Dubbo 云原生之路】系列文章,和大家一起回顾 Apache Dubbo 社区的发展。系列文章主要涵盖 Dubbo 技术解读、社区、应用案例解析三大部分,之后每周都会和大家见面。 在【阿里巴巴云原生公众号】留言说出与 Apache Dubbo 的故事,点赞排名前十的同学可领取 Dubbo 送出的专属奖品杯子一只;另外由Apache Dubbo PMC @Chickenlj 随机抽取一名幸运读者,赠送价值 260 元护眼灯一台。下周三开奖。 作者简介 刘军,花名陆龟,GitHub 账号 Chickenlj,Apache Dubbo PMC,项目核心开发,见证了 Dubbo 重启开源,到从 Apache 基金会毕业的整个过程。现任职阿里云云原生应用平台团队,参与服务框架、微服务相关工作,目前主要在推动 Dubbo 3.0 - Dubbo 云原生。 系列开篇:3.0 全面铺开、ASF 毕业一周年从 2019 年到现在,在 Dubbo 毕业的这一年时间里,Dubbo 社区和产品都取得长足进步,同时 Dubbo 云原生版本 - Dubbo 3.0 的开发工作也已经全面铺开。 ...

July 7, 2020 · 3 min · jiezi

80会问到的18个Dubbo面试题快来看看你都掌握了吗

文末领取全套面试题 dubbo是什么dubbo是一个分布式框架,远程服务调用的分布式框架,其核心部分包含:集群容错:提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。远程通讯:提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。自动发现:基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。 dubbo能做什么透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。 1、默认使用的是什么通信框架,还有别的选择吗? 答:默认也推荐使用 netty 框架,还有 mina。 2、服务调用是阻塞的吗? 答:默认是阻塞的,可以异步调用,没有返回值的可以这么做。 3、一般使用什么注册中心?还有别的选择吗? 答:推荐使用 zookeeper 注册中心,还有 Multicast注册中心, Redis注册中心, Simple注册中心. ZooKeeper的节点是通过像树一样的结构来进行维护的,并且每一个节点通过路径来标示以及访问。除此之外,每一个节点还拥有自身的一些信息,包括:数据、数据长度、创建时间、修改时间等等。 4、默认使用什么序列化框架,你知道的还有哪些? 答:默认使用 Hessian 序列化,还有 Duddo、FastJson、Java 自带序列化。hessian是一个采用二进制格式传输的服务框架,相对传统soap web service,更轻量,更快速。 Hessian原理与协议简析:http的协议约定了数据传输的方式,hessian也无法改变太多: 1) hessian中client与server的交互,基于http-post方式。 2) hessian将辅助信息,封装在http header中,比如“授权token”等,我们可以基于http-header来封装关于“安全校验”“meta数据”等。hessian提供了简单的”校验”机制。 3) 对于hessian的交互核心数据,比如“调用的方法”和参数列表信息,将通过post请求的body体直接发送,格式为字节流。 4) 对于hessian的server端响应数据,将在response中通过字节流的方式直接输出。 hessian的协议本身并不复杂,在此不再赘言;所谓协议(protocol)就是约束数据的格式,client按照协议将请求信息序列化成字节序列发送给server端,server端根据协议,将数据反序列化成“对象”,然后执行指定的方法,并将方法的返回值再次按照协议序列化成字节流,响应给client,client按照协议将字节流反序列话成”对象”。 5、服务提供者能实现失效踢出是什么原理? 答:服务失效踢出基于 zookeeper 的临时节点原理。 6、服务上线怎么不影响旧版本? 答:采用多版本开发,不影响旧版本。在配置中添加version来作为版本区分 7、如何解决服务调用链过长的问题? 答:可以结合 zipkin 实现分布式服务追踪。 8、说说核心的配置有哪些? 核心配置有: 1) dubbo:service/ 2) dubbo:reference/ 3) dubbo:protocol/ 4) dubbo:registry/ 5) dubbo:application/ 6) dubbo:provider/ 7) dubbo:consumer/ 8) dubbo:method/ ...

July 4, 2020 · 2 min · jiezi

dubbo自定义日志拦截器

背景目前的项目,远程服务调用全部都是基于dubbo,有的是部门内部互相调用,有的是调用其他部门的服务。由于业务里面涉及到远程调用服务的地方比较多,目前调用每个服务的时候都要手动写打印入参、响应和异常,比较麻烦。 现在对这块进行优化,目的是实现自动打印入参、响应和异常,从而避免每个服务都要手动写重复的代码。 实现1.实现过滤器新建包 XXX.solid.filter //以filter结尾 新建类-自定义服务消费者日志拦截器 package XXX.solid.filter;import com.alibaba.dubbo.common.Constants;import com.alibaba.dubbo.common.extension.Activate;import com.alibaba.dubbo.rpc.*;import com.alibaba.dubbo.rpc.service.GenericService;import com.alibaba.fastjson.JSON;import lombok.extern.slf4j.Slf4j;/** * 服务消费者日志拦截器,作用是打印dubbo调用的入参和响应 * @author gongzhihao */@Slf4j@Activate(group = {Constants.CONSUMER})public class LogDubboConsumerFilter implements Filter { @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { //打印入参 log.info("dubbo入参,InterfaceName={},MethodName={},Parameter={}", invocation.getInvoker().getInterface().getName(), invocation.getMethodName(), invocation.getArguments()); //开始时间 long startTime = System.currentTimeMillis(); //执行接口调用逻辑 Result result = invoker.invoke(invocation); //调用耗时 long elapsed = System.currentTimeMillis() - startTime; //如果发生异常,则打印异常日志 if (result.hasException() && invoker.getInterface() != GenericService.class) {// log.error("dubbo执行异常: ", result.getException()); log.error("dubbo执行异常!!!"); } else { log.info("dubbo响应,InterfaceName={},MethodName={},Resposne={},SpendTime={} ms", invocation.getInvoker().getInterface().getName(), invocation.getMethodName(), JSON.toJSONString(new Object[]{result.getValue()}), elapsed); } //返回结果响应数据 return result; }}新建类-自定义服务提供者日志拦截器 ...

July 1, 2020 · 1 min · jiezi

使用dubbo-api完成纯粹的RPC调用

有的时候我们不想和spring集成,也不想使用netty,可以使用dubbo api的方式手动构建服务提供者,服务消费者。 一、依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.0</version> <exclusions> <exclusion> <artifactId>spring-context</artifactId> <groupId>org.springframework</groupId> </exclusion> <exclusion> <artifactId>spring-beans</artifactId> <groupId>org.springframework</groupId> </exclusion> <exclusion> <artifactId>spring-web</artifactId> <groupId>org.springframework</groupId> </exclusion> <exclusion> <artifactId>netty</artifactId> <groupId>org.jboss.netty</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency>可以看到我已经把所有spring依赖和netty依赖全部排除了。引入zkclient是因为dubbo这个版本本身不带连接zkclient的jar。 二、服务 public interface HelloService { String hello();}public class HelloServiceImpl implements HelloService { public String hello() { return "hello"; }}三、构建dubbo服务提供者 public class Provider { public static void main(String[] args) throws IOException { HelloServiceImpl helloService = new HelloServiceImpl(); // 当前应用配置 ApplicationConfig application = new ApplicationConfig(); application.setName("hello"); // 连接注册中心配置 RegistryConfig registry = new RegistryConfig(); registry.setAddress("zookeeper://127.0.0.1:2181"); // registry.setUsername("aaa"); //registry.setPassword("bbb"); // 服务提供者协议配置 ProtocolConfig protocol = new ProtocolConfig(); protocol.setName("rmi"); // 使用jdk的RMI,替代netty protocol.setPort(8888); protocol.setThreads(10); // 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口// 服务提供者暴露服务配置 ServiceConfig<HelloService> service = new ServiceConfig<HelloService>(); // 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏 service.setApplication(application); service.setRegistry(registry); // 多个注册中心可以用setRegistries() service.setProtocol(protocol); // 多个协议可以用setProtocols() service.setInterface(HelloService.class); service.setRef(helloService); service.setVersion("1.0.0");// 暴露及注册服务 service.export(); System.out.println("启动成功"); }}四、构建dubbo服务消费者 ...

June 29, 2020 · 1 min · jiezi

Dubbo-源码解读

《Dubbo 源码解读》傻瓜源码-内容简介傻瓜源码-内容简介????【职场经验】(持续更新)精编短文:如何成为值钱的Java开发-指南如何日常学习、如何书写简历、引导面试官、系统准备面试、选择offer、提高绩效、晋升TeamLeader.....????【源码解读】(持续更新) <br/>1. 源码选材:Java架构师必须掌握的所有框架和类库源码<br/>2. 内容大纲:按照“企业应用Demo”讲解执行源码:总纲“阅读指南”、第一章“源码基础”、第二章“相关Java基础”、第三章“白话讲源码”、第四章“代码解读”、第五章“设计模式”、第六章“附录-面试习题、相关JDK方法、中文注释可运行源码项目”3. 读后问题:粉丝群答疑解惑已收录:HashMap、ReentrantLock、ThreadPoolExecutor、《Spring源码解读》、《Dubbo源码解读》.....????【面试题集】(持续更新)<br/>1. 面试题选材:Java面试常问的所有面试题和必会知识点<br/>2. 内容大纲:第一部分”注意事项“、第二部分“面试题解读”(包括:”面试题“、”答案“、”答案详解“、“实际开发解说”)3. 深度/广度:面试题集中的答案和答案详解,都是对齐一般面试要求的深度和广度4. 读后问题:粉丝群答疑解惑已收录:Java基础面试题集、Java并发面试题集、JVM面试题集、数据库(Mysql)面试题集、缓存(Redis)面试题集 .....????【粉丝群】(持续更新) <br/>收录:阿里、字节跳动、京东、小米、美团、哔哩哔哩等大厂内推???? 作者介绍:Spring系源码贡献者、世界五百强互联网公司、TeamLeader、Github开源产品作者???? 作者微信:wowangle03 (企业内推联系我) 加入我的粉丝社群,阅读更多内容。从学习到面试,从面试到工作,从 coder 到 TeamLeader,每天给你答疑解惑,还能有第二份收入! 第 1 章 阅读指南本书基于 Dubbo 2.6.7 版本。本书根据“企业应用 Demo”解读源码。本书建议分为两个学习阶段,掌握了第一阶段,再进行第二阶段; 第一阶段,理解章节“源码解读”前的所有内容。即掌握 IT 技能:熟悉 Dubbo 原理。第二阶段,理解章节“源码解读”(包括源码解读)之后的内容。即掌握 IT 技能:精通 Dubbo 源码。建议按照本书内容顺序阅读(内容前后顺序存在依赖关系)。阅读本书的过程中如果遇到问题,记下来,后面不远的地方肯定有解答。阅读章节“源码解读”时,建议获得中文注释源码项目配合本书,Debug 进行阅读学习。源码项目中的注释含义; ”企业应用 Demo “的启动代码在源码中,会标注“ // Dubbo Demo ”;在源码中的不易定位到的主线源码,会标注 “ // tofix 主线 ”;以下注释的源码,暂时不深入讲解: 在执行“企业应用 Demo ”过程中,没有被执行到的源码(由于遍历空集合、 if 判断),会标注“ /* Demo不涉及 / ”;从头到尾都是空的变量(包括不包含元素的集合),会标注“ /* 空变量 / ”;有值的变量,但“企业应用 Demo ”运行过程中没有使用到该变量,会标注” /* 无用逻辑 / “;不是核心逻辑,并且不影响源码理解,会标注” /* 非主要逻辑 / “;锁、异常处理逻辑、非空校验、日志打印没有标注注释 ;待进一步解读的源码,会标注” // tofix “。第 2 章 Dubbo 简介 Dubbo 简单来讲,就是通过简单的配置,可以使调用远程方法像调用本地方法一样的分布式服务框架。 ...

June 24, 2020 · 16 min · jiezi

dubbo自定义日志拦截器

背景目前的项目,远程服务调用全部都是基于dubbo,有的是部门内部互相调用,有的是调用其他部门的服务。由于业务里面涉及到远程调用服务的地方比较多,目前调用每个服务的时候都要手动写打印入参、响应和异常,比较麻烦。 现在对这块进行优化,目的是实现自动打印入参、响应和异常,从而避免每个服务都要手动写重复的代码。 实现1.实现过滤器新建包 XXX.solid.filter //以filter结尾 新建类-自定义服务消费者日志拦截器 package XXX.solid.filter;import com.alibaba.dubbo.common.Constants;import com.alibaba.dubbo.common.extension.Activate;import com.alibaba.dubbo.rpc.*;import com.alibaba.dubbo.rpc.service.GenericService;import com.alibaba.fastjson.JSON;import lombok.extern.slf4j.Slf4j;/** * 服务消费者日志拦截器,作用是打印dubbo调用的入参和响应 * @author gongzhihao */@Slf4j@Activate(group = {Constants.CONSUMER})public class LogDubboConsumerFilter implements Filter { @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { //打印入参 log.info("dubbo入参,InterfaceName={},MethodName={},Parameter={}", invocation.getInvoker().getInterface().getName(), invocation.getMethodName(), invocation.getArguments()); //开始时间 long startTime = System.currentTimeMillis(); //执行接口调用逻辑 Result result = invoker.invoke(invocation); //调用耗时 long elapsed = System.currentTimeMillis() - startTime; //如果发生异常,则打印异常日志 if (result.hasException() && invoker.getInterface() != GenericService.class) {// log.error("dubbo执行异常: ", result.getException()); log.error("dubbo执行异常!!!"); } else { log.info("dubbo响应,InterfaceName={},MethodName={},Resposne={},SpendTime={} ms", invocation.getInvoker().getInterface().getName(), invocation.getMethodName(), JSON.toJSONString(new Object[]{result.getValue()}), elapsed); } //返回结果响应数据 return result; }}新建类-自定义服务提供者日志拦截器 ...

June 22, 2020 · 1 min · jiezi

dubbo学习的问题

1 tomcat安装dubbo管理控制台,将dubbo-admin的war包放到webapps中,在bin文件夹下启动tomacatorg.apache.catalina.core.StandardService.initInternal Failed to initialize connector此时需要改conf下server.xml中tomcat的端口2 log4j开发阶段设置成debug 线上阶段设置成info

June 13, 2020 · 1 min · jiezi

Dubbo和SpringCloud微服务架构对比

一、为什么要使用微服务? 微服务提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合。今天我们来了解下业内主要的微服务框架:Dubbo 和 Spring Cloud 微服务主要的优势 降低复杂度将原来耦合在一起的复杂业务拆分为单个服务,规避了原本复杂度无止境的积累。每一个微服务专注于单一功能,并通过定义良好的接口清晰表述服务边界。 每个服务开发者只专注服务本身,通过使用缓存、DAL 等各种技术手段来提升系统的性能,而对于消费方来说完全透明。 可独立部署 由于微服务具备独立的运行进程,所以每个微服务可以独立部署。当业务迭代时只需要发布相关服务的迭代即可,降低了测试的工作量同时也降低了服务发布的风险。 容错 在微服务架构下,当某一组件发生故障时,故障会被隔离在单个服务中。比如通过限流、熔断等方式降低错误导致的危害,保障核心业务正常运行。 扩展 单块架构应用也可以实现横向扩展,就是将整个应用完整的复制到不同的节点。当应用的不同组件在扩展需求上存在差异时,微服务架构便体现出其灵活性, 因为每个服务可以根据实际需求独立进行扩展。 微服务的核心要素在于服务的发现、注册、路由、熔断、降级、分布式配置!! 二、Dubbo 和 SpringCloud 的比较 1、Dubbo 核心部件Provider:暴露服务的提供方,可以通过 jar 或者容器的方式启动服务。Consumer:调用远程服务的服务消费方。 Registry:服务注册中心和发现中心。 Monitor:统计服务和调用次数,调用时间监控中心,Dubbo 的控制台页面中可以显示。 Container:服务运行的容器。 Spring Cloud总体架构Service Provider: 暴露服务的提供方。Service Consumer:调用远程服务的服务消费方。 EureKa Server: 服务注册中心和服务发现中心。 从整体架构上来看,二者模式接近,都需要服务提供方,注册中心,服务消费方。2、微服务架构核心要素 Dubbo 只是实现了服务治理,而 Spring Cloud 子项目分别覆盖了微服务架构下的众多部件,服务治理只是其中的一个方面。Dubbo 提供了各种 Filter,对于上述中没有的要素,可以通过扩展 Filter 来完善: a. 分布式配置:可以使用淘宝的 diamond、百度的 disconf 来实现分布式配置管理。 b. 服务跟踪:可以使用京东开源的 Hydra,或者扩展 Filter 用 Zippin 来做服务跟踪。 c. 批量任务:可以使用当当开源的 Elastic-Job、tbschedule。 从核心要素来看,Spring Cloud 更胜一筹,在开发过程中只要整合 Spring Cloud 的子项目就可以顺利完成各种组件的融合,而 Dubbo 却需要通过实现各种 Filter 来做定制,开发成本以及技术难度略高。 ...

November 4, 2019 · 2 min · jiezi

dubbospringboot的autoconfigure示例找不到服务的解决办法

本示例基于dubbo-spring-boot-project 2.7.3版本,可能会根据新版的发布而过时,阅读时请注意。关于dubbo在spring-boot中该如何使用,网上有很多例子,但因为时间跨度太久,很多例子已经过时了,一切还是要以官方的例子为准。 在github上搜索dubbo和spring-boot整合的项目的话,可能会找到下面两个,分别是 alibaba / dubbo-spring-boot-starterapache / dubbo-spring-boot-project第一个项目,已经归档了(archived),不再更新,所以我们要以第二个项目为准,千万别搞错了。 打开第二个项目的主页,就开始浏览README中的Getting Started章节。 这个章节给我们展示了一个无注册中心(dubbo.registry.address=N/A)的例子。 但是它却跑不起来,消费者启动后无法找到service provider,报Not found exported service的错误。 解决办法如下:需要在消费者Reference服务提供者时,url里指明version。其实version已经指明了,但不知为何还要在url里再次指定。 // @Reference(version = "1.0.0", url = "dubbo://127.0.0.1:12345") @Reference(version = "1.0.0", url = "dubbo://127.0.0.1:12345?version=1.0.0") private DemoService demoService;另外,Getting Started中的pom依赖也比较简略,省略了spring-boot原本需要的依赖,您可以参考我这个修复版里pom中的依赖。 源码地址:https://github.com/kongxiangxin/dubbo-spring-boot-samples

October 7, 2019 · 1 min · jiezi

10Dubbo的服务引入

1、Dubbo服务引入简介前两篇文章 Dubbo的服务导出1之导出到本地、Dubbo的服务导出2之导出到远程 详细分析了服务导出的过程,本篇文章我们趁热打铁,继续分析服务引用过程。在 Dubbo 中,我们可以通过两种方式引用远程服务。第一种是使用服务直连的方式引用服务,第二种方式是基于注册中心进行引用。服务直连的方式仅适合在调试或测试服务的场景下使用,不适合在线上环境使用。因此,本文我将重点分析通过注册中心引用服务的过程。从注册中心中获取服务配置只是服务引用过程中的一环,除此之外,服务消费者还需要经历 Invoker 创建、代理类创建等步骤。这些步骤,将在后续章节中一一进行分析。 2、服务引用原理Dubbo 服务引用的时机有两个,第一个是在Spring 容器调用 ReferenceBean的afterPropertiesSet方法时引用服务,第二个是在 ReferenceBean对应的服务被注入到其他类中时引用。这两个引用服务的时机区别在于,第一个是饿汉式的,第二个是懒汉式的。默认情况下,Dubbo使用懒汉式引用服务。如果需要使用饿汉式,可通过配置 <dubbo:reference> 的 init 属性开启。下面我们按照 Dubbo 默认配置进行分析,整个分析过程从 ReferenceBean 的 getObject 方法开始。当我们的服务被注入到其他类中时,Spring 会第一时间调用 getObject 方法,并由该方法执行服务引用逻辑。按照惯例,在进行具体工作之前,需先进行配置检查与收集工作。接着根据收集到的信息决定服务用的方式,有三种,第一种是引用本地 (JVM) 服务,第二是通过直连方式引用远程服务,第三是通过注册中心引用远程服务。不管是哪种引用方式,最后都会得到一个 Invoker 实例。如果有多个注册中心,多个服务提供者,这个时候会得到一组 Invoker 实例,此时需要通过集群管理类 Cluster 将多个 Invoker 合并成一个实例。合并后的 Invoker 实例已经具备调用本地或远程服务的能力了,但并不能将此实例暴露给用户使用,这会对用户业务代码造成侵入。此时框架还需要通过代理工厂类 (ProxyFactory) 为服务接口生成代理类,并让代理类去调用 Invoker 逻辑。避免了 Dubbo 框架代码对业务代码的侵入,同时也让框架更容易使用。以上就是服务引用的大致原理,下面我们深入到代码中,详细分析服务引用细节。 3、源码分析3.1、配置检查与收集// ReferenceBean实现了InitializingBean接口,因此在Spring容器初始化时会调用该方法,这里也对应上述第一个引用时机// 默认不会走这里的引用服务方法,需要配置init=true@Overridepublic void afterPropertiesSet() throws Exception { // 删除一些代码 // Dubbo服务引用的时机有两个,第一个是在Spring容器调用ReferenceBean的afterPropertiesSet // 方法时引用服务,第二个是在ReferenceBean对应的服务被注入到其他类中时引用.这两个引用服务的时机 // 区别在于,第一个是饿汉式的,第二个是懒汉式的.默认情况下,Dubbo使用懒汉式引用服务.如果需要使用 // 饿汉式,可通过配置<dubbo:reference>的init属性开启. Boolean b = isInit(); if (b == null && getConsumer() != null) { b = getConsumer().isInit(); } if (b != null && b.booleanValue()) { getObject(); }}/** * 整个分析过程从ReferenceBean的getObject方法开始.当我们的服务被注入到其他类中时, * Spring会第一时间调用getObject方法,并由该方法执行服务引用逻辑 */@Overridepublic Object getObject() throws Exception { return get();}public synchronized T get() { if (destroyed) { throw new IllegalStateException("Already destroyed!"); } // 检测ref是否为空,为空则通过init方法创建 if (ref == null) { // init方法主要用于处理配置,以及调用createProxy生成代理类 init(); } return ref;}init方法比较长,为了排版,分成几段,并删除异常捕捉、日志记录等代码,核心代码是ref = createProxy(map)。 ...

October 6, 2019 · 5 min · jiezi

9Dubbo的SPI机制分析5Activate详解

1、Dubbo的@Activate例子@SPIpublic interface ActivateExt { String echo(String msg);}@Activate(group = {"default"})public class ActivateExtImpl1 implements ActivateExt { @Override public String echo(String msg) { return msg; }}@Activate(group = {"group1", "group2"})public class GroupActivateExtImpl implements ActivateExt { @Override public String echo(String msg) { return msg; }}@Activate(order = 2, group = {"order"})public class OrderActivateExtImpl1 implements ActivateExt { @Override public String echo(String msg) { return msg; }}@Activate(order = 1, group = {"order"})public class OrderActivateExtImpl2 implements ActivateExt { @Override public String echo(String msg) { return msg; }}@Activate(value = {"value"}, group = {"group"})public class ValueActivateExtImpl implements ActivateExt { @Override public String echo(String msg) { return msg; }}在resources下新建META-INF/dubbo/internal文件夹,新建com.alibaba.dubbo.demo.provider.activate.ActivateExt,即接口的全限定名,文件内容为: ...

October 6, 2019 · 3 min · jiezi

Dubbo注册中心

1.注册中心的作用利用注册中心,服务提供者可以动态添加删除服务,服务消费者在收到更新通知后,可以拉取最新的服务从而实现同步。可以在注册中心实现统一配置,参数的动态调整可以自动通知到所有服务节点。 2.Dubbo四种注册中心实现Dubbo注册中心的实现在dubbo-registry模块。 2.1 ZooKeeper基于Zookeeper。ZooKeeper学习 2.1.1 Zookeeper注册中心数据结构 2.1.2 Zookeeper注册中心实现原理Zookeeper注册中心采用"事件通知" + “客户端拉取”的实现方式: 客户端在第一次连接注册中心的时候,会获取对应目录下的全量数据。客户端会在订阅的节点上注册一个watch,客户端与注册中心之间保持TCP长连接。当节点发生事务操作,节点的版本号发生改变,就会触发watch事件,推送数据给订阅方,订阅方收到通知之后,就会拉取对应目录下的数据。服务治理中心会订阅所有service层的数据,service被设置成"*",表示订阅全部。2.1.3 Zookeeper注册和取消注册//注册protected void doRegister(URL url) { try { //创建目录 zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true)); } catch (Throwable e) { throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e); }}//取消注册protected void doUnregister(URL url) { try { //删除目录 zkClient.delete(toUrlPath(url)); } catch (Throwable e) { throw new RpcException("Failed to unregister " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e); }}private String toUrlPath(URL url) { return toCategoryPath(url) + Constants.PATH_SEPARATOR + URL.encode(url.toFullString());}//返回"/dubbo/接口名称/providers"private String toCategoryPath(URL url) { return toServicePath(url) + Constants.PATH_SEPARATOR + url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);}//返回"/dubbo/接口名称"private String toServicePath(URL url) { String name = url.getServiceInterface(); if (Constants.ANY_VALUE.equals(name)) { return toRootPath(); } return toRootDir() + URL.encode(name);}//返回"/"或者"/dubbo/"private String toRootDir() { if (root.equals(Constants.PATH_SEPARATOR)) { return root; } return root + Constants.PATH_SEPARATOR;}private String toRootPath() { return root;}private final static String DEFAULT_ROOT = "dubbo";private final ZookeeperClient zkClient;public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) { //省略n行代码 String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT); //添加前缀"/" if (!group.startsWith(Constants.PATH_SEPARATOR)) { group = Constants.PATH_SEPARATOR + group; } this.root = group; zkClient = zookeeperTransporter.connect(url); //省略n行代码}ZookeeperClient和ZookeeperTransporter都是接口,在Dubbo中有两种实现,一种是基于curator客户端的CuratorZookeeperClient和CuratorZookeeperTransporter;另一种是基于zkclient客户端的ZkclientZookeeperClient和ZkclientZookeeperTransporter。默认实现是curator。 ...

October 5, 2019 · 6 min · jiezi

8Dubbo中JavaAssist的WrappergetWrapper生成代理分析

1、getWrapper方法入口private void exportLocal(URL url) { if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) { URL local = URL.valueOf(url.toFullString()) .setProtocol(Constants.LOCAL_PROTOCOL) .setHost(LOCALHOST) .setPort(0); ServiceClassHolder.getInstance().pushServiceClass(getServiceClass(ref)); // 这里会调用proxyFactory的getInvoker方法,proxyFactory是自适应拓展对象,默认是JavassistProxyFactory // 所以这里会走到它的getInvoker方法里面 Exporter<?> exporter = protocol.export( proxyFactory.getInvoker(ref, (Class) interfaceClass, local)); exporters.add(exporter); }}// 我们先来看一下调用getInvoker时传递进来的几个参数具体是什么,见下图public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) { final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type); return new AbstractProxyInvoker<T>(proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable { return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); } };} ...

October 4, 2019 · 1 min · jiezi

Dubbo的三种使用方式

启动zookeeper使用的是zookeeper作为注册中心,在运行dubbo项目之前需要启动zookeeper。 xml实现xml实现是最常使用的一种方式,好处是可以通过配置文件配置注册中心,暴露协议和服务接口,开发人员不需要理会太多Dubbo框架的实现,专注业务逻辑。在公司的项目中使用的也是xml的方式,可以集中管理配置。在github上给出的dubbo-demo有例子。 github上的Dubbo项目 注解实现maven的依赖直接使用dubbo-demo的就行,代码实现如下: Api模块:公共的接口public interface AnnotationService { public void salHello(String name);}Provider:服务提供者服务接口的实现: import gdut.ff.api.AnnotationService;import org.apache.dubbo.config.annotation.Reference;import org.springframework.stereotype.Component;import gdut.ff.api.AnnotationService;import org.apache.dubbo.config.annotation.Service;import org.apache.dubbo.rpc.RpcContext;@Servicepublic class AnnotationServiceImpl implements AnnotationService { public void salHello(String name) { System.out.println(name + " from" + RpcContext.getContext().getRemoteAddress()); }}注意这里的@Service注解是org.apache.dubbo.config.annotation.Service,不然在扫描包的时候会扫描不到。 用注解实现xml的配置。 import org.apache.dubbo.config.ApplicationConfig;import org.apache.dubbo.config.ProtocolConfig;import org.apache.dubbo.config.ProviderConfig;import org.apache.dubbo.config.RegistryConfig;import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configuration@EnableDubbo(scanBasePackages = "gdut.ff.provider")public class ProviderConfiguration { @Bean public ProviderConfig providerConfig() { return new ProviderConfig(); } @Bean public ApplicationConfig applicationConfig() { ApplicationConfig applicationConfig = new ApplicationConfig(); applicationConfig.setName("annotation-provider"); return applicationConfig; } //配置Zookeeper注册中心 @Bean public RegistryConfig registryConfig() { RegistryConfig registryConfig = new RegistryConfig(); registryConfig.setProtocol("zookeeper"); registryConfig.setAddress("127.0.0.1"); registryConfig.setPort(2181); return registryConfig; } //使用Dubbo协议,20880端口监听服务 @Bean public ProtocolConfig protocolConfig() { ProtocolConfig protocolConfig = new ProtocolConfig(); protocolConfig.setName("dubbo"); protocolConfig.setPort(20880); return protocolConfig; }}启动的时候,会调用ProviderConfiguration类,根据配置的scanBasePackages扫描对应包下的带有@Service注解的类,并进行注册。 ...

October 2, 2019 · 2 min · jiezi

7Dubbo的服务导出2之导出到远程

1、暴露服务到远程上一篇文章分析了暴露服务到本地,6、Dubbo的服务导出1之导出到本地。接下来分析暴露服务到远程。 if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) { if (registryURLs != null && !registryURLs.isEmpty()) { for (URL registryURL : registryURLs) { // 添加动态参数,此动态参数是决定Zookeeper创建临时节点还是持久节点 url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY)); String proxy = url.getParameter(Constants.PROXY_KEY); if (StringUtils.isNotEmpty(proxy)) { registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy); } // 步骤1)创建Invoker,这里创建Invoker逻辑和上面一样 Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded( Constants.EXPORT_KEY, url.toFullString())); DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); // 步骤2)暴露服务 Exporter<?> exporter = ServiceConfig.protocol.export(wrapperInvoker); exporters.add(exporter); } }} /** * 下面分析步骤2,该方法两大核心逻辑,导出服务和注册服务,服务注册下篇文章分析 */@Overridepublic <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException { // 1. 导出服务,export invoker,本篇文章仅分析第一步导出服务到远程 final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker); // zookeeper://10.101.99.127:2181/com.alibaba.dubbo.registry.RegistryService // ?application=demo-provider&dubbo=2.0.2 URL registryUrl = getRegistryUrl(originInvoker); // registry provider,默认返回ZookeeperRegistry实例 final Registry registry = getRegistry(originInvoker); // dubbo://172.22.213.93:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true // &application=demo-provider&default.server=netty4&dubbo=2.0.2&generic=false // &interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=8140&side=provider final URL registeredProviderUrl = getRegisteredProviderUrl(originInvoker); // 不配置的话默认返回true boolean register = registeredProviderUrl.getParameter("register", true); ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registeredProviderUrl); // 2.注册服务,这篇文章已经比较长了,决定将步骤2和步骤3新起一篇文章分析,服务暴露之后需要注册到注册中心 if (register) { register(registryUrl, registeredProviderUrl); ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true); } // 3.数据更新订阅 final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registeredProviderUrl); final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker); overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener); registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener); return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registeredProviderUrl);} private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker) { String key = getCacheKey(originInvoker); ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key); if (exporter == null) { synchronized (bounds) { exporter = (ExporterChangeableWrapper<T>) bounds.get(key); if (exporter == null) { final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker)); // 调用protocol的export方法导出服务,默认是采用Dubbo协议,对应DubboProtocol的export方法 // 但是这里protocol.export()并不是先走DubboProtocol的export方法,而是先走 // ProtocolListenerWrapper的wrapper方法 // 因为ProtocolListenerWrapper对DubboProtocol做了一层包装,具体参考 // https://segmentfault.com/a/1190000020387196,核心方法protocal.export() exporter = new ExporterChangeableWrapper<T>( (Exporter<T>) protocol.export(invokerDelegete), originInvoker); bounds.put(key, exporter); } } } return exporter;}/** * 上述核心方法protocol.export()会先走到ProtocolListenerWrapper的export方法,该方法是在服务暴露上做了 监听器功能的增强,也就是加上了监听器 */@Overridepublic <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { // 如果是注册中心,则暴露该invoker if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) { return protocol.export(invoker); } // 创建一个暴露者监听器包装类对象,暴露服务时这里的protocol是ProtocolFilterWrapper,这里用到了 // Wrapper包装原有的DubboProtocol,可以参考https://segmentfault.com/a/1190000020387196 return new ListenerExporterWrapper<T>(protocol.export(invoker), Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class) .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));} /** * ProtocolFilterWrapper的export方法,该方法是在服务暴露上做了过滤器链的增强,也就是加上了过滤器 */@Overridepublic <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { // 如果是注册中心,则直接暴露服务 if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) { return protocol.export(invoker); } // 服务提供侧暴露服务,这里通过buildInvokerChain形成了过滤器链 return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));}/** * 该方法就是创建带Filter链的Invoker对象,倒序的把每一个过滤器串连起来,形成一个invoker */private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) { Invoker<T> last = invoker; // 获得过滤器的所有扩展实现类实例集合 List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class). getActivateExtension(invoker.getUrl(), key, group); if (!filters.isEmpty()) { // 从最后一个过滤器开始循环,创建一个带有过滤器链的invoker对象 for (int i = filters.size() - 1; i >= 0; i--) { final Filter filter = filters.get(i); final Invoker<T> next = last; last = new Invoker<T>() { @Override public Class<T> getInterface() { return invoker.getInterface(); } @Override public URL getUrl() { return invoker.getUrl(); } @Override public boolean isAvailable() { return invoker.isAvailable(); } // 关键在这里,调用下一个filter代表的invoker,把每一个过滤器串起来 @Override public Result invoke(Invocation invocation) throws RpcException { return filter.invoke(next, invocation); } @Override public void destroy() { invoker.destroy(); } @Override public String toString() { return invoker.toString(); } }; } } return last;}// 经过两个Wrapper的export方法包装之后,走到DubboProtocol的export方法,这里是核心方法public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { // url形如dubbo://172.22.213.93:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true // &application=demo-provider&bind.ip=172.22.213.93&bind.port=20880&dubbo=2.0.2&generic=false // /&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=648&qos.port=22222 // &side=provider&timestamp=1569585915258 URL url = invoker.getUrl(); // 获取服务标识,理解成服务坐标也行,由服务组名,服务名,服务版本号以及端口组成,key形如 // com.alibaba.dubbo.demo.DemoService:20880 String key = serviceKey(url); // 创建DubboExporter DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap); // 将<key, exporter>键值对放入缓存中 exporterMap.put(key, exporter); // 本地存根相关代码, export an stub service for dispatching event // 删除,暂时还没有分析本地存根相关 // 启动服务器,重点关注这里 openServer(url); optimizeSerialization(url); return exporter;} ...

September 30, 2019 · 7 min · jiezi

dubbo设置mock返回统一的自定义对象

Mock在dubbo中,Mock只有拦截到RpcException时才会启用,属于异常容错方式的一种。 问题描述在开发微服务应用中,我的所有的Rpc接口都有一个统一的封装:ApiResponse。如果某个微服务未启动或者出现故障的时候,其他服务调用这个服务的接口时,就会抛异常,我希望设置为不抛异常,而是同样返回一个ApiResponse。 处理方式在配置文件中,添加如下配置:dubbo.consumer.mock=return {"code":300,"message":"fail"}将mock设置为return+空格+对象的json字符串即可 分析在com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker中,有以下一段代码,如果设置了mock,则会根据设置的mock来执行不同的操作: @Override public Result invoke(Invocation invocation) throws RpcException { Result result = null; String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim(); if (value.length() == 0 || value.equalsIgnoreCase("false")) { //no mock result = this.invoker.invoke(invocation); } else if (value.startsWith("force")) { if (logger.isWarnEnabled()) { logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl()); } //force:direct mock result = doMockInvoke(invocation, null); } else { //fail-mock try { result = this.invoker.invoke(invocation); } catch (RpcException e) { if (e.isBiz()) { throw e; } else { if (logger.isWarnEnabled()) { logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e); } result = doMockInvoke(invocation, e); } } } return result; }对设置的mock的处理是在com.alibaba.dubbo.rpc.support.MockInvoker.invoke(Invocation invocation)中,如果设置的mock是以return开始的,则会调用下面的方法: ...

September 30, 2019 · 2 min · jiezi

Dubbo-Spring-Cloud-之-HTTP-实战

上一篇文章《Spring Cloud Alibaba | Dubbo 与 Spring Cloud 完美结合》我们介绍了Dubbo Spring Cloud的基本使用,使用的服务中心为Spring Cloud Alibaba提供的Nacos,Dubbo内部提供了基于Dubbo的RPC调用,同时,Dubbo Spring Cloud在整合了Spring Cloud之后,可以直接提供HTTP接口,同Spring Cloud无缝衔接,直接支持Feign、RestTemplate等方式的远程调用,在提供HTTP服务的同时可以提供Dubbo服务。Dubbo Spring Cloud支持HTTP远程调用级大的方便了我们的对接外部系统,无需对Dubbo再做二次封装。 1. 案例实战接下来,我们通过一个简单的案例来介绍一下Dubbo Spring Cloud通过注解的方式是如何同时提供Dubbo服务和HTTP服务的。 1.1 创建父工程dubbo-spring-cloud-http工程依赖pom.xml如下: 代码清单:Alibaba/dubbo-spring-cloud-http/pom.xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Cloud Nacos Service Discovery --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies>1.2 创建子工程dubbo_provider_web,服务提供方工程依赖pom.xml如下: 代码清单:Alibaba/dubbo-spring-cloud-http/dubbo_provider_web/pom.xml <dependencies> <!-- API --> <dependency> <groupId>com.springcloud</groupId> <artifactId>dubbo_api</artifactId> <version>${project.version}</version> </dependency> <!-- Dubbo Spring Cloud Starter --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId> </dependency></dependencies>这里引入Dubbo Spring Cloud工具包和Dubbo API依赖包。 ...

September 20, 2019 · 2 min · jiezi

聊聊dubbo的DubboComponentScanRegistrar

序本文主要研究一下dubbo的DubboComponentScanRegistrar DubboComponentScanRegistrardubbo-2.7.3/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrar.java public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { Set<String> packagesToScan = getPackagesToScan(importingClassMetadata); registerServiceAnnotationBeanPostProcessor(packagesToScan, registry); registerReferenceAnnotationBeanPostProcessor(registry); } /** * Registers {@link ServiceAnnotationBeanPostProcessor} * * @param packagesToScan packages to scan without resolving placeholders * @param registry {@link BeanDefinitionRegistry} * @since 2.5.8 */ private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) { BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class); builder.addConstructorArgValue(packagesToScan); builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry); } /** * Registers {@link ReferenceAnnotationBeanPostProcessor} into {@link BeanFactory} * * @param registry {@link BeanDefinitionRegistry} */ private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) { // Register @Reference Annotation Bean Processor BeanRegistrar.registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); } private Set<String> getPackagesToScan(AnnotationMetadata metadata) { AnnotationAttributes attributes = AnnotationAttributes.fromMap( metadata.getAnnotationAttributes(DubboComponentScan.class.getName())); String[] basePackages = attributes.getStringArray("basePackages"); Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses"); String[] value = attributes.getStringArray("value"); // Appends value array attributes Set<String> packagesToScan = new LinkedHashSet<String>(Arrays.asList(value)); packagesToScan.addAll(Arrays.asList(basePackages)); for (Class<?> basePackageClass : basePackageClasses) { packagesToScan.add(ClassUtils.getPackageName(basePackageClass)); } if (packagesToScan.isEmpty()) { return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName())); } return packagesToScan; }}DubboComponentScanRegistrar实现了ImportBeanDefinitionRegistrar接口定义的registerBeanDefinitions方法;它首先通过getPackagesToScan方法从AnnotationMetadata读取要扫描的包,然后再执行registerServiceAnnotationBeanPostProcessor、registerReferenceAnnotationBeanPostProcessor方法getPackagesToScan方法读取DubboComponentScan注解信息,获取要扫描的包;registerServiceAnnotationBeanPostProcessor方法则是通过BeanDefinitionReaderUtils.registerWithGeneratedName注册ServiceAnnotationBeanPostProcessorregisterReferenceAnnotationBeanPostProcessor方法则是通过BeanRegistrar.registerInfrastructureBean注册ReferenceAnnotationBeanPostProcessorDubboComponentScanRegistrarTestdubbo-2.7.3/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java ...

August 28, 2019 · 2 min · jiezi

聊聊dubbo的AccessLogFilter

序本文主要研究一下dubbo的AccessLogFilter AccessLogFilterdubbo-2.7.3/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/AccessLogFilter.java @Activate(group = PROVIDER, value = ACCESS_LOG_KEY)public class AccessLogFilter implements Filter { private static final Logger logger = LoggerFactory.getLogger(AccessLogFilter.class); private static final String ACCESS_LOG_KEY = "dubbo.accesslog"; private static final int LOG_MAX_BUFFER = 5000; private static final long LOG_OUTPUT_INTERVAL = 5000; private static final String FILE_DATE_FORMAT = "yyyyMMdd"; // It's safe to declare it as singleton since it runs on single thread only private static final DateFormat FILE_NAME_FORMATTER = new SimpleDateFormat(FILE_DATE_FORMAT); private static final Map<String, Set<AccessLogData>> LOG_ENTRIES = new ConcurrentHashMap<String, Set<AccessLogData>>(); private static final ScheduledExecutorService LOG_SCHEDULED = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("Dubbo-Access-Log", true)); /** * Default constructor initialize demon thread for writing into access log file with names with access log key * defined in url <b>accesslog</b> */ public AccessLogFilter() { LOG_SCHEDULED.scheduleWithFixedDelay(this::writeLogToFile, LOG_OUTPUT_INTERVAL, LOG_OUTPUT_INTERVAL, TimeUnit.MILLISECONDS); } /** * This method logs the access log for service method invocation call. * * @param invoker service * @param inv Invocation service method. * @return Result from service method. * @throws RpcException */ @Override public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException { try { String accessLogKey = invoker.getUrl().getParameter(ACCESS_LOG_KEY); if (ConfigUtils.isNotEmpty(accessLogKey)) { AccessLogData logData = buildAccessLogData(invoker, inv); log(accessLogKey, logData); } } catch (Throwable t) { logger.warn("Exception in AccessLogFilter of service(" + invoker + " -> " + inv + ")", t); } return invoker.invoke(inv); } private void log(String accessLog, AccessLogData accessLogData) { Set<AccessLogData> logSet = LOG_ENTRIES.computeIfAbsent(accessLog, k -> new ConcurrentHashSet<>()); if (logSet.size() < LOG_MAX_BUFFER) { logSet.add(accessLogData); } else { //TODO we needs use force writing to file so that buffer gets clear and new log can be written. logger.warn("AccessLog buffer is full skipping buffer "); } } private void writeLogToFile() { if (!LOG_ENTRIES.isEmpty()) { for (Map.Entry<String, Set<AccessLogData>> entry : LOG_ENTRIES.entrySet()) { try { String accessLog = entry.getKey(); Set<AccessLogData> logSet = entry.getValue(); if (ConfigUtils.isDefault(accessLog)) { processWithServiceLogger(logSet); } else { File file = new File(accessLog); createIfLogDirAbsent(file); if (logger.isDebugEnabled()) { logger.debug("Append log to " + accessLog); } renameFile(file); processWithAccessKeyLogger(logSet, file); } } catch (Exception e) { logger.error(e.getMessage(), e); } } } } private void processWithAccessKeyLogger(Set<AccessLogData> logSet, File file) throws IOException { try (FileWriter writer = new FileWriter(file, true)) { for (Iterator<AccessLogData> iterator = logSet.iterator(); iterator.hasNext(); iterator.remove()) { writer.write(iterator.next().getLogMessage()); writer.write("\r\n"); } writer.flush(); } } private AccessLogData buildAccessLogData(Invoker<?> invoker, Invocation inv) { RpcContext context = RpcContext.getContext(); AccessLogData logData = AccessLogData.newLogData(); logData.setServiceName(invoker.getInterface().getName()); logData.setMethodName(inv.getMethodName()); logData.setVersion(invoker.getUrl().getParameter(VERSION_KEY)); logData.setGroup(invoker.getUrl().getParameter(GROUP_KEY)); logData.setInvocationTime(new Date()); logData.setTypes(inv.getParameterTypes()); logData.setArguments(inv.getArguments()); return logData; } private void processWithServiceLogger(Set<AccessLogData> logSet) { for (Iterator<AccessLogData> iterator = logSet.iterator(); iterator.hasNext(); iterator.remove()) { AccessLogData logData = iterator.next(); LoggerFactory.getLogger(ACCESS_LOG_KEY + "." + logData.getServiceName()).info(logData.getLogMessage()); } } private void createIfLogDirAbsent(File file) { File dir = file.getParentFile(); if (null != dir && !dir.exists()) { dir.mkdirs(); } } private void renameFile(File file) { if (file.exists()) { String now = FILE_NAME_FORMATTER.format(new Date()); String last = FILE_NAME_FORMATTER.format(new Date(file.lastModified())); if (!now.equals(last)) { File archive = new File(file.getAbsolutePath() + "." + last); file.renameTo(archive); } } }}AccessLogFilter实现了org.apache.dubbo.rpc.Filter接口,其构造器注册了一个定时任务,每隔LOG_OUTPUT_INTERVAL执行一次writeLogToFileinvoke方法从invoker.getUrl()获取accessLogKey,如果不为空则使用buildAccessLogData构建AccessLogData,然后放入到LOG_ENTRIES中,如果超出LOG_MAX_BUFFER则对其并打印warn日志writeLogToFile方法遍历LOG_ENTRIES,将AccessLogData写入文件,如果是default的则使用processWithServiceLogger,否则使用processWithAccessKeyLogger方法AccessLogFilterTestdubbo-2.7.3/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/AccessLogFilterTest.java ...

August 21, 2019 · 4 min · jiezi

聊聊DubboDefaultPropertiesEnvironmentPostProcessor

序本文主要研究一下DubboDefaultPropertiesEnvironmentPostProcessor DubboDefaultPropertiesEnvironmentPostProcessordubbo-spring-boot-project-2.7.3/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessor.java public class DubboDefaultPropertiesEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { /** * The name of default {@link PropertySource} defined in SpringApplication#configurePropertySources method. */ public static final String PROPERTY_SOURCE_NAME = "defaultProperties"; /** * The property name of "spring.main.allow-bean-definition-overriding". * Please refer to: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.1-Release-Notes#bean-overriding */ public static final String ALLOW_BEAN_DEFINITION_OVERRIDING_PROPERTY = "spring.main.allow-bean-definition-overriding"; @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { MutablePropertySources propertySources = environment.getPropertySources(); Map<String, Object> defaultProperties = createDefaultProperties(environment); if (!CollectionUtils.isEmpty(defaultProperties)) { addOrReplace(propertySources, defaultProperties); } } @Override public int getOrder() { return LOWEST_PRECEDENCE; } private Map<String, Object> createDefaultProperties(ConfigurableEnvironment environment) { Map<String, Object> defaultProperties = new HashMap<String, Object>(); setDubboApplicationNameProperty(environment, defaultProperties); setDubboConfigMultipleProperty(defaultProperties); setDubboApplicationQosEnableProperty(defaultProperties); setAllowBeanDefinitionOverriding(defaultProperties); return defaultProperties; } private void setDubboApplicationNameProperty(Environment environment, Map<String, Object> defaultProperties) { String springApplicationName = environment.getProperty(SPRING_APPLICATION_NAME_PROPERTY); if (StringUtils.hasLength(springApplicationName) && !environment.containsProperty(DUBBO_APPLICATION_NAME_PROPERTY)) { defaultProperties.put(DUBBO_APPLICATION_NAME_PROPERTY, springApplicationName); } } private void setDubboConfigMultipleProperty(Map<String, Object> defaultProperties) { defaultProperties.put(DUBBO_CONFIG_MULTIPLE_PROPERTY, Boolean.TRUE.toString()); } private void setDubboApplicationQosEnableProperty(Map<String, Object> defaultProperties) { defaultProperties.put(DUBBO_APPLICATION_QOS_ENABLE_PROPERTY, Boolean.FALSE.toString()); } /** * Set {@link #ALLOW_BEAN_DEFINITION_OVERRIDING_PROPERTY "spring.main.allow-bean-definition-overriding"} to be * <code>true</code> as default. * * @param defaultProperties the default {@link Properties properties} * @see #ALLOW_BEAN_DEFINITION_OVERRIDING_PROPERTY * @since 2.7.1 */ private void setAllowBeanDefinitionOverriding(Map<String, Object> defaultProperties) { defaultProperties.put(ALLOW_BEAN_DEFINITION_OVERRIDING_PROPERTY, Boolean.TRUE.toString()); } /** * Copy from BusEnvironmentPostProcessor#addOrReplace(MutablePropertySources, Map) * * @param propertySources {@link MutablePropertySources} * @param map Default Dubbo Properties */ private void addOrReplace(MutablePropertySources propertySources, Map<String, Object> map) { MapPropertySource target = null; if (propertySources.contains(PROPERTY_SOURCE_NAME)) { PropertySource<?> source = propertySources.get(PROPERTY_SOURCE_NAME); if (source instanceof MapPropertySource) { target = (MapPropertySource) source; for (String key : map.keySet()) { if (!target.containsProperty(key)) { target.getSource().put(key, map.get(key)); } } } } if (target == null) { target = new MapPropertySource(PROPERTY_SOURCE_NAME, map); } if (!propertySources.contains(PROPERTY_SOURCE_NAME)) { propertySources.addLast(target); } }}DubboDefaultPropertiesEnvironmentPostProcessor实现了EnvironmentPostProcessor, Ordered接口;postProcessEnvironment方法首先从environment获取MutablePropertySources,然后通过createDefaultProperties创建默认配置defaultProperties(这里默认设置了DUBBO_APPLICATION_NAME_PROPERTY为springApplicationName、DUBBO_CONFIG_MULTIPLE_PROPERTY为true、DUBBO_APPLICATION_QOS_ENABLE_PROPERTY为false),最后通过addOrReplace方法把defaultProperties覆盖到propertySources;getOrder方法返回的是LOWEST_PRECEDENCEDubboDefaultPropertiesEnvironmentPostProcessorTestdubbo-spring-boot-project-2.7.3/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java ...

August 20, 2019 · 3 min · jiezi

聊聊dubbo的DubboApplicationContextInitializer

序本文主要研究一下dubbo的DubboApplicationContextInitializer DubboApplicationContextInitializerdubbo-spring-boot-project-2.7.3/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/context/DubboApplicationContextInitializer.java public class DubboApplicationContextInitializer implements ApplicationContextInitializer, Ordered { @Override public void initialize(ConfigurableApplicationContext applicationContext) { overrideBeanDefinitions(applicationContext); } private void overrideBeanDefinitions(ConfigurableApplicationContext applicationContext) { applicationContext.addBeanFactoryPostProcessor(new OverrideBeanDefinitionRegistryPostProcessor()); applicationContext.addBeanFactoryPostProcessor(new DubboConfigBeanDefinitionConflictProcessor()); } @Override public int getOrder() { return HIGHEST_PRECEDENCE; }}DubboApplicationContextInitializer实现了ApplicationContextInitializer, Ordered接口,initialize方法执行overrideBeanDefinitions,它往applicationContext添加了OverrideBeanDefinitionRegistryPostProcessor、DubboConfigBeanDefinitionConflictProcessor;getOrder返回的是HIGHEST_PRECEDENCEOverrideBeanDefinitionRegistryPostProcessordubbo-spring-boot-project-2.7.3/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/beans/factory/config/OverrideBeanDefinitionRegistryPostProcessor.java public class OverrideBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { registerInfrastructureBean(registry, BEAN_NAME, DubboConfigBeanCustomizer.class); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { }}OverrideBeanDefinitionRegistryPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,其postProcessBeanDefinitionRegistry方法调用了BeanRegistrar.registerInfrastructureBean方法注册DubboConfigBeanCustomizerBeanRegistrardubbo-2.7.3-sources.jar!/org/apache/dubbo/config/spring/util/BeanRegistrar.java public class BeanRegistrar { /** * Register Infrastructure Bean * * @param beanDefinitionRegistry {@link BeanDefinitionRegistry} * @param beanType the type of bean * @param beanName the name of bean */ public static void registerInfrastructureBean(BeanDefinitionRegistry beanDefinitionRegistry, String beanName, Class<?> beanType) { if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) { RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition); } }}registerInfrastructureBean在beanDefinitionRegistry没有该beanDefinition的情况下会注册BeanDefinition.ROLE_INFRASTRUCTURE的beanDubboConfigBeanCustomizerdubbo-spring-boot-project-2.7.3/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/beans/factory/config/DubboConfigBeanCustomizer.java ...

August 18, 2019 · 2 min · jiezi

手撕面试官系列三-微服务架构面试题DubboSpring-BootSpring-Cloud

直接进入主题Dubbo(面试题+答案领取方式见个人主页) Dubbo 中 中 zookeeper 做注册中心,如果注册中心集群都挂掉,发布者和订阅者之间还能通信么?dubbo 服务负载均衡策略?Dubbo 在安全机制方面是如何解决的dubbo 连接注册中心和直连的区别dubbo 服务集群配置(集群容错模式)dubbo 通信协议 dubbo 协议为什么要消费者比提供者个数多dubbo 通信协议 dubbo 协议为什么不能传大包dubbo 通信协议 dubbo 协议为什么采用异步单一长连接dubbo 通信协议 dubbo 协议适用范围和适用场景RMI 协议Hessian 协议httpWebserviceThrifSpring Boot 什么是 Spring Boot?Spring Boot 有哪些优点?什么是 JavaConfig?如何重新加载 Spring Boot 上的更改,而无需重新启动服务器?Spring Boot 中的监视器是什么?如何在 Spring Boot 中禁用 Actuator 端点安全性?如何在自定义端口上运行 Spring Boot 应用程序?什么是 YAML?如何实现 Spring Boot 应用程序的安全性?如何集成 Spring Boot 和 ActiveMQ?如何使用 Spring Boot 实现分页和排序?什么是 Swagger?你用 Spring Boot 实现了它吗?什么是 Spring Profiles?什么是 Spring Batch?什么是 FreeMarker 模板?如何使用 Spring Boot 实现异常处理?您使用了哪些 starter maven 依赖项?什么是 CSRF 攻击?什么是 WebSockets?什么是 AOP?什么是 Apache Kafka?我们如何监视所有 Spring Boot 微服务?Spring Cloud ...

July 12, 2019 · 1 min · jiezi

springboot中使用dubbo多注册中心的配置方法

在工作中遇到dubbo多注册中心的需求当前工程基于springboot 1.5.9.RELEASE dubbo 2.5.10团队已经熟悉使用properties + springboot starter 这种方法配置集成的框架 下面是dubbo 多注册中心在 application.properties中的配置方法: # 非常重要必须声明当前为多选方法dubbo.config.multiple=true# 注册中心1 命名为wallet# 默认注册中心dubbo.registries.wallet.default=truedubbo.registries.wallet.protocol=zookeeperdubbo.registries.wallet.client=zkclient# 注册中心2 命名为paydubbo.registries.pay.protocol=zookeeperdubbo.registries.pay.client=zkclient消费者引用注册中心pay中的接口,默认注册中心不用定义registry属性 @Reference(registry = "pay") private FukaAccountService fukaAccountService;生产者发布接口到注册中心pay,默认注册中心不用定义registry属性 @Service(registry = "pay") public class GetCardBalance extends ApiInvoker<APICardBalanceReq>{

July 9, 2019 · 1 min · jiezi

Dubbo-开发者日-720-深圳站这可能是微服务开发者们最关注的技术盛宴

亮点解读与 Apache Dubbo PMC 主席罗毅面对面交流。Apache Dubbo PMC 小马哥首次分享 Dubbo 2.7.4 新特性。中国人寿、平安银行资深专家现场分享 Duboo 在保险、金融业的实践。阿里巴巴微服务专家联袂就高可用、分布式事务等热点切磋技艺。报名线下活动:http://hdxu.cn/bpb1g 若您无法来现场 参与调研,有机会免费拿《码出高效,Java 开发手册》:http://alibabadeveloper.mikec... 预约线上直播:https://developer.aliyun.com/... 钉钉搜索群号 : 21973601,加入 3000+ 人的 Dubbo 开源讨论群

July 9, 2019 · 1 min · jiezi

聊聊dubbo的DubboSwaggerService

序本文主要研究一下dubbo的DubboSwaggerService DubboSwaggerServicedubbo-2.7.2/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/integration/swagger/DubboSwaggerService.java @Path("dubbo")@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})@Produces({MediaType.APPLICATION_JSON + "; " + "charset=UTF-8", MediaType.TEXT_XML + "; " + "charset=UTF-8"})public interface DubboSwaggerService { @GET @Path("swagger") public Response getListingJson(@Context Application app, @Context ServletConfig sc, @Context HttpHeaders headers, @Context UriInfo uriInfo) throws JsonProcessingException;}DubboSwaggerService定义了getListingJson方法DubboSwaggerApiListingResourcedubbo-2.7.2/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/integration/swagger/DubboSwaggerApiListingResource.java @Servicepublic class DubboSwaggerApiListingResource extends BaseApiListingResource implements DubboSwaggerService { @Context ServletContext context; @Override public Response getListingJson(Application app, ServletConfig sc, HttpHeaders headers, UriInfo uriInfo) throws JsonProcessingException { Response response = getListingJsonResponse(app, context, sc, headers, uriInfo); response.getHeaders().add("Access-Control-Allow-Origin", "*"); response.getHeaders().add("Access-Control-Allow-Headers", "x-requested-with, ssi-token"); response.getHeaders().add("Access-Control-Max-Age", "3600"); response.getHeaders().add("Access-Control-Allow-Methods","GET,POST,PUT,DELETE,OPTIONS"); return response; }}DubboSwaggerApiListingResource继承了swagger-jaxrs的BaseApiListingResource,同时实现了DubboSwaggerService接口;其实现的getListingJson方法首先调用父类的getListingJsonResponse获取response,然后往header里头添加了跨域设置实例dubbo-2.7.2/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/integration/swagger/DubboSwaggerApiListingResourceTest.java ...

July 7, 2019 · 1 min · jiezi

聊聊dubbo的CommandExecutor

序本文主要研究一下dubbo的CommandExecutor CommandExecutordubbo-2.7.2/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/CommandExecutor.java public interface CommandExecutor { /** * Execute one command and return the execution result * * @param commandContext command context * @return command execution result * @throws NoSuchCommandException */ String execute(CommandContext commandContext) throws NoSuchCommandException;}CommandExecutor定义了execute方法,其方法传入CommandContext参数CommandContextdubbo-2.7.2/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/CommandContext.java public class CommandContext { private String commandName; private String[] args; private Channel remote; private boolean isHttp; private Object originRequest; public CommandContext(String commandName) { this.commandName = commandName; } public CommandContext(String commandName, String[] args, boolean isHttp) { this.commandName = commandName; this.args = args; this.isHttp = isHttp; } public String getCommandName() { return commandName; } public void setCommandName(String commandName) { this.commandName = commandName; } public String[] getArgs() { return args; } public void setArgs(String[] args) { this.args = args; } public Channel getRemote() { return remote; } public void setRemote(Channel remote) { this.remote = remote; } public boolean isHttp() { return isHttp; } public void setHttp(boolean http) { isHttp = http; } public Object getOriginRequest() { return originRequest; } public void setOriginRequest(Object originRequest) { this.originRequest = originRequest; }}CommandContext定义了commandName、args、remote、isHttp、originRequest参数DefaultCommandExecutordubbo-2.7.2/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/DefaultCommandExecutor.java ...

July 6, 2019 · 1 min · jiezi

What一个-Dubbo-服务启动要两个小时

前言前几天在测试环境碰到一个非常奇怪的与 dubbo 相关的问题,事后我在网上搜索了一圈并没有发现类似的帖子或文章,于是便有了这篇。 希望对还未碰到或正在碰到的朋友有所帮助。 现象现象是这样的,有一天测试在测试环境重新部署一个 dubbo 应用的时候发现应用“启动不起来”。 但过几个小时候之后又能自己慢慢恢复,并能够对外提供 dubbo 服务。 但其实经过我后续排查发现刚开始其实并不是启动不起来,而是启动速度非常缓慢,所以当应用长时间启动后才会对外提供服务。 而这个速度慢到居然要花费 2 个小时。 导致的一个结果是测试完全不敢在测试环境发版验证了,每验证一个功能修复一个 bug 就得等上两个小时,这谁受得了????。 而且经过多次观察,确实每次都是花费两小时左右应用才能启动起来。尝试解决最后测试顶不住了,只能让我这个“事故报告撰写专家”来看看。 当我得知这个问题的现象时其实完全没当一回事: 都不用想,这不就是主线程阻塞了嘛,先看看是否在初始化的时候数据库、Zookeeper 之类的连不上导致阻塞了-------来之多次事故处理的经验告诉我。于是我把这事打回给测试让他先找运维排查下,不到万不得已不要影响我 Touch fish????。 第二天一早看到测试同学的微信头像跳动时我都已经准备接受又一句 “膜拜大佬????” 的回复时,却收到 “网络一切正常,没人动过,再不解决就要罢工了????”。 好吧,忽悠不过去了。 首先这类问题的排查方向应该不会错,就是主线程阻塞了,至于是啥导致的阻塞就不能像之前那样瞎猜了。 我将应用重启后用 jstack pid 将线程快照打印到终端,直接拉到最后看看 main 线程到底在干啥。 前几次的快照都是很正常: 加载 Spring ---->连接 Zookeeper ---> 连接 Redis,都是依次执行下来没有阻塞。 隔了一段后应用确实还没起来,我再次 jstack 后得到如下信息: 翻源码我一直等了十几分钟再多次 jstack 得到的快照得到的信息都是一样的。 如图所示可见主线程是卡在了 dubbo 的某个方法 ServiceConfig.java 的 303 行中。 于是我找到此处的源码: 简单来说这里的逻辑就是要获取本机的 IP 将其注册到 Zookeeper 中用于其他服务调用。 ...

July 5, 2019 · 1 min · jiezi

聊聊dubbo的MetadataReportService

序本文主要研究一下dubbo的MetadataReportService MetadataReportServicedubbo-2.7.2/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/integration/MetadataReportService.java public class MetadataReportService { protected final Logger logger = LoggerFactory.getLogger(getClass()); private static volatile MetadataReportService metadataReportService; private static Object lock = new Object(); private MetadataReportFactory metadataReportFactory = ExtensionLoader.getExtensionLoader(MetadataReportFactory.class).getAdaptiveExtension(); MetadataReport metadataReport; URL metadataReportUrl; MetadataReportService(URL metadataReportURL) { if (METADATA_REPORT_KEY.equals(metadataReportURL.getProtocol())) { String protocol = metadataReportURL.getParameter(METADATA_REPORT_KEY, DEFAULT_DIRECTORY); metadataReportURL = URLBuilder.from(metadataReportURL) .setProtocol(protocol) .removeParameter(METADATA_REPORT_KEY) .build(); } this.metadataReportUrl = metadataReportURL; metadataReport = metadataReportFactory.getMetadataReport(this.metadataReportUrl); } public static MetadataReportService instance(Supplier<URL> metadataReportUrl) { if (metadataReportService == null) { synchronized (lock) { if (metadataReportService == null) { URL metadataReportURLTmp = metadataReportUrl.get(); if (metadataReportURLTmp == null) { return null; } metadataReportService = new MetadataReportService(metadataReportURLTmp); } } } return metadataReportService; } public void publishProvider(URL providerUrl) throws RpcException { //first add into the list // remove the individul param providerUrl = providerUrl.removeParameters(PID_KEY, TIMESTAMP_KEY, Constants.BIND_IP_KEY, Constants.BIND_PORT_KEY, TIMESTAMP_KEY); try { String interfaceName = providerUrl.getParameter(INTERFACE_KEY); if (StringUtils.isNotEmpty(interfaceName)) { Class interfaceClass = Class.forName(interfaceName); FullServiceDefinition fullServiceDefinition = ServiceDefinitionBuilder.buildFullDefinition(interfaceClass, providerUrl.getParameters()); metadataReport.storeProviderMetadata(new MetadataIdentifier(providerUrl.getServiceInterface(), providerUrl.getParameter(VERSION_KEY), providerUrl.getParameter(GROUP_KEY), PROVIDER_SIDE, providerUrl.getParameter(APPLICATION_KEY)), fullServiceDefinition); return; } logger.error("publishProvider interfaceName is empty . providerUrl: " + providerUrl.toFullString()); } catch (ClassNotFoundException e) { //ignore error logger.error("publishProvider getServiceDescriptor error. providerUrl: " + providerUrl.toFullString(), e); } } public void publishConsumer(URL consumerURL) throws RpcException { consumerURL = consumerURL.removeParameters(PID_KEY, TIMESTAMP_KEY, Constants.BIND_IP_KEY, Constants.BIND_PORT_KEY, TIMESTAMP_KEY); metadataReport.storeConsumerMetadata(new MetadataIdentifier(consumerURL.getServiceInterface(), consumerURL.getParameter(VERSION_KEY), consumerURL.getParameter(GROUP_KEY), CONSUMER_SIDE, consumerURL.getParameter(APPLICATION_KEY)), consumerURL.getParameters()); }}MetadataReportService的构造器通过metadataReportURL来获取对应的MetadataReport;它定义了publishProvider方法主要是执行metadataReport.storeProviderMetadata方法;还定义了publishConsumer方法主要是执行metadataReport.storeConsumerMetadata方法;同时还提供了一个静态方法使用双重检锁的单例模式创建MetadataReportService实例dubbo-2.7.2/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/integration/MetadataReportServiceTest.java ...

July 5, 2019 · 2 min · jiezi

聊聊dubbo的LogbackContainer

序本文主要研究一下dubbo的LogbackContainer LogbackContainerdubbo-2.7.2/dubbo-container/dubbo-container-logback/src/main/java/org/apache/dubbo/container/logback/LogbackContainer.java public class LogbackContainer implements Container { public static final String LOGBACK_FILE = "dubbo.logback.file"; public static final String LOGBACK_LEVEL = "dubbo.logback.level"; public static final String LOGBACK_MAX_HISTORY = "dubbo.logback.maxhistory"; public static final String DEFAULT_LOGBACK_LEVEL = "ERROR"; @Override public void start() { String file = ConfigUtils.getProperty(LOGBACK_FILE); if (file != null && file.length() > 0) { String level = ConfigUtils.getProperty(LOGBACK_LEVEL); if (StringUtils.isEmpty(level)) { level = DEFAULT_LOGBACK_LEVEL; } // maxHistory=0 Infinite history int maxHistory = StringUtils.parseInteger(ConfigUtils.getProperty(LOGBACK_MAX_HISTORY)); doInitializer(file, level, maxHistory); } } @Override public void stop() { } /** * Initializer logback * * @param file * @param level * @param maxHistory */ private void doInitializer(String file, String level, int maxHistory) { LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); Logger rootLogger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME); rootLogger.detachAndStopAllAppenders(); // appender RollingFileAppender<ILoggingEvent> fileAppender = new RollingFileAppender<ILoggingEvent>(); fileAppender.setContext(loggerContext); fileAppender.setName("application"); fileAppender.setFile(file); fileAppender.setAppend(true); // policy TimeBasedRollingPolicy<ILoggingEvent> policy = new TimeBasedRollingPolicy<ILoggingEvent>(); policy.setContext(loggerContext); policy.setMaxHistory(maxHistory); policy.setFileNamePattern(file + ".%d{yyyy-MM-dd}"); policy.setParent(fileAppender); policy.start(); fileAppender.setRollingPolicy(policy); // encoder PatternLayoutEncoder encoder = new PatternLayoutEncoder(); encoder.setContext(loggerContext); encoder.setPattern("%date [%thread] %-5level %logger (%file:%line\\) - %msg%n"); encoder.start(); fileAppender.setEncoder(encoder); fileAppender.start(); rootLogger.addAppender(fileAppender); rootLogger.setLevel(Level.toLevel(level)); rootLogger.setAdditive(false); }}LogbackContainer实现了Container接口,其start方法判断是否有指定dubbo.logback.file,如果有则进一步获取dubbo.logback.level,如果为空则默认为ERROR级别,然后再获取dubbo.logback.maxhistory,最后调用doInitializer;doInitializer方法先获取rootLogger,然后执行detachAndStopAllAppenders,然后配置RollingFileAppender,并指定policy为TimeBasedRollingPolicy,并设置PatternLayoutEncoder,然后启动fileAppender,并添加到rootLogger中实例dubbo-2.7.2/dubbo-container/dubbo-container-logback/src/test/java/org/apache/dubbo/container/logback/LogbackContainerTest.java ...

July 4, 2019 · 1 min · jiezi

聊聊dubbo的SpringContainer

序本文主要研究一下dubbo的SpringContainer Containerdubbo-2.7.2/dubbo-container/dubbo-container-api/src/main/java/org/apache/dubbo/container/Container.java @SPI("spring")public interface Container { /** * start method to load the container. */ void start(); /** * stop method to unload the container. */ void stop();}Container接口定义了start、stop方法SpringContainerdubbo-2.7.2/dubbo-container/dubbo-container-spring/src/main/java/org/apache/dubbo/container/spring/SpringContainer.java public class SpringContainer implements Container { public static final String SPRING_CONFIG = "dubbo.spring.config"; public static final String DEFAULT_SPRING_CONFIG = "classpath*:META-INF/spring/*.xml"; private static final Logger logger = LoggerFactory.getLogger(SpringContainer.class); static ClassPathXmlApplicationContext context; public static ClassPathXmlApplicationContext getContext() { return context; } @Override public void start() { String configPath = ConfigUtils.getProperty(SPRING_CONFIG); if (StringUtils.isEmpty(configPath)) { configPath = DEFAULT_SPRING_CONFIG; } context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+"), false); context.refresh(); context.start(); } @Override public void stop() { try { if (context != null) { context.stop(); context.close(); context = null; } } catch (Throwable e) { logger.error(e.getMessage(), e); } }}SpringContainer实现了Container接口,其start方法会创建ClassPathXmlApplicationContext,然后执行refresh及start方法;其stop方法执行ClassPathXmlApplicationContext的stop及close方法Maindubbo-2.7.2/dubbo-container/dubbo-container-api/src/main/java/org/apache/dubbo/container/Main.java ...

July 3, 2019 · 2 min · jiezi

聊聊dubbo的ConsumerContextFilter

序本文主要研究一下dubbo的ConsumerContextFilter ConsumerContextFilterdubbo-2.7.2/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java @Activate(group = CONSUMER, order = -10000)public class ConsumerContextFilter extends ListenableFilter { public ConsumerContextFilter() { super.listener = new ConsumerContextListener(); } @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { RpcContext.getContext() .setInvoker(invoker) .setInvocation(invocation) .setLocalAddress(NetUtils.getLocalHost(), 0) .setRemoteAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort()); if (invocation instanceof RpcInvocation) { ((RpcInvocation) invocation).setInvoker(invoker); } try { RpcContext.removeServerContext(); return invoker.invoke(invocation); } finally { RpcContext.removeContext(); } } static class ConsumerContextListener implements Listener { @Override public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) { RpcContext.getServerContext().setAttachments(appResponse.getAttachments()); } @Override public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) { } }}ConsumerContextFilter继承了ListenableFilter,其invoke方法在invoke之前会给RpcContext.getContext()设置invoker、invocation、localAddress、remoteAddress并移除serverContext;在invoke之后移除当前context;其listener为ConsumerContextListener,在onResponse的时候,会给RpcContext.getServerContext()设置attachments实例dubbo-2.7.2/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/ConsumerContextFilterTest.java ...

July 1, 2019 · 1 min · jiezi