Nacos

  • Post author:
  • Post category:其他




Nacos



1.1 nacos-sever



1.1.1 下载安装

https://github.com/alibaba/nacos/releases



1.1.2 部署

解压后启动:

sh bin/startup.sh -m standalone


-m standalone

表示单机启动。

部署后访问

localhost:8848/nacos

可访问nacos控制台,然后以nacos/nacos(用户名/密码)登录。

停止nacos-server使用如下命令:

sh bin/shutdown.sh


1.1.3 数据持久化

nacos-sever默认使用的是derby数据库来保存数据的,derby是一个基于内存的数据库,所以在服务重新启动后,derby中保存的数据就会丢失。

在Nacos控制台

命名空间

菜单项中新建一个命名空间。然后重新启动,会发现新建的命名空间不见了。

  • 本地数据库

准备本地数据库,在数据库中执行nacos-server中

./conf/nacos-mysql.sql

,准备表数据。

  • 配置Mysql连接信息

修改nacos-server 项目中的

./conf/application.properties

数据库相关配置:

### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=1234
  • 重启server
> sh ./bin/shutdown.sh 
The nacosServer(52861) is running...
Send shutdown request to nacosServer(52861) OK
> ./bin/startup.sh -m standalone

在Nacos控制台

命名空间

菜单项中新建一个命名空间。然后重新启动,会发现新建的命名空间还在,说明持久化配置成功。



1.1.4 集群配置
  • 环境准备

将nacos-server复制出来3个,修改这3个nacos-server中

conf/application.properties

中的端口号及数据库配置。这三个nacos-server的端口分别为8848,8849,8850。

  • 集群配置

分别将naocs-server下的cluster.conf.example复制为cluster.conf,并在末尾修改或添加如下配置:

192.168.0.125:8848
192.168.0.125:8849
192.168.0.125:8850
  • 启动

分别在三个nacos-server下执行下面的命令启动:

sh bin/startup.sh

三个nacos-server启动后,访问127.0.0.1:8848/nacos, 127.0.0.1:8849/nacos, 127.0.0.1:8850/nacos可以访问对应的nacos-server。

在nacos-server控制台的

集群管理->节点列表

中可以看到三个server服务节点。



1.2 nacos-client



1.2.1 注册中心


准备

在Nacos控制台中

命名空间

菜单添加一个一个新的命名空间

Test

(命名空间ID项要为Test,与后面演示一致)。



父工程依赖

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>

    <!-- Spring Boot -->
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.6.3</version>
    </parent>

    <groupId>org.example</groupId>
    <artifactId>nacos</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>nacos-client01</module>
    </modules>
    <packaging>pom</packaging>

    <!-- Spring Cloud 及 Spring cloud alibaba 依赖管理 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2021.0.1.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>


本工程

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">
    <parent>
        <artifactId>nacos</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>nacos-client01</artifactId>

    <dependencies>
        <!-- Spring Cloud 项目加载 bootstrap.yml 文件 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>

        <!-- Nacos discover client -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

    </dependencies>


</project>


启动类

NacosClientApp.java


@SpringBootApplication
@EnableDiscoveryClient
public class NacosClientApp {
    public static void main(String[] args) {
        SpringApplication.run(NacosClientApp.class, args);
    }
}


配置

bootstrap.yml

server:
  port: 9000
spring:
  application:
    name: nacos-client
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: Test # 默认为Public
        group: TEST_GROUP # 默认为DEFAULT_GROUP

以上信息配置完成后,启动项目,观察nacos控制台


服务管理->服务列表->Test


中有当前服务。

服务名 分组名称 集群数目 实例数 健康实例数 触发保护阈值 操作
nacos-client TEST_GROUP 1 1 1 false 详情\示例代码\订阅者\ 删除


添加接口

NacosProviderController.java


@RestController
@RequestMapping("/provider")
public class NacosProviderController {

    @Value("${server.port}")
    private Integer port;

    @GetMapping("/port")
    public Integer port() {
        return port;
    }

    @GetMapping("/info")
    public String info() {
        return "Nacos provider info";
    }

}

重启服务,使接口生效。



1.2.2 服务消费

添加新的服务,作为消费方消费上面

nacos-client

提供的服务。



添加依赖

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">
    <parent>
        <artifactId>nacos</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>nacos-consumer01</artifactId>

    <dependencies>
        <!-- 加载 bootstrap.yml -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <!-- Nacos Discovery -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- loadbalancer -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <!-- Web模块 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>


</project>


配置

bootstrap.yml

server:
  port: 9010

spring:
  application:
    name: nacos-client-consumer01
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: Test
        group: TEST_GROUP



启动类

NacosConsumerApp.java


@SpringBootApplication
@EnableDiscoveryClient
// 开启Feign支持
@EnableFeignClients
public class NacosConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(NacosConsumerApp.class, args);
    }
}



Feign Client

NacosProviderClient.java


@FeignClient("nacos-client")
public interface NacosProviderClient {


    @GetMapping("/provider/port")
    Integer port();

    @GetMapping("/provider/info")
    String info();

}



请求接口

NacosConsumerController.java


@RestController
@RequestMapping("/consumer")
public class NacosConsumerController {
    @Resource
    private NacosProviderClient nacosProviderClient;

    @GetMapping("/provider/port")
    public Integer providerPort() {
        return nacosProviderClient.port();
    }

    @GetMapping("/provider/info")
    public String providerInfo() {
        return nacosProviderClient.info();
    }
}

启动项目访问接口,可正常访问到

nacos-client

服务。



1.2.2 配置中心

注册中心采用父工程+子模块的方式演示,为了能理清晰的知道导入的依赖的作用,该项目为单模块项目演示。



添加依赖

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>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.6.3</version>
        <relativePath/>
    </parent>


    <groupId>org.example</groupId>
    <artifactId>nacos-config-client</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2021.0.1.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>


启动类

NacosConfigClientApp.java


@SpringBootApplication
public class NacosConfigClientApp {
    public static void main(String[] args) {
        SpringApplication.run(NacosConfigClientApp.class, args);
    }
}


配置

bootstrap.yml

基本配置

server:
  port: 9003

spring:
  profiles:
    active: dev
  application:
    name: nacos-config-client
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        # 命名空间
        namespace: Test
        # 分组
        group: TEST_GROUP
        # 文件后缀
        file-extension: yml

对于以上配置,需要在Nacos控制台对应的namespace下新建一个配置文件,文件分组要为

TEST_GROUP

配置文件命名组成:

${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

进入Nacos控制台在

Test

命名空间下添加配置。 Data Id: nacos-config-client-dev.yml Group: TEST_GROUP 配置格式: yaml 配置内容:

server:
  port: 10003

配置好后启动项目。 控制台可以看到类似如下日志输出:

Ignore the empty nacos configuration and get it based on dataId[nacos-config-client] & group[TEST_GROUP]
Ignore the empty nacos configuration and get it based on dataId[nacos-config-client.yml] & group[TEST_GROUP]
.......
listening config: dataId=nacos-config-client-dev.yml, group=TEST_GROUP
listening config: dataId=nacos-config-client.yml, group=TEST_GROUP
listening config: dataId=nacos-config-client, group=TEST_GROUP

项目最终在10003端口(Nacos中配置)启动。

如果项目启动不是10003端口,而是本地配置文件中的端口,检查Nacos中的配置文件是否配置正确,如命名空间、分组配置。



配置动态刷新
  • 添加配置 修改Nacos中配置文件中的配置,并发布:
server:
  port: 10003

info: Nacos config test
  • 读取配置 编写AutoRefreshController.java读取配置:

@RefreshScope // 刷新配置
@RestController
@RequestMapping("/config")
public class AutoRefreshController {

    @Value("${info}")
    private String info;

    @GetMapping("/info")
    public String configInfo() {
        return info;
    }
}

启动项目,访问

/config/info

,可以看到接口返回配置文件中配置的内容。更改Nacos中的配置,再次访问接口查看响应数据也跟着发生变化。


@RefreshScope



多配置文件(扩展多个配置)
  • 配置文件

通过

extension-configs

添加多个配置文件:

server:
  port: 9003

spring:
  profiles:
    active: dev
  application:
    name: nacos-config-client
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        namespace: Test
        group: TEST_GROUP
        file-extension: yml
        # 添加扩展配置
        extension-configs:
          - dataId: datasource.yml
            group: DATASOURCE_GROUP
            # 是否自动刷新
            refresh: true
          - dataId: redis.yml
            group: CACHE_GROUP
            refresh: false
  • Nacos控制台添加配置

Data Id: datasource.yml

Group: DATASOURCE_GROUP

内容:

datasource:
  platform: mysql

Data Id: redis.yml

Group: CACHE_GROUP

内容:

redis:
  host: 127.0.0.1

  • 新增接口访问配置
@RefreshScope
@RestController
@RequestMapping("/config")
public class ConfigController {

    @Value("${datasource.platform}")
    private String datasourcePlatform;

    @Value("${redis.host}")
    private String redisHost;

    @GetMapping("/datasource/platform")
    public String datasourcePlatform() {
        return datasourcePlatform;
    }

    @GetMapping("/redis/host")
    public String redisHost() {
        return redisHost;
    }

}

启动项目,访问新增的两个接口,接口将响应新增的配置文件中对应的内容。(如果项目启动报错@Value加载不到配置,需要检查配置文件是否正确)。

  • 测试动态刷新

确保接口开启了自动刷新,

@RefreshScope

。由于配置文件datasource.yml开启了refresh,而redis.yml没有开启refresh,所以在nacos修改redis.yml的内容时,接口无法动态获取并刷新。



1.2.3 配置中心、服务发现及集群配置


依赖

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">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version>
        <relativePath/>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <version>1.0-SNAPSHOT</version>
    <artifactId>nacos-client-cluster</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2021.0.1.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</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.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>


启动类

NacosClientClusterApp.java

@SpringBootApplication
@EnableDiscoveryClient
public class NacosClientClusterApp {
    public static void main(String[] args) {
        SpringApplication.run(NacosClientClusterApp.class, args);
    }
}



配置

bootstrap.yml

server:
  port: 9004

spring:
  application:
    name: nacos-client-cluster
  cloud:
    nacos:
      server-addr: 192.168.0.125:8848,192.168.0.125:8849,192.168.0.125:8850
      discovery:
        namespace: Test
        group: TEST_GROUP
      config:
        namespace: Test
        group: TEST_GROUP
        file-extension: yml


Nacos-server中添加配置文件

Data ID: nacos-client-cluster.yml

Group: TEST_GROUP

配置格式: YAML

配置内容:

info: nacos client cluster info


添加接口

ClientInfoController.java

@RestController
public class ClientInfoController {

    @Value("${info}")
    private String info;

    @Value("${server.port}")
    private Integer port;

    @GetMapping("/info")
    public String info() {
        return info;
    }

    @GetMapping("/port")
    public Integer port() {
        return port;
    }

}



打成可执行jar包

要把项目打包成一个可执行jar包,在pom.xml添加如下配置:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

在项目根目录执行:

mvn package

执行完成后在 **项目根目录/target/**会生成nacos-client-cluster-1.0-SNAPSHOT.jar。



运行jar

执行下面命令运行jar包,使用多个服务构成集群

java -jar nacos-client-cluster-1.0-SNAPSHOT.jar --server.port=9004 
java -jar nacos-client-cluster-1.0-SNAPSHOT.jar --server.port=9005  
java -jar nacos-client-cluster-1.0-SNAPSHOT.jar --server.port=9006 

分别启动项目后,在nacos控制台

服务管理->服务列表

能看到服务nacos-client-cluster有三个实例。



2 Sentinel

高并发大流量导致系统服务不可用。Sentinel应对这些场景常见策略有服务降级、熔断、限流。



2.1 常见的限流算法



2.1.1 计数器算法

设定某个时间内接口访问频次,如1s访问某接口100次,访问达到100次后限制访问,进入下一秒时,计数器清零。但是处在临界值时,访问次数会变成2倍。如在临界值前0.5秒到1.5秒分别有访问了100次,那么这一秒内就连续访问了200次。



2.1.2 滑动窗口算法


2.1.3 令牌桶算法

固定大小的令牌桶,以一定的速率生成令牌(如果令牌桶满,生成的令牌丢弃)。每次接口访问前从桶中获取令牌,拥有令牌的请求才能继续访问。如果访问速率大于令牌生成速率,令牌桶中的令牌很快就被取完了,一些请求拿不到令牌就会触发限流。



2.1.4 漏桶限流算法

有一个以恒定速率出水的漏桶,每次能漏出的水是恒定的,如果进水速率大于出水速率漏桶很快就被填满,然后触发限流。



2.2



2.2.1 sentinel-server



下载

https://github.com/alibaba/Sentinel/releases



安装

将下载的jar包运行,服务默认在8080端口启动。

java -jar sentinel-dashboard-1.8.4.jar

访问 127.0.0.1:8080 ,然后以 sentinel/sentinel(用户名/密码)登录。



2.2.2 sentinel-client



添加依赖

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>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.6.3</version>
    </parent>

    <groupId>org.example</groupId>
    <artifactId>sentinel</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2021.0.1.0</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>


启动类

SentinelApp.java

@SpringBootApplication
public class SentinelApp {
    public static void main(String[] args) {
        SpringApplication.run(SentinelApp.class, args);
    }
}


配置文件
server:
  port: 9010

spring:
  application:
    name: sentinel-client
  cloud:
    sentinel:
      transport:
        # IP 访问
        dashboard: 127.0.0.1:8080


添加接口

SentinelController.java

@RestController
public class SentinelController {
    @Value("${server.port}")
    private Integer port;

    @GetMapping("/port")
    public Integer getPort() {
        return port;
    }
}

完成上述步骤后,启动项目并访问

/port

接口,然后在sentinel控制台可以看到当前服务的实例。



实时监控

菜单中可以看到接口访问信息,如QPS、响应时间等。



簇点链路

菜单中可以看到请求路径,并且可以配置流控、熔断等限制。



2.2.3 限流



限流配置

在Sentinel的

触点链路

菜单中对接口

/port

选择

流控

设置,并将单机阈值选项改为3。然后访问该接口,如果每秒钟访问该接口的频次大于3次,触发限流。

Blocked by Sentinel (flow limiting)


自定义限流异常
@Service
public class CustomBlockException implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        httpServletResponse.getWriter().write("{\"message\": \"访问频繁\"}");
    }
}



版权声明:本文为qq122516902原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。