SpringCloudAlibaba系列微服务搭建笔记一_Nacos

二、SpringCloud技术栈

Spring Cloud 本身并不是一个拿来即用的框架,而是一套规范。主流的 Spring Cloud NetfixSpring Cloud Alibaba 实现了这一套规范

微服务常用技术栈:

技术栈落地实现
服务注册与返现Eureka、Zookeeper、Consul、Nacos
服务熔断、限流、降级Hystrix、Reslience4j、Sentinel
服务调用Ribbin、Loadbalancer、Feign、OpenFeign、Dubbo
配置中心Config、Zookeeper、Consul、Nacos
服务网关Zuul、Gateway
消息总线Bus、Nacos

Spring Cloud Alibaba 微服务解决方案提供的组件:

组件名详情
Nacos服务注册与发现、服务管理、配置中心
RocketMQ分布式消息中间件,主要提供可靠的消息发布与订阅消费服务
Dubbo Spring Cloud远程调用框架
Sentinel流程控制框架,提供服务限流、降级、熔断等功能,保证服务的稳定性
Seata分布式事务解决方案,保证数据一致性
OSS(收费)高可用的文件存储服务
SchedulerX(收费)分布式任务调度
SMS(收费)短信服务

三、环境搭建

3.1 开发环境搭建

  • JDK1.8(最低)
  • Maven 3.6.3
  • IDEA 2019.3.4

3.2 安装部署mysql

版本5.7.24

3.3 创建 SpringBoot 项目

3.3.1 简介

Spring Boot简化了Spring MVC:

  • 集成了很多第三方技术框架如数据库MQ等
  • 简化了配置文件,不需要 XML 文件配置
  • 内嵌Tomcat、Jetty、Undertow Servlet容器,默认用Tomcat

3.3.2 构建项目

创建 SpringBoot项目有很多种方式

  • 到 SpringBoot 官网用网页创建,地址:https://start.spring.io
  • 使用IDEA创建,主界面点击Create New Project,选择 Spring Initializr
  • 使用阿里云的网页创建,地址:https://start.aliyun.com

这里选择到官网用网页创建
创建之前先查询版本依赖关系,选择一个
https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
![在这里插入图片描述](https://img-blog.csdnimg.cn/2734fe806aa0425d86dc0980b28747a6.png在这里插入图片描述

这里选了springboot 2.6.11,(随便选)后面再改 ,依赖只加了个 Spring Web
在这里插入图片描述

3.3.3 热部署

添加依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

配置
在这里插入图片描述
配置注册表
在这里插入图片描述
在这里插入图片描述

3.4 建立 Spring Cloud Alibaba 模板项目

搭建 Spring Cloud Alibaba 需要基于 Spring Boot 项目

3.4.1创建父项目

以父子项目的形式管理整个 Spring Cloud Alibaba 项目
先创建一个 Maven 项目作为父项目,再把之前生成的 smaple 项目加进去即可
在这里插入图片描述

再修改 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- 在依赖管理中声明了spring boot 依赖,就可以不用继承这种方式 -->
    <!-- <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.11</version>
        <relativePath/> &lt;!&ndash; lookup parent from repository &ndash;&gt;
    </parent>-->
    <!-- 项目信息 -->
    <groupId>com.echoo</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.0</version>
    <name>echoo-cloud</name>
    <description>Parent For Spring Cloud Alibaba</description>

    <modules>
        <module>sample</module>
    </modules>

    <!-- 版本管理 -->
    <properties>
        <java.version>1.8</java.version>
        <spring.boot.version>2.3.2.RELEASE</spring.boot.version>
        <spring.cloud.version>Spring Cloud Hoxton.SR9</spring.cloud.version>
        <spring.cloud.alibaba.version>2.2.6.RELEASE</spring.cloud.alibaba.version>
    </properties>

    <!-- 依赖管理 -->
    <dependencyManagement>
        <dependencies>
            <!-- spring-boot 依赖,代替继承的方式 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- spring-boot-starter-web 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>${spring.boot.version}</version>
            </dependency>
            <!-- spring-boot测试 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <version>${spring.boot.version}</version>
                <scope>test</scope>
            </dependency>
            <!-- spring-cloud-dependencies -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- spring-cloud-alibaba-dependencies -->
            <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>


        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!-- maven 编译插件,用于编译java代码 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <!-- 指定源代码和目标代码的JDK版本
                        否则会使用与当前maven版本对应的默认JDK版本去识别、编译代码
                         很有可能会识别、编译失败 -->
                    <source>${java.version}</source> <!-- 指定源代码使用的 JDK 版本,用于事变 -->
                    <target>${java.version}</target> <!-- 生成目标(.class)文件的JDK版本,用于编译-->
                    <encoding>UTF-8</encoding> <!-- 字符集编码 -->
                </configuration>
            </plugin>
        </plugins>
    </build>

    <!-- 使用远程仓库 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>

    <!-- 使用远程插件仓库 -->
    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </pluginRepository>
        <pluginRepository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

</project>

sample.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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.echoo</groupId>
        <artifactId>parent</artifactId>
        <version>1.0.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.echoo.base</groupId>
    <artifactId>sample</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sample</name>
    <description>base project for Spring Cloud Alibaba</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 热部署,单独作用于模块,所以不用声明在父pom -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

四、服务中心、配置中心-Nacos

4.1 Nacos 简介

Nacos = Naming + Configuration +Service
           = 服务命名管理 + 配置管理 + 服务注册中心

4.2 Nacos下载安装

地址:https://github.com/alibaba/nacos/releases
根据推荐版本,这里选择下载 v1.4.2
在这里插入图片描述
我选择了用 docker 镜像装在自己的云服务器上,参考:https://blog.csdn.net/qq_31856061/article/details/123621927
安装后直接访问,修改密码即可。

4.3 使用Nacos的服务注册中心功能

下面正式开始编写代码,将会编写一个消费服务,两个服务供应,服务之间的调用暂时用 RestTemplate + Ribbon 实现,顺带测试一下负载均衡的效果。

4.3.1 创建第一个服务provider

在之前创建了一个父子项目 echoo-cloud
复制一份修改一下项目名称路径pom.xml文件即可
父 pom.xml

    <!-- 项目信息 -->
    <groupId>com.echoo.cloud.nacos</groupId>
    <artifactId>spring-cloud-alibaba-nacos-sample</artifactId>
    <version>1.0.0</version>
    <name>spring-cloud-alibaba-nacos-sample</name>
    <description>nacos-sample</description>

子 pom.xml

    <parent>
        <groupId>com.echoo.cloud.nacos</groupId>
        <artifactId>spring-cloud-alibaba-nacos-sample</artifactId>
        <version>1.0.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.echoo.cloud.nacos.provicer</groupId>
    <artifactId>provider8031</artifactId>
    <version>1.0.0</version>
    <name>provider8031</name>
    <description>nacos-provider8031</description>

修改项目的项目名和目录名
在这里插入图片描述
因为子项目的目录修改了,所以父项目的 pom.xml 对子项目的引用也要改

    <!-- 引入子模块(子模块的相对目录) -->
    <modules>
        <module>provider8031</module>
    </modules>

在 Provider8031 的 pom.xml 中添加 Nacos 注册中心/服务发现和健康监控依赖

<!-- 服务健康监控 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Nacos 服务注册/服务发现 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

配置文件:

server:
  port: 8031 # 服务端口

spring:
  application:
    name: nacos-provider-one # 应用名
  cloud:
    nacos:
      discovery:
        server-addr: 124.221.89.209:8849 # Nacos 服务地址
        
management:
  endpoints:
    web:
      exposure:
        include: '*' # 公开所有端点

编写测试接口

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

    @RequestMapping("/test")
    public String test() {
        return "信息返回自①号服务,服务端口:" + port;
    }
}

复制一份 provider8031 项目,修改成 provider8032 ,添加到父项目中
此时就有两个服务供应了
在这里插入图片描述
启动后可以看到 Nacos 上注册了两个服务供应
在这里插入图片描述
服务接口通过 postman 或 curl 测试也是完全没问题
在这里插入图片描述

4.3.2 创建服务消费者

复制一份 provider 项目,修改成 consumer8041
至此有了三个子项目, 两个供应者一个消费者
在这里插入图片描述
注意,两个服务供应者的名字是一样的,端口不同(后续通过这个名字调取服务)
在这里插入图片描述
使用 Java Config 的方式配置一个负载均衡的 RestTemplate

@Configuration
public class GenericConfig {
    @Bean
    @LoadBalanced // 必须添加负载均衡注解
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

在测试接口处通过 RestTemplate 来远程调用

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

    private final String SERVER_URL = "http://nacos-provider"; // 这里不写具体的某个服务的ip和端口,而是通过注册到 Nacos 的服务名代替
    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/test")
    public String test() {
        String result = restTemplate.getForObject(SERVER_URL + "/test", String.class);
        return "①号消费者(" + port + "):" + result;
    }
}

调用消费者测试接口
在这里插入图片描述
可以看到消费者测试接口轮流调用两个供应服务的接口,实现了负载均衡
这个负载均衡是由 Ribbon 框架实现的,而 Nacos 整合了 Ribbon

RestTemplate 在Config类中已经被 Ribbon 代理, 当调 用 restTemplate的 postForObject()、getForObject() 时根据微服务名称,到注册中心查找对应的具体的服务地址。

4.4 使用Nacos 配置中心功能

通常我们在项目的 application.propertiesd 或 application.yml 文件里写配置,有个非常明显的缺点,就是每次修改配置后需要重启项目才能生效。如果对多个相同的服务做了集群,那么就有了很多个重复的配置文件,修改起来非常麻烦。为此,Nacos 提供了配置中心解决方案。

4.4.1 集成 Nacos 配置中心

我们直接用消费者项目修改,引入 Nacos 配置中心。

修改 pom.xml : 引入 nacos 配置中心的依赖

<!-- Nacos 配置中心 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

创建基础配置文件 bootstrap.yml 或 bootstrap.properties

在 SpringBoot 框架中,配置文件不止一种,名为 bootstrap 的配置文件 优先级 比名为 application 的配置文件高,启动时会先加载 bootstrap 配置文件。因此我们把启动项目的基本配置写在 bootstrap 中,待项目启动后再从 Nacos 配置中心拉取哪些次要配置。是这样一个逻辑

在这里插入图片描述

server:
  port: 8041 # 服务端口

spring:
  application:
    name: nacos-consumer-one # 应用名
  cloud:
    nacos:
      discovery:
        server-addr: 124.221.89.209:8849 # Nacos 注册中心地址
      config:
        server-addr: 124.221.89.209:8849 # Nacos 配置中心地址(因为是同一个所以和注册中心地址一样)
        file-extension: yml              # 指定配置文件的数据格式

management:
  endpoints:
    web:
      exposure:
        include: '*' # 公开所有端点

4.4.2 Nacos DataId 配置

DataId 目的是使项目快速切换多套配置内容。
DataId 格式:

${prefix}-${spring.profiles.active}.${file-extention}
  • prefix 默认值是 spring.application.name 的值

注意:
可以通过 spring.cloud.nacos.config.prefix 配置项覆盖

  • spring.profiles.active 是当前选择的环境

注意:
当 spring.profiles.active 为空时,对应的连接符 “-” 也将不存在,dataId 的格式变成 p r e f i x . {prefix}. prefix.{file-extention}

  • file-extention 是配置内容的数据格式

注意:
通过 spring.cloud.nacos.config.file-extention 配置项来配置

有了基础认识后,我们开始用 DataId 创建配置
先在消费者的 application.yml 配置中:

spring:
  profiles:
    active: dev

在 Nacos 平台上添加配置
开发配置 DataId:

nacos-consumer-dev.yml

配置项:

custom:
    info: nacos config dev

生产配置 DataId:

nacos-consumer-prod.yml

配置项:

custom:
    info: nacos config prod

在这里插入图片描述
然后在消费者项目中添加一个测试接口

@RefreshScope // 配置自动更新
@RestController
public class TestController {
    @Value("${custom.info}") // 从配置文件读取配置
    private String config;

    @RequestMapping("/getConfig")
    public String getConfig() {
        return config;
    }
}

@RefreshScope 是 SpringCloud 的原生注解
测试:
在这里插入图片描述
成功拿到 开发配置 的配置项的值
修改开发配置

custom:
    info: nacos config dev update

再测试看看有没有自动更新

在这里插入图片描述
更新成功,完美

4.4.3 Nacos Group 配置

group 是分组,表示配置归属于哪个组,默认是 DEFAULT_GROUP 组。

我们可以通过 spring.cloud.nacos.config.group 配置项 指定获取哪个组的配置

在 Nacos 配置中心新建一个配置
在这里插入图片描述
修改 bootstrap.yml 文件,增加 spring.cloud.nacos.config.group 配置项,指定 CUSTOM_GROUP 组

spring:
  application:
    name: nacos-consumer # 应用名
  cloud:
    nacos:
      discovery:
        server-addr: 124.221.89.209:8849 # Nacos 注册中心地址
      config:
        server-addr: 124.221.89.209:8849 # Nacos 配置中心地址(因为是同一个所以和注册中心地址一样)
        file-extension: yml              # 指定配置文件的数据格式
        group: CUSTOM_GROUP              # 指定组

完了拿到的就是 CUSTOM_GROUP 的配置了

完了拿到的就是 CUSTOM_GROUP 的配置了

4.4.4 Nacos Namespace 配置

namespace 命名空间,是一种粗粒度的控制。默认的命名空间是 public。
命名空间囊括了 Group、DataId。
创建自定义命名空间
在这里插入图片描述
回到配置列表,public 旁多出了个 fatst_team 命名空间
在这里插入图片描述
选择 fast_team 命名空间,添加一条配置
在这里插入图片描述
在消费者 bootstrap.yml 增加一项配置项,指定命名空间(必须是命名空间的 id)

spring:
  application:
    name: nacos-consumer # 应用名
  cloud:
    nacos:
      discovery:
        server-addr: 124.221.89.209:8849 # Nacos 注册中心地址
      config:
        server-addr: 124.221.89.209:8849 # Nacos 配置中心地址(因为是同一个所以和注册中心地址一样)
        file-extension: yml              # 指定配置文件的数据格式
        group: CUSTOM_GROUP              # 指定组
        namespace: 19b1fec0-b937-457b-b322-171086446ba2 # 命名空间 id

测试取到的值就是 fast_team 命名空间下 dev 配置文件的值
在这里插入图片描述

4.4.5 Namespace、Group、DataId 之间的关系

三者都是用于将区分配置,其中 Namespace 为第一级,Group 为第二级,DataId 为第三级,粒度由粗到细。
比如用 Namespace 区分团队,以 Group 区分功能模块,以 DataId 做最后的环境区分。

4.5 Nacos 持久化配置

Nacos 默认使用嵌入式数据库 - Derby 数据库,因为 存储容量限制,不方便查询、优化,做集群时不能将应用和数据分开 等原因,往往需要一个外部的数据库做为数据的持久化仓库。目前仅支持 MySql ,版本要求为 5.6.5+ 。

4.5.1 为 Nacos 配置数据库

先创建一个数据库 nacos_config (任意名),并通过脚本文件 nacos-mysql.sql 导入对应的表
在这里插入图片描述

nacos-mysql.sql 脚本文件可以在源码找到(nacos-1.4.2.zip\nacos-1.4.2\distribution\conf\nacos-mysql.sql
也可以在安装目录找到 (安装目录\conf\nacos-mysql.sql )

然后修改 Nacos 的配置文件
我用的是 docker 部署 Nacos,所以先进入容器

docker exec -it 594c187f55f9 /bin/bash

编辑 /conf/application.properties 配置文件

spring.datasource.platform=mysql
db.url.0=jdbc:mysql://124.221.89.200:3305/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=xxxxx

重启容器

docker stop 594c187f55f9 
docker start 594c187f55f9 

重新访问 Nacos ,此时的 Nacos 是初始状态
刷新看看服务注册是否正常,至此完成对单机版 Nacos 的持久化。

4.5.2 重新创建配置

重新创建命名空间和配置

custom:
    info: nacos config namespace fast_team group CUSTOM_GROUP active dev repository with mysql

修改消费者项目 bootstrap.yml 中的 namespace 项并重启项目
在这里插入图片描述
测试没问题,完美。

4.6 Nacos 集群部署

上面实现的 Nacos 数据持久化,就是在为集群部署奠定基础。在实际生产中,如果以单机模式运行 Nacos 服务,一旦宕机,就会引发单点故障,而 Nacos 作为一个基础服务,影响非常大。
首先看看 Nacos 的集群架构
在这里插入图片描述

客户端指代所有连接到 Nacos 的服务,如浏览器
负载均衡常用 Nginx 、Keepalived、OpenResty 等
所有 Nacos 节点都用的同一数据库(集群),保证数据统一。

4.6.1 Nacos + OpenResty 搭建简单集群

业界常用的负载均衡中间件是 Keepalived,它能解决使用静态路由地址单点故障的问题,保证99.99%高可用 。
但是 Keepalived 使用起来比较麻烦,这里先选择 OpenResty 实现,后面再引申到 Keepalived

OpenResty:
有一个大名鼎鼎的中间件 Nginx,它有两个重要的功能:反向代理和负载均衡。OpenResty 就是基于 Nginx 开发的,集成了很多优秀的 Nginx模块,其中最出名的就是 Lua 了,OpenResty 相当于是 Nginx 的增强。

搭建 Nacos 集群节点

① 下载安装 nacos-server

Nacos 集群至少 3 个节点,我这里用自己的云服务器搭。
下载 nacos-server-1.4.2.tar.gz 压缩包 (地址:https://github.com/alibaba/nacos/releases)
上传服务器、解压即可

② 配置文件配置 mysql数据库

修改 conf/application.properties 配置文件

#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql

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

### Connect URL of DB:
db.url.0=jdbc:mysql://124.221.89.200:3305/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=true&serverTimezone=UTC
db.user.0=root
db.password.0=xxxxx

注意:

  1. url 中的默认 useSSL=false,在启动过程中报错 Public Key Retrieval is not allowed,改成 useSSL=true 后正常启动。
  2. 集群节点共用一个 数据库(集群)。

③ 添加集群配置

conf/ 下添加一个集群配置文件 cluster.conf
内容如下:

124.221.89.200:8848
124.221.89.200:8847
124.221.89.200:8846

注意:分别是3个 Nacos (包括自己)的地址和端口

④ 复制 nacos 文件夹

因为我们需要3个 Nacos 服务,因此直接将 nacos 改名,再复制2份即可,分别命名 nacos1、nacos2,nacos3

mv nacos/ nacos1
cp -R nacos1/ nacos2
cp -R nacos1/ nacos3

⑤ 修改启动脚本

vi nacos1/bin/startup.sh 

定位到启动命令行

nohup $JAVA ${JAVA_OPT} nacos.nacos >> ${BASE_DIR}/logs/start.out 2>&1 &

插入指定启动端口配置项: -Dserver.port=8848

nohup $JAVA -Dserver.port=8848 ${JAVA_OPT} nacos.nacos >> ${BASE_DIR}/logs/start.out 2>&1 &

其他两个 nacos 同理指定 8847,8846 端口即可

⑥ 启动三个服务

./nacos1/bin/startup.sh
./nacos2/bin/startup.sh
./nacos3/bin/startup.sh

分别查看启动日志观察是否有如下启动成功日志

2022-08-25 09:11:16,636 INFO Nacos started successfully in cluster mode. use external storage

至此 nacos 集群节点搭建好了,访问任意 nacos 服务平台可看到节点信息
在这里插入图片描述

安装 OpenResty

下载 OpenResty 及其依赖的安装包

wget -O openresty-1.15.8.2.tar.gz -c https://sourceforge.net/projects/generic-software/files/php/openresty-1.15.8.2.tar.gz/download
wget -O openssl-1.0.2q.tar.gz -c https://sourceforge.net/projects/generic-software/files/php/openssl-1.0.2q.tar.gz/download
wget -O pcre-8.41.tar.gz -c https://sourceforge.net/projects/generic-software/files/php/pcre-8.41.tar.gz/download
wget -O zlib-1.2.11.tar.gz -c https://sourceforge.net/projects/generic-software/files/php/zlib-1.2.11.tar.gz/download
wget -O perl-5.30.1.tar.gz -c https://sourceforge.net/projects/generic-software/files/php/perl-5.30.1.tar.gz/download

安装 perl (安装路径随意)

tar -zxvf perl-5.30.1.tar.gz
cd perl-5.30.1
./Configure -des -Dprefix=$HOME/localperl
make
make test
make install

分别解压 openssl pcre zlib

tar -zxvf openresty-1.15.8.2.tar.gz
tar -zxvf openssl-1.0.2q.tar.gz
tar -zxvf pcre-8.41.tar.gz
tar -zxvf zlib-1.2.11.tar.gz

安装 OpenResty

cd openresty-1.15.8.2
./configure --prefix=/usr/openresty --with-pcre=/usr/pcre/pcre-8.41 --with-zlib=/usr/zlib/zlib-1.2.11 --with-http_ssl_module   --with-openssl=/usr/ssl/openssl-1.0.2q
make & make install

–prefix : 指定 OpenResty 安装路径
–with-pcre : 指定 pcre 所在路径
–with-zlib : 指定 zlib 所在路径
–with-openssl : 指定 openssl 所在路径
–with-http_ssl_module : 是个 ssl 模块,支持配置 https

如果执行make & make install的时候出现编译器错误:

checking for gcc... cc
sed: can't read conftest.err: No such file or directory

安装 gcc gcc-c++ 编译器即可

yum install -y gcc gcc-c++

启动 OpenResty 服务

/usr/openresty/bin/openresty

OpenResty 服务的默认端口是 80 端口
启动成功后直接访问,页面出现 Welcome to OpenResty! 即成功

接下来是把 nacos 集群挂载到 OpenResty 上
编辑 /usr/openresty/nginx/conf 配置文件
http{}代码块中添加一个upstream (溯源流) 对象,给此对象起名为 nacosCluster (起名随意), 对象内容是指定 nacos 集群的服务节点地址,

http {
	upstream nacosCluster{
		server 127.0.0.1:8848;
    	server 127.0.0.1:8847;
    	server 127.0.0.1:8846;
	}
}

server{} 代码块的 location / {} 对象中添加代理

server {
    location / {
        proxy_pass http://nacosCluster;
        index  index.html index.htm;
	}
}

重载配置文件

/usr/openresty/bin/openresty -s reload

proxy_pass http://nacosCluster
nacosCluster 为溯源流对象名,意思是通过 nginx 代理 nacosCluster 中的 nacos 服务地址
例如:
     当访问 http://124.221.89.200:80/nacos 时,自动把 124.221.89.200:80 替换成 127.0.0.1:8847,再拼接上资源路径 /nacos,即 http://127.0.0.1:8847/nacos, 至于负载均衡策略先忽略.

测试
修改消费之模块的 nacos 服务地址端口为 OpenResty 的服务地址

spring:
  application:
    name: nacos-consumer # 应用名
  cloud:
    nacos:
      discovery:
        server-addr: 124.221.89.200:80 # Nacos 注册中心地址
      config:
        server-addr: 124.221.89.200:80 # Nacos 配置中心地址(因为是同一个所以和注册中心地址一样)
        file-extension: yml              # 指定配置文件的数据格式
        group: CUSTOM_GROUP              # 指定组
        namespace: 8f60737f-6b74-47f7-8f29-2c908d133fca # 命名空间 id

启动访问是否能获取配置数据
如果能,说明 OpenResty 算部署好了
接下来关掉一个 nacos 节点
在这里插入图片描述
此时只有两个可用节点.再测试是否能正常获取配置数据
如果能,则我们想要的 nacos 集群高可用就算实现了.

4.7 Nacos+OpenResty+Keepalived高可用集群

在4.6中实现了 Nacos 集群服务的基本高可用,短板此时来到了 OpenResty 身上,因为只有一个 OpenResty 服务,如果它挂了,下面的 Nacos 服务都废了,这就引发了单点故障。解决方案就是 OpenResty 也做一个集群,联合 Keepalived。
架构如下:
在这里插入图片描述
VIP 就是 Visual IP ,虚拟IP,也就是等下要用的 Keepalived 服务。我们主要用到 Keepalived 服务的 VRRP 功能。

VRRP:
  虚拟路由器冗余协议功能,用来解决静态路由单点故障问题,保证服务高可用。
  VRRP 协议为两台或以上设备提供一个或多个虚拟IP,内部节点分为 MASTER 主节点和 BACKUP 备用节点两种。假如有两台服务,一个 MASTER 一个 BACKUP 。首先会选举 MASTER 作为服务节点提供服务,当 MASTER 挂了,BACKUP 节点没有接受到 MASTER 节点的反馈时会重新选举(根据优先级)BACKUP 节点作提供服务。

4.7.1部署 OpenResty 集群

因为上面已经部署了一台 OpenResty 服务器,已经有一个节点了。接下载再部署另外一台 OpenResty 服务器形成双节点集群即可。部署方式直接参考 安装 OpenResty

注意:
新部署的这台 OpenResty 服务器不需要部署 Nacos 服务了,直接配置现有的那 3 个 Nacos 服务即可,这次的 ip 就不是 127.0.0.1 了。
upstream nacosCluster{
  server 124.221.89.200:8848;
  server 124.221.89.200:8847;
  server 124.221.89.200:8846;
}

部署 Keepalived 服务

两台服务器都需要部署 Keepalived 服务。

1.下载 Keepalived 安装包

下载地址:https://www.keepalived.org/download.html
上传、解压

2.配置安装路径

进入解压目录
直接配置,后面编译和安装就按默认的安装路径去装,比较不好找

 ./configure

指定目录,后面编译和安装就安装在自己指定的目录,更加清晰

./configure -- prefix=/usr/local/keepalived 

如果配置或者后面编译的时候出现
在这里插入图片描述
这是因为缺少了一些头文件(库),装上即可:

yum install -y openssl-devel

3.编译安装

make && make install

4.把 Keepalived 设置为系统服务
如果是没有配置指定目录安装的,需要先查看安装位置

whereis keepalived
/etc/keepalived /usr/local/sbin/keepalived /usr/local/etc/keepalived

三个路径分别是 启动目录 执行文件 配置文件目录

如果是自己指定安装目录的,创建一个系统配置文件目录/etc/keepalived的配置文件存放目录

mkdir /etc/keepalived

把安装路径(注意自己的安装路径)下的配置文件复制一份到启动目录

# 没有指定目录
cp /usr/local/etc/keepalived/keepalived.conf  /etc/keepalived/ 
# 指定安装目录
cp /usr/local/keepalived/etc/keepalived/keepalived.conf  /etc/keepalived/ 

把执行文件拷贝一份到 /usr/sbin/ 目录下

# 没有指定目录
cp /usr/local/sbin/keepalived /usr/sbin/
# 指定安装目录
cp /usr/local/keepalived/sbin/keepalived /usr/sbin/

将源码包中的初始化脚本拷贝一份到系统初始化目录下,系统初始化的时候会初始化keepalived

cp /usr/keepalived-2.1.5/keepalived/etc/init.d/keepalived /etc/init.d/

给执行文件添加可执行权限

chmod +x /etc/init.d/keepalived 

将源码包中的配置文件拷贝一份到系统配置目录中,系统初始化keepalived的时候用

cp /usr/keepalived-2.1.5/keepalived/etc/sysconfig/keepalived /etc/sysconfig/

加入开机自启动

chkconfig --add keepalived
chkconfig keepalived  on

在这里插入图片描述
允许 vrrp 包发送(两台主机都要这样设置)

firewall-cmd --direct --permanent --add-rule  ipv4 filter  INPUT 0 --protocol vrrp  -j ACCEPT
firewall-cmd --reload

编辑 MASTER /etc/keepalived/keepalived.conf 文件

vrrp_script chk_openresty {
        script "/etc/keepalived/openresty_check.sh"
        interval 2
        weight -20
}

vrrp_instance VI_1 {
        state MASTER
        interface ens33
        virtual_router_id 51
        priority 100
        advert_int 1
        authentication {
                auth_type PASS
                auth_pass 1111
        }
        track_script {
                chk_openresty
        }
        virtual_ipaddress {
                192.168.1.115/24
        }
}

编辑 BACKUP /etc/keepalived/keepalived.conf 文件

vrrp_script chk_openresty {
        script "/etc/keepalived/openresty_check.sh"
        interval 2
        weight -20
}

vrrp_instance VI_1 {
        state BACKUP
        interface ens33
        virtual_router_id 51
        priority 50
        advert_int 1
        authentication {
                auth_type PASS
                auth_pass 1111
        }
        track_script {
                chk_openresty
        }
        virtual_ipaddress {
                192.168.1.115/24
        }
}

编写检测 OpenResty 服务的脚本

touch /etc/keepalived/openresty_check.sh
#!/bin/bash
echo "开始执行 openresty 进程检查脚本"
 	
echo "当前 openresty 进程数:$n"
if [ $n -eq 0 ];then
	echo "开始启动 openresty"
	/usr/openresty/bin/openresty
	sleep 2
	if [ `/usr/openresty/bin/openresty` -eq 0 ];then
		echo "openresty 启动失败,关闭 keepalived"
		killall keepalived	
	fi
fi

注意 shell 脚本中命令行用的不是单引号 '',而是反引号 ``

启动keepalived

service keepalived start

如下启动成功

[root@VM-16-13-centos bin]# service keepalived start 
Starting keepalived (via systemctl):  [  OK  ]

看看虚拟地址有没有起来

ip addr

在这里插入图片描述
5.测试访问
用虚拟地址访问 nacos 服务
在这里插入图片描述
关掉一台服务模拟宕机再访问
如果也没问题就是成功啦
到这里 Nacos + OpenResty + Keepalived 的集群高可用就部署完成噜

注册中心产品对比

在这里插入图片描述

CAP:

  • 一致性(Consistency):集群所有节点同一时间的数据是一致的,每次读取要么是最新的数据,要么是一个错误。
  • 可用性(Availability):client 在任何时刻的读写操作都能在限定的延迟内完成的,即每次请求都能获得一个响应(非错误),但不保证是最新的数据。
  • 分区容错性(Partition tolerance):在分布式系统中,服务之间通过网络相互通信,但网络不一定实时可靠,出现网络故障时,就有可能造成数据不一致,也就是发生了网络分区,分区容错性就是系统应该能保证在这种情况下可以正常工作。

CAP理论:
  对于C A P这三个特性,我们只能三选二,无法同时满足这三个特性,而现大多数是分布式系统,P一般是必须存在的,所以一般是在CA之间做取舍。具体详情参考某大鸟博客https://blog.csdn.net/paolei/article/details/119912023

承上:
启下:SpringCloudAlibaba系列微服务搭建笔记二_RestTemplate+Ribbon

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值