微服务中服务间通信

微服务中服务间通信

  • Nacos(服务发现/注册中心)
    • Nacos是构建以“服务”为中心的现代应用架构(微服务范式、云原生范式)的服务基础设施
    • Nacos快速实现动态服务发现、服务配置、服务元数据及流量管理,更敏捷和容易地构建、交付和管理微服务平台。
    • 常见的注册中心
      • Eureka(原生,2.0版本遇到性能瓶颈期,现已停止维护)
      • Zookeeper(支持,专业的独立产品,如Dubbo)
      • Consul(原生,采用GO语言开发)
      • Nacos(推荐使用)
    • Nacos的使用流程
      • 事先说明:假设现在A服务调用B服务的方法
        • 将A服务和B服务都在Nacos注册中心中注册
        • 根据注册中心提供的地址,A服务才可以调用B服务
        • 这里说的服务是小项目工程(maven工程)
      • 安装Nacos,注意SpringBootSpringCloudNacos的版本对应
      • 双击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中看到
  • 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服务的控制类方法了
  • 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, "删除视频失败,熔断器。。。");
      }
      
hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 微服务中服务间通信