Dubbo:Spring Cloud 服务调用的新选择
无论是Dubbo,还是Spring Cloud,大家可能都不会感到陌生。
那什么是Dubbo Spring Cloud呢?使用Dubbo Spring Cloud可以实现什么目的?基于其实现的路由和负载均衡又是怎样的呢?
本文就带大家来一探究竟!
以下节选自《深入理解Spring Cloud与实战》一书。
▼
什么是Dubbo Spring Cloud
Dubbo Spring Cloud是Spring Cloud Alibaba项目内部提供的一个可以使用Spring Cloud客户端RestTemplate或OpenFeign调用Dubbo服务的模块。
Apache Dubbo和Spring Cloud是两套架构完全不同的开发框架。
在讲解Dubbo Spring Cloud之前,我们先来看这个问题:Apache Dubbo暴露的服务都是接口级别的,而Spring Cloud暴露的服务是应用级别的,RestTemplate或OpenFeign发起调用服务都会有对应的URL Path、Query Parameter、Header等内容(这是HTTP协议调用),如何让这些内容关联Dubbo服务呢?
针对上述问题,Dubbo Spring Cloud实现了以应用为粒度的注册机制,每个Dubbo应用注册到注册中心后有且仅有一个服务。那么原先以接口为维度的那些接口信息去哪里了?
Dubbo Spring Cloud 定义了 DubboMetadataService 元数据服务的概念。这是一个专门用于存储 Dubbo 服务的元数据接口。DubboMetadataService 接口定义如下:
public interface DubboMetadataService {// 最核心的接口,用于获取 Dubbo 服务的 Rest 元数据 String getServiceRestMetadata();// 返回所有 Dubbo 服务的 ServiceKey 集合 Set<String> getAllServiceKeys();// 返回所有对外暴露的Dubbo服务。key为ServiceKey,value为URL的json格式 Map<String, String> getAllExportedURLs();// 基于接口名分组及版本获取到 URL 的 json 格式 String getExportedURLs(String serviceInterface, String group, String version);
}
核心方法 getServiceRestMetadata 获取 Dubbo 服务的 Rest 元数据是指:当一个 Dubbo 服务同时也被 SpringMVC 相关注解修饰时,SpringMVC 相关注解修饰的内容就是这些 Rest 元数据。这些 Rest 元数据由 RestMethodMetadata 类修饰,比如,这个 Dubbo 服务 RestService 接口,其定义如下:
@Service
@RestController
public class SpringRestService implements RestService {@Override @GetMapping("/param") public String param(@RequestParam String param) {return param; }
}
RestService服务对应的Rest元数据内容如下:
RestMethodMetadata{method=MethodMetadata{name='param',
returnType='java.lang.String', params=[MethodParameterMetadata{index=0,
name='param', type='java.lang.String'}], method=public java.lang.String
com.alibaba.cloud.dubbo.service.SpringRestService.param(java.lang.String)},
request=RequestMetadata{method='GET', path='/param', params={param=[{param}]},
headers=[], consumes=[], produces=[]}, urlIndex=null, bodyIndex=null,
headerMapIndex=null, queryMapIndex=null, queryMapEncoded=false,
returnType='java.lang.String', bodyType='null', indexToName={0=[param]},
formParams=[], indexToEncoded={}}
除了SpringMVC相关注解,当Dubbo服务自身也暴露Rest协议的时候,这些JAX-RS相关注解修饰的内容也会被解析成Rest元数据。比如,这个Dubbo服务RestService接口的代码如下:
@Service(protocol = { "dubbo", "rest" })
@Path("/")
public class StandardRestService implements RestService {@Override @Path("param") @GET public String param(@QueryParam("param") String param) { return param; }
}
RestService服务对应的Rest元数据内容如下:
RestMethodMetadata{method=MethodMetadata{name='param',
returnType='java.lang.String', params=[MethodParameterMetadata{index=0,
name='param', type='java.lang.String'}], method=public java.lang.String
com.alibaba.cloud.dubbo.service.SpringRestService.param(java.lang.String)},
request=RequestMetadata{method='GET', path='/param', params={param=[{param}]},
headers=[], consumes=[], produces=[]}, urlIndex=null, bodyIndex=null,
headerMapIndex=null, queryMapIndex=null, queryMapEncoded=false,
returnType='java.lang.String', bodyType='null', indexToName={0=[param]},
formParams=[], indexToEncoded={}}
从这两个例子的RestMethodMetadata内容可看出,SpringMVC和JAX-RS的Rest元数据是一致的。
Rest元数据出现的意义是为了匹配RestTemplate或OpenFeign的HTTP协议内容,匹配HTTP协议内容的目的是为了让HTTP协议内容关联上Dubbo服务。
使用RestTemplate或OpenFeign调用Dubbo服务会经历以下过程:
(1)根据服务名得到注册中心的Dubbo服务DubboMetadataService。
(2)使用DubboMetadataService里提供的getServiceRestMetadata方法获取要使用的Dubbo服务和对应的Rest元数据。
(3)基于Dubbo服务和Rest元数据构造GenericService。
(4)服务调用过程中使用GenericService发起泛化调用。
调用Dubbo服务的步骤
下面是使用Dubbo Spring Cloud调用Dubbo服务的开发步骤。
(1)引入spring-cloud-starter-dubbo依赖。
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
加上依赖后,将注册中心改成 spring-cloud 注册中心:
dubbo.registry.address=spring-cloud://localhost
(2)Provider 端接口加上 SpringMVC 相关注解或使用JAX-RS暴露Rest协议。
① 加上 SpringMVC 相关注解。
@Service(version = "1.0.0")
@RestController
public class SpringRestService implements RestService {@Override @GetMapping("/param") public String param(@RequestParam String param) {log("/param", param); return param; }@Override @PostMapping("/params") public String params(@RequestParam int a, @RequestParam String b) {log("/params", a + b); return a + b; }
}
② 使用 JAX-RS 暴露 Rest 协议。
配置文件暴露 rest 协议:
dubbo.protocols.rest.name=rest
dubbo.protocols.rest.port=9090
dubbo.protocols.rest.server=netty
接口使用 JAX-RS 注解修饰:
@Service(version = "1.0.0", protocol = { "dubbo", "rest" })
@Path("/")
public class StandardRestService implements RestService {@Override @Path("param") @GET public String param(@QueryParam("param") String param) {log("/param", param); return param; }@Override @Path("params") @POST public String params(@QueryParam("a") int a, @QueryParam("b") String b) { log("/params", a + b); return a + b; }
}
(3)Consumer 客户端加上 @DubboTransported 注解。
RestTemplate 和 OpenFeign 客户端都支持 @DubboTransported 注解。
RestTemplate 的使用方式如下:
@Bean
@LoadBalanced
@DubboTransported
public RestTemplate restTemplate() { return new RestTemplate();
}
OpenFeign 的使用方式如下:
@FeignClient("nacos-provider-lb")
@DubboTransported(protocol = "dubbo")
public interface DubboFeignRestService {@GetMapping("/param") String param(@RequestParam("param") String param);@PostMapping("/params") String params(@RequestParam("b") String paramB, @RequestParam("a") int paramA);}
(4)使用 RestTemplate 或 OpenFeign 调用 Dubbo 服务。
使用 RestTemplate调用的方式如下:
restTemplate.getForEntity(“http://dubbo-provider-service/param?param=deepinspringcloud”, String.class);
使用 OpenFeign调用的方式如下:
dubboFeignRestService.param(“deepinspringcloud”);
再谈路由和负载均衡
基于Netflix Ribbon的Spring Cloud 负载均衡设计了以下两个核心接口:
路由对应的ILoadBalancer 接口,获取服务的 Server 实例列表。
负载均衡对应的 IRule 接口,从服务的 Server 实例列表中根据负载均衡算法获取一个实例。
Spring Cloud应用的流量控制本质上就是对 Server 列表的控制:
自定义 ILoadBalancer 接口,重写获取 Server 列表的逻辑(找出与当前请求匹配的 Server 列表)。
自定义 IRule 接口,从所有的 Server 列表里找出与当前请求匹配的 Server。
很明显,第一种基于 ILoadBalancer 的方式更加合理。
我们来看 Dubbo 路由 Router 的实现。
Route 方法会从 Invoker 列表中过滤一批 Invoker,得到另一批 Invoker 列表:
public interface Router extends Comparable<Router> {<T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;}
然后 Router 在RouterChain 里被使用:
public class RouterChain<T> {public List<Invoker<T>> route(URL url, Invocation invocation) { List<Invoker<T>> finalInvokers = invokers; for (Router router : routers) { finalInvokers = router.route(finalInvokers, url, invocation); } return finalInvokers; }
}
RouterChain中的Router列表可以随意被添加,开发者可以基于SPI添加各式各样的Router。
笔者认为 Duboo 在路由侧的实现更加优雅。在Spring Cloud的设计中,Ribbon的路由设计与Request(流量)请求信息是解耦的,而 Dubbo 的 Router与Invocation(流量)是绑定的,这意味着路由过程可以直接基于流量特征进行动态操作,无须引入类似 ThreadLocal 的方式来传递流量特征。
另外,我们提到过Spring Cloud默认提供的ZoneAvoidanceRule这个IRule负载均衡策略,它内部会依赖ServerStats去根据Server状态摘除异常节点。
Spring Cloud 提供的其他 IRule 负载均衡策略并没有这个能力,如果想在自定义的 IRule 负载均衡也拥有摘除异常节点的能力,需要在代码里配合 ServerStats 使用。
▼
▊ 更多相关内容请看《深入理解Spring Cloud与实战》一书!
▊《深入理解Spring Cloud与实战》
方剑 编著
Spring Cloud Alibba创始人倾力打造
巨献理论与实践相结合,核心知识点辅以案例讲解
本书共分10章,主要介绍Spring Cloud各个核心组件的设计原理,以及目前流行的Spring Cloud Alibba和 Netflix组件,并且剖析Spring Cloud对流处理、批处理,以及目前业界流行的Serverless的支持。在介绍各部分内容时,本书将理论与实践相结合,对每个核心知识点都给出了具体的案例应用,以帮助读者掌握核心组件的设计理念。
本书适合对Spring Cloud感兴趣并且想透彻理解Spring Cloud的读者阅读,也适合正在进行微服务选型的开发者阅读。
抽奖赠书
截止时间:2021年3月15日 17:00
如何抽奖:点击下方卡片,关注并回复关键词 :20210310
下次你更希望我们送哪本书呢?
留言告诉我们!
Dubbo:Spring Cloud 服务调用的新选择相关推荐
- Dubbo 3.0 前瞻:重塑 Spring Cloud 服务治理
作者 | 小马哥 **导读:**Dubbo 社区策划了[Dubbo 云原生之路]系列文章,和大家一起回顾 Apache Dubbo 产品和社区的发展,并展望未来发展.系列文章主要涵盖 Dubbo 技术 ...
- Spring Cloud Feign调用令牌携带问题
Spring Cloud Feign调用令牌携带问题 微服务项目中模块之间的调用,检测令牌的合法性问题不可避免.使用feign拦截器可以解决. 1:在公用模块中添加maven依赖 [外链图片转存失败, ...
- SpringCloud微服务架构,Spring Cloud 服务治理(Eureka,Consul,Nacos),Ribbon 客户端负载均衡,RestTemplate与OpenFeign实现远程调用
什么是SpringCloud 微服务架构 • "微服务"一词源于 Martin Fowler的名为 Microservices的博文,可以在他的官方博客上找到 http://mar ...
- Dubbo Spring Cloud 逆向分析服务注册事件变化的处理过程
这篇介绍了如何从接收事件的方法逆向推出完整的事件处理过程,这个方法适合在解决具体问题或学习源码时,倒着把处理过程理顺. 起因 原来用的 Spring Boot + Dubbo 开发架构,在架构中有一个 ...
- spring cloud服务之间的调用Fegin
SpringCloud微服务之间的通信并不是使用RPC这种进程间通信技术,而是利用了一种基于http的rest接口调用方式,SpringCloud中有两种方式的实现: 使用 RestT ...
- 从零搭建 Spring Cloud 服务(超级详细)
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! ...
- spring cloud服务发现组件Eureka详解
Eureka是Netflix开发的服务发现组件,本身是一个基于REST的服务.Spring Cloud将它集成在其子项目spring-cloud-netflix中,以实现Spring Cloud的服务 ...
- 从 0 搭建 Spring Cloud 服务,完整教程!
微信搜索逆锋起笔关注后回复编程pdf 领取编程大佬们所推荐的 23 种编程资料! 一.微服务基础 1.什么是 SpringCloud? SpringCloud 官网:https://spring.io ...
- Spring Cloud远程服务调用
远程调用流程 Spring Cloud 在接口调用上,大致会经过如下几个组件配合: 1.Nacos 服务注册 2.Feign 服务调用 3.Hystrix 熔断器 4.Ribbon 负载均衡 5.Ht ...
最新文章
- 从FFmpeg 4. 2源码中提取dshow mjpeg code步骤
- 《Visual C# 2010入门经典》一导读
- 物理Data Guard的日常维护
- CircleList
- python运行时间过长怎么优化_Python性能优化的20条建议
- 腾讯云正式发布遨驰云原生操作系统
- java技术秘籍 转摘
- java 文件下载预览_javaweb简单的实现文件下载及预览
- 使用PS从图片中抠取签章部分
- UE4之Import源码解析
- 拓端tecdat|R语言探索BRFSS数据可视化
- 数据库操作导入导出以及加快查询速度
- 极客大学产品经理训练营 产品文档和原型 作业5
- ASP.NET学生管理系统(.NET毕业设计)
- ERP的主要功能模块简介
- 华普天健会计师事务所管理合伙人朱宗瑞:期待数据资产价值在财务报表里充分体现...
- 银行家算法和安全性算法笔记
- 早早起来真的可以做许多事,比如再睡一觉
- VBA语言入门:一些简单语法在Excel应用实例
- CMU 15-445/645-Note11-Distributed Databases