一 Spring Cloud Alibaba简介
什么是Spring Cloud Alibaba
Spring Cloud Alibaba致力于提供微服务开发的一站式解决方案。 此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
为什么要推出SpringCloud Alibaba呢?
问题:
但近几年来呢,许多的微服务组件已经闭源或者已经停止维护了 。
SpringCloudAlibaba 微服务组件内容与功能对比
Spring Cloud Alibaba是阿里巴巴结合自身的微服务实践开源的微服务全家桶。
微服务组件如下:
- 流量控制和服务降级:使用阿里巴巴前哨进行流量控制,断路和系统自适应保护
- 服务注册和发现:实例可以在阿里巴巴Nacos上注册,客户可以使用Spring管理的bean发现实例。 通过Spring Cloud Netflix支持Ribbon(客户端负载均衡器)
- 分布式配置:使用阿里巴巴Nacos作为数据存储
- 事件驱动:构建与Spring Cloud Stream RocketMQ Binder连接的高度可扩展的事件驱动微服务
- 消息总线:使用Spring Cloud Bus RocketMQ链接分布式系统的节点
- 分布式事务:支持高性能且易于使用的Seata分布式事务解决方案
- Dubbo RPC:通过Apache Dubbo RPC扩展Spring Cloud服务间调用的通信协议
SpringCloud 和 Spring Cloud Alibaba的功能对比
功能 | Spring Cloud Netflix | Spring Cloud Alibaba |
---|---|---|
网关 | Spring Cloud Netflix Zuul | Spring Cloud Gateway |
服务注册与发现 | Spring Cloud Netflix Eureka Spring | Cloud Alibaba Nacos |
配置中心 | Spring Cloud Config | Spring Cloud Alibaba Nacos |
服务限流 | Spring Cloud Netflix Hystrix | Spring Cloud Alibaba Sentinel |
服务熔断 | Spring Cloud Netflix Hystrix | Spring Cloud Alibaba Sentinel |
分布式事务 | TX-LCN | Spring Cloud Alibaba Seata |
服务调用 | Ribbon/Feign | Ribbon/OpenFeign/Dubbo |
更换组件后微服务架构图
二 Spring Cloud Alibaba版本与兼容性
https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明
Spring Cloud维护主线版本
- Spring Cloud 2021.x
- Spring Cloud 2020.x
- Spring Cloud Hoxton.x
Spring Cloud Alibaba维护主线版本
- Spring Cloud Alibaba 2021.0.1.0
- Spring Cloud Alibaba 2.2.7.RELEASE
- Spring Cloud Alibaba 2.1.2.RELEASE
- Spring Cloud Alibaba 2.0.2.RELEASE
- Spring Cloud Alibaba 1.5.1.RELEASE
SpringCloud与SpringBoot版本选型
https://github.com/alibaba/spring-cloud-alibaba/wiki/
下表为按时间顺序发布的 Spring Cloud Alibaba 以及对应的适配 Spring Cloud 和 Spring Boot 版本关系(由于 Spring Cloud 版本命名有调整,所以对应的 Spring Cloud Alibaba 版本号也做了对应变化)
三 分布式服务治理
1 什么是Nacos
Nacos是阿里巴巴开源的服务注册中心以及配置中心,致力于给开发者提供一款便捷、简单上手的开源框架。
Nacos惊人的地方
注意:
从上图不难看出阿里巴巴的野心,一个Nacos干掉了Spring Cloud的三大组件,分别是 注册中心Eureka 、 服务配置Config , 服务总线 Bus 。
为什么Nacos这么受欢迎
Nacos官方文档的介绍中有这么一句话,如下:
Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。
Eureka 、 Config 这两个组件相信大家都用过,有什么感受?
感受就是繁琐:
- 无论是Eureka还是Config都必须自己搭建个服务
- 英文界面不是那么友好
用过Nacos的开发者都说很爽,不用自己搭建服务,阿里给你准备好了服务,只需要启动即可;界面中英文都有,很适合初学者。当然最重要的原因就是以上组件很可能面临停更 、比如 Eureka已经停更了,谁知道后面其他的组件会不会如此呢?
Nacos主要提供以下四大功能
- 服务发现和服务健康监测
Nacos 使服务更容易注册,并通过DNS或HTTP接口发现其他服务, Nacos还提供服务的实时健康检查,以防止向不健康的主机或服务实例发送请求。
- 动态配置服务
动态配置服务允许您在所有环境中以集中和动态的方式管理所有服务的配置。Nacos消除了在更新配置时重新部署应用程序, 这使配置的更改更加高效和灵活。
- 动态 DNS 服务
Nacos提供基于DNS协议的服务发现能力,旨在支持异构语言的服务发现,支持将注册在Nacos上的服务以域名的方式暴露端点,让三方应用方便查阅及发现。
- 服务及其元数据管理
Nacos能让您从微服务平台建设的视觉管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、 服务的健康状态、服务的流量管理、路由及安全策略。
Nacos名字由来
注意:
Naming:名字
Configurations:
配置 Service:服务
2 Nacos Server下载安装
官网下载
https://github.com/alibaba/nacos/releases
下载后解压
tar -zxvf nacos-server-1.4.3.tar.gz -C /usr/local
启动服务器
sh startup.sh -m standalone
注意:
standalone代表着单机模式运行
测试
请求http://114.117.183.67:8848/nacos
注意
nacos运行需要java环境
3 Docker安装Nacos Server服务
下载镜像
docker pull docker.io/nacos/nacos-server:1.4.3
单机版部署
docker run --name nacos -d -p 8848:8848 -e MODE=standalone -e NACOS_SERVER_IP=192.168.66.100 nacos/nacosserver
参数:
- MODE:单节点模式
- NACOS_SERVER_IP:服务ip地址
测试
请求http://114.117.183.67:8848/nacos
4 微服务聚合父工程构建
New Project
聚合总工程名称
字符编码
注解生效激活
Java编译版本选择
File Type过滤
父工程POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lxx</groupId>
<artifactId>cloudalibaba</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<!-- 统一管理jar包版本 -->
<properties>
<project.build.sourceEncoding>UTF8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring-boot.version>2.6.3</spring-boot.version>
<spring.cloud.version>2021.0.1</spring.cloud.version>
<spring.cloud.alibaba.version>2021.0.1.0</spring.cloud.alibaba.version>
<lombok.version>1.18.22</lombok.version>
</properties>
<dependencyManagement>
<dependencies>
<!--spring boot 2.6.3-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringCloud 2021.0.1 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringCloud Aliabab 2021.0.1.0 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
IDEA开启Dashboard
2022-06-16更新idea后面的版本将Dashboard改成了Services
1.在idea中打开Services窗口,View > Tool Windows > Services 或者直接快捷键 Alt + 8
2.添加service服务
5 创建支付服务生产者
创建服务提供者工程cloud-provider-payment8001
POM文件引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
编写主启动类
@Slf4j
//注解开启服务注册与发现功能
@EnableDiscoveryClient
@SpringBootApplication
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
log.info("************ PaymentMain8001 启动成功 ********");
}
}
注意:
@EnableDiscoveryClient:开启注册发现服务
编写YML配置文件
server:
port: 8001
spring:
application:
# 微服务名字
name: provider-payment
cloud:
nacos:
discovery:
# Nacos服务地址
server-addr: 114.117.183.67:8848
查看Nacos控制台服务
6 创建服务消费者
创建服务提供者工程cloud-consumer-order80
POM文件引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
编写主启动类
@SpringBootApplication
@Slf4j
@EnableDiscoveryClient
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class, args);
log.info("************ OrderMain80 启动成功 ********");
}
}
编写YML配置文件
server:
port: 80
spring:
application:
# 微服务名字
name: consumer-order
cloud:
nacos:
discovery:
# Nacos服务地址
server-addr: 114.117.183.67:8848
查看Nacos控制台服务
四 服务调用
1 Dubbo和OpenFeign区别
回顾Dubbo
Apache Dubbo 是一款微服务开发框架,它提供了 RPC通信与微服务治理两大关键能力。这意味着,使用 Dubbo 开发的微服务,将具备相互之间的远程发现与通信能力, 同时利用 Dubbo 提供的丰富服务治理能力,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。
通信性能方面
从通信的性能上来分析,SpringCloud的通信采用Openfeign (feign)组件。Feign基于Http传输协议,底层实现是Rest。从OSI7层模型上来看Rest属于应用层。
注意: 在高并发场景下性能不够理想,成为性能瓶颈。
Dubbo框架的通信协议采用RPC协议,属于传输层协议,性能上自然比rest高。提升了交互的性能,保持了长连接,高性能。
注意: Dubbo性能更好,比如支持异步调用、Netty性能更好。
比较类型 | Dubbo | Feign |
---|---|---|
协议 | 支持多种传输协议(Dubbo、Rmi、HTTP) | 基于HTTP协 议,短连接 |
负载均衡 | Dubbo支持4种算法,随机、权重轮询、最少活跃调用数、一致性 Hash策略 | 随机、轮询 |
容错机制 | 支持多重容错策略:failover、failfast、forking等,也引入了retry 次数,timeout等配置参数。 | 利用熔断机制来实现容错 |
是用场景 | 数据小,高并发 | 并发不高,性能要求不高 |
2 微服务接入OpenFeign
创建工程cloud-consumer-openfeign-order80
添加OpenFeign依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
主启动类添加feign注解
@EnableFeignClients
@SpringBootApplication
@Slf4j
@EnableDiscoveryClient
public class OrderOpenFeignMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderOpenFeignMain80.class, args);
log.info("************* OrderOpenFeignMain80 启动成功 ********");
}
}
创建YML配置文件
server:
port: 80
spring:
application:
# 微服务名字
name: consumer-openfeign-order
cloud:
nacos:
discovery:
# Nacos服务地址
server-addr: 114.117.183.67:8848
feign:
client:
config:
default:
# ⽹络连接阶段1秒超时
connectTimeout: 1000
# 服务请求响应阶段2秒超时
readTimeout: 2000
在生产者cloud-provider-payment8001创建一个测试rpc的接口
@RestController
@RequestMapping("/payment")
public class PaymentController {
@GetMapping("/index")
public String index() {
return "payment success";
}
}
创建要调用的微服务接口
@Service
@FeignClient(value = "provider-payment")
public interface PaymentService {
@GetMapping("/payment/index")
String index();
}
创建控制层
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private PaymentService paymentService;
@GetMapping("/index")
public String index() {
return paymentService.index();
}
}
测试
请求http://localhost:80/order/index
3 OpenFeign实现服务降级
引入降级依赖
<!-- 引入降级依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
开启openfeign对sentinel支持
feign:
sentinel:
enabled: true
client:
config:
default:
# ⽹络连接阶段1秒超时
connectTimeout: 1000
# 服务请求响应阶段2秒超时
readTimeout: 2000
编写降级类
@Component
public class PaymentServiceFallback implements PaymentService {
@Override
public String index() {
return "系统繁忙请稍后再试一试~~~~";
}
}
设置降级
/**
* 支付远程调用类
*/
@Service
@FeignClient(value = "provider-payment", fallback = PaymentServiceFallback.class)
public interface PaymentService {
@GetMapping("/payment/index")
String index();
}
测试
关闭服务生产者服务请求http://localhost:80/order/index
4 Dubbo实现服务生产者
创建接口服务工程cloud-service-api
创建公共支付接口
public interface IPaymentService {
String index();
}
创建支付生产者工程cloud-dubbo-provider-payment8001
POM引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
<groupId>com.lxx</groupId>
<artifactId>cloud-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
编写主启动类
@EnableDiscoveryClient
@SpringBootApplication
@Slf4j
public class ProviderDubboMain8001 {
public static void main(String[] args) {
SpringApplication.run(ProviderDubboMain8001.class,args);
log.info("************** ProviderDubboMain8001 *********");
}
}
编写配置文件YML
server:
port: 8001
spring:
main:
allow-circular-references: true
allow-bean-definition-overriding: true
application:
name: provider-dubbo-payment
cloud:
nacos:
discovery:
server-addr: 114.117.183.67:8848
#dubbo配置
dubbo:
scan:
base-packages: com.lxx.service
registry:
address: nacos://114.117.183.67:8848
timeout: 10000
protocol:
name: dubbo
port: -1
注意:
- dubbo.scan.base-packages :指定 Dubbo 服务实现类的扫描基准包
- dubbo.protocol :Dubbo服务暴露的协议配置,其中子属性name为协议名称,port为协议 端口(-1 表示自增端口,从 20880 开始)
- dubbo.registry :Dubbo 服务注册中心配置
- spring.application.name :应用名称
- spring.main.allow-bean-definition-overriding :在 Spring Boot 2.1 以及更高的版本增加该设定,因为 Spring Boot 默认调整了 Bean 定义覆盖行为。
- spring.cloud.nacos.discovery :Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口。
支付接口实现
@DubboService(timeout = 5000,
methods = {@Method(name = "index", retries = 2)})
public class PaymentServiceImpl implements IPaymentService {
@Override
public String index() {
return "hello dubbo payment";
}
}
测试
启动支付生产者服务
5 Dubbo消费者调用接口
创建订单服务消费者工程cloud-dubbo-consumer-order80
POM添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
<groupId>com.lxx</groupId>
<artifactId>cloud-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
编写主启动类
@EnableDiscoveryClient
@SpringBootApplication
@Slf4j
public class OrderConsumerDubboMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderConsumerDubboMain80.class, args);
log.info("************** OrderConsumerDubboMain80 *********");
}
}
编写配置文件YML
server:
port: 80
spring:
main:
allow-circular-references: true
allow-bean-definition-overriding: true
application:
name: consumer-dubbo-order
cloud:
nacos:
discovery:
server-addr: 114.117.183.67:8848
dubbo:
cloud:
# dubbo.cloud.subscribed-services:
# 表示要订阅服务的服务名,可以配置'*',代表订阅所有服务,不推荐使用。若需订阅多应用,使用 "," 分割。
subscribed-services: "*"
registry:
#注册地址
address: nacos://114.117.183.67:8848
timeout: 10000
protocol:
# Dubbo服务暴露的协议的配置 dubbo
name: dubbo
# 端口从20880开始 自增
port: -1
#Dubbo缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止Spring初始化完成,以便上线时,能及早发现问题,默认check=true。
#如果你的Spring容器是懒加载的,或者通过API编程延迟引用服务,请关闭check,否则服务临时不可用时,会抛出异常,拿到null引用,如果check=false,总是会返回引用,当服务恢复时,能自动连上。
#解决办法:
#可以通过check="false"关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
consumer:
check: false
实现接口调用
/**
* 订单业务层
*/
@Service
public class OrderService {
//支付服务远程调用
@DubboReference
private IPaymentService iPaymentService;
public String index() {
return iPaymentService.index();
}
}
注意: @Reference 的包路径,不要导错包。
编写订单控制层
/**
* 订单控制层
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
/**
* 测试dubbo远程调用
*
* @return
*/
@GetMapping("/index")
public String index() {
return orderService.index();
}
}
测试
请求http://localhost:80/order/index
6 Dubbo实现服务降级
设置服务生产者集群容错模式
@DubboService(timeout = 5000,
methods = {@Method(name = "index", retries = 2)},
// 快速失败模式,调用只执行一次,失败则立即报错。
cluster = "failfast")
public class PaymentServiceImpl implements IPaymentService {
@Override
public String index() {
return "hello dubbo payment";
}
}
注意:
- Failfast Cluster模式:这种模式称为快速失败模式,调用只执行一次,失败则立即报错。
- Failsafe Cluster模式:失败安全模式,如果调用失败, 则直接忽略失败的调用,而是要记 录下失败的调用到日志文件。
- Failback Cluster模式:失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知 操作。
- Forking Cluster模式:并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较 高的读操作,但需要浪费更多服务资源。
- Broadcast Cluster模式:配置值为broadcast。广播调用所有提供者,逐个调用,任意一台 报错则报错(2.1.0开始支持)。通常用于通知所有提供者更新缓存或日志等本地资源信息。
服务消费者编写降级实现类
public class PaymentServiceFallback implements IPaymentService {
@Override
public String index() {
return "系统繁忙请稍后再试一试~~~~";
}
}
服务消费者编写订单业务层
/**
* 订单业务层
*/
@Service
public class OrderService {
//支付服务远程调用
@DubboReference(mock = "com.lxx.service.fallback.PaymentServiceFallback")
private IPaymentService iPaymentService;
public String index() {
return iPaymentService.index();
}
}
注意: 该处mock直接配置服务降级类的全路径。
测试
五 分布式配置中心
1 为什么需要分布式配置中心
为什么需要分布式配置中心
作为一个开发人员,对配置文件都不陌生。在Spring项目中,默认提供了一个application.yml或者application.properties。
主要缺点:
- 不支持配置文件的动态更新:在实际的业务开发过程中,需要动态地更新配置文件,比如切换业务功能开关、变更图片服务器地址、变更数据库连接信息等。在传统配置模式下,需要修改本地配置文件并重新打包,然后重启应用并发布,这样才能保证配置文件能够生效。但这样会导致该服务在重启阶段不可用,从而影响服务整体的可用率。
- 不支持配置集中式管理:在微服务架构中,为了保证某些核心服务的高性能会部署几百个节点。如果在每个节点上都维护一个本地配置文件,则不管是对运维人员或者开发人员而言,成本都是巨大的。
- 不支持多环境部署:如果通过底层框架来维护不同环境的信息,则成本也是非常高的。
注意:
把各个服务的某些配置信息统一交给第三方中间件来维护,分布式配置管理上的数据变变更,需要实时地推送到相对应的应用服务节点上。
2 了解主流的配置中心
主流的分布式配置中心有以下三种,其中,Nacos是Alibaba开源的分布式配置中心。
Nacos
这是SpingCloud alibaba技术栈中的一个组件,前面我们已经使用它做过服务注册中心。其实它也集成了服务配置的功能,我们可以直接使用它作为服务配置中心。
应用和配置中心间的数据同步通常如下三种模式:
- Pull模式:让应用开后长轮询,即定时地从配置中心拉取最新的配置信息,并更新到应用的内存中。
- Push模式:在配置中心配置数据变更之后,主动推送配置数据到指定的应用,应用更新到本地内存中。
- 混合模式:应用和配置中心通过“事件机制+监听器”模式保持长连接。如果应用监听的配置信息发生了变化,则配置中心发布对应类型的事件。应用只有在监听到该事件之后,才会处理对应的配置信息,并更新到应用本地。
Apollo
Apollo是由携程开源的分布式配置中心。特点有很多,比如:配置更新之后可以实时生效,支持灰度发布功能,并且能对所有的配置进行版本管理、操作审计等功能,提供开放平台API。携程的分布式 配置中心框架,有图形界面可以管理配置文件信息,配置文件信息存放 在数据库中。
Spring Cloud Config
它和Spring是无缝集成,使用起来非常方便,并且它的配置存储支持Git。不过它没有可视化的操作界面,配置的生效也不是实时的, 需要重启或去刷新。
分布式配置中心对比
3 Namespace命名空间
前言
现如今,在微服务体系中,一个系统往往被拆分为多个服务,每个服务都有自己的配置文件,然后每个系统往往还会准备开发环境、 测试环境、正式环境。
问题:
我们来说算一算,假设某系统有10个微服务,那么至少有10个配置文件吧,三个环境(dev\test\prod),那就有30个配置文件需要进行管理。
概念
用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。默认namespace=public的保留空间,不支持删除;默认情况下。
场景
Nacos给的最佳实践表明,最外层的namespace是可以用于区分部署环境的,比如test,dev,prod等。
注意:
命名空间可用于进行不同环境的配置隔离。一般一个环境划分到一个命名空间。
新建dev/test的Namespac
查看命名空间
4 DataID配置
概念
Nacos 中的某个配置集的 ID,配置集 ID 是组织划分配置的维度之 一。Data ID 通常用于组织划分系统的配置集。一个系统或者应用可以包含多个配置集,每个配置集都可以被一个有意义的名称标识。
注意:
在系统中,一个配置文件通常就是一个配置集。一般微服务的配置就是一个配置集。
dataId的拼接格式
解释
- prefix:默认为 spring.application.name 的值。
- spring.profiles.active:即为当前环境对应的 profile。
- file-extension:文件后缀
当active profile为空时。
新建cloud-consumer-order80在dev环境下的配置DataID
编写配置
5 Group分组方案
概念
Nacos中的一组配置集,是组织配置的维度之一。通过一个有意义的字符串对配置集进行分组,从而区分Data ID相同的配置集。当您在 Nacos上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用DEFAULT_GROUP 。
通过Group实现环境区分
注意:
用Group来区分不同项目。比如说不同的两个项目都有相同的一个Data Id,则这时就可以用Group来做分组。
6 Nacos中namespace、group与dataid的关系
网上说烂的两个问题:
- 如果实际开发中,通常一个系统会准备,dev开发环境,test测试环境,prod生产环境,那如何保证指定环境启动时服务能正确读取到Nacos上相应环境的配置文件呢?
- 一个大型分布式微服务系统会有很多微服务子项目,每个微服务项目又都会有相应的开发环境、测试环境、预发环境、正式环境…等等,那么怎么对这些微服务配置进行管理呢?
直接进入主题,Nacos
有分类管理的操作。抛出三个概念,namespace(命令空间)、group(分组)、dataid。
- dataid:就是配置文件的名字,相当于主键的作用
- group(分组): 就是可以分组,不同的微服务的配置文件可以放在一个组里。比如当多个项目同时使用该Nacos集群时,还可以通过Group进行Namespace内的细化分组。在某一个 Namespace(比如dev环境)中通过不同Group进行同一环境中不同项目的再分类
- 命名空间(namespace) :Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
总的来说,namespace是可以用于区分部署环境的,Group和DataID逻辑上区分两个目标对象。
7 Namespace实施方案
Nacos给出了两种Namespace的实践方案
- 面向一个租户
- 面向多个租户
面向一个租户
从一个租户(用户)的角度来看,如果有多套不同的环境,那么这个时候可以根据指定的环境来创建不同的 namespce,以此来实现多环境的隔离。
例如,你可能有dev,test和prod三个不同的环境,那么使用一套 nacos 集群可以分别建以下三个不同的 namespace。
问题:
这里的单租户同样也适于小型项目,或者是项目不太多时的实施方案,通过定义不同的环境,不同环境的项目在不同的 Namespace下进行管理,不同环境之间通过Namespace进行隔离。
面向多个租户
当多个项目同时使用该Nacos集群时,还可以通过Group进行Namespace内的细化分组。这里以 Namespace:dev 为例,在 Namespace中通过不同Group进行同一环境中不同项目的再分类 。
注意: 通过上面的理论分析,可以看出方案二有很好的扩展性
8 将应用对接Nacos配置中心
新建配置
创建工程cloud-nacos-config3344
POM引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 分布式配置中心的依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
编写主启动类
/**
* 主启动类
*/
@SpringBootApplication
@Slf4j
@EnableDiscoveryClient
public class NacosConfigMain3344 {
public static void main(String[] args) {
SpringApplication.run(NacosConfigMain3344.class, args);
log.info("*********** NacosConfigMain3344 **********");
}
}
创建配置文件
创建配置文件名为 bootstrap.yml ,注意是bootstrap.yml,而不是 application 。
原因:
Nacos同SpringCloud-Config一样,在项目初始化时,要保证先从配置中心进行配置拉取,拉取配置之后,才能保证项目的正常启动。SpringBoot中配置文件的加载是存在优先级顺序的, bootstrap优先级高于application。
server:
port: 3344
spring:
application:
name: nacos-config
cloud:
nacos:
discovery:
server-addr: 114.117.183.67:8848
config:
# Nacos服务地址
server-addr: 114.117.183.67:8848
# 命名空间 不指定命名空间默认 public 指定命名空间 UUID
namespace: f2eb678c-f0b2-44b5-bb08-282ad0f8f067
# 指定配置群组 如果不指定就是默认 DEFAULT_GROUP
group: DEFAULT_GROUP
# 文件名 如果没有配置则默认为${spring.appliction.name}
prefix: nacos-config
#后缀
file-extension: yaml
profiles:
active: dev
注意:
- spring.application.name :可以看到必须可少的配置项
- spring.cloud.nacos.discovery.server-addr :指定注册中心的地址,如果你不需要注册该服务,也可以去掉该项,并删除discovery依赖
- spring.cloud.nacos.config.server-addr :指定配置中心的地址
- file-extension :指定配置中心中配置文件的格式
上面的配置是为了保证服务的正常注册和配置获取,以及配置 DataID 的正确性
创建对外接口来从nacos中读取配置
@RestController
public class NacosConfigController {
@Value("${nacos.config}")
private String config;
@RequestMapping("/getValue")
public String getValue() {
return config;
}
}
出现问题
出现报错,肯定配置写错了,检查5步曲
具体细节看下图
测试
请求http://localhost:3344/getValue
9 Nacos配置动态刷新
配置动态刷新
配置的动态刷新,仅需要使用 @RefreshScope注解即可。
注解方式
@RestController
/* 只需要在需要动态读取配置的类上添加此注解就可以 */
@RefreshScope
public class NacosConfigController {
@Value("${nacos.config}")
private String config;
@RequestMapping("/getValue")
public String getValue() {
return config;
}
}
10 Dubbo服务对接分布式配置中心
在cloud-dubbo-provider-payment8001和cloud-dubbo-consumer-order80中POM引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
控制台创建dataId
其中完整的配置内容为:
server:
port: 8001
spring:
cloud:
nacos:
discovery:
server-addr: 114.117.183.67:8848
#dubbo配置
dubbo:
scan:
base-packages: com.lxx.service
registry:
address: nacos://114.117.183.67:8848
timeout: 10000
protocol:
name: dubbo
port: -1
其中完整的配置内容为:
server:
port: 80
spring:
cloud:
nacos:
discovery:
server-addr: 114.117.183.67:8848
dubbo:
cloud:
# dubbo.cloud.subscribed-services:
# 表示要订阅服务的服务名,可以配置'*',代表订阅所有服务,不推荐使用。若需订阅多应用,使用 "," 分割。
subscribed-services: "*"
registry:
#注册地址
address: nacos://114.117.183.67:8848
timeout: 10000
protocol:
# Dubbo服务暴露的协议的配置 dubbo
name: dubbo
# 端口从20880开始 自增
port: -1
#Dubbo缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止Spring初始化完成,以便上线时,能及早发现问题,默认check=true。
#如果你的Spring容器是懒加载的,或者通过API编程延迟引用服务,请关闭check,否则服务临时不可用时,会抛出异常,拿到null引用,如果check=false,总是会返回引用,当服务恢复时,能自动连上。
#解决办法:
#可以通过check="false"关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
consumer:
check: false
cloud-dubbo-provider-payment8001创建bootstrap.yml
spring:
main:
allow-circular-references: true
allow-bean-definition-overriding: true
application:
name: provider-dubbo-payment
cloud:
nacos:
config:
# Nacos服务地址
server-addr: 114.117.183.67:8848
# 命名空间 不指定命名空间默认 public 指定命名空间 UUID
namespace: f2eb678c-f0b2-44b5-bb08-282ad0f8f067
# 指定配置群组 如果不指定就是默认 DEFAULT_GROUP
group: DEFAULT_GROUP
# 文件名 如果没有配置则默认为${spring.appliction.name}
prefix: provider-dubbo-payment
#后缀
file-extension: yaml
profiles:
active: dev
cloud-dubbo-consumer-order80创建bootstrap.yml
spring:
application:
name: consumer-dubbo-order
main:
allow-circular-references: true
allow-bean-definition-overriding: true
cloud:
nacos:
config:
# Nacos服务地址
server-addr: 114.117.183.67:8848
# 命名空间 不指定命名空间默认 public 指定命名空间 UUID
namespace: f2eb678c-f0b2-44b5-bb08-282ad0f8f067
# 指定配置群组 如果不指定就是默认 DEFAULT_GROUP
group: DEFAULT_GROUP
# 文件名 如果没有配置则默认为${spring.appliction.name}
prefix: consumer-dubbo-order
#后缀
file-extension: yaml
profiles:
active: dev
测试
请求http://localhost:80/order/index
11 Nacos集群架构介绍
为什么需要搭建Nacos集群
默认Nacos使用嵌入式数据库Derby实现数据的存储。所以,如果启动多个默认配置下的Nacos节点,数据存储是存在一致性问题的。为了解决这个问题,Nacos采用了集中式存储的方式来支持集群化部署,目前只支持MySQL的存储。
Nacos支持三种部署模式
- 单机模式 - 用于测试和单机试用。
- 集群模式 - 用于生产环境,确保高可用。
- 多集群模式 - 用于多数据中心场景。
集群模式
12 Nacos的数据持久化
初始化数据库
Nacos的数据库脚本文件在我们下载Nacos-server时的压缩包中就有,进入 \nacos\conf 目录,初始化文件: nacos-mysql.sql 此处我创建一个名为 mynacos 的数据库,然后执行初始化脚本,成功后会生成 11 张表;
Docker安装Mysql
查看镜像
docker search mysql:5.7
下载镜像
docker pull mysql:5.7
启动镜像
docker run --name mysql -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
参数:
-e 配置环境变量 MYSQL_ROOT_PASSWORD 设置容器内mysql root 密码
修改配置文件
这里是需要修改Nacos-server的配置文件Nacos-server其实就是一 个Java工程或者说是一个Springboot项目,他的配置文件在 nacos\conf目录下,名为 application.properties,在文件底部添加数据源配置:
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://114.117.183.67:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=123456
启动Nacos-server和Nacos-config
先启动Nacos-server,启动成功后进入Nacos控制台,此时的 Nacos控制台中焕然一新,之前的数据都不见了。
注意:
因为加入了新的数据源,Nacos从mysql中读取所有的配置文 件,而我们刚刚初始化的数据库是干干净净的,自然不会有什么数据和信息显示
在公共空间(public)中新建一个配置文件DataID: nacos-config.yaml , 配置内容如下:
server:
port: 9989
nacos:
config: 配置文件已持久化到数据库中...
再启动cloud-nacos-config3344。服务启动成功后,观察Nacos 控制台如下
验证是否持久化到数据库中
13 Nacos集群配置
集群启动
在本地通过3个端口模拟3台机器,端口分别是:8848,8858,8868。
#copy3份解压后的nacos,修改各自的application.properties中的端口号,分别为:8848,8858,8868
server.port=8848
server.port=8858
server.port=8868
各自的conf目录下放cluster.conf文件,文件内容为:
114.117.183.67:8848
114.117.183.67:8858
114.117.183.67:8868
分别启动3台Nacos服务
./startup.sh
注意:
如果内存不够可以修改内存参数。
- Xms 是指设定程序启动时占用内存大小
- Xmx 是指设定程序运行期间最大可占用的内存大小
- Xmn 新生代的大小
vim startup.sh
使用Nginx作负载均衡访问集群的Nacos
环境安装
yum -y install gcc make automake pcre-devel zlib zlib-devel openssl openssl-devel
安装Nginx
./configure
make && make install
配置nginx.conf文件
#定义upstream名字,下面会引用
upstream nacos{
#指定后端服务器地址
server 114.117.183.67:8848;
server 114.117.183.67:8858;
server 114.117.183.67:8868;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://nacos; #引用 upstream
}
}
启动nginx
./nginx
通过访问nginx就可以实现nacos访问的负载均衡
请求http://114.117.183.67/nacos