基于Nacos的服务治理、配置中心

  |   0 评论   |   浏览

file

Nacos集群环境的搭建

参看《基于Docker搭建Nacos集群》:https://lupf.cn/articles/2020/05/21/1590058654840.html ; 亦或者通过官方提供的其他方式安装,详情参考:https://nacos.io/zh-cn/docs/quick-start.html

Nacos作为配置中心

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR5</spring-cloud.version>
        <spring-cloud-starter-alibaba-nacos-discovery.version>2.1.1.RELEASE
        </spring-cloud-starter-alibaba-nacos-discovery.version>
        <spring-cloud-starter-alibaba-nacos-config.version>2.1.1.RELEASE
        </spring-cloud-starter-alibaba-nacos-config.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--Nacos配置中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>${spring-cloud-starter-alibaba-nacos-config.version}</version>
        </dependency>

        <!--Nacos服务治理-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>${spring-cloud-starter-alibaba-nacos-discovery.version}</version>
        </dependency>

        <!-- 服务的API -->
        <dependency>
            <groupId>com.lupf</groupId>
            <artifactId>nacos-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>

file

  • Nacos配置
    • Nacos配置文件的命名规则

      • dataId,用于匹配nacos中对应的配置文件 : 默认规则${spring.application.name}-${spring.profiles.active}.${file-extension} 如: nacos-provider-dev.yml ,如果没有环境区分就是nacos-provider.yml ; dataId允许根据自己的要求进行配置,具体如下
        # 规则: ${prefix}-${spring.profiles.active}-${spring.profiles.active}.${file-extension}
        # 如下的配置最终匹配的配置文件为: nacos-provider-dev.yml  如果没有匹配上会去匹配nacos-provider.yml
        spring: 
          application:
            name: nacos-provider
          cloud:
            nacos:
              config:
                server-addr: 192.168.1.160:8848,192.168.1.160:8848 # nacos的地址
                file-extension: yml # 配置文件的格式
                prefix: ${spring.application.name} # 配置文件的前缀 不配置默认使用的是
                group: DEFAULT_GROUP
          profiles:
            active: dev
        
      • group: 用于对配置文件进行分组
    • 添加nacos-provider.yml

      server:
        port: 9112
      spring:
        application:
          name: nacos-provider
        cloud:
          nacos:
            discovery:
              server-addr: 192.168.1.160:8848,192.168.1.161:8848,192.168.1.162:8848
            config:
              server-addr: 192.168.1.160:8848,192.168.1.161:8848,192.168.1.162:8848
      key1: value1
      profix_key1: value3
      

      file

    • 添加nacos-consumer.yml

      server:
        port: 9113
      spring:
        application:
          name: nacos-consumer
        cloud:
          nacos:
            discovery:
              server-addr: 192.168.1.160:8848,192.168.1.161:8848,192.168.1.162:8848
            config:
              server-addr: 192.168.1.160:8848,192.168.1.161:8848,192.168.1.162:8848
      

      file
      file

    • 将启动文件application.yml修改为bootstrap.yml 并添加一下配置

      spring:
        application:
          name: nacos-provider
        cloud:
          nacos:
            config:
              server-addr: 192.168.1.160:8848,192.168.1.161:8848 # nacos的地址
              file-extension: yml # 配置文件的格式
              prefix: ${spring.application.name} # 配置文件的前缀 不配置默认使用的是
              group: DEFAULT_GROUP
        profiles:
          active: dev
      
    • 启动项目

      // 出现以下日志说明配置文件加载成功
      2020-06-16 16:19:17.369  INFO [nacos-provider,,,] 13892 --- [           main] c.a.c.n.c.NacosPropertySourceBuilder     : Loading nacos data, dataId: 'nacos-provider.yml', group: 'DEFAULT_GROUP', data: server:
        port: 9112
      spring:
        application:
          name: nacos-provider
        cloud:
          nacos:
            discovery:
              server-addr: 192.168.1.160:8848,192.168.1.161:8848,192.168.1.162:8848
            config:
              server-addr: 192.168.1.160:8848,192.168.1.161:8848,192.168.1.162:8848
      key1: value1
      profix_key1: value3
      
    • 添加配置文件获取的工具类 RemoteConfig // @RefreshScope 为自动刷新配置

      @Data
      @Component
      @RefreshScope
      public class RemoteConfig {
      
          @Value ("${key1}")
          private String key1;
      
          @Value ("${profix_key1}")
          private String profixKey1;
      }
      
    • 添加测试使用的NacosConfigController

      @RestController
      @RequestMapping ("echo")
      @Slf4j
      public class NacosConfigController {
          @Autowired
          RemoteConfig remoteConfig;
      
          @GetMapping ("conf")
          public String echo() {
              log.info("provider rest conf resp {}", remoteConfig.toString());
              return remoteConfig.toString();
          }
      }
      
    • 测试获取及自动刷新

      http://127.0.0.1:9112/echo/conf
      

      file

      // 直接修改nacos上的配置 将value3修改为value1 并发布
      // 控制台会出现以下日志
      2020-06-16 16:29:11.216  INFO [nacos-provider,,,] 2880 --- [.168.1.208_8848] o.s.c.e.event.RefreshEventListener       : Refresh keys changed: [profix_key1]
      
      // 再次刷新,发现值已经修改成功了
      

      file

服务治理

RestFul API
  • provider就使用上面echo/conf接口作为测试接口
    • provider和consumer添加配置文件

      spring:
        cloud:
          nacos:
            discovery:
              server-addr: 192.168.1.160:8848,192.168.1.161:8848,192.168.1.162:8848
      
    • provider和consumer启动类添加以下注解

      @EnableDiscoveryClient
      
    • consumer实例化RestTemplate

      @LoadBalanced
      @Bean
      public RestTemplate restTemplate() {
          return new RestTemplate();
      }
      
    • 测试RestFulController

      @RestController
      @RequestMapping ("rest")
      @Slf4j
      public class RestFulController {
          @Autowired
          RestTemplate restTemplate;
      
          @GetMapping ("conf")
          public String echo() {
              log.info("consumer rest conf req start....");
              return restTemplate.getForObject("http://nacos-provider/echo/conf", String.class);
          }
      }
      
    • 启动服务,nacos中可以看到如下的服务
      file

    • 测试

      http://127.0.0.1:9113/rest/conf
      

      file

    • 服务的命名空间
      当不通的环境需要进行区分的时候,如开发环境、测试环境、正式环境;那么这些环境下的服务可能是有区别且不能穿插调用,因此我们就可以通过命名空间各个服务进行隔离;

      • 添加命名空间
        file

      • 配置将服务发布到指定命名空间

        spring:
            cloud:
                nacos:
                    discovery:
                        namespace: local
        

        file

整合feign的服务治理
  • nacos-api添加fiegn的请求及响应对象已经对应的service

    @Data
    @AllArgsConstructor
    public class ReqBean implements Serializable {
        private String name;
    
        private String msg;
    }
    
    @Data
    @AllArgsConstructor
    public class RespBean implements Serializable {
        private String code;
    
        private String msg;
    }
    
    @FeignClient (value = "nacos-provider", path = "/api", fallback = FeignService.DefaultFallback.class)
    public interface FeignService {
    
        @PostMapping ("/hello")
        RespBean hello(@RequestBody ReqBean reqBean);
    
        @PostMapping ("/hi")
        String hi(@RequestParam (value = "name") String name);
    
        class DefaultFallback implements FeignService {
    
            @Override
            public RespBean hello(ReqBean reqBean) {
                return new RespBean("-1", "ERR");
            }
    
            @Override
            public String hi(String name) {
                return "hello name";
            }
        }
    }
    
  • provider和consumer模块添加api模块

    <dependency>
        <groupId>com.lupf</groupId>
        <artifactId>nacos-api</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
    
  • provider和consumer添加以下注解,开启feign

    @EnableFeignClients (basePackages = "com.lupf.*")
    
  • provider实现FeignService

    @Service
    @Slf4j
    public class FeignServiceImpl implements FeignService {
        @Override
        public RespBean hello(ReqBean reqBean) {
            log.info("provider feign hello reqBean:{}", reqBean.toString());
            return new RespBean("0", "success");
        }
    
        @Override
        public String hi(String name) {
            log.info("provider feign hi req name:{}", name);
            return "hi:" + name;
        }
    }
    
  • provider添加对外暴露的controller;注意,路径、参数需要和FeignService配置的路径一致

    @RestController
    @RequestMapping ("api")
    public class FeignController {
        @Qualifier ("feignServiceImpl")
        @Autowired
        FeignService feignService;
    
        @PostMapping ("hello")
        public RespBean trans(@RequestBody ReqBean reqBean) {
            return feignService.hello(reqBean);
        }
    
        @PostMapping ("hi")
        public String hello(String name) {
            return feignService.hi(name);
        }
    }
    
  • consumer的调用FeignController

    @RestController
    @RequestMapping ("feign")
    @Slf4j
    public class FeignController {
    
        @Autowired (required = false)
        FeignService feignService;
    
        @GetMapping ("hello")
        public String hello() {
            log.info("consumer feign hello request start....");
            ReqBean reqBean = new ReqBean("张三", "hello");
            RespBean trans = feignService.hello(reqBean);
            log.info("consumer feign hello request return:{}", trans.toString());
            return trans.toString();
        }
    
        @GetMapping ("hi")
        public String hi() {
            log.info("consumer feign hi request start....");
            String zhang_san = feignService.hi("zhang san");
            log.info("consumer feign hi request return:{}", zhang_san);
            return zhang_san;
        }
    }
    
  • 测试

http://127.0.0.1:9113/feign/hello
http://127.0.0.1:9113/feign/hello

file

dubbo服务的治理
  • 添加dubbo的引用

    <spring-cloud-starter-dubbo.version>2.1.1.RELEASE</spring-cloud-starter-dubbo.version>
    
    <dependency>
        <!--<groupId>org.springframework.cloud</groupId>-->
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-dubbo</artifactId>
        <version>${spring-cloud-starter-dubbo.version}</version>
    </dependency>
    
  • nacos的nacos-provider.yml和nacos-consumer.yml添加一下配置

    dubbo:
      application:
        qos-enable: false
      consumer:
        check: false
      protocol:
        name: dubbo
        port: -1
      reference:
        check: false
      registry:
        address: spring-cloud://localhost
        check: false
      scan:
        base-packages: com.lupf
    

    dubbo.scan.base-packages 为你的包路径

  • provider添加Dubbo的具体实现

    // 注意,这里的Service为:org.apache.dubbo.config.annotation.Service 不是Spring的service
    @Service
    @Slf4j
    public class DubboServiceImpl implements DubboService {
        @Override
        public RespBean hello(ReqBean reqBean) {
            log.info("provider reqBean:{}", reqBean.toString());
            return new RespBean("999", "dubbo success");
        }
    }
    
  • consumer创建测试DubboController

    @RestController
    @RequestMapping ("dubbo")
    @Slf4j
    public class DubboController {
        @Reference
        DubboService dubboService;
    
        @GetMapping ("hello")
        public String hello() {
            log.info("consumer dubbo request start....");
            ReqBean reqBean = new ReqBean("张三", "hello");
            RespBean trans = dubboService.hello(reqBean);
            log.info("consumer dubbo request return:{}", trans.toString());
            return "success";
        }
    }
    

    file

  • 测试

    http://127.0.0.1:9113/dubbo/hello
    

    file

sleuth链路追踪

  • 引入sleuth依赖
    <spring-cloud-starter-sleuth.version>2.1.0.RELEASE</spring-cloud-starter-sleuth.version>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-sleuth</artifactId>
        <version>${spring-cloud-starter-sleuth.version}</version>
    </dependency>
    
  • 请求测试filefile
dubbo的链路追踪
  • 添加一个dubbo zipkin的依赖
    • 2.7.0之前的版本

      <brave-instrumentation-dubbo-rpc.version>5.10.0</brave-instrumentation-dubbo-rpc.version>
      
      <dependency>
          <groupId>io.zipkin.brave</groupId>
          <artifactId>brave-instrumentation-dubbo-rpc</artifactId>
          <version>${brave-instrumentation-dubbo-rpc.version}</version>
      </dependency>
      
    • 大于等于 2.7.0之前的版本

      <brave-instrumentation-dubbo.version>5.10.0</brave-instrumentation-dubbo.version>
      
      <dependency>
          <groupId>io.zipkin.brave</groupId>
          <artifactId>brave-instrumentation-dubbo</artifactId>
          <version>${brave-instrumentation-dubbo.version}</version>
      </dependency>
      

      file

Nacos常见问题

导致log4j2不打印日志日志的问题
  • 错误描述

    WARN No Root logger was configured, creating default ERROR-level Root logger with Console appender
    
  • 解决方式,启动类添加配置

    public static void main(String[] args) {
      // 因为nacos的log4j2导致本项目的日志不输出的问题
      // 配置关闭nacos日志
      System.setProperty("nacos.logging.default.config.enabled", "false");
      SpringApplication.run(xxxx.class, args);
    }
    
Nacos频繁的心跳日志

服务频繁的心跳导致较多无效的日志输出

  • 提升nacos的日志级别,使其不输出
    logging.level.com.alibaba.nacos.client.naming=error
    


标题:基于Nacos的服务治理、配置中心
作者:码霸霸
地址:https://blog.lupf.cn/articles/2020/07/17/1594981065479.html