基于Nacos的服务治理、配置中心
Nacos集群环境的搭建
参看《基于Docker搭建Nacos集群》:https://lupf.cn/articles/2020/05/21/1590058654840.html ; 亦或者通过官方提供的其他方式安装,详情参考:https://nacos.io/zh-cn/docs/quick-start.html
Nacos作为配置中心
apollo配置中心
整理Nacos的服务治理,顺带着整理一下Nacos的配置中心; 目前实际的生产使用的是Apollo; 个人相比较更加喜欢Apollo一点,如果想了解Apollo的使用可参考:《SpringBoot集成Apollo配置中心(5分钟集成系列)》 https://lupf.cn/articles/2019/11/19/1574169822114.html- 创建一个基础的SpringCloud项目,并添加一下配置
<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>
- 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: 用于对配置文件进行分组
- dataId,用于匹配nacos中对应的配置文件 : 默认规则
-
添加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
-
添加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
-
将启动文件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
// 直接修改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] // 再次刷新,发现值已经修改成功了
-
服务治理
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中可以看到如下的服务
-
测试
http://127.0.0.1:9113/rest/conf
-
服务的命名空间
当不通的环境需要进行区分的时候,如开发环境、测试环境、正式环境;那么这些环境下的服务可能是有区别且不能穿插调用,因此我们就可以通过命名空间各个服务进行隔离;-
添加命名空间
-
配置将服务发布到指定命名空间
spring: cloud: nacos: discovery: namespace: local
-
-
整合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
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"; } }
-
测试
http://127.0.0.1:9113/dubbo/hello
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>
- 请求测试
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>
-
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