nacos和openfeign

为什么不用集群架构,而用分布式:

  1. 集群架构项目改了之后需要重新打包,重新部署,牵一发而动全身
  2. 有些服务可能不适合用java语言写,比如流媒体服务器,直播功能,甚至对视频做一些处理,,java语言可能不擅长这个,,一般用c++开发,,就必须用分布式

分布式架构需要消除单点故障

Nacos

注册中心

每一个服务上线或者下线的是否,都去告诉nacos,nacos作为注册中心,维护了,这些服务节点的信息

nacos官网: https://nacos.io/docs/v2.4/quickstart/quick-start/

下载对应版本nacos,以单机模式启动

shell 复制代码
# -m : mode 什么模式
startup.cmd -m standalone

http://localhost:8848/nacos

cloud版本:

springboot使用nacos:

导入依赖:

xml 复制代码
<!--        服务发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

@EnableDiscoveryClient开启服务发现的功能

spring容器会有一个DiscoveryClient的Bean,,

  • getServices() : 获取所有的服务
  • getInstances("服务名字") : 获取指定服务名字的实例,,可能是多个实例
    • 返回的ServiceInstance实例,可以从中获取到ip和port,,进行远程调用

上面是获取指定某一个实例去调用,,实际中不可能请求都打在一个实例上,,需要将请求负载均衡:

引入spring-cloud-starter-loadbalancer

xml 复制代码
     <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

引入这个包之后,spring容器中会有一个负载均衡的客户端LoadBalancerClient,可以通过LoadBalancerClientchoose(服务名字)通过负载均衡,选择一个实例返回:

java 复制代码
    @Autowired
    private LoadBalancerClient loadBalancerClient;

  // 负载均衡调用 product
    public Product getProductFromRemoteWithLoadBalance(Long productId){
        ServiceInstance choose = loadBalancerClient.choose("service-product");

        String url = "http://"+choose.getHost()+":"+choose.getPort()+"/product/"+productId;

        // 给远程发送请求
        log.info("远程请求:{}",url);

        Product product = restTemplate.getForObject(url, Product.class);
        return product;
    }

但是一般不会这样用,,,

也可以使用@LoadBalanced 打在RestTemplate的bean上面,这样,直接通过restTemplate就可以直接负载均衡发送请求:

java 复制代码
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
    
    
      /**
     * 基于注解的 负载均衡   @LoadBalancer,,, url的host换成服务名字
     * @return
     */
    private Product getProductFromRemoteWithLoadBalancerAndAnnotation(Long productId){
        String url = "http://service-product/product/"+productId;

        // 底层去负载均衡的,,这里看不到他具体调用了哪个的日志
        Product product = restTemplate.getForObject(url, Product.class);
        return product;
    }

但是一般也不会这样用,,都是直接集成openfeign,openfeign直接发送网络请求,自带负载均衡,还有一些重试,兜底,拦截器等功能

nacos作为配置中心

依赖:

xml 复制代码
<!--        nacos作为配置中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

nacos中的配置中心,使用了spring.config.import ...这个是springboot2.4之后的特性,,自动导入配置文件,,配置文件生效的规则就是:

  1. 先导入的先生效,,后导入的如果有属性和先导入的重复了,,使用先导入的

一旦统一引入了nacos配置的依赖,,如果当前服务没有指定对应的配置,,项目启动就会报错,,可以暂时使用spring.cloud-nacos.config.import-check.enabled=false关闭配置中心

nacos配置文件分环境,服务,数据集(每个具体的配置文件)

  • 名称空间 :区分多套环境 dev ,prod
    • group : 区分是哪一种微服务,,比如是order 还是 product
      • 数据集 : 配置文件,比如common.properties,database.properties

配置文件中设置名称空间 spring.cloud.nacos.config.namespace=dev

在导入的使用,,使用 group=xxx 区分是哪一个组,,

在nacos中创建名称空间和配置文件:

yml 复制代码
spring:
  application:
    name: service-order
  cloud:
    nacos:
      # 配置注册中心的位置,,, 项目启动就会去注册
      server-addr: 127.0.0.1:8848
      config:
        # 读取的是 这个名称空间的 配置
        namespace: dev
  config:
    # 自动导入这个配置文件  ===》 灵活,统一的导入外部配置源,,, 替代了旧版本中部分零散的配置方式
    # 显示指定要导入当前应用中的额外配置源
    import:
      # 导入 order组的配置
      - nacos:common.properties?group=order
      - nacos:datasource.properties?group=order

server:
  port: 8000


order:
  timeout: 111
  auto-confirm: 222

配置文件实时更新:

使用@ConfigurationProperties,nacos配置文件改了之后,会实时更新
@Value引入不会实时更新,,但是在类上加上@RefreshScope

NacosConfigManager: 会将nacos拉取的配置融入spring的Environment体系,
NacosConfigManager能获取到ConfigService: 这个是nacos官方提供的底层客户端接口,,负责与Nacos服务建立连接,拉取配置,监听配置变更,,,

监听配置文件变更发送通知:

java 复制代码
    /**
     * 项目启动之后执行,,, 在CommandLineRunner后面
     * @param nacosConfigManager :  nacos配置中心交互的 核心管理类 ---》 封装了底层的配置连接,拉取,监听等核心逻辑,,让你无需手动处理Nacos客户端的创建和管理
     *                           spring应用与 Nacos配置中心之间的 桥梁,统一管理Nacos配置客户端(configService),配置拉取,配置监听等操作
     *
     *                           ConfigService : nacos官方提供的底层客户端接口,,, 负责与Nacos服务建立连接,拉取配置,监听配置变更,,,
     *                           NacosConfigManager 可以获取到ConfigService 实例
     *
     *
     *                           NacosConfigManager 会将从Nacos拉取的配置融入 Spring的Environment体系,,比如@Value,@ConfigurationProperties能读取nacos配置
     * @return
     */
    @Bean
    ApplicationRunner applicationRunner(NacosConfigManager nacosConfigManager){
        return new ApplicationRunner() {
            @Override
            public void run(ApplicationArguments args) throws Exception {
                System.out.println("==============");

                ConfigService configService = nacosConfigManager.getConfigService();
                configService.addListener("service-order.properties", "DEFAULT_GROUP", new Listener() {
                    @Override
                    public Executor getExecutor() {
                        // 监听器的监听任务,,是在线程池中进行的
                        return Executors.newFixedThreadPool(4);
                    }

                    @Override
                    public void receiveConfigInfo(String configInfo) {
                        // 接收配置信息
                        System.out.println("configInfo = " + configInfo);

                        System.out.println("邮件通知。。。");
                    }
                });

            }
        };
    }

yml中--- 文档分隔符,, 在同一个yml文件中,分隔成多个独立的,完整的yaml文档,,每一个---分隔的部分都是一个独立的yaml结构

解决了,单个文件存储多套配置的问题,,可以将,开发,测试,生产的配置文件都写在一个yml中

nacos在不同的 名称空间 引入不同个数的配置文件,,可以使用---文档分隔符

yml 复制代码
spring:
  application:
    name: service-order
  cloud:
    nacos:
      # 配置注册中心的位置,,, 项目启动就会去注册
      server-addr: 127.0.0.1:8848
      config:
        # 读取的是 这个名称空间的 配置 ===> 动态取值 ===> 如果没有配置,,默认是public
        namespace: ${spring.profiles.active:public}
  profiles:
    active: dev
    include: feign  # 除了dev,,还包含了feign环境

server:
  port: 8000


order:
  timeout: 111
  auto-confirm: 222


# 开启openfeign日志
logging:
  level:
    com.cj.order.feign: debug

---
# 生产环境 和 开发环境,, 导入的配置文件个数也不一致 ,,  --- : 文档分隔符,,每个被分割的部分都是一个独立的yaml,,默认不激活,,满足条件才会激活
spring:
  config:
    import:
        - nacos:common.properties?group=order
        - nacos:datasource.properties?group=order
    activate:
      on-profile: dev

---

spring:
  config:
    import:
      - nacos:common.properties?group=order
      - nacos:datasource.properties?group=order
      - nacos:xxx.properties?group=order
    activate:
      on-profile: prod

OpenFeign使用

openfeign是spring cloud中 声明式的http客户端,,用注解和接口来简化微服务之间的远程调用,,

可以重试,兜底,拦截器

开启openfeign远程调用:@EnableFeignClients,用@FeignClient标注发请求的客户端

记录openfeign远程调用日志

在yml中,设置日志级别

yml 复制代码
# 开启openfeign日志
logging:
  level:
    com.cj.order.feign: debug

注入日志的bean

java 复制代码
  // feign打印日志
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
设置超时自动中断

服务之间调用,长时间没有相应,,会导致请求积压,服务雪崩,,需要引入超时机制

超时分为 : 连接超时读取超时

yml 复制代码
spring:
  cloud:
    openfeign:
      client:
        config:
          # 默认设置
          default:
            logger-level: full
            connect-timeout: 2000
            read-timeout: 3000
          # 对这个service-product客户端的配置
          service-product:
            logger-level: full
            connect-timeout: 3000
            read-timeout: 5000
            # 这样配置只针对这个服务有效
#            request-interceptors:
#              - com.cj.order.interceptor.XTokenRequestInterceptor
feign:
  sentinel:
    # 开启之后,远程调用失败,,就会自动走,,兜底的方法
    enabled: true
重试

openfeign默认不重试,,当时可以配置重试

java 复制代码
    /**
     * openfeign 的重试 器,,, 间隔100ms重试一次,最大1s,,重试次数为3,,,, 下一次就会是100*1.5 ,,, 直到1s
     * @return
     */
    @Bean
    Retryer retryer(){
       return new Retryer.Default(100, 1, 3);
   }
拦截器

分为请求拦截器响应拦截器 ,,, 可以在配置文件中,单独给某个服务配置拦截器,,,也可以将拦截器注入到spring容器,,所有的openfeign请求都会被拦截

java 复制代码
/**
 * 想要让拦截器生效,,第一种方法,,在配置文件中指定拦截器
 */
@Component // 容器中只要有这个RequestInterceptor,,,他就会自动调用上,,每一次请求都会应用这个拦截器
public class XTokenRequestInterceptor implements RequestInterceptor {

    /**
     *
     * @param requestTemplate  这次请求的详细信息,,,如果需要对这次请求进行修改,,直接修改这个RequestTemplate
     */
    @Override
    public void apply(RequestTemplate requestTemplate) {

        System.out.println("xTokenInterceptor,,,,");
        // 给请求添加请求头,或者是请求体
        requestTemplate.header("X-Token", UUID.randomUUID().toString());
//        requestTemplate.header()

    }
}

可以用来整个链路共享数据

兜底fallback

需要配合sentinel才能使用默认的兜底策略

引入sentinel:

xml 复制代码
 <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
java 复制代码
/**
 * 兜里回调
 */
@Component
public class ProductFeignClientFallback implements ProductFeignClient {
    @Override
    public Product getProductById(Long id) {

        System.out.println("兜底回调");
        // 远程失败了,,才会走这里
        Product product = new Product();
        product.setProductName("未知商品");

        return product;
    }
}

在openfeign的调用里面,声明fallback:

java 复制代码
// contextId是客户端的名字,,, 如果不写的话,,客户端名字默认是value值
//@FeignClient(value = "service-product",contextId = "product-feignclient")
@FeignClient(value = "service-product",fallback = ProductFeignClientFallback.class)
public interface ProductFeignClient {

    //
    @GetMapping("/product/{id}")
    Product getProductById(@PathVariable("id") Long id);

}
openFeign调用外部接口

openfeign不仅能发送服务之间的调用,也能直接对外部的api发送请求

java 复制代码
// 也可以之前放请求
@FeignClient(value = "weather-client",url = "http://www.baidu.com")
public interface WeatherFeignClient {

    @PostMapping("/xxx")
    String getWeather(@RequestHeader("Authorization") String auth, @RequestParam("token") String token,@RequestParam("cityId") String cityId);
相关推荐
无心水9 小时前
【分布式利器:腾讯TSF】11、腾讯TSF微服务框架深度对比:全面解析TSF vs Spring Cloud vs Dubbo vs Service Mesh
分布式·spring cloud·微服务·dubbo·springcloud·service mesh·分布式利器
sunnyday04262 天前
Spring Cloud Alibaba Sentinel 流量控制与熔断降级实战指南
spring boot·sentinel·springcloud
悟空码字4 天前
Spring Cloud 集成 Nacos,全面的配置中心与服务发现解决方案
java·nacos·springcloud·编程技术·后端开发
坐不住的爱码11 天前
Bootstrap和application.yml
springcloud
悟空码字11 天前
Spring Cloud Gateway实战,从零搭建API网关,构建高性能微服务统一入口
java·gateway·springcloud·编程技术·后端开发
没有bug.的程序员13 天前
Service Mesh 与 Spring Cloud 共存方案:双体系治理、平滑迁移与风险控制实战指南
云原生·springcloud·流量治理·混合架构·servicemesh·微服务迁移·技术演进
奥升新能源平台15 天前
奥升充电平台安全稳定体系构建
运维·安全·开源·springcloud
qq_1659016915 天前
spring-cloud读取Nacos上的配置
java·spring cloud·springcloud
无心水15 天前
【分布式利器:腾讯TSF】2、腾讯微服务框架TSF实战指南:Spring Boot零侵入接入与容器化部署全流程
java·spring boot·分布式·微服务·springcloud·分布式利器·腾讯tsf