本文为稀土技能社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究!


Hello,这儿是爱 Coding,爱 Hiphop,爱喝点小酒的 AKA 柏炎。

本篇是手把手建立根底架构专栏的第五篇,是专栏历史文章,顺次读取效果更佳。

第一篇:从零到一建立根底架构(1)-玩转maven依靠版别管理

第二篇:从零到一建立根底架构(2)-怎么构建根底架构模块区别

第三篇:从零到一建立根底架构(3)-base模块建立上篇

第四篇:从零到一建立根底架构(4)-base模块建立下篇

微服务的生态体系下,RPC是服务之间不行缺少的通讯方法。

在庞大的微服务生态下,可能存在成百上千的服务。越上层的事务服务,关于一些根底服务的依靠就会越多。比方订单服务会依靠付出服务、用户服务、产品服务等等。

这么多的依靠,咱们怎么让服务之间的依靠松懈化,开箱即用化?

这将是本文为咱们所解说的,废话不多说,Let‘s get it.

从零到一搭建基础架构(5)-让你的RPC原地起飞

本文无特别阐明,均已Spring Cloud Open-Feign作为RPC结构做演示

  1. 根底架构:common-frame
  2. 事务运用:Authentication

你需求先clone common-dependency

然后执行mvn clean install 将 common-dependency包打到你本地仓库

不然你拉下来common-frame工程后会报找不到

<parent>
  <groupId>com.baiyan</groupId>
  <artifactId>common-dependency</artifactId>
  <version>1.0.0-SNAPSHOT</version>
</parent>

一、RPC调用与依靠的困境

我在看过许多大的单体服务做微服务改造的时分,从事务动身,将工程区别为多个微服务。

原有事务之间的关联与调用关系从体系内变为体系外

服务之间的通讯方法从service调用改为rpc调用,从spring的事件告诉改为MQ的音讯告诉。

跨服务之间音讯通讯也是遵守增修正查的逻辑。

咱们以订单服务call用户服务获取用户信息为例

从零到一搭建基础架构(5)-让你的RPC原地起飞

这种比较常见的方法就是运用订单服务拜访用户服务的RPC接口

在同一注册中心下,运用openFeign作为RPC结构的调用下,比较常见的开发过程是怎么样的?

1.用户服务在UserController里边界说一个detail的方法。

@ApiOperation(value = "用户详情")
@GetMapping("{id}")
public Result<UserDetailDTO> detail(@PathVariable Long id) {
  return Result.success(userService.detail(id));
}

2.订单服务在工程内界说UserClient的OpenFeign界说。

@FeignClient(
     name = "user",
     url = "https://www.baiyan.com/user",
     fallback = UserClient.UserFallback.class,
     configuration = UserClient.UserFallback.class
)
public interface UserClient {
​
   @GetMapping("/{id}")
   Result<UserDTO> getUserDetail(@PathVariable("id") Long id);
  
   @Component
   class UserFallback {
     public Result<UserDTO> getUserDetail(Long id){return null;}
  }
}

3.订单服务启动类添加 @EnableFeignClients 注解扫描UserClient,将UserClient界说为一个bean。

4.订单服务在需求获取用户数据的当地直接注入订单工程内界说的UserClient运用。


应该有很大一部分同学都是这么接入openFeign的。从功用视点来说,这种编码方法能够完成订单服务获取用户服务所供给的的用户信息。可是从编码视点,上面的代码存在许多问题

问题 描绘
POJO重复界说 细心的小伙伴应该发现,UserController里边回来的实体是UserDetailDTO,UserClient接收的结构是UserDTO。服务间的对接需求经过文档来进行对齐,用户服务现已界说的结构,在订单服务还要再界说一遍。用户服务一旦关于用户信息结构做了改动,添加字段或者修正字段等等,服务的恳求方都感知不到,只能经过交流,文档对接的方法拉平
过多的用户接口 用户服务供给的是web层面的controller接口。因为web接口都是对用户开放的,内部的RPC接口需求也会被露出给用户
鉴权的冗余 相同的,内部服务之间的相互调用,理论上不需求再经过网关的鉴权,应该是相互信任的。但因为供给方界说的接口是Controller接口,露出给了用户,因此鉴权也成为了必须的。关于订单服务的普通用户恳求还好说,还能传递一下用户恳求的身份信息。可是假如是守时使命,订单服务根本不存在用户身份,为了能够经过用户服务的鉴权,还需求去伪造一份身份信息,十分麻瓜。
反常感知弱 咱们需求依据规范Result里边的code字段来感知当前RPC接口出现了什么样的问题。但实际上,关于调用方来说,直接处理RPC接口的反常比解析RPC接口回来的errorCode是什么,再做出什么样的处理愈加方便。
接入RPC不够丝滑 添加一个服务的接口依靠,咱们就要在依靠工程内添加一个openFeign的界说,太难受了。

二、根底架构能做点什么?

为了解决上述粗犷的openFeign运用方法所带来的问题,根底架构能做点什么?

咱们先来回忆一下api包与rpc包的界说

Maven模块 模块界说 补白
api 界说微服务供给者的接口界说,将openFeign相关的接口界说,所必须的交互实体,枚举等界说在此处 Common-Frame工程中所界说的api包仅做模块分层辅导,并无实际意义
rpc api包的openFeign界说完成,这儿假如嫌费事api包跟rpc包能够兼并,我习气分隔,接口结构愈加明晰 Common-Frame工程中所界说的rpc包供给一致的序列化、熔断、反常处理等装备

先说为什么在架构辅导上咱们要把api包与rpc包分隔来。

api包的定位更像是一个三方的结构声明包。里边将会包含一切能够露出给外部工程的工具类、常量、POJO、枚举等。而rpc包的定位是将openFeign供给starter,让服务的依靠方引进了rpc的maven依靠后,能够直接运用注入openFeign开箱即用。在有的场景下,A服务只需求依靠B服务的某个工具类或者某个枚举界说,并不想要调用B服务所供给的RPC接口。这种时分就能够削减RPC界说的引进到A服务中。把包的职责区别清楚。

关于事务服务来说,RPC包中包含了api包中界说的rpc接口的openFeign界说,那在根底架构中,rpc包能做什么呢?

答案是:公共装备

在运用openFeign作为RPC结构之后,随之会引进许多常见的微服务问题:熔断、限流、降级等等。而这些装备关于一切事务服务来说都是互通的,无非是熔断的时刻,限流的规矩等差异。所以咱们在根底架构中能够界说上述的这些公共装备,将这些装备做成base-rpc-starter包。事务服务中的rpc依靠common-frame中的rpc包就能够获取一系列的公共装备。

common-frame-rpc-demo

三、事务运用中怎么界说与运用RPC

界说完common-frame中的公共装备后,在事务服务中,咱们该怎么界说并运用rpc包呢?

以文章开头的项目Authentication为例,咱们能够看到工程中,咱们现已区别了api包与rpc包。

Authentication服务是比较前期我做分布式用户中心时的demo,是依照common-frame的思维建立的,为了项目开箱即用,所以并没有直接1对1的引进common-frame中现已设定好的maven装备。这个在最后一两章的时分会为咱们全局性的演示怎么完美运用common-frame。

这儿Authentication服务仅为咱们演示在api包与rpc包是怎么运用在事务服务中的。

在api包中界说了一切需求露出给服务调用方的POJO界说、枚举界说、常量界说和接口界说。

在rpc包中,pom依靠引进了api包,将在api包中界说的接口进行openFeign界说。而且咱们在rpc包中界说了一个主动装备类

/**
 * auth服务RPC主动装备类
 *
 * @author baiyan
 * @date 2020/11/26
 */
@Configuration
@Import(AuthFeignConfig.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@EnableFeignClients(basePackages = "com.baiyan.auth.rpc")
public class AuthFeignClientAutoConfiguration {
​
}

这个主动装备类的好处是什么?

假定订单服务为服务调用方。那么订单服务只要引进了用户服务的rpc包,订单服务无需做任何装备,就能够直接注入api包中界说UserApi或者rpc中界说的UserApiClient,就能够完成拜访用户服务。

假如仅仅在rpc中界说openFeign的结构,订单服务仍旧无法注入上述用户服务的bean,需求在订单服务的启动类上添加 @EnableFeignClients(basePackages = “com.baiyan.auth.rpc”) 才行。这还仅仅依靠一个服务,假如依靠的服务许多,那界说的途径也太多了。

因此每个服务供给方在所要供给出去的rpc包中界说这样一个主动装备类,让运用者无需添加任何装备,只要引进供给方的Maven依靠即可完成对供给方的拜访。

四、api包为什么要多完成

在第二篇多模块的文章下面有个小老弟提问

从零到一搭建基础架构(5)-让你的RPC原地起飞

api中界说的rpc接口是需求区别于controller中界说的web接口的。

api中界说的http接口是符合rpc结构界说规范的,在nginx层面是不会开放这部分接口的。api包内的http接口仅为其他服务供给事务支撑,并不是用户接口。而在controller层的http接口是用户接口,两者在运用场景上是有差异的。

现在咱们有一个用户详情的接口,在interaction的controller包中现已界说了一个接口。

api包中关于此部分的接口回来值是一样的,咱们能够直接把api中rpc接口的完成指向这个controller吗?

不能!

从零到一搭建基础架构(5)-让你的RPC原地起飞

为啥?

1.api界说的接口可能有10个方法,controller中可能只有9个方法,在接口完成上有差异。有的同学可能会说接口能够界说默许完成,回来空值。

比方在api包中界说

@PostMapping("by_accessKey")
default UserDTO getUserDetail(@RequestParam("accessKey") String accessKey){return null;}

想想也不合理,第一api仅仅一层壳,你让壳做了默许完成。第二controller与api的结构无法匹配。

2.用户完成与rpc完成被捆绑。假定用户接口需求做升级,修正几个字段。可是RPC缺并不需求修正原有的逻辑与回来,这个时分rpc接口将会被逼去修正。rpc一旦deploy到中心仓库被其他服务运用,你的恣意改动,其他服务都会感知到,从服务供给的了历史兼容视点来看,咱们也应该将接口分隔。

从零到一搭建基础架构(5)-让你的RPC原地起飞

五、总结

本篇从微服务中怎么运用openFeign触发,为咱们介绍了RPC供给方与RPC运用方常见的运用坑点。从坑点触发,为咱们介绍根底架构架构中咱们怎么界说api与rpc包。从底层rpc包的作用触发,介绍了事务服务在运用rpc包时,咱们需求留意的点:

  1. api包中仅界说rpc对外供给http结构的壳,不界说rpc的结构。demo中咱们运用openFeign做为rpc包中的rpc结构。假如咱们要运用dubbo作为咱们的rpc结构,咱们能够将common-frame中公共装备修正为dubbo的公共装备,事务服务的rpc珍重rpc的界说改为dubbo的rpc界说。后续就算rpc结构切换,那么关于服务供给方来说,影响也是十分小的。
  2. interaction中apiImpl与controller中的接口需求区别。controller中的接口是开放给用户的,interaction中apiImpl中的完成是开放给内部服务的。

根据上述的结构构造的微服务,服务之间根据openFeign的调用都不需求在调用方内界说供给方的数据结构与接口。调用方能够经过引进供给方的rpc包,开箱即用供给方的rpc接口,此时纵享丝滑。

从零到一搭建基础架构(5)-让你的RPC原地起飞

六、联系我

假如你觉得文章写得不错,点赞评论+关注,么么哒~

微信:baiyan_lou

我的第一本小册《浅显易懂DDD》现已在上线,欢迎咱们试读~

DDD的微信群我也现已建好了,因为文章内不能放二维码,咱们能够加我微信,补白DDD交流,我拉你进群,欢迎交流共同进步。