1. 基础入门
1.1. 简介
Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
1.2. 安装
- Docker 安装
docker run -d -p 8848:8848 -p 9848:9848 -e MODE=standalone --name nacos nacos/nacos-server:v2.4.3
- 下载软件包:📎nacos-server-2.4.3.zip
- 启动:
startup.cmd -m standalone
2. 注册中心
2.1. 依赖引入
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2.2. 整合配置
1、在 application.properties
中配置如下
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#暂未用到配置中心功能,需要关闭配置检查
#spring.cloud.nacos.config.import-check.enabled=false
2、开启服务注册/发现功能
@EnableDiscoveryClient //核心注解
@SpringBootApplication
public class OrderMainApplication {
public static void main(String[] args) {
SpringApplication.run(OrderMainApplication.class, args);
}
}
2.3. 服务注册
2.3.1. 查看效果
访问:http://localhost:8848/nacos 可以看到服务已经注册上来;
2.3.2. 注册更多
- 创建
service-product
服务 - 引入
nacos依赖
- 配置
nacos地址信息
-
- 注意:每个微服务端口不一样
- 启动应用,查看是否注册成功
2.3.3. 启动集群
以 service-order
为例,启动 movie 的三个服务。
- idea 搜索
services
面板,添加 SpringBoot 项目。 - 复制
OrderMainApplication
三份,每个启动命令重新指定端口
2.3.4. 查看集群
2.4. 服务发现(官方或第三方配置好的组件,直接注入使用)
2.4.1. DiscoveryClient
@Autowired
DiscoveryClient discoveryClient;
@Test
void discoveryClientTest(){
for (String service : discoveryClient.getServices()) {
System.out.println("service = " + service);
//获取ip+port
List<ServiceInstance> instances = discoveryClient.getInstances(service);
for (ServiceInstance instance : instances) {
System.out.println("ip:"+instance.getHost()+";"+"port = " + instance.getPort());
}
}
}
2.4.2. NacosServiceDiscovery
@Autowired
NacosServiceDiscovery nacosServiceDiscovery;
@Test
void nacosServiceDiscoveryTest() throws NacosException {
for (String service : nacosServiceDiscovery.getServices()) {
System.out.println("service = " + service);
List<ServiceInstance> instances = nacosServiceDiscovery.getInstances(service);
for (ServiceInstance instance : instances) {
System.out.println("ip:"+instance.getHost()+";"+"port = " + instance.getPort());
}
}
}
2.5. 远程调用
2.5.1. 配置 RestTemplate(全局可唯一使用,直接注入Bean)
@Configuration
public class UserConfiguration {
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
2.5.2. 测试调用
@Autowired
RestTemplate restTemplate;
@Test
void testRestTemplate() {
String forObject = restTemplate.getForObject("http://localhost:8080/movie", String.class);
System.out.println(forObject);
System.out.println("-----------------------------");
}
2.5.3. 小结
- 使用 RestTemplate 可以获取到远程数据
- 必须精确指定地址和端口
- 如果远程宕机将不可用
期望:可以负载均衡调用,不用担心远程宕机
2.6. 负载均衡
2.6.1. 依赖导入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
2.6.2. LoadBalancerClient
// 进阶2:完成负载均衡发送请求
private Product getProductFromRemoteWithLoadBalance(Long productId){
//1、获取到商品服务所在的所有机器IP+port
ServiceInstance choose = loadBalancerClient.choose("service-product");
//远程URL
String url = "http://"+choose.getHost() +":" +choose.getPort() +"/product/"+productId;
log.info("远程请求:{}",url);
//2、给远程发送请求
Product product = restTemplate.getForObject(url, Product.class);
return product;
}
2.6.3. 注解式负载均衡
@Configuration
public class UserConfiguration {
@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
// 进阶3:基于注解的负载均衡
private Product getProductFromRemoteWithLoadBalanceAnnotation(Long productId){
String url = "http://service-product/product/"+productId;
//2、给远程发送请求; service-product 会被动态替换
Product product = restTemplate.getForObject(url, Product.class);
return product;
}
2.6.4.
2.6.5. 小结
- 负载均衡调用只需要传入
服务名
- 请求发起之前会自动去注册中心确定微服务地址
- 如果微服务宕机,会自动剔除在线名单,请求将不会发过去
2.7. 深入探索
经典面试题:
如果注册中心宕机,远程调用是否可以成功?
- 从未调用过,如果宕机,调用会立即失败
- 调用过,如果宕机,因为会缓存名单,调用会成功
- 调用过,如果注册中心和对方服务宕机,因为会缓存名单,调用会阻塞后失败(Connection Refused)
3. 配置中心
主要提示:
3.1. 整合配置
3.1.1. 依赖引入
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
3.1.2. 配置文件
application.properties
# 指定配置中心地址
spring.cloud.nacos.server-addr=localhost:8848
spring.config.import=nacos:service-order.properties
3.1.3. 配置集-dataId
3.2. 动态刷新
3.2.1. @RefreshScope
@RefreshScope//自动刷新
@RestController
public class OrderController {
@Autowired
OrderService orderService;
@Value("${order.timeout}")
String orderTimeout;
@Value("${order.auto-confirm}")
String orderAutoConfirm;
@Autowired
OrderProperties orderProperties;
@GetMapping("/config")
public String config(){
return "order.timeout="+orderProperties.getTimeout()+"; " +
"order.auto-confirm="+orderProperties.getAutoConfirm() +";"+
"order.db-url="+orderProperties.getDbUrl();
}
}
3.2.2. ConfigurationProperties
无需 @RefreshScope,自动绑定配置,动态更新
@Component
@ConfigurationProperties(prefix = "order") //配置批量绑定在nacos下,可以无需@RefreshScope就能实现自动刷新
@Data
public class OrderProperties {
String timeout;
String autoConfirm;
String dbUrl;
}
3.3. NacosConfigManager配置监听
@Bean
ApplicationRunner applicationRunner(NacosConfigManager manager){
return args -> {
ConfigService configService = manager.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);
}
});
};
}
3.4.
3.5. namespace、dataId、group
3.5.1. namespace
命名空间:实现多环境隔离,如:开发、测试、预发、生产等
3.5.2. dataId
数据集id:就是以前配置文件的名字。完整写法:名字.后缀
如:common.properties
3.5.3. groupId
分组id:一般可以用微服务的名字作为自己的组。
3.5.4. 推荐用法
后续将讲解OpenFeign如何更简化远程调用开发