blog

vuePress-theme-reco blog    2019 - 2020
blog blog

Choose mode

  • dark
  • auto
  • light
Home
Category
  • Linux
  • java
  • java 后端
  • typora
  • vue
  • java 基础
  • 编程方法
  • Mysql
Tag
TimeLine
在线工具
  • PDF 转换器
  • JSON 编辑器
  • MD 表格生成器
  • CRON 表达式
  • 代码格式化
  • 公式编辑器
  • 二维码生成器
  • 在线编码转换
  • YAML <-> Properties
  • 在线 Web 练习
Contact
  • GitHub
  • 简书
  • CSDN
  • 博客圆
  • WeChat
author-avatar

blog

23

文章

16

标签

Home
Category
  • Linux
  • java
  • java 后端
  • typora
  • vue
  • java 基础
  • 编程方法
  • Mysql
Tag
TimeLine
在线工具
  • PDF 转换器
  • JSON 编辑器
  • MD 表格生成器
  • CRON 表达式
  • 代码格式化
  • 公式编辑器
  • 二维码生成器
  • 在线编码转换
  • YAML <-> Properties
  • 在线 Web 练习
Contact
  • GitHub
  • 简书
  • CSDN
  • 博客圆
  • WeChat
  • SpringCloudAlibaba_01

    • Springboot创建项目与配置
      • 概述
      • 版本对应关系
      • 创建项目工程
      • 创建统一的依赖管理
      • 服务提供者
      • 服务消费者
      • 什么是 Feign
      • 附:扩展阅读
    • Nacos
      • Nacos Docker 快速开始
      • Nacos 分布式配置中心
      • Nacos多环境配置
    • Sentinel
      • 什么是服务雪崩
      • 什么是 Sentinel
      • Sentinel控制台
      • Sentinel客户端接入

SpringCloudAlibaba_01

vuePress-theme-reco blog    2019 - 2020

SpringCloudAlibaba_01


blog 2019-10-14 spring Cloud

# SpringCloudAlibaba_01

# Springboot创建项目与配置

# 概述

2018 年 10 月 31 日的凌晨,这个伟大的日子里,Spring Cloud Alibaba 正式入驻了 Spring Cloud 官方孵化器,并在 Maven 中央库发布了第一个版本。

Spring

Spring Cloud for Alibaba,它是由一些阿里巴巴的开源组件和云产品组成的。这个项目的目的是为了让大家所熟知的 Spring 框架,其优秀的设计模式和抽象理念,以给使用阿里巴巴产品的 Java 开发者带来使用 Spring Boot 和 Spring Cloud 的更多便利。

Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。

依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。

Spring Cloud Github

# 主要功能

  • 服务限流降级: 默认支持 Servlet、Feign、RestTemplate、Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
  • 服务注册与发现: 适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
  • 分布式配置管理: 支持分布式系统中的外部化配置,配置更改时自动刷新。
  • 消息驱动能力: 基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。
  • 阿里云对象存储: 阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。
  • 分布式任务调度: 提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有 Worker(schedulerx-client)上执行。

# 组件

  • Sentinel: 把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
  • Nacos: 一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
  • RocketMQ: 一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
  • Dubbo: Apache Dubbo™ 是一款高性能 Java RPC 框架。
  • Seata: 阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
  • Alibaba Cloud ACM: 一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心产品。
  • Alibaba Cloud OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
  • Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
  • Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。

# 注意:Spring Cloud Alibaba 已毕业

Spring Cloud Alibaba 已于 2019 年 7 月 30 日 从 Spring Cloud 孵化器中正式毕业并迎来了毕业的第一个版本,孵化器中的 Spring Cloud Alibaba 仓库迁移回 Alibaba 官方仓库,进行正式的毕业发布,对原有使用 Spring Cloud Alibaba 开发的项目影响如下:

# 更新包名和 Maven 坐标

接到阿里官方通知在 2019 年 7 月 4 日修改相关包名和 Maven 坐标,请参考 Update package name & maven coordinates ,由于视频录制于 2019 年 6 月 28 日,故所使用的包名和坐标依然沿用原先的 org.springframework.cloud,后面的视频会改用最新的标准,看到这里的小伙伴可以尝试使用新坐标。

# 包名修改

包名前缀由 org.springframework.cloud.alibaba 变更为 com.alibaba.cloud

# Maven 坐标修改

bom 由 spring-cloud-alibaba-dependencies 变更为 alibaba-spring-cloud-dependencies

maven groupid 由 org.springframework.cloud 变更为 com.alibaba.cloud

# Spring Cloud Alibaba
修改前 修改后
sentinel starter spring-cloud-starter-alibaba-sentinel alibaba-sentinel-spring-cloud-starter
nacos config starter spring-cloud-starter-alibaba-nacos-config alibaba-nacos-config-spring-cloud-starter
nacos discovery starter spring-cloud-starter-alibaba-nacos-discovery alibaba-nacos-discovery-spring-cloud-starter
seata starter spring-cloud-starter-alibaba-seata alibaba-seata-spring-cloud-starter
dubbo starter spring-cloud-starter-dubbo dubbo-spring-cloud-starter
rocketmq binder starter spring-cloud-starter-stream-rocketmq rocketmq-stream-spring-cloud-starter
rocketmq bus module name spring-cloud-starter-bus-rocketmq rocketmq-bus-spring-cloud-starter
sentinel module name spring-cloud-alibaba-sentinel alibaba-sentinel-spring-cloud
sentinel datasource module name spring-cloud-alibaba-sentinel-datasource alibaba-sentinel-datasource-spring-cloud
sentinel gateway module name spring-cloud-alibaba-sentinel-gateway alibaba-sentinel-gateway-spring-cloud
nacos config module name spring-cloud-alibaba-nacos-config alibaba-nacos-config-spring-cloud
nacos discovery module name spring-cloud-alibaba-nacos-discovery alibaba-nacos-discovery-spring-cloud
dubbo module name spring-cloud-alibaba-dubbo alibaba-dubbo-spring-cloud
seata module name spring-cloud-alibaba-seata alibaba-seata-spring-cloud
rocketmq binder module name spring-cloud-stream-binder-rocketmq rocketmq-spring-cloud-stream-binder
# Spring Cloud Alicloud(商业化组件)
修改前 修改后
oss starter spring-cloud-alicloud-oss alicloud-oss-spring-cloud
sms starter spring-cloud-alicloud-sms alicloud-sms-spring-cloud
schedulerx starter spring-cloud-alicloud-schedulerx alicloud-schedulerx-spring-cloud
ans starter spring-cloud-alicloud-ans alicloud-ans-spring-cloud
acm starter spring-cloud-alicloud-acm alicloud-acm-spring-cloud
oss module name spring-cloud-alicloud-oss alicloud-oss-spring-cloud
sms module name spring-cloud-alicloud-sms alicloud-sms-spring-cloud
schedulerx module name spring-cloud-alicloud-schedulerx alicloud-schedulerx-spring-cloud
ans module name spring-cloud-alicloud-ans alicloud-ans-spring-cloud
acm module name spring-cloud-alicloud-acm alicloud-acm-spring-cloud

# 版本对应关系

官网

"spring-cloud": {
      "Finchley.M2": "Spring Boot >=2.0.0.M3 and <2.0.0.M5",
      "Finchley.M3": "Spring Boot >=2.0.0.M5 and <=2.0.0.M5",
      "Finchley.M4": "Spring Boot >=2.0.0.M6 and <=2.0.0.M6",
      "Finchley.M5": "Spring Boot >=2.0.0.M7 and <=2.0.0.M7",
      "Finchley.M6": "Spring Boot >=2.0.0.RC1 and <=2.0.0.RC1",
      "Finchley.M7": "Spring Boot >=2.0.0.RC2 and <=2.0.0.RC2",
      "Finchley.M9": "Spring Boot >=2.0.0.RELEASE and <=2.0.0.RELEASE",
      "Finchley.RC1": "Spring Boot >=2.0.1.RELEASE and <2.0.2.RELEASE",
      "Finchley.RC2": "Spring Boot >=2.0.2.RELEASE and <2.0.3.RELEASE",
      "Finchley.SR4": "Spring Boot >=2.0.3.RELEASE and <2.0.999.BUILD-SNAPSHOT",
      "Finchley.BUILD-SNAPSHOT": "Spring Boot >=2.0.999.BUILD-SNAPSHOT and <2.1.0.M3",
      "Greenwich.M1": "Spring Boot >=2.1.0.M3 and <2.1.0.RELEASE",
      "Greenwich.SR3": "Spring Boot >=2.1.0.RELEASE and <2.1.10.BUILD-SNAPSHOT",
      "Greenwich.BUILD-SNAPSHOT": "Spring Boot >=2.1.10.BUILD-SNAPSHOT and <2.2.0.M4",
      "Hoxton.M2": "Spring Boot >=2.2.0.M4 and <2.2.0.BUILD-SNAPSHOT",
      "Hoxton.BUILD-SNAPSHOT": "Spring Boot >=2.2.0.BUILD-SNAPSHOT"
    },
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 创建项目工程

新建Springboot工程,不添加任何依赖,打开pom

# 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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.smxy</groupId>
    <artifactId>hello-spring-cloud-alibaba</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <url>https://rxt520.github.io/Ruan.X.T.blog</url>
        <modules>
            <module>hello-spring-cloud-alibaba-dependencies</module>
            <module>hello-spring-cloud-alibaba-provider</module>
        </modules>
    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>
    <licenses>
        <license>
            <name>Apache 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
        </license>
    </licenses>
    <developers>
        <developer>
            <id>ruanxiongteng</id>
            <name>Liberty ruan</name>
            <email>958465427@qq.com</email>
        </developer>
    </developers>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.smxy</groupId>
                <artifactId>hello-spring-cloud-alibaba-dependencies</artifactId>
                <version>${project.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <profiles>
        <profile>
            <id>default</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <spring-javaformat.version>0.0.12</spring-javaformat.version>
            </properties>
            <build>
                <plugins>
                    <plugin>
                        <groupId>io.spring.javaformat</groupId>
                        <artifactId>spring-javaformat-maven-plugin</artifactId>
                        <version>${spring-javaformat.version}</version>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <configuration>
                            <includes>
                                <include>**/*Tests.java</include>
                            </includes>
                            <excludes>
                                <exclude>**/Abstract*.java</exclude>
                            </excludes>
                            <systemPropertyVariables>
                                <java.security.egd>file:/dev/./urandom</java.security.egd>
                                <java.awt.headless>true</java.awt.headless>
                            </systemPropertyVariables>
                        </configuration>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-enforcer-plugin</artifactId>
                        <executions>
                            <execution>
                                <id>enforce-rules</id>
                                <goals>
                                    <goal>enforce</goal>
                                </goals>
                                <configuration>
                                    <rules>
                                        <bannedDependencies>
                                            <excludes>
                                                <exclude>commons-logging:*:*</exclude>
                                            </excludes>
                                            <searchTransitive>true</searchTransitive>
                                        </bannedDependencies>
                                    </rules>
                                    <fail>true</fail>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-install-plugin</artifactId>
                        <configuration>
                            <skip>true</skip>
                        </configuration>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-javadoc-plugin</artifactId>
                        <configuration>
                            <skip>true</skip>
                        </configuration>
                        <inherited>true</inherited>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
    <repositories>
        <repository>
            <id>spring-milestone</id>
            <name>Spring Milestone</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-snapshot</id>
            <name>Spring Snapshot</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestone</id>
            <name>Spring Milestone</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-snapshot</id>
            <name>Spring Snapshot</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161

# 创建统一的依赖管理

根目录新建文件夹hello-spring-cloud-alibaba-dependencies

新建文件pom

# 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.smxy</groupId>
    <artifactId>hello-spring-cloud-alibaba-dependencies</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <url>https://rxt520.github.io/Ruan.X.T.blog</url>
    <properties>
        <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
        <spring-cloud-alibaba.version>0.9.0.RELEASE</spring-cloud-alibaba.version>
    </properties>
    <licenses>
        <license>
            <name>Apache 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
        </license>
    </licenses>
    <developers>
        <developer>
            <id>ruanxiongteng</id>
            <name>Liberty ruan</name>
            <email>958465427@qq.com</email>
        </developer>
    </developers>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <repositories>
        <repository>
            <id>spring-milestone</id>
            <name>Spring Milestone</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-snapshot</id>
            <name>Spring Snapshot</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestone</id>
            <name>Spring Milestone</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-snapshot</id>
            <name>Spring Snapshot</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

# 服务提供者

服务提供方: 是指提供可复用和可调用服务的应用方
1

# POM

创建一个名为 hello-spring-cloud-alibaba-provider 的服务提供者项目,pom.xml 配置如下:

<?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>
    <parent>
        <groupId>com.smxy</groupId>
        <artifactId>hello-spring-cloud-alibaba</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>hello-spring-cloud-alibaba-provider</artifactId>
    <packaging>jar</packaging>
    <url>https://rxt520.github.io/Ruan.X.T.blog/</url>
    <inceptionYear>2018-Now</inceptionYear>
    <licenses>
        <license>
            <name>Apache 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
        </license>
    </licenses>
    <developers>
        <developer>
            <id>ruanxiongteng</id>
            <name>Liberty ruan</name>
            <email>958465427@qq.com</email>
        </developer>
    </developers>
    <dependencies>
        <!-- Spring Boot Begin -->
        <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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->
        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.smxy.spring.cloud.alibaba.provider.ProviderApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# application.yml

在 application.yml 中配置 Nacos Server 的地址

spring:
  application:
    # 服务名
    name: service-provider
  cloud:
    nacos:
      discovery:
        # 服务注册中心
        server-addr: 192.168.141.132:8848
server:
  # 服务端口
  port: 8070
management:
  # 端点检查(健康检查)
  endpoints:
    web:
      exposure:
        include: "*"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Application

通过 Spring Cloud 原生注解 @EnableDiscoveryClient 开启服务注册发现功能

package com.funtl.spring.cloud.alibaba.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }
}
1
2
3
4
5
6
7
8
9
10
11

# Controller

编写一个 RestController 提供 RESTFul API 用于测试提供者

package com.funtl.spring.cloud.alibaba.provider.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class EchoController {
    @GetMapping(value = "/echo/{string}")
    public String echo(@PathVariable String string) {
        return "Hello Nacos Provider " + string;
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 验证是否成功

通过浏览器访问 http:ip:8848/nacos Nacos Server 网址

# 服务端点检查

健康检查: 以指定方式检查服务下挂载的实例 (Instance) 的健康度,从而确认该实例 (Instance) 是否能提供服务。根据检查结果,实例 (Instance) 会被判断为健康或不健康。对服务发起解析请求时,不健康的实例 (Instance) 不会返回给客户端。

通过浏览器访问 http://localhost:8070/actuator/nacos-discovery

{
    "subscribe": [
        {
            "jsonFromServer": "",
            "name": "service-provider",
            "groupName": "DEFAULT_GROUP",
            "clusters": null,
            "cacheMillis": 1000,
            "hosts": [],
            "lastRefTime": 0,
            "checksum": "",
            "allIPs": false,
            "key": "service-provider",
            "valid": true,
            "keyEncoded": "service-provider"
        },
        {
            "jsonFromServer": "",
            "name": "service-consumer",
            "groupName": "DEFAULT_GROUP",
            "clusters": null,
            "cacheMillis": 1000,
            "hosts": [],
            "lastRefTime": 0,
            "checksum": "",
            "allIPs": false,
            "key": "service-consumer",
            "valid": true,
            "keyEncoded": "service-consumer"
        }
    ],
    "NacosDiscoveryProperties": {
        "serverAddr": "192.168.141.132:8848",
        "endpoint": "",
        "namespace": "",
        "watchDelay": 30000,
        "logName": "",
        "service": "service-provider",
        "weight": 1,
        "clusterName": "DEFAULT",
        "namingLoadCacheAtStart": "false",
        "metadata": {
            "preserved.register.source": "SPRING_CLOUD"
        },
        "registerEnabled": true,
        "ip": "192.168.141.1",
        "networkInterface": "",
        "port": 8070,
        "secure": false,
        "accessKey": "",
        "secretKey": ""
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# 服务消费者

服务消费方: 是指会发起对某个服务调用的应用方

服务消费者的创建与服务提供者大同小异,这里采用最原始的一种方式,即显示的使用 LoadBalanceClient 和 RestTemplate 结合的方式来访问

# POM

创建一个名为 hello-spring-cloud-alibaba-consumer 的服务消费者项目,pom.xml 配置如下:

<?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>
    <parent>
        <groupId>com.smxy</groupId>
        <artifactId>hello-spring-cloud-alibaba</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>hello-spring-cloud-alibaba-consumer</artifactId>
    <packaging>jar</packaging>
    <url>https://rxt520.github.io/Ruan.X.T.blog</url>
    <inceptionYear>2018-Now</inceptionYear>
    <licenses>
        <license>
            <name>Apache 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
        </license>
    </licenses>
    <developers>
        <developer>
            <id>ruanxiongteng</id>
            <name>Liberty ruan</name>
            <email>958465427@qq.com</email>
        </developer>
    </developers>
    <dependencies>
        <!-- Spring Boot Begin -->
        <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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->
        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.funtl.spring.cloud.alibaba.consumer.ConsumerApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# application.yml

在 application.yml 中配置 Nacos Server 的地址

spring:
  application:
    # 服务名
    name: service-consumer
  cloud:
    nacos:
      discovery:
        # 服务注册中心
        server-addr: 192.168.141.132:8848
server:
  # 服务端口
  port: 8080
management:
  # 端点检查(健康检查)
  endpoints:
    web:
      exposure:
        include: "*"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Application

通过 Spring Cloud 原生注解 @EnableDiscoveryClient 开启服务注册发现功能

package com.funtl.spring.cloud.alibaba.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}
1
2
3
4
5
6
7
8
9
10
11

# Configuration

创建一个 Java 配置类,主要作用是为了注入 RestTemplate

package com.funtl.spring.cloud.alibaba.consumer.configure;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConsumerConfiguration {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# Controller

package com.funtl.spring.cloud.alibaba.consumer.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class TestController {
    private final RestTemplate restTemplate;
    @Autowired
    public TestController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }
    @GetMapping(value = "/echo/{str}")
    public String echo(@PathVariable String str) {
        // 使用服务名请求服务提供者
        return restTemplate.getForObject("http://service-provider/echo/" + str, String.class);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 验证是否成功

通过浏览器访问 http://192.168.141.132:8848/nacos Nacos Server 网址

# 服务端点检查

通过浏览器访问 http://localhost:8080/actuator/nacos-discovery

{
    "subscribe": [
        {
            "jsonFromServer": "",
            "name": "service-provider",
            "groupName": "DEFAULT_GROUP",
            "clusters": null,
            "cacheMillis": 1000,
            "hosts": [],
            "lastRefTime": 0,
            "checksum": "",
            "allIPs": false,
            "key": "service-provider",
            "valid": true,
            "keyEncoded": "service-provider"
        },
        {
            "jsonFromServer": "",
            "name": "service-consumer",
            "groupName": "DEFAULT_GROUP",
            "clusters": null,
            "cacheMillis": 1000,
            "hosts": [],
            "lastRefTime": 0,
            "checksum": "",
            "allIPs": false,
            "key": "service-consumer",
            "valid": true,
            "keyEncoded": "service-consumer"
        }
    ],
    "NacosDiscoveryProperties": {
        "serverAddr": "192.168.141.132:8848",
        "endpoint": "",
        "namespace": "",
        "watchDelay": 30000,
        "logName": "",
        "service": "service-consumer",
        "weight": 1,
        "clusterName": "DEFAULT",
        "namingLoadCacheAtStart": "false",
        "metadata": {
            "preserved.register.source": "SPRING_CLOUD"
        },
        "registerEnabled": true,
        "ip": "192.168.141.1",
        "networkInterface": "",
        "port": 8080,
        "secure": false,
        "accessKey": "",
        "secretKey": ""
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# 什么是 Feign

Feign 是一个声明式的伪 HTTP 客户端,它使得写 HTTP 客户端变得更简单。使用 Feign,只需要创建一个接口并注解。它具有可插拔的注解特性,可使用 Feign 注解和 JAX-RS 注解。Feign 支持可插拔的编码器和解码器。Feign 默认集成了 Ribbon,Nacos 也很好的兼容了 Feign,默认实现了负载均衡的效果

  • Feign 采用的是基于接口的注解
  • Feign 整合了 Ribbon

# POM

在 hello-spring-cloud-alibaba-consumer 项目中增加 org.springframework.cloud:spring-cloud-starter-openfeign 依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
1
2
3
4

# Application

通过 @EnableFeignClients 注解开启 Feign 功能

package com.funtl.spring.cloud.alibaba.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# Service

创建业务结构,通过 @FeignClient("服务名") 注解来指定调用哪个服务

package com.funtl.spring.cloud.alibaba.consumer.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "service-provider")
public interface EchoService {
    @GetMapping(value = "/echo/{string}")
    String echo(@PathVariable("string") String string);
}
1
2
3
4
5
6
7
8
9

# Controller

package com.funtl.spring.cloud.alibaba.consumer.controller;
import com.funtl.spring.cloud.alibaba.consumer.service.EchoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestEchoController {
    @Autowired
    private EchoService echoService;
    @GetMapping(value = "/feign/echo/{str}")
    public String echo(@PathVariable String str) {
        return echoService.echo(str);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 验证是否成功

通过浏览器访问 http://localhost:8080/feign/echo/hi

Hello Nacos Provider hi
1

# 配置负载均衡

  • 修改 service-provider 服务的端口号如 8071,并启动多个实例,IDEA 中依次点击 Run -> Edit Configurations 并勾选 Allow parallel run 以允许 IDEA 多实例运行项目
  • 再次启动 service-provider 实例,IDEA Spring Boot 面板可以看到
  • Nacos Server 控制台可以看到 service-provider 有 2 个实例

服务: 通过预定义接口网络访问的提供给客户端的软件功能 服务名: 服务提供的标识,通过该标识可以唯一确定其指代的服务 服务分组: 不同的服务可以归类到同一分组 虚拟集群: 同一个服务下的所有服务实例组成一个默认集群,集群可以被进一步按需求划分,划分的单位可以是虚拟集群 实例: 提供一个或多个服务的具有可访问网络地址(IP:Port)的进程 权重: 实例级别的配置。权重为浮点数。权重越大,分配给该实例的流量越大 健康保护阈值: 为了防止因过多实例 (Instance) 不健康导致流量全部流向健康实例 (Instance) ,继而造成流量压力把健康 健康实例 (Instance) 压垮并形成雪崩效应,应将健康保护阈值定义为一个 0 到 1 之间的浮点数。当域名健康实例 (Instance) 占总服务实例 (Instance) 的比例小于该值时,无论实例 (Instance) 是否健康,都会将这个实例 (Instance) 返回给客户端。这样做虽然损失了一部分流量,但是保证了集群的剩余健康实例 (Instance) 能正常工作

  • 在 service-provider 项目的 EchoController 中增加测试方法
@Value("${server.port}")
private String port;
@GetMapping(value = "/lb")
public String lb() {
    return "Hello Nacos Provider i am from port: " + port;
}
1
2
3
4
5
6
  • 在 service-consumer 项目的 EchoService 中增加测试方法
@GetMapping(value = "/lb")
String lb();
1
2
  • 在 service-consumer 项目的 TestEchoController 中增加测试方法
@GetMapping(value = "/lb")
public String lb() {
    return echoService.lb();
}
1
2
3
4
  • 重启服务,通过浏览器访问 http://localhost:8080/lb ,反复刷新浏览器,浏览器交替显示
Hello Nacos Provider i am from port: 8070
Hello Nacos Provider i am from port: 8071
1
2

# 附:扩展阅读

# 常见负载均衡策略

负载主机可以提供很多种负载均衡方法,也就是我们常说的调度方法或算法

# 轮循

Round Robin: 这种方法会将收到的请求循环分配到服务器集群中的每台机器,即有效服务器。如果使用这种方式,所有的标记进入虚拟服务的服务器应该有相近的资源容量 以及负载形同的应用程序。如果所有的服务器有相同或者相近的性能那么选择这种方式会使服务器负载形同。基于这个前提,轮循调度是一个简单而有效的分配请求 的方式。然而对于服务器不同的情况,选择这种方式就意味着能力比较弱的服务器也会在下一轮循环中接受轮循,即使这个服务器已经不能再处理当前这个请求了。 这可能导致能力较弱的服务器超载。

# 加权轮循

Weighted Round Robin: 这种算法解决了简单轮循调度算法的缺点:传入的请求按顺序被分配到集群中服务器,但是会考虑提前为每台服务器分配的权重。管理员只是简单的通过服务 器的处理能力来定义各台服务器的权重。例如,能力最强的服务器 A 给的权重是 100,同时能力最低的服务器给的权重是 50。这意味着在服务器 B 接收到第一个 请求之前前,服务器 A 会连续的接受到 2 个请求,以此类推。

# 最少连接数

Least Connection: 以上两种方法都没有考虑的是系统不能识别在给定的时间里保持了多少连接。因此可能发生,服务器 B 服务器收到的连接比服务器 A 少但是它已经超载,因为 服务器 B 上的用户打开连接持续的时间更长。这就是说连接数即服务器的负载是累加的。这种潜在的问题可以通过 “最少连接数” 算法来避免:传入的请求是根据每 台服务器当前所打开的连接数来分配的。即活跃连接数最少的服务器会自动接收下一个传入的请求。接本上和简单轮询的原则相同:所有拥有虚拟服务的服务器资源 容量应该相近。值得注意的是,在流量率低的配置环境中,各服务器的流量并不是相同的,会优先考虑第一台服务器。这是因为,如果所有的服务器是相同的,那么 第一个服务器优先,直到第一台服务器有连续的活跃流量,否则总是会优先选择第一台服务器。

# 最少连接数慢启动时间

Least Connection Slow Start Time: 对最少连接数和带权重的最小连接数调度方法来说,当一个服务器刚加入线上环境是,可以为其配置一个时间段,在这段时间内连接数是有限制的而且是缓慢 增加的。这为服务器提供了一个‘过渡时间’以保证这个服务器不会因为刚启动后因为分配的连接数过多而超载。这个值在 L7 配置界面设置。

# 加权最少连接

Weighted Least Connection: 如果服务器的资源容量各不相同,那么 “加权最少连接” 方法更合适:由管理员根据服务器情况定制的权重所决定的活跃连接数一般提供了一种对服务器非常 平衡的利用,因为他它借鉴了最少连接和权重两者的优势。通常,这是一个非常公平的分配方式,因为它使用了连接数和服务器权重比例;集群中比例最低的服务器 自动接收下一个请求。但是请注意,在低流量情况中使用这种方法时,请参考 “最小连接数” 方法中的注意事项。

# 基于代理的自适应负载均衡

Agent Based Adaptive Balancing: 除了上述方法之外,负载主机包含一个自适用逻辑用来定时监测服务器状态和该服务器的权重。对于非常强大的 “基于代理的自适应负载均衡” 方法来说,负 载主机以这种方式来定时检测所有服务器负载情况:每台服务器都必须提供一个包含文件,这个文件包含一个 0~99 的数字用来标明改服务器的实际负载情况 (0 = 空前,99 = 超载,101 = 失败,102 = 管理员禁用),而服务器同构 http get 方法来获取这个文件;同时对集群中服务器来说,以二进制文件形式提供自身负载情况也是该服务器工作之一,然而,并没有限制服务器如何计算自身的负载 情况。根据服务器整体负载情况,有两种策略可以选择:在常规的操作中,调度算法通过收集的服务器负载值和分配给该服务器的连接数的比例计算出一个权重比 例。因此,如果一个服务器负载过大,权重会通过系统透明的作重新调整。和加权轮循调度方法一样,不正确的分配可以被记录下来使得可以有效的为不同服务器分 配不同的权重。然而,在流量非常低的环境下,服务器报上来的负载值将不能建立一个有代表性的样本;那么基于这些值来分配负载的话将导致失控以及指令震荡。 因此,在这种情况下更合理的做法是基于静态的权重比来计算负载分配。当所有服务器的负载低于管理员定义的下限时,负载主机就会自动切换为加权轮循方式来分 配请求;如果负载大于管理员定义的下限,那么负载主机又会切换回自适应方式。

# 固定权重

Fixed Weighted: 最高权重只有在其他服务器的权重值都很低时才使用。然而,如果最高权重的服务器下降,则下一个最高优先级的服务器将为客户端服务。这种方式中每个真实服务器的权重需要基于服务器优先级来配置。

# 加权响应

Weighted Response: 流量的调度是通过加权轮循方式。加权轮循中所使用的权重是根据服务器有效性检测的响应时间来计算。每个有效性检测都会被计时,用来标记它响应成功花 了多长时间。但是需要注意的是,这种方式假定服务器心跳检测是基于机器的快慢,但是这种假设也许不总是能够成立。所有服务器在虚拟服务上的响应时间的总和 加在一起,通过这个值来计算单个服务物理服务器的权重;这个权重值大约每 15 秒计算一次。

# 源 IP 哈希

Source IP Hash: 这种方式通过生成请求源 IP 的哈希值,并通过这个哈希值来找到正确的真实服务器。这意味着对于同一主机来说他对应的服务器总是相同。使用这种方式,你不需要保存任何源 IP。但是需要注意,这种方式可能导致服务器负载不平衡。

# Nacos

# Nacos Docker 快速开始

Clone 项目

git clone https://github.com/nacos-group/nacos-docker.git
cd nacos-docker
1
2
  • 单机模式 Derby

    docker-compose -f example/standalone-derby.yaml up -d
    
    1
  • 单机模式 Mysql

    docker-compose -f example/standalone-mysql.yaml up -d
    
    1
  • 集群模式

    docker-compose -f example/cluster-hostname.yaml up -d
    
    1
  • 服务注册

    curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'
    
    1
  • 服务发现

    curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instances?serviceName=nacos.naming.serviceName'
    
    1
  • 发布配置

    curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=helloWorld"
    
    1
  • 获取配置

      curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"
    
    1
  • Nacos 控制台

    link:http://127.0.0.1:8848/nacos/
    
    1
  • 查看日志

    docker-compose -f example/standalone-derby.yaml logs
    
    1

# Nacos 分布式配置中心

# 概述

在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件

# 什么是 Nacos Config

Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持。使用 Spring Cloud Alibaba Nacos Config,您可以在 Nacos Server 集中管理你 Spring Cloud 应用的外部属性配置。

Spring Cloud Alibaba Nacos Config 是 Spring Cloud Config Server 和 Client 的替代方案,客户端和服务器上的概念与 Spring Environment 和 PropertySource 有着一致的抽象,在特殊的 bootstrap 阶段,配置被加载到 Spring 环境中。当应用程序通过部署管道从开发到测试再到生产时,您可以管理这些环境之间的配置,并确保应用程序具有迁移时需要运行的所有内容。

# 接入配置中心

# POM

我们以 service-consumer 项目为例,修改 pom.xml ,引入 Nacos Config Starter

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
1
2
3
4

# Controller

完成上述两步后,应用会从 Nacos Config 中获取相应的配置,并添加在 Spring Environment 的 PropertySources 中。这里我们使用 @Value 注解来将对应的配置注入到 TestEchoController 的 username字段,并添加 @RefreshScope 打开动态刷新功能

package com.funtl.spring.cloud.alibaba.consumer.controller;
import com.funtl.spring.cloud.alibaba.consumer.service.EchoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RefreshScope
@RestController
public class TestEchoController {
    @Autowired
    private EchoService echoService;
    @Value("${user.name}")
    private String username;
    @GetMapping(value = "/config")
    public String config() {
        return echoService.echo(username);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 使用控制台发布配置

通过浏览器访问 http://192.168.141.132:8848/nacos ,访问 Nacos Server

img

img

注意: Data ID 的默认扩展名为 .properties ,希望使用 YAML 配置,此处必须指明是 .yaml

img

spring:
  application:
    # 服务名
    name: service-consumer
  cloud:
    nacos:
      discovery:
        # 服务注册中心
        server-addr: 192.168.12.130:8848
server:
  # 服务端口
  port: 8080
management:
  # 端点检查(健康检查)
  endpoints:
    web:
      exposure:
        include: "*"
user:
  name: "RXT"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 修改客户端配置

创建名为 bootstrap.properties 的配置文件并删除之前创建的 application.yml 配置文件

spring.application.name=service-consumer-config
spring.cloud.nacos.config.server-addr=192.168.12.130:8848
spring.cloud.nacos.config.file-extension=yaml
1
2
3

通过浏览器访问 http://localhost:8080/config ,浏览器输出如下

Hello Nacos Provider 灶门炭治郎
1

注意: Spring Boot 配置文件的加载顺序,依次为 bootstrap.properties -> bootstrap.yml -> application.properties -> application.yml ,其中 bootstrap.properties 配置为最高优先级

# 动态刷新配置

在 Nacos Server 控制台修改配置文件,将 user.name 属性修改为 灶门祢豆子,此时观察控制台日志,你会发现我们已经成功刷新了配置

img

# 验证是否成功

通过浏览器访问 http://localhost:8080/config ,浏览器输出如下

Hello Nacos Provider 灶门祢豆子
1

提示: 你可以使用 spring.cloud.nacos.config.refresh.enabled=false 来关闭动态刷新

# 附:扩展阅读

# Endpoint 信息查看

Spring Boot 应用支持通过 Endpoint 来暴露相关信息,Nacos Config Starter 也支持这一点。在使用之前需要在 maven 中添加 spring-boot-starter-actuator依赖,并在配置中允许 Endpoints 的访问。

  • nacos-discovery: http://localhost:8080/actuator/nacos-discovery
{
    "subscribe": [
        {
            "jsonFromServer": "",
            "name": "service-consumer",
            "groupName": "DEFAULT_GROUP",
            "clusters": null,
            "cacheMillis": 1000,
            "hosts": [],
            "lastRefTime": 0,
            "checksum": "",
            "allIPs": false,
            "key": "service-consumer",
            "valid": true,
            "keyEncoded": "service-consumer"
        },
        {
            "jsonFromServer": "",
            "name": "service-provider",
            "groupName": "DEFAULT_GROUP",
            "clusters": null,
            "cacheMillis": 1000,
            "hosts": [],
            "lastRefTime": 0,
            "checksum": "",
            "allIPs": false,
            "key": "service-provider",
            "valid": true,
            "keyEncoded": "service-provider"
        }
    ],
    "NacosDiscoveryProperties": {
        "serverAddr": "192.168.141.132:8848",
        "endpoint": "",
        "namespace": "",
        "watchDelay": 30000,
        "logName": "",
        "service": "service-consumer",
        "weight": 1,
        "clusterName": "DEFAULT",
        "namingLoadCacheAtStart": "false",
        "metadata": {
            "preserved.register.source": "SPRING_CLOUD"
        },
        "registerEnabled": true,
        "ip": "192.168.141.1",
        "networkInterface": "",
        "port": 8080,
        "secure": false,
        "accessKey": "",
        "secretKey": ""
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  • nacos-config: http://localhost:8080/actuator/nacos-config
{
    "NacosConfigProperties": {
        "serverAddr": "192.168.141.132:8848",
        "encode": null,
        "group": "DEFAULT_GROUP",
        "prefix": null,
        "fileExtension": "yaml",
        "timeout": 3000,
        "endpoint": null,
        "namespace": null,
        "accessKey": null,
        "secretKey": null,
        "contextPath": null,
        "clusterName": null,
        "name": null,
        "sharedDataids": null,
        "refreshableDataids": null,
        "extConfig": null
    },
    "RefreshHistory": [
        {
            "timestamp": "2019-06-30 18:30:45",
            "dataId": "service-consumer-config.yaml",
            "md5": "690fd78b5ae9fac5b545c1a8d7ec4e2b"
        },
        {
            "timestamp": "2019-06-30 18:22:08",
            "dataId": "service-consumer-config.yaml",
            "md5": "40b12ffc9d305ec1cad65d606e8f4708"
        }
    ],
    "Sources": [
        {
            "lastSynced": "2019-06-30 18:22:05",
            "dataId": "service-consumer-config.yaml"
        }
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

注意: Sources 表示此客户端从哪些 Nacos Config 配置项中获取了信息,RefreshHistory 表示动态刷新的历史记录,最多保存20条,NacosConfigProperties 则为 Nacos Config Starter 本身的配置

# 更多配置

配置项 key 默认值 说明
服务端地址 spring.cloud.nacos.config.server-addr
DataId前缀 spring.cloud.nacos.config.prefix spring.application.name
Group spring.cloud.nacos.config.group DEFAULT_GROUP
dataID后缀及内容文件格式 spring.cloud.nacos.config.file-extension properties dataId的后缀,同时也是配置内容的文件格式,目前只支持 properties
配置内容的编码方式 spring.cloud.nacos.config.encode UTF-8 配置的编码
获取配置的超时时间 spring.cloud.nacos.config.timeout 3000 单位为 ms
配置的命名空间 spring.cloud.nacos.config.namespace 常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源隔离等。
AccessKey spring.cloud.nacos.config.access-key
SecretKey spring.cloud.nacos.config.secret-key
相对路径 spring.cloud.nacos.config.context-path 服务端 API 的相对路径
接入点 spring.cloud.nacos.config.endpoint UTF-8 地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址
是否开启监听和自动刷新 spring.cloud.nacos.config.refresh.enabled true

# 更多介绍

Nacos为用户提供包括动态服务发现,配置管理,服务管理等服务基础设施,帮助用户更灵活,更轻松地构建,交付和管理他们的微服务平台,基于 Nacos, 用户可以更快速的构建以“服务”为中心的现代云原生应用。Nacos 可以和 Spring Cloud、Kubernetes/CNCF、Dubbo 等微服务生态无缝融合,为用户提供更卓越的体验

# Nacos多环境配置

# 概述

我们在做项目开发的时候,生产环境和测试环境的一些配置可能会不一样,有时候一些功能也可能会不一样,所以我们可能会在上线的时候手工修改这些配置信息。Spring 为我们提供了 Spring Boot Profile 这个功能(Maven 也为我们提供了 Maven Profile)。我们只需要在启动的时候添加一个虚拟机参数,激活自己环境所要用的 Profile 就可以了。

操作起来很简单,只需要为不同的环境编写专门的配置文件,如:application-dev.yml、application-prod.yml, 启动项目时只需要增加一个命令参数 --spring.profiles.active= 环境配置即可

java -jar 1.0.0-SNAPSHOT.jar --spring.profiles.active=prod
1

# 什么是 Nacos Config Profile

spring-cloud-starter-alibaba-nacos-config 在加载配置的时候,不仅仅加载了以 dataid 为 ${spring.application.name}.${file-extension:properties} 为前缀的基础配置,还加载了 dataid 为 ${spring.application.name}-${profile}.${file-extension:properties} 的基础配置。在日常开发中如果遇到多套环境下的不同配置,可以通过 Spring 提供的 ${spring.profiles.active} 这个配置项来配置。

# 使用 Nacos Config Profile

我们以 service-provider 项目为例,演示多环境配置效果,不要忘记依赖 Nacos Config Starter

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
1
2
3
4

# 使用控制台发布配置

注意: 控制台发布配置时不要加注释,否则打成 Jar 包后运行会报无法解析配置文件的错误

通过浏览器访问 http://192.168.141.132:8848/nacos ,访问 Nacos Server

  • 发布一个名为 service-provider-config.yaml 的 测试环境 配置
spring:
  application:
    # 服务名
    name: service-provider
  cloud:
    nacos:
      discovery:
        # 服务注册中心
        server-addr: 192.168.12.130:8848
server:
  # 服务端口
  port: 8070
management:
  # 端点检查(健康检查)
  endpoints:
    web:
      exposure:
        include: "*"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • 发布一个名为 service-provider-config-prod.yaml 的 生产环境 配置
spring:
  application:
    # 服务名
    name: service-provider
  cloud:
    nacos:
      discovery:
        # 服务注册中心
        server-addr: 192.168.12.130:8848
server:
  # 修改了上面的端口号,区分配置的不同
  port: 8071
management:
  # 端点检查(健康检查)
  endpoints:
    web:
      exposure:
        include: "*"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 修改客户端配置

  • 创建名为 bootstrap.properties 的配置文件并删除之前创建的 application.yml 配置文件
spring.application.name=service-provider-config
spring.cloud.nacos.config.server-addr=192.168.12.130:8848
spring.cloud.nacos.config.file-extension=yaml
1
2
3
  • 创建名为 bootstrap-prod.properties 的配置文件
spring.profiles.active=prod
spring.application.name=service-provider-config
spring.cloud.nacos.config.server-addr=192.168.12.130:8848
spring.cloud.nacos.config.file-extension=yaml
1
2
3
4

# 测试多环境配置

此时我们有两个配置文件,分别为 bootstrap.properties 和 bootstrap-prod.properties ,我们需要指定启动时加载哪一个配置文件

Run -> Edit Configurations -> Active profiles:

img

运行项目并观察日志

img

由上图可知,我们成功加载了不同环境的配置

# Sentinel

# 什么是服务雪崩

在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以通过 HTTP/RPC 相互调用,在 Spring Cloud 中可以用 RestTemplate + LoadBalanceClient 和 Feign 来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证 100% 可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet 容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 “雪崩” 效应。为了解决这个问题,业界提出了 熔断器模型。

阿里巴巴开源了 Sentinel 组件,实现了熔断器模式,Spring Cloud 对这一组件进行了整合。在微服务架构中,一个请求需要调用多个服务是非常常见的

img

较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阀值熔断器将会被打开

img

熔断器打开后,为了避免连锁故障,通过 fallback 方法可以直接返回一个固定值。

# 什么是 Sentinel

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

# Sentinel 的特征

  • 丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷(对于突然到来的大量请求,您可以配置流控规则,以稳定的速度逐步处理这些请求,从而避免流量突刺造成系统负载过高)、集群流量控制、实时熔断下游不可用应用等
  • 完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况
  • 广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架 / 库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel
  • 完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等

# Sentinel 的主要特性

img

# Sentinel 的开源生态

img

# Sentinel 的组成

  • 核心库(Java 客户端): 不依赖任何框架 / 库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持
  • 控制台(Dashboard): 基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器

# Sentinel控制台

# 概述

Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。另外,鉴权在生产环境中也必不可少。这里,我们将会详细讲述如何通过简单的步骤就可以使用这些功能。Sentinel 控制台最少应该包含如下功能

  • 查看机器列表以及健康情况: 收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
  • 监控 (单机和集群聚合): 通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
  • 规则管理和推送: 统一管理推送规则。
  • 鉴权: 生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。

# 启动控制台

# 获取

您可以从 官方 GitHub Release 页面 页面下载最新版本的控制台 JAR 包。

# 启动

注意: 启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本

java -Dserver.port=8888 -Dcsp.sentinel.dashboard.server=localhost:8888 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
1

其中 -Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080

注意: 从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的 登录 功能,默认用户名和密码都是 sentinel

# 鉴权

用户可以通过如下参数进行配置

  • -Dsentinel.dashboard.auth.username=sentinel 用于指定控制台的登录用户名为 sentinel
  • -Dsentinel.dashboard.auth.password=123456 用于指定控制台的登录密码为 123456;如果省略这两个参数,默认用户和密码均为 sentinel
  • -Dserver.servlet.session.timeout=7200 用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟
# 验证安装是否成功

通过浏览器访问 http://localhost:8080/#/login

img

  • 账号: sentinel
  • 密码: sentinel

img

详细说明请参考 官方 Sentinel Wiki

# Sentinel客户端接入

# POM

如果要在您的项目中引入 Sentinel,需要增加 org.springframework.cloud:spring-cloud-starter-alibaba-sentinel Starter POM

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
1
2
3
4

# 修改配置文件

在 Nacos 控制台修改配置文件,增加对 Sentinel 的支持

spring:
  application:
    # 服务名
    name: service-consumer
  cloud:
    nacos:
      discovery:
        # 服务注册中心
        server-addr: 192.168.141.132:8848
      config:
        # 服务配置中心
        server-addr: 192.168.141.132:8848
    # 熔断限流
    sentinel:
      transport:
        dashboard: localhost:8888
# 开启 Feign 对 Sentinel 的支持
feign:
  sentinel:
    enabled: true
server:
  # 服务端口
  port: 8080
management:
  # 端点检查(健康检查)
  endpoints:
    web:
      exposure:
        include: "*"
user:
  name: "灶门祢豆子"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 配置熔断类

编写一个 Feign 接口的实现类并增加 @Component 注解

package com.funtl.spring.cloud.alibaba.consumer.service.fallback;
import com.funtl.spring.cloud.alibaba.consumer.service.EchoService;
import org.springframework.stereotype.Component;
@Component
public class EchoServiceFallback implements EchoService {
    @Override
    public String echo(String string) {
        return "echo fallback";
    }
    @Override
    public String lb() {
        return "lb fallback";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 修改 Feign 接口

在 @FeignClient 接口上增加 fallback 属性指定熔断类即可

package com.funtl.spring.cloud.alibaba.consumer.service;
import com.funtl.spring.cloud.alibaba.consumer.service.fallback.EchoServiceFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "service-provider", fallback = EchoServiceFallback.class)
public interface EchoService {
    @GetMapping(value = "/echo/{string}")
    String echo(@PathVariable("string") String string);
    @GetMapping(value = "/lb")
    String lb();
}
1
2
3
4
5
6
7
8
9
10
11
12

# 测试熔断

启动 service-consumer 服务并停止 service-provider 服务,通过浏览器访问 http://localhost:8080/feign/echo/hi

echo fallback
1

img

注意: 必须至少请求过一次才能在 Sentinel 控制台看到对应的服务