Nacos 服务注册与配置中心
简介
- 官方地址:https://nacos.io/docs/latest/quickstart/quick-start/
- 一个易于构建云原生应用的动态服务发现、配置管理和服务管理平台
安装
- docker 安装
shell
docker run -d -p 8848:8848 -p 9848:9848 -e MODE=standalone --name nacos nacos/nacos-server:v2.4.3
- 官方下载地址:https://nacos.io/download/nacos-server/
- 单机模式启动:
startup.cmd -m standalone
服务注册中心
引入依赖
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
整合配置
- 在
application.yml
中配置nacos
地址,默认127.0.0.1:8848
yml
spring:
application:
name: service-order
profiles:
active: dev
cloud:
nacos:
server-addr: 127.0.0.1:8848
- 开启服务注册/发现功能
java
@EnableDiscoveryClient //核心注解
@SpringBootApplication
public class OrderMainApplication {
public static void main(String[] args) {
SpringApplication.run(OrderMainApplication.class, args);
}
}
查看效果
访问 http://127.0.0.1:8848/nacos/
可以看到 service-order
服务注册成功
服务发现
在代码里面可以通过 DiscoveryClient
或 NacosServiceDiscovery
从注册中心获取服务
java
@SpringBootTest(classes = ProductMainApplication.class)
public class DiscoveryTest {
@Resource
private DiscoveryClient discoveryClient;
@Resource
private NacosDiscoveryClient nacosDiscoveryClient;
@Test
void discoveryClientTest() {
for (String service : discoveryClient.getServices()) {
List<ServiceInstance> instances = discoveryClient.getInstances(service);
for (ServiceInstance instance : instances) {
System.out.println("ip:" + instance.getHost());
System.out.println("port:" + instance.getPort());
}
}
}
@Test
void nacosDiscoveryClientTest() {
for (String service : nacosDiscoveryClient.getServices()) {
List<ServiceInstance> instances = nacosDiscoveryClient.getInstances(service);
for (ServiceInstance instance : instances) {
System.out.println("ip:" + instance.getHost());
System.out.println("port:" + instance.getPort());
}
}
}
}
远程调用
向容器注册 RestTemplate
java
@Configuration
public class OrderServiceConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
先通过 discoveryClient
获取服务信息,再通过 RestTemplate
远程调用
java
@Resouce
RestTemplate restTemplate;
// 第一版 获取商品服务信息,远程调用
private Product getProductFromRemote(Long productId) {
// 1、获取商品服务所在的所有机器 IP 和 port
List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
ServiceInstance serviceInstance = instances.get(0);
// http://127.0.0.1:9000/product/1
String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/product/" + productId;
log.info("远程请求:{}",url);
return restTemplate.getForObject(url, Product.class);
}
小结
- 使用
RestTemplate
可以进行远程调用 - 必须精确指定调用地址和端口
- 如果远程宕机将不可用
期望:可以负载均衡调用,不用担心远程宕机
负载均衡
引入依赖
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
LoadBalancerClient
loadBalancerClient.choose("service-product")
会负载均衡地获取 service-product
的服务地址
java
@Resource
LoadBalancerClient loadBalancerClient;
//第二版 通过 loadBalancerClient 负载均衡远程调用
private Product getProductFromRemoteWithLoadBalance(Long productId) {
// 1、获取商品服务所在的所有机器 IP 和 port
ServiceInstance instance = loadBalancerClient.choose("service-product");
String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/product/" + productId;
log.info("远程请求:{}",url);
return restTemplate.getForObject(url, Product.class);
}
基于注解的负载均衡
- 为
RestTemplate
添加注解@LoadBalanced
java
@Configuration
public class OrderServiceConfig {
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
- 基于注解的负载均衡,不需要
LoadBalancerClient
java
//第三版 通过 restTemplate 加注解 负载均衡远程调用
public Product getProductFromRemoteWithLoadBalance2(Long productId) {
// restTemplate 负载均衡自动替换 service-product 为服务 IP + port
String url = "http://service-product/product/" + productId;
return restTemplate.getForObject(url, Product.class);
}
面试题: 如果注册中心宕机,远程调用是否可用?
- 从未调用过,如果宕机,调用直接失败
- 调用过,如果宕机,不影响,因为有缓存名单
- 调用过,如果对方服务也宕机,则调用会阻塞后失败
配置中心
依赖引入
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
配置整合
application.yml
中配置spring.config.import
yaml
spring:
config:
import: nacos:service-order.properties
cloud:
nacos:
server-addr: 127.0.0.1:8848
nacos
中编写配置文件
编写代码进行测试
java
//用于自动刷新 配置中心配置值
@RefreshScope
@RestController
public class OrderController {
@Value("${order.timeout}")
String orderTimeout;
@Value("${order.auto-confirm}")
String orderAutoConfirm;
@GetMapping("/config")
public String config() {
return "orderTimeout:" + orderTimeout + ",orderAutoConfirm:" + orderAutoConfirm;
}
}
- 成功读取到,而且
@RefreshScope
支持自动刷新
ConfigurationProperties 自动绑定
ConfigurationProperties
推荐
java
@Data
@Component
// springboot 的自动绑定功能可以批量读取 nacos 的配置中心配置,而且自动刷新 (推荐)
@ConfigurationProperties(prefix = "order")
public class OrderProperties {
private String timeout;
private String autoConfirm;
}
配置监听
Nacos 中的 NacosConfigManager
可以监听配置文件变化,并拿到变化值
案例: 项目一启动就监听配置文件变化,当配置文件变化时发送邮件
java
/**
* 项目一启动就监听配置文件变化
* 发生变化后拿到变化值
* 发送邮件
*/
@Bean
ApplicationRunner applicationRunner(NacosConfigManager nacosConfigManager) {
return args -> {
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 s) {
System.out.println("变化的配置信息: " + s);
System.out.println("发送邮件");
}
});
System.out.println("监听配置文件变化");
};
}
面试题:配置中心的配置文件和微服务的 application.yml
配置文件的优先级谁高?
配置中心的目的是为了统一管理微服务的环境变量,如果配置中心与微服务中的配置冲突,以微服务的配置为准的话,那么配置中心将无法统一管理 各微服务的配置信息,因此配置中心配置文件优先级高
数据隔离
根据环境不同,指定不同的配置文件
yaml
spring:
application:
name: service-order
profiles:
active: dev
cloud:
nacos:
server-addr: 127.0.0.1:8848
---
spring:
config:
import:
- nacos:common.properties?group=order
- nacos:database.properties?group=order
activate:
on-profile: dev
---
spring:
config:
import:
- nacos:common.properties?group=order
- nacos:database.properties?group=order
- nacos:haha.properties?group=order
activate:
on-profile: test
---
spring:
config:
import:
- nacos:common.properties?group=order
- nacos:database.properties?group=order
- nacos:haha.properties?group=order
activate:
on-profile: prod