1、dubbo:分布式服务框架
什么是dubbo?
高性能和透明化的RPC远程服务调用方案(SOA服务治理方案,通过注册中心解决服务发现问题,通过hessian2序列化解决协议约定问题,通过Netty来实现网络传输)
能做什么:(让多机器中的进程相互通信)
Dubbo实现服务调用是通过RPC的方式,即客户端和服务端共用一个接口(将接口打成一个jar包,在客户端和服务端引入这个jar包),客户端面向接口写调用,服务端面向接口写实现,中间的网络通信交给框架去实现
同类产品:微服务/服务中间件 阿里dubbo/HSF spring生态的Spring cloud facebook的thrift google的grpc twitter的finagle
2、dubbo核心部分包含:
核心 | 细节 |
1、面向接口的远程方法调用(就像调用本地方法一样调用远程方法) | 基于长连接的NIO框架抽象封装,包括多种线程模型,序列化方式; |
2、软负载均衡及容错机制(可以在内网代替F5等硬负载均衡器) | 负载策略:轮询、随机、权重 ;容错:某个server挂了,还有其它的server,就算注册中心挂了,内部的缓存仍然有效 |
3、服务自动注册与发现 | 服务不需写死服务提供方地址,注册中心基于接口名查询服务提供者的ip地址,并且能够平滑添加或删除服务提供者 |
3、dubbo的使用情况?
在阿里内部:除淘系外的阿里子公司,都在使用dubbo,包括:中文主站,国际主站,aliexpree,阿里云,阿里金融,等等
外部:去哪儿,京东,吉利汽车,海康威视,政采云,网易考拉,当当(dubbox)
阿里集团内部使用的分布式服务框架HSF(high speed framework)dubbo从2012年底,阿里停止了对此开源项目的更新,然后由当当维护dubbox
HSF服务框架主要组件(简要介绍,非重点)
图片来自于《企业IT转型之道》 钟华
1)服务提供者
进行配置服务器发现、服务注册、订阅、失效转移等相关功能
目前淘宝内部大部分应用的部署方式还是一个虚拟机(对应一个操作系统)运行一个Tomcat容器(最近以Docker容器来部署应用)
2)服务调用者
3)地址服务器
地址服务器负责给服务提供者和服务调用者提供部署环境中所有配置服务器和diamond服务器的服务器列表信息,由Nginx提供服务能力
获取服务器列表
服务器列表返回
4)配置服务器(服务注册,服务订阅)
配置服务器在 HSF 框架中主要负责记录环境内所有服务发布和服务订阅信息,并将服务相关信息推送到服务节点上。
配置服务器与所有服务者提供者和调用者均是长连接,采用心跳的方式可监控到各服务运行节点的状况
5)Diamond 服务器(规则推送)
Diamond服务器是一个通用的统一配置管理服务,类似 ZooKeeper,给应用提供统一的配置设置和推送服务,使用场景非常广泛
在HSF服务框架中,则主要承担了服务调用过程中对于服务调用安全管控的规则、服务路由权重、服务QPS阀值等配置规则的保存,所有的信息均是持久化保存到了后端的MySQL 服务器中
HSF细节:
HSF框架采用Netty+Hessian数据序列化协议实现服务交互(与dubbo相同)
1、这类RPC协议采用多路复用的TCP长连接方式,在服务提供者和调用者间有多个服务请求同时调用时会共用同一个长连接,即一个连接交替传输不同请求的字节块
2、Hessian相比JDK标准的序列化方式(基于serializable接口的标准序列化),时间开销可以缩短很多
3、Hessian 是在性能和稳定性同时考虑下最优的序列化协议
HSF的容错机制
多个应用实例作为服务提供者提供某一相同服务
HSF有风险的地方
依赖大量的闭源项目工程,所以对外部实际也是不可用的。
4、如何使用dubbo?
1)基于rpc(传输层的协议,上层表现层不封装,跳过了很多步骤) 远程服务调用 直接写在@autowired中,很方便
传输层(报文) 网络层(包) 数据链路层(帧格式) 物理层(bite流)
2)dubbo使用方式 全spring配置 接口/ 实现类/zk注册中心
使用流程:
第一步:要在系统中使用dubbo应该先搭建一个注册中心,一般推荐使用zookeeper。
第二步:有了注册中心然后是发布服务,发布服务需要使用spring容器和dubbo标签来发布服务。并且发布服务时需要指定注册中心的位置
第三步:服务发布之后就是调用服务。一般调用服务也是使用spring容器和dubbo标签来引用服务,这样就可以在客户端的容器中生成一个服务的代理对象,然后在action(struts2)或者Controller(springWeb)中直接调用service的方法即可
Zookeeper注册中心的作用:注册和发现服务的作用。类似于房产中介的作用,在系统中并不参与服务的调用及数据的传输。
3)服务提供者
1、定义服务接口(实际开发中,接口的读写接口是分开的)
package com.zjut.dubbotest.provider; import java.util.List; public interface DemoService{ String sayHello(String name); public List getUsers(); }
2、实现服务接口
public class DemoServiceImpl implements DemoService{ public String sayHello(String name){ return "Hello"+name; } public List getUsers(){ return list; } }
3、配置Spring:接口、是吸纳类、zk地址
<!-- 声明服务接口 --> <dubbo:service version="1.0.0" retries="0" interface="com.zjut.dubbotest.provider.DemoService" ref="demoService" /> <!-- 服务实现类bean配置 --> <bean id="demoService" class="com.zjut.dubbotest.provider.DemoServiceImpl" /> <!-- 使用zookeeper注册中心暴露服务地址 -- 常用--> <dubbo:registry address="zookeeper://127.0.0.1:2181" /> <!-- 服务端口号 --> <dubbo:protocol name="dubbo" port="20880" /> <!-- 提供方应用信息,用于计算依赖关系 --> <dubbo:application name="xixi_provider" />
4、服务消费者
<!--配置spring zk地址、接口--> <!--使用zookeeper注册中心暴露服务地址--> <dubbo:registry address="zookeeper://127.0.0.1:2181" /> <!-- 配置接口、生成远程服务代理,可以像使用本地bean一样使用demoService --> <dubbo:reference version="1.0.0" retries="0" id="demoService" interface="com.zjut.dubbotest.provider.DemoService" />
- 加载spring文件并写代码调试 context.getBean(“demoSerice”) (实际开发中由springboot来管理)
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); context.start(); DemoService demoService = (DemoService)context.getBean("demoService"); String hello = demoServic.sayHello("tom"); syso(hello);
5、dubbo节点角色说明
1)、Provider: 服务提供方
作用:服务提供者在启动时,向注册中心注册自己提供的服务
2)、Consumer: 调用远程服务的服务消费方
作用:服务消费者在启动时,向注册中心订阅自己所需的服务。
服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用
3)、Registry: 服务注册中心
作用:注册中心返回服务提供者地址列表给消费者;如果有变更,基于长连接推送变更数据给消费者
有哪些注册中心:
注册中心 | 特点 |
1、Zookeeper注册中心(政采云目前在使用的) | 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者; 建议使用dubbo233以上版本(政采云目前使用dubbo2.5.3) |
2、redis | 支持基于客户端双写的集群方式,性能高;采用key/Map存储,key存储服务名和类型,Map中key存储服务URL,value服务过期时间。基于redis的发布/订阅模式通知数据变更 |
3、multicast | Multicast注册中心不需要任何中心节点,只要广播地址,就能进行服务注册和发现。基于网络中组播传输实现 |
zookeeper注册中心的特点 |
1、采用push、pull相结合的方式:客户端向服务端注册自己需要关注的节点,一旦该节点的数据发生变更,那么服务端就会向相应的客户端发送watcher事件通知。
2、软负载均衡:消费者需要在对等的服务提供方中选择一个来执行相关的业务逻辑。实现了动态DNS方案
3、分布式协调/通知 watcher注册、异步通知机制
4、ZooKeeper的节点是通过像树一样的结构来进行维护的,并且每一个节点通过路径来标示以及访问。除此之外,每一个节点还拥有自身的一些信息,包括:数据、数据长度、创建时间、修改时间等等
zookeeper分布式锁:
排它锁(写锁) :如果事务a对数据对象o1加了排它锁,那么在整个加锁期间,只允许事务a对o1进行读取和更新操作,其他任何事务都不能对o1进行操作,直至a释放排它锁。
java中的锁:synchronized和reentrantLock,在zookeeper中,没有类似这样的api可以使用
共享锁(读锁):加上共享锁,数据对所有事务可见
4)、Monitor: 统计服务的调用次调和调用时间的监控中心(提供可视化界面,看服务是否能运行)(公司目前提供的页面特别low)
定时每分钟发送一次统计数据到监控中心,统计服务消费者和提供者,在内存中累计调用次数和调用时间
5)、Container: 服务运行容器
服务容器Container负责启动,加载,运行服务
6、dubbo源码模块图?(使用maven管理,与maven工程很相似) 20181117
模块名 | 特点 |
1、dubbo-common | 公共逻辑模块,包括util类和通用模型 |
2、dubbo-remoting | 远程通讯模块,相当于dubbo协议的实现,如果rpc用rmi协议就不用这个包 |
3、dubbo-rpc | 远程调用模块,抽象各种协议,以及动态代理,只包含一对一的调用,不关心集群的管理 |
4、dubbo-cluster | 集群模块,将多个服务提供方伪装成一个提供方,包括:负载,容错,路由 |
5、dubbo-monitor | 监控模块,统计服务调用次数,调用时间 |
6、dubbo-config | 配置模块,是dubbo对外的api,用户通过config使用dubbo,隐藏dubbo实现的细节 |
7、dubbo-container | 容器模块,是一个standlone容器,以简单的main加载spring启动,无需把dubbo放入tomcat中。 |
7、dubbo原理(invoker 动态代理)
1、dubbo总体架构(dubbo框架设计一共分为10层)
最上面的Service层是留给使用Dubbo开发分布式服务的开发者实现业务逻辑的接口层
左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口;位于中轴线上的为双方都用到的接口。
层 | 作用 |
1、服务接口层(service) | 该层是与实际业务逻辑相关,根据服务提供方和服务消费方的业务设计对应的接口和实现 |
2、配置层(config) | 对外配置接口,以serviceConfig和referenceConfig为中心,可以直接new配置类,也可以通过spring解析配置生成配置类 |
3、服务代理层(proxy) | 服务接口同名代理,生成服务的客户端stub和服务器端skeleton,以serviceproxy为中心,扩展接口为proxyfactory |
4、服务注册层(registry) | 封装服务地址的注册和发现(使用zookeeper),以服务url为中心,扩展接口为registryFactory、registry和registryService。可能没有服务注册中心,此时服务提供方直接暴露服务 |
5、集群层cluster | 封装多个提供者的路由及负载均衡,并桥接注册中心,以invoker为中心,扩展接口为cluster,directory,router和loadbalance |
6、监控层monitor | rpc调用次数和调用时间监控(dubbo-admin),以statistics为中心,扩展接口为monitorfactory,monitor和monitorService。 |
7、远程调用层protocal ** | 封装RPC调用,以invocation和result为中心,扩展接口为protocol,invoker和exportor =》(完成非透明的RPC调用);protocol是服务域,它是invoker暴露和引用的主功能入口,他负责invoker的生命周期管理;invoker是实体域,它是dubbo的核心模型,其他模型都向他靠拢,或转换成它,它代表一个可执行体 |
8、信息交换层exchange | 封装请求响应模式,同步转异步,以request和response为中心,扩展接口为 Exchanger(好熟悉,线程间交换数据), ExchangeChannel, ExchangeClient, ExchangeServer |
9、网络传输层transport | 抽象mina和netty为统一接口,以message为中心,扩展接口为channel,transportor,client、server和codec |
10、数据序列化层serialize | 可复用的一些工具,扩展接口为serialization,objectInput,objectOutput和ThreadPool |
2、dubbo原理-启动解析、加载配置信息
application module registry monitor provider consumer protocol service reference annotation
如下图所示:
3、服务提供者暴露一个服务的详细过程:(基于反射,调用实现类通过网络协议发送出去)
如下图所示:
1、首先ServiceConfig类拿到对外提供服务的实际类引用(引用全部放在applicationcontext容器里面)(如:HelloWorldImpl)
2、然后通过ProxyFactory类的getInvoker方法使用引用生成一个AbstractProxyInvoker实例,到这一步就完成具体服务到Invoker的转化
3、接下来就是Invoker转换到Exporter的过程
Dubbo处理服务暴露的关键就在Invoker转换到Exporter的过程(如上图中的红色部分),下面我们以Dubbo协议和RMI协议的实现来进行说明:
Dubbo的实现:Dubbo协议的Invoker转为Exporter发生在DubboProtocol类的export方法,它主要是打开socket侦听服务,并接收客户端发来的各种请求,通讯细节由Dubbo自己实现
//RMI的实现: RMI协议的Invoker转为Exporter发生在RmiProtocol类的export方法,它通过Spring或Dubbo或JDK来实现RMI服务,通讯细节这一块由JDK底层来实现,这就省了不少工作量
4、服务消费者消费一个服务的详细过程(基于动态代理,把接口的实例注入到invoker中)
首先ReferenceConfig类的init方法调用Protocol的refer方法生成Invoker实例(如上图中的红色部分),这是服务消费的关键。 //refer()引用远程服务
接下来把Invoker转换为客户端需要的接口(如:HelloWorld)。
关于每种协议如RMI/Dubbo/Web service等它们在调用refer方法生成Invoker实例的细节和上一章节所描述的类似
Invoker是Dubbo领域模型中非常重要的一个概念
Invoker实现了真正的远程服务调用。(invoker实现了集群容错)
用户代码通过proxy调用其对应的Invoker(DubboInvoker、 HessianRpcInvoker中的任何一个)
5、dubbo原理-服务注册与发现原理 20210305 补
8、dubbo面试题?**
1、dubbo连接注册中心和直连的区别 dubbo服务都是注册在注册中心的,然后表现层查询注册中心获取服务真实地址,然后直接调用
- 1、dubbo直连:一般在开发中环境中使用,但是生产环境很少使用,因为服务是直接调用,没有使用注册中心,很难对服务进行管理。
Dubbo直连如何使用?
首先要取消广播,然后客户端直接到指定需要的服务的url获取服务即可。
服务层配置:
<dubbo:registry address=”N/A” />
- 表现层配置:
<!-- <dubbo:registry address=”multicast://224.5.6.7:1234” /> -->// 取消广播,从指定的url中获取服务 <dubbo:service interface=”com.taotao.manager.service.TestService” id=”testService” timeout=”10000000” />
- 2、使用zookeeper注册中心 :
需要指定注册中心类型和注册中心地址,这个时候就不是把服务信息进行广播了,而是告诉给注册中心进行管理。
表示从注册中心发现监控中心地址,否则直连监控中心:
<dubbo:registry address=”registry” />
2、dubbo与http传统调接口的方法的优势?** 20200920 补
通俗点讲:http是个标准的好比普通话,大家谁都懂;
dubbo :是某个地区的方言,当地人直接用方言,更加的迅速
对外提供对话,则需要把方言做一层包装,满足普通话的标准,这样别人才听得懂
区别:
dubbo RPC支持的协议更广泛,而且它最有效地特性是支持长连接,这样避免了多次重复创建TCP连接的开销。另外,HTTP因为协议的特效,会有一系列的HTTP header,这些内容往往会占用几K的数据,访问量特别巨大的时候,这些无关的数据其实也是一种负担。而使用dubboRPC,协议可以自定义,这些无关数据都可以省掉的。至于安全,dubbo设计之初基本都是考虑内网通讯,安全上基本没什么考虑,比http的安全差远了。
rpc长连接、传输效率较高,可定制化路由,适用于内部系统互联;
http短连接,协议标准化且易读,容易对接外部系统,适用于浏览器接口调用,APP接口调用,第三方接口调用。
3、Dubbo支持哪些协议,每种协议的应用场景,优缺点?
协议 | 特点 |
1、dubbo协议(默认选择) | 特点:1、单一长连接 (减少网络建立释放带来的性能损失)2、传输方式:NIO2异步非阻塞通讯(考点:异步通信是如何实现的?可以讲nio的三大核心)3、适用范围:适合大并发,小数据量的服务调用,以及消费者远大于提供者(使得数据不会堆积)4、传输协议 TCP(保证数据的可靠传输)5、使用Hessian来序列化 (比java自带的序列化方案强很多) |
2、rmi协议 | 采用JDK标准的rmi协议实现,传输参数和返回参数对象需要实现Serializable接口,使用java标准序列化机制,使用阻塞式短连接 ,传输数据包大小混合,消费者和提供者个数差不多,可传文件,传输协议TCP。多个短连接,TCP协议传输,同步传输,适用常规的远程服务调用和rmi互操作。在依赖低版本的Common-Collections包,java序列化存在安全漏洞;缺点:使用rmi协议,一般会受防火墙的限制,所以对于外部与内部进行通信的场景,就不要使用rmi协议,可以选择http协议或hessian协议 |
3、webservice | 基于WebService的远程调用协议,集成CXF实现,提供和原生WebService的互操作。多个短连接,基于HTTP传输,同步传输,适用系统集成和跨语言调用 |
4、http | 基于Http表单提交的远程调用协议,使用Spring的HttpInvoke实现。多个短连接,传输协议HTTP,传入参数大小混合,提供者个数多于消费者,需要给应用程序和浏览器JS调用 |
5、hessian | 集成Hessian服务,基于HTTP通讯,采用Servlet暴露服务,Dubbo内嵌Jetty作为服务器时默认实现,提供与Hession服务互操作。多个短连接,同步HTTP传输,Hessian序列化,传入参数较大,提供者大于消费者,提供者压力较大,可传文件 |
6、memcache | 基于memcached实现的RPC协议 |
7、redis | 基于redis实现的RPC协议 |
4、dubbo面试踩坑,使用dubbo遇到过的问题?
1. 增加提供服务版本号和消费服务版本号 (目前公司所有接口均为1.0.0)
<dubbo:service interface=“com.xxx.XxxService” ref=“xxxService” version=“1.0.0”/> <dubbo:reference id=“xxxService” interface=“com.xxx.XxxService” version=“1.0.0”/>
2. dubbo reference注解问题 (目前公司将接口引用全写在xml文件中)
@Reference只能在springbean实例对应的当前类中使用,暂时无法在父类使用;如果确实要在父类声明一个引用,可通过配置文件配置dubbo:reference
3、出现 RpcException: No provider available for remote service异常,表示没有可用的服务提供者***
排查步骤:
1)检查连接的注册中心是否正确
- 若是无法连接到注册中心,检查IP与端口号是否填写正确,检查注册中心是否正常启动
2)到注册中心查看相应的服务提供者是否存在(这个该怎么查看,还不会)
- 检查服务层代码是否添加了@service注解,并且该注解的包一定是com.alibaba.dubbo.config.annotation包,不是org.Springframework的包
- 通过dubbo-admin检查服务层和表现层的ip地址是否正确,以免影响通信
3)检查服务提供者是否正常运行
- 注意包名不要导错,害老子找了半天,真他妈坑
4、服务提供者没挂,但在注册中心里看不到
首先,确认服务提供者是否连接了正确的注册中心,不只是检查配置中的注册中心地址,而且要检查实际的网络连接。
其次,看服务提供者是否非常繁忙,比如压力测试,以至于没有CPU片段向注册中心发送心跳,这种情况,减小压力,将自动恢复。
5、spring和dubbo整合时可能会出现问题
jar包冲突 dubbo中maven依赖传递中存在spring包,当我们在项目中再次引入spring依赖包的时候,项目就会出现冲突问题。(这种情况应该在新引进jar包时剔除对dubbo的依赖)
解决方法:在pom文件中加入
<exclusions> <groupId>org.springframework</groupId> </exclusions>
去掉dubbo的spring传递依赖
6、解决mapper映射文件不发布的问题?
在dao层的pom文件中添加下面的配置信息 ;若是不添加此节点,mybatis的mapper.xml文件都会被漏掉
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build>
- 如果是springboot,只需要在启动项中加上注解 @EnableConfigurationProperties({MybatisProperties.class})
7、同时配置了 XML 和 properties 文件,则 properties 中的配置无效
- 只有 XML 没有配置时,properties 才生效。(优先级的问题)
覆盖策略(优先级由低到高):dubbo.properties -> dubbo.xml -> 虚拟机启动参数 -D(最高)
jvm启动Ddubbo.protocol.port=20880 -D参数优先,这样可以使用户在部署和启动时进行参数重写;dubbo.xml配置后,会使得dubbo.properties中响应配置项失效;(properties级别最低 ) ;dubbo推荐在Provider上尽量多配置Consumer 端属性;
配置的覆盖规则:1) 方法级别配置优于接口级别,即小Scope优先 ;2) Consumer端配置 优于 Provider配置 优于 全局配置;3) 最后是Dubbo Hard Code的配置值
公式:方法级优先,接口级次之,全局配置再次之
如果级别相同,则消费方优先,提供方次之
适用范围:timeout retries loadBalance actives
8、dubbo 缺省会在启动时检查依赖是否可用,不可用就抛出异常,阻止 spring 初始化完成,check 属性默认为 true。
- 测试时有些服务不关心或者出现了循环依赖,将 check 设置为 false。
- 公司的check全设置为false
9、为了方便开发测试,线下有一个所有服务可用的注册中心,这时,如果有一个正在开发中的服务提供者注册,可能会影响消费者不能正常运行。
- 让服务提供者开发方,只订阅服务,而不注册正在开发的服务,通过直连测试正在开发的服务。设置 dubbo:registry 标签的 register 属性为 false。
- dubbo:registry 并不能配置,解决方法可以是:将服务提供者版本号改为独一无二的,然后自测
10、服务注册不上
- 检查 dubbo 的 jar 包有没有在 classpath 中,以及有没有重复的 jar 包(实际开发不会有这样的问题)
检查暴露服务的 spring 配置有没有加载(get)
在服务提供者机器上测试与注册中心的网络是否通(通过dubbo monitor工具检查)
11、出现” 消息发送失败” 异常
- 通常是接口方法的传入传出参数未实现 Serializable 接口。
5、Dubbo工程架构,根据服务化最佳实践**
1、分包 在api包放置一份spring的引用配置,这样,只需在spring加载过程中引用此配置即可
2、粒度 服务接口尽可能大粒度,每个服务方法应代表一个功能,而不是某个步骤,否则将面临分布式事务问题(dubbo未提供分布式事务支持)
- 不建议使用过于抽象的通用接口,如:Map query(Map)
6、Dubbo整合springboot
1、引入spring-boot-starter以及dubbo和curator的依赖
版本适配:java 1.8+ spring boot 2.0.3 dubbo 2.5.3
2、配置application.properties
application.name 是服务名,不能跟别的dubbo提供端重复 registry.protocol 是指定注册中心协议 registry.address 是注册中心的地址加端口号 protocol.name 是分布式固定是dubbo,不要改。 base-package 注解方式要扫描的包
3、dubbo注解 @Service、@Reference
7、Dubbo调优?
**1、配置原则**
调优项 | 细节 |
1、配置原则 | jvm启动D dubbo.protocol.port=20880 -D参数优先,这样可以使用户在部署和启动时进行参数重写;dubbo.xml配置后,会使得dubbo.properties中响应配置项失效; (properties级别最低 ) ;dubbo推荐在Provider上尽量多配置Consumer端属性;配置的覆盖规则:1) 方法级别配置优于接口级别,即小Scope优先 ;2)Consumer端配置 优于 Provider配置 优于 全局配置;3) 最后是Dubbo Hard Code的配置值 |
2、重试次数 | dubbo失败自动切换,当出现失败,重试其它服务器,但重试会带来更长延迟。可通过retries="2"来设置重试次数 |
3、超时时间 | 为了避免超时导致线程资源耗尽,必须设置超时时间;消费端方法超时1000,消费端接口超时3000(超时后会自动重试3次。数据库会收到3条相同的数据),服务方方法超时2000,服务方接口超时4000 消费端全局6000,服务方全局5000 |
4、版本号 | 当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用;可以按照以下的步骤进行版本迁移:在低压力时间段,先升级一半提供者为新版本;再将所有消费者升级为新版本;然后将剩下的一半提供者升级为新版本 |
9、如何实现dubbo的高可用? 整合spring cloud hystrix **
1)zookeeper注册中心宕机,还可以消费dubbo暴露的服务
- 1、dubbo的健壮性
1、监控中心宕掉不影响使用,只是丢失部分采样数据
2、zookeeper的数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
3、注册中心对等集群,任意一台宕掉后,将自动切换到另一台
4、注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
5、服务提供者无状态,任意一台宕掉后,不影响使用
6、服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
- 2、注册信息在zookeeper中如何保存?
类似文件系统,zookeeper的根节点多了一个dubbo节点,最后一个节点是临时节点,而其他节点是持久节点,这样,当服务宕机时,这个节点就会自动消失,不再提供服务,服务消费者也不会再请求。不同的框架会在zookeeper上建不同的节点,互不影响。
2)集群下dubbo负载均衡配置(LoadBalance属性)
Dubbo集群的负载均衡有哪些策略 | 特点 |
1、Random LoadBalance默认 | 随机,按权重设置随机概率 |
2、RoundRobin LoadBalance | 轮循,按公约后的权重设置轮循比率;缺点:存在慢的提供者累积请求的问题;比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上 |
3、LeastActive LoadBalance | 最少活跃;慢的提供者收到更少请求 |
4、ConsistentHash | 一致性Hash策略;相同参数的请求总是发到同一提供者,基于虚拟节点,当某一台提供者挂时,原本发往该提供者的请求,平摊到其它提供者,不会引起剧烈变动;默认只对第一个参数Hash,如果要修改,请配置 <dubbo:parameter key=“hash.arguments” value=“0,1” />;缺省用160份虚拟节点,如果要修改,请配置 <dubbo:parameter key=“hash.nodes” value=“320” /> |
3)整合hystrix / sentinel,服务熔断与降级处理
- 1、什么是服务降级?
当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作 - 2、如何实现服务降级?
向注册中心写入动态配置覆盖规则:
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null"));
1、mock=force:return+null //表示消费方对该服务的方法调用都直接返回null值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响 2、还可以改为 mock=fail:return+null //表示消费方对该服务的方法调用在失败后,再返回null值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响
- 3、集群容错
在集群调用失败时,Dubbo提供了多种容错方案,缺省为failover重试;提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,地址路由等集群支持。
容错机制 | 特点 |
1、Failover Cluster默认 | 失败自动切换,当出现失败,重试其它服务器;通常用于读操作,但重试会带来更长延迟。可通过 retries=“2” 来设置重试次数(不含第一次)。<dubbo:service retries=“2” /> 服务配置;<dubbo:reference retries=“2” /> 引用协议 或 dubbo:reference <dubbo:method name=“findFoo” retries=“2” /> </dubbo:reference> |
2、Failfast Cluster | 快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。 |
3、Failsafe Cluster | 失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作 |
4、Failback Cluster | 失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作 |
5、Forking Cluster | 并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过forks=”2”来设置最大并行数 |
6、Broadcast Cluster | 广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息 |
集群模式配置 |
在服务提供方和消费方配置集群模式<dubbo:service cluster="failsafe"/>或<dubbo:reference cluster="failsafe"/> **总结:** 1、在实际应用中,==查询语句容错策略使用Failover Cluster== 2、==增删改建议使用Failfast Cluster或者使用Failover Cluster(retries=”0”)策略==,防止出现数据重复添加问题 (**快速失败**)
- 4、整合hystrix 还可更深入
hystrix作用: 旨在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力;拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以及监控和配置等功能
整合步骤:
1、配置spring-cloud-starter-netflix-hystrix
spring boot官方提供了对hystrix的集成,直接在pom.xml里加入依赖;然后在 Application类上增加@EnableHystrix来启用hystrix starter:
@SpringBootApplication @EnableHystrix public class ProviderApplication {
2、配置Provider端
在Dubbo的Provider上增加@HystrixCommand配置,这样调用就会经过Hystrix代理
3、配置Consumer端
对于Consumer端,则可以增加一层method调用,并在method上配置@HystrixCommand。当调用出错时,会走到fallbackMethod = "reliable"的调用里
@HystrixCommand(fallbackMethod = "reliable") public String doSayHello(String name) { return demoService.sayHello(name); } public String reliable(String name) { return "hystrix fallback value"; }
10、 dubbo和spring cloud的技术选择?**
当前开源可选用的微服务框架主要有dubbo、spring cloud等, dubbo具有完备的功能和文档,且在国内被众多大型互联网公司选用(当当、考拉、政采云);Spring cloud可以说是一个更完备的微服务解决方案,对中小型的企业,spring cloud可能是一个更好的选择。
如何评估微服务?
1、内部是否存在异构系统集成的问题;
2、备选框架功能特性是否满足需求;
3、http协议的通信对于应用的负载是否会成为瓶颈点
4、社区活跃度、团队技术储备
为什么选择spring cloud?
- 1、从两个公司的背景来谈
dubbo是阿里巴巴服务化治理的核心框架,并被广泛应用于中国各互联网公司,专注于自身的业务;spring cloud是spring家族的产品,专注于企业级开源框架的研发 - 2、社区活跃度的角度
dubbo是一个非常优秀的服务治理框架,并且在服务治理、灰度发布、流量分布这方面做得比spring cloud好;除了当当网在基础上增加了rest支持外、已经两年多的时间几乎没有任何更新;spring cloud自从发展到现在,任在不断的高速发展,现在spring cloud即将发布2.0版本 - 3、从整个大的平台架构来讲
1)dubbo框架只是专注于服务治理,如果我们需要使用使用注册中心、分布式跟踪这些内容都需要自己去集成;Spring cloud几乎考虑了服务治理的方方面面,加上spring boot的支持,开发起来非常便利
2)dubbo使用rpc通信协议,Spring cloud使用http协议REST API
3)dubbo通信性能略胜于 spring cloud
4)dubbo 通过接口的方式相互依赖 ,强依赖关系,需要严格的版本控制,对程序无入侵;Spring cloud 无接口依赖,定义好相关的json字段即可,对程序有一定入侵性。 - 4、从技术发展的角度来讲
Dubbo一直停滞不前,自然有些掉队(这点我不认同);微服务、分布式链路跟踪等更多新的技术理念的出现,Spring急需一款框架来改善以前的开发模式,因此才会出现Spring Boot/Cloud项目 - 总结
dubbo曾经确实很牛逼,但是Spring Cloud是站在近些年技术发展之上进行开发,因此更具技术代表性
11、Dubbo与DubboX区别?
Dubbox:dubbo extensions是当当网基于dubbo2.x的升级版本,其中升级了zookeeper和spring版本,并且支持restful风格的远程调用
- 在REST中支持dubbo统一的方式用bean validation annotation作参数校验
- 在RpcContext上支持获取底层协议的Request/Response
- 支持采用Spring的Java Config方式配置dubbo
- 在Dubbo协议中支持基于Jackson的json序列化
- 在Spring AOP代理过的对象上支持dubbo annotation配置
- 修正@Reference annotation中protocol设置不起作用的bug
- 修正@Reference annotation放在setter方法上即会出错的bug
使用场景:
- dubbo:使用Dubbo的RPC调用方式,服务间仍然会存在API强依赖
- dubbox:相对于Dubbo支持了REST风格的原创调用(HTTP +JSON/XML)
12、 默认使用的是什么通信框架,还有别的选择吗?
- 默认也推荐使用 netty 框架,还有 mina。
13、服务调用是阻塞的吗?
- 默认是阻塞的,可以异步调用,没有返回值的可以这么做。
14、服务提供者能实现失效踢出是什么原理?
- 服务失效踢出基于 zookeeper 的临时节点原理。
15、服务上线怎么不影响旧版本?(灰度发布)
- 采用多版本开发,不影响旧版本。在配置中添加version来作为版本区分
16、如何解决服务调用链过长的问题?
- 可以结合 zipkin 实现分布式服务追踪。(后续去了解)
- 公司使用traceId来追踪调用链路
17、说说核心的配置有哪些? 后续解析
核心配置有
dubbo:service/
dubbo:reference/
dubbo:protocol/
dubbo:registry/
dubbo:application/
dubbo:provider/
dubbo:consumer/
dubbo:method/
18、dubbo 在安全机制方面如何解决的?
- dubbo 通过 token 令牌防止用户绕过注册中心直连,然后在注册中心管理授权,dubbo 提供了黑白名单,控制服务所允许的调用方。
19、服务调用超时问题怎么解决
- dubbo在调用服务不成功时,默认是会重试两次的。这样在服务端的处理时间超过了设定的超时时间时,就会有重复请求,比如在发邮件时,可能就会发出多份重复邮件,执行注册请求时,就会插入多条重复的注册数据,那么怎么解决超时问题呢?如下
- 对于核心的服务中心,去除dubbo超时重试机制,并重新评估设置超时时间。业务处理代码必须放在服务端,客户端只做参数验证和服务调用,不涉及业务流程处理 全局配置实例
<dubbo:provider delay=“-1” timeout=“6000” retries=“0”/>
当然Dubbo的重试机制其实是非常好的QOS保证,它的路由机制,是会帮你把超时的请求路由到其他机器上,而不是本机尝试,所以 dubbo的重试机器也能一定程度的保证服务的质量。但是请一定要综合线上的访问情况,给出综合的评估。
20、dubbo网关与 dubbo Filter 20200920补
Dubbo网关即通过HTTP协议调用服务端dubbo接口的统一入口(把HTTP协议转换为Dubbo协议)
- 架构图
- dubbo网关的使用限制
关于Dubbo网关的使用,这里需要注意几点:
1、Dubbo网关的主要使用场景是跨网调用(岛调用云上接口),既然是跨网调用,在稳定性和性能上都可能存在问题,所有业务方在使用时要充分评估风险,对于特别重要的业务不要对跨网调用有强依赖(比如交易业务,要做到即使跨网调用不可用时,也不受影响)
dubbo网关接入
- 1、maven引入包
<dependency> <groupId>cn.gov.zcy</groupId> <artifactId>zcy-dubbo-proxy</artifactId> <version>3.0.7-RELEASE</version> </dependency>
- 2、配置需要过滤的Provider(岛端)
在自己的center应用的dubbo-provider.xml配置文件,自定义需要过滤的dubbo接口,单个接口见如下配(filter=“dubboFilter”):
<dubbo:service retries="0" version="1.0.0" interface="cn.gov.zcy.user.service.ZcyUserReadService" ref="zcyUserReadServiceImpl" filter="dubboFilter" />
如果需要配置全部走过滤器,需要进行如下配置:
<dubbo:provider port="-1" filter="dubboFilter" retries="0" />
- 3、Apollo的参数配置(岛端)
/dubbo.proxy.url=http://39.107.176.28:22275/
/dubbo.connect.timeout=10000/
/dubbo.read.timeout=10000/
注意,上面的3个配置已经调整到公共配置,各应用自己无需重复配置。同时下面2个配置也是可选配置,业务线可以按需要自行配置。
log.switch=true // 不配置表示不开启客户端日志 ctrl.switch=true // 不配置表示不开启dubboFilter功能
说明:
log.switch是配置是否打印带跨网RT的时间日志,值为true表示开启,否则关闭
ctrl.switch是配置是否打开dubboFilter的开关,,值为true表示开启,否则关闭
注意事项
1、由于Dubbo反序列化存在限制,目前已明确支持场景如下:
1、返回类型为普通对象:T(其中T为非泛型对象)
2、返回类型为泛型对象: Response(其中T为自定义的非泛型对象,即支持非嵌套的泛型对象)
目前已明确不支持场景如下:
1、返回类型不能是基本类型,比如boolean, int等
2、返回类型为泛型对象Response,其中T是Optional(google的code包提供的Optional类)
2、Dubbo网关的主要使用场景是跨网调用(岛调用云上接口),既然是跨网调用,在稳定性和性能上都可能存在问题,所有业务方在使用时要充分评估风险,对于特别重要的业务不要对跨网调用有强依赖。
3、目前针对本地化项目的跨网调用网络方案,默认走的是互联网通道。因物理距离和网络延迟,会给业务访问RT产生一定的影响,请业务方充分评估对业务的影响(插件本身会尽可能降低损耗)。
4、Dubbo网关的本意是开发提效,即为了实现现在的云岛模式,业务方无需改代码(接入JAR包和添加部分配置)即可实现岛调用云上的接口,但由于云岛模式初建,还未经过真线大流量检验,还存在一些不确定性,故需业务方在接入时务必要进行充分的测试,确保能满足现在的功能需求和性能需求。
dubbo网关原理分析
1、Dubbo Filter
岛上的业务center的Dubbo接口的Provider,通过添加Dubbo Filter过滤器进行拦截岛上的Dubbo调用请求,统一把请求通过HTTP协议中转到云端Dubbo网关服务,待Dubbo网关响应后把结果反序列化成指定对象后返回到调用方。
2、Dubbo泛化调用
Dubbo网关接受到客户端请求后,统一通过Dubbo泛化调用的方式调用云端的Dubbo接口,然后把返回结果返回给客户端。
在Dubbo中,对于服务的调用,最终是将其抽象为一个Invoker进行的,而在抽象的过程中,Dubbo会获取配置文件中指定的所有实现了Filter接口的类,然后根据为其指定的key名称,将其组织成一条链。具体的代码在ProtocolFilterWrapper中
public class ProtocolFilterWrapper implements Protocol { @Override public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) { return protocol.export(invoker); } // 进行服务导出时会会通过buildInvokerChain()方法查找所有实现了Filter接口的子类, // 将其按照一定的顺序组装为一个Filter链 return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER)); } private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) { Invoker<T> last = invoker; // 获取所有实现了Filter接口的子类,这里key是service.filter,也就是说,其对应的配置位置在 // <dubbo:service/>标签的filter属性中。group是provider,这个参数指明了这些Filter中 // 只有provider类型的Filter才会在这里被组装进来。 // 从整体上看,如果在配置文件中通过filter属性指定了各个filter的名称,那么这里就会通过SPI // 读取指定文件中的Filter实现子类,然后取其中的provider组内的Filter将其返回,以便进行后续的组装 List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class) .getActivateExtension(invoker.getUrl(), key, group); if (!filters.isEmpty()) { // 这里的整个动作其实就是对链的一个组装,比如通过上面的步骤获取到了三个Filter:A、B和C。 // 在这里会为每一个子类都声明一个Invoker对象,将该对象的invoke()方法委托给链的下一个节点。 // 这样,通过不断的委托动作,在遍历完成之后,就会得到一个Invoker的头结点,最后将头结点返回。 // 这样就达到了组装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(); } @Override public Result invoke(Invocation invocation) throws RpcException { // filter指向的是当前节点,而传入的Invoker参数是其下一个节点 Result result = filter.invoke(next, invocation); if (result instanceof AsyncRpcResult) { AsyncRpcResult asyncResult = (AsyncRpcResult) result; asyncResult.thenApplyWithContext(r -> filter.onResponse(r, invoker, invocation)); return asyncResult; } else { return filter.onResponse(result, invoker, invocation); } } @Override public void destroy() { invoker.destroy(); } @Override public String toString() { return invoker.toString(); } }; } } return last; } }
上面的组装过程,从整体上来看,其实就是对获取到的Filter从尾部开始遍历,然后依次为该节点创建一个Invoker对象,由该Invoker对象调用该Filter节点,从而达到一个链的传递工作。Dubbo过滤器的整个调用过程都是通过Invoker驱动的,最终对外的表现就是一个Invoker的头结点对象,通过这种方式,Dubbo能够将整个调用过程都统一化到一个Invoker对象中。
21、dubbo 分布式限流方案 20200920补
dubbo 分为consumer端和provider端.
provider 限流。为了限制某一个接口在一段时间内的调用次数,对于过快的调用会直接返回异常信息。这对于有效的控制接口的调用频率,保护provider不会过载很有帮助。
consumer 限流。一个provider可能会有多个consumer,如果某一个consumer调用频率特别高,导致占用过多的服务资源,而导致其他的consumer无法正常调用,针对这种情况可以针对某个consumer进行限流。
- 1、引入依赖
<dependency> <groupId>cn.gov.zcy</groupId> <artifactId>zcy-dubbo-limiter</artifactId> <version>3.0.1-RELEASE</version> </dependency>
- 注意事项
1:引入限流插件并不是意味着dubbo接口都要做限流,默认真线环境的接口都不会做限流,这只是一个未雨绸缪的方案,一旦发生某个接口的流量陡增可能导致大面积服务瘫痪的时候,我们能有快速的手段来进行限流。
2: 引入依赖就相当于为所有的dubbo接口上加了一层“切面”,但是如果没有对这个dubbo接口配置对应的限流策略,限流是不起作用的
3: 引入了依赖就意味着限流已经接入完成了。但是我们建议需要在test、staging等环境进行实际限流测试,实际体验限流的效果。 - 2、通过控制台配置限流策略
在控制台里可以方便快捷的新增、删除、修改、暂停、开启 限流规则
a.进入非真线环境控制台
b.provider 端限流配置,如下图所示
c. 选择环境 目前支持除了真线之外的所有环境,真线环境也在开通中
d. 输入dubbo接口,这里支持模糊查询,输入几个字母即可自动补全
e. 选择需要限流的方法
f. 输入限流规则
g. 点击提交,限流规则自动开始生效,你也可以随时在下放的列表中关闭任意一个限流规则
h. 限流规则的修改和删除,点击编辑和删除按钮,可以针对这条规则进行修改,修改将在下一次dubbo调用的时候生效
- 3、验证
配置 xxxx 接口,10s 内只能调用1次
快速的调用该接口,在dubbo调用的时候会出现类似以下的错误
com.alibaba.dubbo.rpc.RpcException: 违背限流规则: LimitConf(limit=1, intervalInMills=2000, intervalPerPermit=0, burstTokens=1, enable=true, submitter=null, submitDate=null) at cn.gov.zcy.dubbo.filter.DubboTpsLimitFilter.invoke(DubboTpsLimitFilter.java:28) at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69) at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:75) at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69) at com.alibaba.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:42) at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69) at com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:78)
- 4、实现原理
自定义Dubbo Filter
Dubbo limit的缺点与不足之处?
- xxx
22、Dubbo泛化调用及实现原理 20210220补
1、为什么要使用泛化调用?
一般使用dubbo,provider端需要暴露出接口和方法,consumer端要十分明确服务使用的接口定义和方法定义(还有入参返参类型等等信息,常常还需要基于provider端提供的API),两端才能正常通信调用。
然而存在一种使用场景,调用方并不关心要调用的接口的详细定义,它只关注我要调用哪个方法,需要传什么参数,我能接收到什么返回结果即可,这样可以大大降低consumer端和provider端的耦合性。
为了应对以上的需求,dubbo提供了泛化调用,也就是在consumer只知道一个接口全限定名以及入参和返参的情况下,就可以调用provider端的调用,而不需要传统的接口定义这些繁杂的结构。
适用场景:云岛模式
缺点:参数传递复杂,不方便使用
2、泛化调用的使用方法
泛化接口调用方式主要用于客户端没有 API 接口的情况,参数及返回值中的所有 POJO 均用 Map 表示,通常用于框架集成,比如:实现一个通用的服务测试框架,可通过 GenericService 调用所有服务实现。
①通过 Spring 方式实现
在 Spring 配置申明 generic=“true”:
<dubbo:reference id="barService" interface="com.foo.BarService" generic="true" />
在 Java 代码获取 barService 并开始泛化调用:
GenericService barService = (GenericService) applicationContext.getBean("barService"); Object result = barService.$invoke("sayHello", new String[] { "java.lang.String" }, new Object[] { "World" });
②通过 API 方式
import com.alibaba.dubbo.rpc.service.GenericService; ... // 引用远程服务 // 该实例很重量,里面封装了所有与注册中心及服务提供方连接,请缓存 ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>(); // 弱类型接口名 reference.setInterface("com.xxx.XxxService"); reference.setVersion("1.0.0"); // 声明为泛化接口 reference.setGeneric(true); // 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用 GenericService genericService = reference.get(); // 基本类型以及Date,List,Map等不需要转换,直接调用 Object result = genericService.$invoke("sayHello", new String[] {"java.lang.String"}, new Object[] {"world"}); // 用Map表示POJO参数,如果返回值为POJO也将自动转成Map Map<String, Object> person = new HashMap<String, Object>(); person.put("name", "xxx"); person.put("password", "yyy"); // 如果返回POJO将自动转成Map Object result = genericService.$invoke("findPerson", new String[] {"com.xxx.Person"}, new Object[]{person}); ...
如果参数中对象存在复杂结构(也就是参数类型中某个参数是复杂对象),这时,可以使用map来包入参,入参类型可以通过class属性保留下来,如下:
如果POJO 数据:
Person person = new PersonImpl(); person.setName("xxx"); person.setPassword("yyy");
可用下面 Map 表示:
Map<String, Object> map = new HashMap<String, Object>(); // 注意:如果参数类型是接口,或者List等丢失泛型,可通过class属性指定类型。 map.put("class", "com.xxx.PersonImpl"); map.put("name", "xxx"); map.put("password", "yyy");
3、demo
import com.alibaba.dubbo.config.ApplicationConfig; import com.alibaba.dubbo.config.ReferenceConfig; import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.rpc.service.GenericService; import com.alibaba.fastjson.JSON; import java.util.HashMap; import java.util.Map; public class TestDubboGeneric { public static void main(String[] args) { ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>(); // 当前dubbo consumer的application配置,不设置会直接抛异常 ApplicationConfig applicationConfig = new ApplicationConfig(); applicationConfig.setName("xxx_test_service"); // 注册中心配置 RegistryConfig registryConfig = new RegistryConfig(); // 注册中心这里需要配置上注册中心协议,例如下面的zookeeper registryConfig.setAddress("zookeeper://192.168.0.1:2181"); registryConfig.setGroup("test_group"); reference.setApplication(applicationConfig); reference.setRegistry(registryConfig); // 设置调用的reference属性,下面只设置了协议、接口名、版本、超时时间 reference.setProtocol("dubbo"); reference.setInterface("com.xxx.test.TestService"); reference.setVersion("1.0.0"); reference.setTimeout(1000); // 声明为泛化接口 reference.setGeneric(true); // GenericService可以接住所有的实现 GenericService genericService = reference.get(); // 构造复杂参数,下面的示例中,头两个参数为string类型,后一个是一个复杂类型,但都可以通过map构造。 Map<String, Object> param = new HashMap<>(); param.put("test1", "a"); param.put("test2", "b"); Map<String,Object> thirdParam = new HashMap<>(); thirdParam.put("class","java.util.Map"); thirdParam.put("subParam1","c"); thirdParam.put("subParam2","d"); param.put("test3",thirdParam); Object result = genericService.$invoke("myMethod", new String[]{"java.lang.String", "java.lang.String", "com.xxxtest.MyParam"}, new Object[]{"123", "ddd",param}); System.out.println(JSON.toJSONString(result)); } }
23、Dubbo SPI设计与扩展 20210305补
1、Dubbo SPI和Java SPI的区别?
- Dubbo的扩展点加载从JDK标准SPI(Service provider Interface)扩展点发现机制加强而来。
改进了JDK标准SPI的以下问题:
- 1、JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但是没用上也加载,会很浪费资源。(我的代码中初始化配置项也存在这样的问题)
- 2、如果扩展点加载失败,连扩展点的名称都拿不到了
- 3、增加了对扩展点IOC和AOP的支持,一个扩展点可以直接setter注入其他扩展点。
2、Dubbo SPI可认为是IOC实现吗?
3、Dubbo传统注册中心与Spring Cloud有什么不同?
4、Dubbo负载均衡与Spring Cloud的实现差异?
5、Dubbo服务路由与SpringCloud路由的方式相同吗?
24、Dubbo 服务化最佳实践
①分包
建议将服务接口,服务模型,服务异常等均放在 API 包中
②粒度
服务接口尽可能大粒度,每个服务方法应代表一个功能,而不是某功能的一个步骤,否则将面临分布式事务问题,Dubbo 暂未提供分布式事务支持
③
25、线上问题排查
1、dubbo Duplicate spring bean id的问题解析
背景:启动测试程序时,报如图所示错误,具体信息为:Duplicate spring bean id outerProductReadFacade
原因:在测试方法中,在provider里面被错误地放入了consumer
解决方案:删除该条错误的consumer,再次运行程序,恢复正常
出身一般,能在社会上有所作为的人,都有这么一些基本特征:有着极为强烈的进取心,一门心思扑在事业上,付出了比绝大多数人都要多的心血与努力;不管学历如何,都有着很强的学习能力,头脑活,而且都有一定的综合能力;赶上了一定的机遇或者有贵人帮扶。进取心越强,能力越大,机遇越大,作为就越大。