基于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配置
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: devgroup: 用于对配置文件进行分组
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
接口作为测试接口添加命名空间
配置将服务发布到指定命名空间
spring:
cloud:
nacos:
discovery:
namespace: localprovider和consumer添加配置文件
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.1.160:8848,192.168.1.161:8848,192.168.1.162:8848provider和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
服务的命名空间 当不同的环境需要进行区分的时候,如开发环境、测试环境、正式环境;那么这些环境下的服务可能是有区别且不能穿插调用,因此我们就可以通过命名空间各个服务进行隔离;
整合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.lupfdubbo.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