微服务中服务间通信
- Nacos(服务发现/注册中心)
- Nacos是构建以“服务”为中心的现代应用架构(微服务范式、云原生范式)的服务基础设施
- Nacos快速实现动态服务发现、服务配置、服务元数据及流量管理,更敏捷和容易地构建、交付和管理微服务平台。
- 常见的注册中心
- Eureka(原生,2.0版本遇到性能瓶颈期,现已停止维护)
- Zookeeper(支持,专业的独立产品,如Dubbo)
- Consul(原生,采用GO语言开发)
- Nacos(推荐使用)
- Nacos的使用流程
- 事先说明:假设现在A服务调用B服务的方法
- 将A服务和B服务都在Nacos注册中心中注册
- 根据注册中心提供的地址,A服务才可以调用B服务
- 这里说的服务是小项目工程(maven工程)
- 安装Nacos,注意
SpringBoot
和SpringCloud
和Nacos
的版本对应 - 双击
startup.cmd
启动nacos,在浏览器中输入 http://localhost:8848/nacos- username: nacos
- password: nacos
- 尽量在外层(包含A、B服务的pom.xml)中引入依赖
<!--服务注册--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
- 在要注册服务(即A、B服务,两服务都要)的配置文件中配置Nacos地址
# Nacos服务地址 spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
- 在要注册服务(即A、B服务,两服务都要)的启动类中添加注解
EnableDiscoveryClient
- 启动服务即可在Nacos中看到
- 事先说明:假设现在A服务调用B服务的方法
- Feign(服务调用)
- 尽量在外层(包含A、B服务的pom.xml)中引入依赖
<!--服务注册--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
- 在调用端服务(即A服务)启动类中添加注解
EnableFeignClients
- 在调用端服务(即A服务)创建一个接口,使用注解指定调用服务名称,定义调用的方法路径
- 添加注解FeignClient(“被调用端服务名称(即B服务)”)
- 指定方法(可从被调用端控制类中复制,这样不会出错,另外注解PathVariable中需指定参数名称)
- 示例如下
package com.xsha.eduservice.client; import com.xsha.commonutils.R; import com.xsha.servicebase.exceptionhandler.MyException; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; @FeignClient("serviceB") @Component public interface VodClient { // 调用的路径写完整 @ApiOperation(value = "删除视频") @DeleteMapping("/eduvod/video/deleteAlyVideo/{videoId}") public R deleteAliyunVideo(@ApiParam(name = "videoId", value = "视频ID") @PathVariable("videoId") String videoId) throws MyException; }
- 最后在调用端服务(A服务)控制类(或者其他层上的类)中注入上面创建的接口即
@Autowired private VodClient vodClient
,现在就可以调用B服务的控制类方法了
- 尽量在外层(包含A、B服务的pom.xml)中引入依赖
- Spring Cloud在接口调用上,大致会经过如下几个组件
- 接口化请求调用 -> Feign -> Hystrix -> Ribbon -> Http Client(apache http components 或者 Okhttp)
- 说明
接口化请求调用
当调用被注解FeignClient修饰的接口时,在框架内部将请求转换成Feign的请求实例feign.Request,交由Feign框架处理Feign(服务调用)
转化请求Feign是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,封装了Http调用流程Hystrix(熔断器)
熔断处理机制Feign的调用关系,会被Hystrix代理拦截,对每一个Feign调用请求,Hystrix都会将其包装成HystrixCommand,
参与Hystrix的流控和熔断规则。如果请求判断需要熔断,则Hystrix直接熔断,抛出异常或者使用FallbackFactory返回熔断Fallback结果,如果通过,
则将调用请求传递给Ribbon组件Ribbon(负载均衡)
主要是当请求传递到Ribbon之后,Ribbon会根据自身维护的服务列表、服务质量等(平均响应时间,Load)结合特定的规则,
从列表中挑选合适的服务实例,选择好机器之后,然后将机器实例的信息请求传递给Http Client客户端,Http Client客户端来执行真正的Http接口调用Http Client(客户端)
真正执行Http调用,根据上层Ribbon传递过来的请求,已经指定了服务地址,则Http Client开始执行真正的请求
- Hystrix(熔断器)
- 导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
- 调用端(A服务)配置文件中开启熔断器
# 开启熔断器 feign.hystrix.enabled=true # 设置熔断器超时时间,默认1000ms hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000
- 调用端(A服务)创建上述为服务调用(VodClient)接口的实现类,并实现出错之后的功能方法
package com.xsha.eduservice.client; import com.xsha.commonutils.R; import com.xsha.servicebase.exceptionhandler.MyException; import java.util.List; public class VodFileDegradeFeignClient implements VodClient { @Override public R deleteAliyunVideo(String videoId) throws MyException { return R.error().message("删除视频出错了!"); } @Override public R deleteVideoBatch(List<String> videoList) throws MyException { return R.error().message("批量删除视频出错了!"); } }
- 在接口上注解FeignClient中添加fallback属性及值
@FeignClient(name="service-vod", fallback=VodFileDegradeFeignClient.class)
- 这时调用端(A服务)调用被调用端(B服务)的方法时,就可以根据返回值,根据需求完成更合理的接口(如抛出异常等)
R result = vodClient.deleteAliyunVideo(videoSourceId); if(result.getCode() == 20001) { throw new MyException(20001, "删除视频失败,熔断器。。。"); }
- 导入依赖