一、概念讲解

        1.1微服务

                把一个大型的单一应用程序,拆分成一组小而独立的服务,每个服务都围绕特定的业务功能运行,可以独立开发、部署和扩展。(单一职责、独立自治、轻量级通信、技术多样性)

               举例:将银行系统划分为:客服部、接待部、管理部、安保部等各个部门,各自负责各自的业务,协同完成银行工作。

        1.2分布式概念

                分布式系统是多台计算机(节点)通过网络连接,协同工作,共同完成一个任务的系统。对用户来说,它就像一个统一的整体。

                举例:将银行分为多个分部,可以在北京存款甘肃取款。

                1.2.1集群

                        集群就是将多台计算机(服务器)组合起来,共同完成同一项任务,对外如同一台机器。(分布式中的每一个节点,都可以做集群。 而集群并不一定就是分布式的。)

                1.2.2服务之间的交互方式

                        RPC:Netty(Socket)+自定义序列化

                        RestAPI:HTTP+JSON(springCloud交互方式)

        1.3微服务架构

                Spring Cloud 是一套用于快速构建微服务架构的“工具箱”或“全家桶”。(而 微服务架构 本身是一种 分布式系统。)

        1.4.spring cloud相关组件
  •         注册中心:Eureka
    • 负载均衡:Ribbon
    • 声明式调用远程方法:OpenFeign(包含ribbon)
    • 熔断、降级、监控:Hystrix
    • 网关:Gateway
    • 链路跟踪:Sleuth 
    • 服务注册和配置中心:Spring Cloud Alibaba Nacos
    • 熔断、降级、限流:Spring Cloud Alibaba Sentinel
               

二、基础服务搭建示例(。。。。。。该示例由:父工程(规定依赖版本) + 子工程())

                服务层级:父工程(规定依赖版本) + 子工程(引入父工程)

                服务链路:公共服务 + 服务提供者(含mysql) + 服务调用者(使用restTemplate进行交互(原理-HTTP+JSON格式))

                业务链路:用户 -> 页面 -> 调用order-cloud服务 -> 调用pay-cloud服务 -> 数据库

        2.1 父工程搭建(demo-cloud)
                2.1.1创建新maven项目
                2.1.2字符编码设置
                2.1.3注解生效激活
                2.1.4pom文件

                        ⚠️注意dependencyManagement(仅规定版本)和dependencies(实际引入)区别!!!!

<?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.demo.cloud</groupId>
    <artifactId>demo-cloud</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>pay-cloud</module>
        <module>order-cloud</module>
        <module>api-cloud</module>
        <module>eureka-cloud</module>
        <module>order-feign-cloud</module>
    </modules>
    <!-- pom代表是父类pom文件 -->
    <packaging>pom</packaging>

    <!-- 统一管理jar包版本 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
        <mysql.version>5.1.47</mysql.version>
        <druid.version>1.1.16</druid.version>
        <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <!-- dependencyManagement:仅规定版本,不实际引入jar,子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version  -->
    <!-- dependency:实际引入jar -->
    <dependencyManagement>
        <dependencies>
            <!-- springBoot核心依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- springCloud核心依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR9</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- springCloud Alibaba核心依赖 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- Mysql JDBC驱动 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <!-- 数据库连接池 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <!-- mybatis依赖 -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.version}</version>
            </dependency>
            <!-- 单元测试框架 -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <!-- 日志 -->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <!-- 注解工具 -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <optional>true</optional>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

</project>
        2.1.5install工程
   
        2.2 公共服务搭建(api-cloud)
                2.2.1 创建子Modlue(仅输入名称即可)
                2.2.2 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">
    <parent>
        <artifactId>demo-cloud</artifactId>
        <groupId>com.demo.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>api-cloud</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- 热加载工具 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- java工具类库 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.1.0</version>
        </dependency>
    </dependencies>
</project>
                2.2.3创建公共实体bean

                        ⚠️注意:使用方服务的文件夹路径(com.ai.springcloud)需要和api的保持一致,否则扫描不到!!!

                2.2.4install工程

        2.3服务提供者搭建(pay-cloud,面向接口编程)
                2.3.1服务架构总览

                        ⚠️注意:1. 前置路径通api-cloud保持一致(com.ai.springcloud)

                                       2.mapper:mapper文件同yml中配置的路径一致                    

                2.3.2创建子项目(同上)
                2.3.3pom文件

                        ⚠️注意:引入公共服务api-cloud!!!

<?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>demo-cloud</artifactId>
        <groupId>com.demo.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>pay-cloud</artifactId>

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

    <dependencies>
        <!-- web项目启动器 -->
        <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>
        <!-- Mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!-- druid数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!-- Mysql JDBC驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- spring JDBC,提供事务等 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- 热部署工具 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- 测试类启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>
        <!-- 引入公共API文件jar -->
        <dependency>
            <artifactId>api-cloud</artifactId>
            <groupId>com.demo.cloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>
                2.3.4yml配置文件(主义mysql相关配置和特殊文件指定扫描路径)
server:
  port: 8081

spring:
  application:
    name: pay-cloud

  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: cb19980702

mybatis:
  mapperLocations: classpath:/mapper/*.xml  # mapper映射文件存放位置
  type-aliases-package: com.ai.springcloud.entities  # 实体 bean文件存放位置
                2.3.5创建启动类
package com.ai.springcloud;


import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@MapperScan("com.ai.springcloud.dao")
public class PayMentMain {
    public static void main(String[] args) {
        SpringApplication.run(PayMentMain.class, args);
    }
}
                2.3.6创建dao层
package com.ai.springcloud.dao;

import com.ai.springcloud.entities.PayMent;
import org.apache.ibatis.annotations.Param;

public interface PayMentDao {
    int create(PayMent payMent);
    PayMent getPaymentById(@Param("id") Long id);
}

                2.3.7创建service层
package com.ai.springcloud.service;

import com.ai.springcloud.entities.PayMent;

public interface PayMentService {
    int create(PayMent payMent); //写
    PayMent getPaymentById(Long id);  //读取
}
                2.3.8创建imp实现(面向接口编程)

                        ⚠️注意:此处Autowired爆红是因为MapperScan是运行时扫描的,而Mapper是编译时扫描,所以如果在PayMentDao加Mapper注解就不会爆红,在启动类加MapperScan就会爆红。!!!

package com.ai.springcloud.service.impl;

import com.ai.springcloud.dao.PayMentDao;
import com.ai.springcloud.entities.PayMent;
import com.ai.springcloud.service.PayMentService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class PayMentServiceImpl implements PayMentService {
// 用Autowired爆红是因为MapperScan是运行时扫描的,而Mapper是编译时扫描,所以如果在PayMentDao加Mapper注解就不会爆红,在启动类加MapperScan就会爆红
//    @Autowired
    @Resource
    private PayMentDao payMentDao;

    @Override
    public int create(PayMent payment){
        return payMentDao.create(payment);
    }

    @Override
    public PayMent getPaymentById( Long id){
        return payMentDao.getPaymentById(id);
    }
}
                2.3.9创建mapper映射文件

                        ⚠️注意:<mapper namespace="com.ai.springcloud.dao.PayMentDao">,需要配置dao文件路径进行扫描!!!

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.ai.springcloud.dao.PayMentDao">

    <insert id="create" >
        insert into payment(serial) values(#{serial});
    </insert>

    <select id="getPaymentById"  parameterType="Long" resultType="com.ai.springcloud.entities.PayMent">
        select * from payment where id=#{id}
    </select>

</mapper>
                2.3.10创建controller层
package com.ai.springcloud.controller;

import com.ai.springcloud.entities.CommonResult;
import com.ai.springcloud.entities.PayMent;
import com.ai.springcloud.service.PayMentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.alibaba.fastjson.JSON;

@RestController
@Slf4j
public class PayMentController {
    @Autowired
    private PayMentService payMentService;

    @PostMapping(value = "/payment/create")
    public CommonResult<Integer> create(@RequestBody PayMent payMent){
        log.info("请求参数payMent:{}", JSON.toJSONString(payMent));
        int result = payMentService.create(payMent);
        log.info("*****插入结果:"+result);
        if (result>0){  //成功
            return new CommonResult(200,"插入数据库成功",result);
        }else {
            return new CommonResult(444,"插入数据库失败",null);
        }
    }

    @GetMapping(value = "/payment/get/{id}")
    // @PathVariable 从路径中获取参数
    public CommonResult<PayMent> getPaymentById(@PathVariable("id") Long id){
        PayMent payMent = payMentService.getPaymentById(id);
        log.info("*****查询结果:"+payMent);
        if (payMent!=null){  //说明有数据,能查询成功
            return new CommonResult(200,"查询成功",payMent);
        }else {
            return new CommonResult(444,"没有对应记录,查询ID:"+id,null);
        }
    }
}
                2.3.11install工程
                2.3.12创建mysql表并进行服务接口测试

        2.4restTemplate
                2.4.1介绍

                        spring提供的一种包含多种便捷访问远程Http服务的方法,也属于Restful方式,即HTTP+JSON。

                2.4.2使用方式

                        1.创建配置类

                        2.注入restTemplate后调用相关方法实现http服务调用(具体查看2.4.6、2.4.7)

        2.5服务调用者搭建(order-cloud)
                2.5.1服务架构总览
                2.5.2创建子项目(同上)
                2.5.3pom文件

                        ⚠️注意:引入公共服务api-cloud!!!

<?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>demo-cloud</artifactId>
        <groupId>com.demo.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order-cloud</artifactId>

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

    <dependencies>
        <!-- web项目启动器 -->
        <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-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 引入公共API文件jar -->
        <dependency>
            <artifactId>api-cloud</artifactId>
            <groupId>com.demo.cloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>
                2.5.4yml配置文件(注意mysql相关配置和特殊文件指定扫描路径)
server:
  port: 8080
spring:
  application:
    name: order-cloud
                2.5.5创建启动类
package com.ai.springcloud;

import com.ai.ribbon.RibbonConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

@SpringBootApplication

public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }
}
                2.5.6创建restTemplate配置类
package com.ai.springcloud.config;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootConfiguration
public class ApplicationContextConfig {

    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

}
                2.5.7创建controller层
package com.ai.springcloud.controller;

import com.ai.springcloud.entities .CommonResult;
import com.ai.springcloud.entities.PayMent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;

@RestController
@Slf4j
public class OrderController {

    public static final String PAYMENT_URL = "http://localhost:8081";


    @Resource
    private RestTemplate restTemplate; // Spring所有,典型的RestFull风格,由HTTP+JSON组成,且使用RestTemplate则不需要实现序列化,但最好加上,避免后续使用redis等

    @PostMapping("/consumer/payment/create")
    public CommonResult<Integer>   create(@RequestBody PayMent payment){
        return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment,CommonResult.class);  //写操作
    }

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<PayMent> getPayment(@PathVariable("id") Long id){
        return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
    }
}
                2.5.8install工程
                2.5.9服务接口测试

三、Euerka介绍及集成

                3.1介绍

                        Eureka是服务注册中心,采用了CS的设计架构。(检测服务心跳,便于监控和运维)

                3.2两大组件

                        Eureka Server:服务端,提供服务的注册能力

                        Eureka Client:客户端,服务通过客户端进行注册

                3.3示例(改造pay-cloud及order-cloud服务)
                        3.3.1 综述

                                搭建euerka注册中心服务端 -> pom文件添加euerka依赖 -> yml增加euerka配置 -> 启动类添加euerka启动注解 -> 重启服务,打开注册中心进行测试

                                3.3.1.1 依赖
        <!-- rureka核心pom文件 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
                                3.3.1.1 配置
eureka:
  instance:
    hostname: localhost # 注册中心服务地址
  client:
    register-with-eureka: false # 是否从注册中心注册自己的信息(此处不注册,因为自己就是注册中心)
    fetchRegistry: false # 是否从注册中心获取信息(此处不获取,因为自己就是注册中心)
    service-url:
      defaultZone: http://localhost:8082/eureka # 注册中心访问全路径
                                3.3.1.1 注解

                                        @EnableEurekaServer

                        3.3.2 搭建Euerka服务端(euerka-cloud)

                                3.3.2.1 创建子项目(同上)
                                3.3.2.2 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">
    <parent>
        <artifactId>demo-cloud</artifactId>
        <groupId>com.demo.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-cloud</artifactId>

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

    <dependencies>
        <!-- rureka核心pom文件 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>



        <dependency>
            <artifactId>api-cloud</artifactId>
            <groupId>com.demo.cloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <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-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>

</project>
                                3.3.2.3 yml文件
server:
  port: 8082 # 注册中心端口号

eureka:
  instance:
    hostname: localhost # 注册中心服务地址

  client:
    register-with-eureka: false # 是否从注册中心注册自己的信息(此处不注册,因为自己就是注册中心)
    fetchRegistry: false # 是否从注册中心获取信息(此处不获取,因为自己就是注册中心)
    service-url:
      defaultZone: http://localhost:8082/eureka # 注册中心访问全路径
                                3.3.2.4 启动类
package com.ai.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer // 启动euerka服务端
public class EuerkaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EuerkaApplication.class,args);
    }
}
                                3.3.2.5 install工程

                        3.3.3 pay-cloud服务改造
                                3.3.3.1 pom新增euerka依赖
        <!-- rureka核心pom文件 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
                                3.3.3.2 yml文件
server:
  port: 8081

spring:
  application:
    name: pay-cloud

  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: cb19980702

mybatis:
  mapperLocations: classpath:/mapper/*.xml  # mapper映射文件存放位置
  type-aliases-package: com.ai.springcloud.entities  # 实体 bean文件存放位置

eureka: # 新增euerka客户端配置
  client:
    register-with-eureka: true # 是否从注册中心注册自己的信息
    fetchRegistry: true # 是否从注册中心获取信息
    service-url:
      defaultZone: http://localhost:8082/eureka # 注册中心访问全路径
                                3.3.3.3 启动类
package com.ai.springcloud;


import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@MapperScan("com.ai.springcloud.dao")
@EnableEurekaServer
public class PayMentMain {
    public static void main(String[] args) {
        SpringApplication.run(PayMentMain.class, args);
    }
}
                                3.3.3.4 install工程

                        3.3.4 order-cloud服务改造

                                步骤同3.3.3一致

                3.4 示例演示

                        ⚠️注意:浏览器访问地址为http://localhost:8082,不用带/eureka

                        pay-cloud有两个服务的原因是本地新增了一个副本服务。

四、Ribbon介绍及集成

        4.1 介绍

                客户端负载均衡工具,主要功能是提供客户端的软件负载均衡算法服务调用。(nginx是服务端负载均衡,ribbon是本地负载均衡)

                简单来说Ribbon=负载均衡+RestTemplate调用

        4.2 核心组件Irule

                com.netflix.loadbalancer.RoundRobinRule 轮询,默认策略。
                com.netflix.loadbalancer.RandomRule  随机
                com.netflix.loadbalancer.RetryRule 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务 
                WeightedResponseTimeRule  对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择
                BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
                AvailabilityFilteringRule 先过滤掉故障实例,再选择并发较小的实例
                ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器

        4.3 示例(改造order-cloud服务调用端)
                4.3.1 综述

                        新增ribbon依赖 -> 添加ribbon配置类 -> RestTemplate配置类新增注解 -> controller中修改RestTemplate公用调用路径 -> 启动类新增ribbon启动注解

                4.3.2 POM
        <!-- rureka核心pom文件,ribbon依赖在内 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
                4.3.3 添加配置类,实现Irule组件

                        ⚠️注意:配置类一定不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化订制的目的了。(此处放在com.ai.ribbon夹下)

package com.ai.ribbon;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;

@SpringBootConfiguration
public class RibbonConfig {
    @Bean
    public IRule myRule(){
        return new RoundRobinRule();//定义为轮询策略
    }
}
                4.3.4 RestTemplate配置类新增注解(@LoadBalanced) 
package com.ai.springcloud.config;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootConfiguration
public class ApplicationContextConfig {

    @Bean
    @LoadBalanced // 让其自持负载均衡的方式,否则报错无法找到PAY-CLOUD,【无ribbon时不需要该注解】
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

}
                4.3.5 修改RestTemplate公用调用路径
                4.3.6 启动类新增ribbon启动注解(@RibbonClient)
package com.ai.springcloud;

import com.ai.ribbon.RibbonConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

@SpringBootApplication
@EnableEurekaServer
// 添加ribbon启动注解 他会自动去euerka里下载相关内容,【name = "ORDER-CLOUD"】代表euerka里注册的名称,【configuration = RibbonConfig.class】代表采用的个性化配置策略
@RibbonClient(name = "ORDER-CLOUD",configuration = RibbonConfig.class)
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }
}
                4.3.7 install工程

五、OpenFeign介绍及集成

        5.1 介绍

                Feign是一个声明式的web服务客户端,便于服务调用(也是http+json),其自身集成了ribbon。

        5.2 OpenFeign及Feign区别    

                OpenFeign 是 Feign的升级版,OpenFeign目前仍然活跃开发,Feign目前已经进入维护状态

        5.3 示例(重新搭建一套由openfeign进行交互的order-cloud工程,order-feign-cloud)
                5.3.1 创建子工程(同上)
                5.3.2 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">
    <parent>
        <artifactId>demo-cloud</artifactId>
        <groupId>com.demo.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order-feign-cloud</artifactId>

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

    <dependencies>
        <!--openfeign核心依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <artifactId>api-cloud</artifactId>
            <groupId>com.demo.cloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <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-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
                5.3.3 yml配置文件
server:
  port: 8083
spring:
  application:
    name: order-feign-cloud
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8082/eureka
# 设置feign客户端超时时间
ribbon:
  ReadTimeout: 3000
  ConnectTimeout: 3000
                5.3.4 启动类
package com.ai.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
// 开启euerka注解
@EnableEurekaClient
// 开启feign注解(不再需要ribbon注解,feign集成你了ribbon)
@EnableFeignClients
public class OrderFeignMain {
    public static void main(String[] args) {
        SpringApplication.run(OrderFeignMain.class,args);
    }
}
                5.3.5 openfeign接口
package com.ai.springcloud.service;

import com.ai.springcloud.entities.CommonResult;
import com.ai.springcloud.entities.PayMent;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

// 面向接口编程
@Component
// feign中继承了ribbon,这里实质相当于ribbon中的根据euerka里的注册名【PAY-CLOUD】获取其注册信息和访问地址
@FeignClient(name = "PAY-CLOUD")
public interface PayCloudFeignService {
    @PostMapping(value = "/payment/create")
    CommonResult<Integer> create(@RequestBody PayMent payMent);

    @GetMapping(value = "/payment/get/{id}")
    CommonResult<PayMent> getPaymentById(@PathVariable("id") Long id);
}
                5.3.6 controller层
package com.ai.springcloud.controller;

import com.ai.springcloud.entities.CommonResult;
import com.ai.springcloud.entities.PayMent;
import com.ai.springcloud.service.PayCloudFeignService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@Slf4j
public class OrderController {
    @Autowired
    PayCloudFeignService payCloudFeignService;

    @PostMapping("/consumer/payment/create")
    public CommonResult<Integer>  create(@RequestBody PayMent payment){
        return payCloudFeignService.create(payment);
    }

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<PayMent> getPayment(@PathVariable("id") Long id){
        return payCloudFeignService.getPaymentById(id);
    }
}

六、Hystrix介绍及集成(已经逐步淘汰,被Resilience4j取代

        6.1 介绍

                断路器,通过断路器机制防止分布式系统中的级联故障和雪崩效应。

                雪崩:A -> B -> C -> D,当C服务有问题时,A、B服务的请求都无法得到释放,当请求数越来越多就会导致整个链路雪崩。

        6.2 功能

                降级:超时、异常、线程池打满、熔断导致降级、人工降级

                熔断:服务已达最大请求量、规定时间内异常数量超过阈值

                限流:秒杀高并发等操作,N个请求/S

        6.3 降级

           【6.3.3为项目常用降级方式,euerka+openfeign(+ribbon)+hystrix。 】

                6.3.1 单服务单方法降级处理(基础版-每个接口单独配置降级处理)
                        6.3.1.1 新增pom依赖
        <!--新增hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
                        6.3.1.2 启动器新增注解

                                @EnableHystrix

                        6.3.1.3 yml配置文件
feign:
  hystrix:
    enabled: true # 为每个Feign客户端接口自动创建Hystrix包装器,当调用失败或超时时,能够执行降级逻辑。!!!只有服务调用者(包含feign)才需要该配置
                        6.3.1.4 业务层处理

                                配置@HystrixCommand注解并定义降级方法

@RestController
@Slf4j
public class OrderHystrixController {

    @GetMapping("/hystrix/ok/{id}")
    public String payOK(@PathVariable("id") Integer id){
        return "测试ok";
    }

    //超时降级(【fallbackMethod = "payment_TimeoutHandler"】是降级兜底方法名,【name="execution.isolation.thread.timeoutInMilliseconds",value="5000"】设置超时时长,默认1S)
    @HystrixCommand(fallbackMethod = "payment_TimeoutHandler",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="5000")})

    @GetMapping("/hystrix/timeout/{id}")
    public String payTimeOut(@PathVariable("id") Integer id){
        int timeNumber = 10; //模拟非正常情况
        try {
            TimeUnit.SECONDS.sleep(timeNumber);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "测试timeOut";
    }

    //兜底方法,上面方法出问题,我来处理,返回一个出错信息
    public String payment_TimeoutHandler(Integer id) {
        return "服务降级测试";
    }
}
                 6.3.2 单服务单类公共降级处理(进阶版-每个class统一配置降级处理)
                        6.3.2.1 新增pom依赖(同上)
                        6.3.2.2 启动器新增注解(同上)
                        6.3.2.3 yml配置文件(同上)
                        6.3.2.4 业务层处理

                                配置@DefaultProperties全局注解、配置@HystrixCommand注解、定义公用降级方法

@RestController
@Slf4j
@DefaultProperties(defaultFallback = "payment_TimeoutHandler")  //全局的
public class OrderHystrixController {

    @GetMapping("/hystrix/ok/{id}")
    public String payOK(@PathVariable("id") Integer id){
        return "测试ok";
    }

    @HystrixCommand
    @GetMapping("/hystrix/timeout/{id}")
    public String payTimeOut(@PathVariable("id") Integer id){
        int timeNumber = 10; //模拟非正常情况
        try {
            TimeUnit.SECONDS.sleep(timeNumber);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "测试timeOut";
    }

    //兜底方法,上面方法出问题,我来处理,返回一个出错信息
    public String payment_TimeoutHandler(Integer id) {
        return "服务降级测试";
    }
}
                  6.3.3 单服务降级处理(常用版-调用者用降级接口对提供者进行统一处理)
                        6.3.3.1 新增pom依赖(同上)
                        6.3.3.2 启动器新增注解(同上)
                        6.3.3.3 yml配置文件(同上)
                        6.3.3.4 OpenFeign接口新增back属性

                        6.3.3.5 新增降级兜底类

                6.3.4 @HystrixCommand降级时间及yml配置中降级时间区别

                        @HystrixCommand的时间:超时降级时间,默认1S,可自定义,如6.3.1、6.3.2。当单个接口、类进行降级处理时,走@HystrixCommand规定的时间。

                        yml配置中的降级时间:feign服务调用 http超时时间,6.3.3案例走yml的超时时间

                6.3.5 服务熔断

                        当服务访问量上限/指定时间内失败次数上限

                        6.3.5.1 示例

                                pom、yml、注解等和上述一致

/*
* requestVolumeThreshold=10,10S内发送10个请求就打开断路
* errorThresholdPercentage=60,10S内发送10个请求,错误率达到60%就打开断路
*/
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
        @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),  //是否开启断路器
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),   //当在配置时间窗口内达到此数量,打开断路,默认20个
        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),  //断路多久以后开始尝试是否恢复,默认5s
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), //出错百分比阈值,当达到此阈值后,开始短路。默认50%
})
                6.3.6 仪表盘搭建
                        6.3.6.1 pom   
        <!--新增hystrix dashboard-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
                        6.3.6.2 yml                        
hystrix:
  dashboard:
    proxy-stream-allow-list: localhost #仪表盘监控哪些服务
                        6.3.6.3 启动类新增注解                        
                                @EnableHystrixDashboard
                        6.3.6.4 工程install并启动,然后打开仪表盘

                                http://localhost:xxxx/hystrix                        

                        6.3.6.5 被监控工程pom                       
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
                        6.3.6.6 被监控工程的启动类新增内容
/**
 *ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",为了设置被监控服务的访问路径,此服务是/hystrix.stream
 */
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
                        6.3.6.6 添加访问被监控服务

                             http://localhost:xxxx/hystrix.stream

                        6.3.6.6 仪表盘讲解

七、网关gateway

        7.1 概念

                网关服务,类似于过滤器,对API进行路由,以及提供一些强大的过滤器功能,基于Spring5.X+SpringBoot2.X和Project Reactor等特定框架

        7.2 作用

                反向代理、过滤、鉴权、流量控制、熔断、日志监控等等

        7.3 核心组成

                Route(路由) -> Predicate(断言)、Filter(过滤)

        7.4 官网
                https://docs.spring.io/spring-cloud-gateway/docs/2.2.6.RELEASE/reference/html/

        7.5 示例
                搭建成功后,通过【http://localhost:9101/consumer/payment/get/60】访问即可,相当于面向用户的是9101端口,实际的8103端口被反向代理了,期间也配置了相关的断言和过滤条件。

                7.5.1 创建子项目

                7.5.2 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">
    <parent>
        <artifactId>demo-cloud</artifactId>
        <groupId>com.demo.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>getway-cloud</artifactId>

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

    <dependencies>
        <!--新增gateway,不需要引入web和actuator模块-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <artifactId>api-cloud</artifactId>
            <groupId>com.demo.cloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

</project>
                7.5.3 yml文件

                        predicates断言共11种,具体查看官网

                        filters过滤同参考官网

server:
  port: 9101
spring:
  application:
    name: gateway-gateway
  cloud:
    gateway:
      routes: # 路由是个集合,- 代表集合元素
        - id: orderment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8083   #predicates断言匹配后 提供服务的路由地址
          predicates: # 断言类型有11种,具体参考官网文档
            - Path=/consumer/payment/get/**   #断言,路径匹配通过的 进行uri路由
            - After=2025-10-08T10:59:34.102+08:00[Asia/Shanghai] # 指定时间之后的请求可以通过
#            - Before=2025-10-08T10:59:34.102+08:00[Asia/Shanghai] # 指定时间之前的请求可以通过
#            - Between=2025-10-08T10:59:34.102+08:00[Asia/Shanghai] ,  2025-11-08T10:59:34.102+08:00[Asia/Shanghai] #指定时间区间内的请求可以通过
        - id: orderment_routh2
          uri: http://localhost:8083
#          filters: #可设置已提供的过滤条件
          predicates:
            - Path=/consumer/payment/create/**   #断言,路径相匹配的进行路由


eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8082/eureka
                7.5.4 启动类
package com.ai.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class GateWayMain {
    public static void main(String[] args) {
        SpringApplication.run(GateWayMain.class,args);
    }
}
                7.5.5 自定义全局过滤器(按需使用)
package com.ai.springcloud.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;

@Component
@Slf4j
public class GatewayConfig implements GlobalFilter, Ordered {
    @Override
    // 过滤内容
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("测试gateway:"+new Date());
        String username = exchange.getRequest().getQueryParams().getFirst("username");
        if(StringUtils.isEmpty(username)){
            log.info("用户名为null");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    // 执行顺序,0最先执行
    public int getOrder() {
        return 0;
    }

}
                7.5.6 install工程

八、SpringCloud Sleuth(分布式链路请求跟踪)+ OpenZipkin(分布式跟踪平台)

        8.1 概念

                分布式服务调用链路跟踪监控并展示

        8.2作用

                监控服务调用链路,等同于pinpoint

        8.3 Zipkin安装
                8.3.1 下载

                        https://github.com/openzipkin/zipkin

                8.3.2 本地安装
                8.3.3 访问(http://ip地址:9411/zipkin/

                        http://localhost:9411/zipkin/

        8.4 SpringCloud Sleuth集成(在已有的服务中集成)
                8.4.1 添加pom依赖
<!--包含了sleuth+zipkin-->
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
                8.4.2 新增yml配置(spring下层)
  zipkin:
    base-url: http://localhost:9411
  sleuth:
    sampler:
      #采样率值介于0~1之间,1表示全部采样
      probability: 1
                8.4.3 重启工程并访问其中的接口

九、SpringCloud Alibaba Nacos

         9.1 作用

                注册中心+配置中心的组合,

        9.2 安装nacos(nacos下载解压即可,不用像euerka进行部署)
                9.2.1 官网下载

        https://nacos.io/download/nacos-server/?spm=5238cd80.2ef5001f.0.0.3f613b7cVw55Dz

                9.2.2 解压文件夹
                9.2.3 变为单例模式进行启动(默认是集群模式)

                9.2.4 访问

                        http://127.0.0.1:8848/nacos

        9.3 搭建提供者服务(注册中心)
                9.3.1 父工程增加alibaba依赖
            <!-- springCloud Alibaba-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
                9.3.2 子工程添加nacos依赖
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
                9.3.3 yml配置
server:
  port: 8084

spring:
  application:
    name: pay-nacos-cloud
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: cb19980702

mybatis:
  mapperLocations: classpath:/mapper/*.xml  # mapper映射文件存放位置
  type-aliases-package: com.ai.springcloud.entities  # 实体 bean文件存放位置

management:
  endpoints:
    web:
      exposure:
        include: '*'  #默认只公开了/health和/info端点,要想暴露所有端点只需设置成星号
                9.3.4 启动类增加注解
package com.ai.springcloud;


import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@MapperScan("com.ai.springcloud.dao")
// nacos启动注解
@EnableDiscoveryClient
public class PayMentMain {
    public static void main(String[] args) {
        SpringApplication.run(PayMentMain.class, args);
    }
}

                9.3.5 启动

        9.4 搭建提供者服务(配置中心)

                        因环境不同(测试、生产等),可能存在多套配置文件,可用application.yml区分dev、pro的方式,也可用分组group的方式。

                9.4.1 新增配置中心依赖
        <!-- nacos配置中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!-- nacos注册中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
                9.4.2 新增bookstrap.yml文件(主要增加nacos配置中心的配置)

                        bookstrap.yml作用同application.yml文件一致,只不过两者同时存在时,项目先加载bookstrap.yml

                9.4.3 创建application.yml
                9.4.4 启动类(同注册中心注解一样)
                9.4.5 编写测试接口
                9.4.6 nacos中心创建配置文件

                        ⚠️注意:名称规则为(${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension})!!!

                9.4.7 测试

        9.5 nacos配置中心的名称空间

                区分不同环境的配置文件,出了上述的配置文件区分、分组区分,还可以通过名称空间区分。

                9.5.1 创建新的名称空间

                9.5.2 增加相关配置

                

        9.6 nacos配置中心持久化(数据库记录)
                9.6.1 提取mysql表文件
                9.6.2 数据库创建表
                9.6.3 配置数据库连接

                9.6.4 重启nacos
# 终端打开nacos的bin文件下
cd /path/to/nacos/bin
# nacos终止命令
sh shutdown.sh
# nacos启动命令
sh startup.sh -m standalone
                9.6.5 测试

        9.7 实际使用

                nacos:多节点集群模式(cluster.conf【nacos所有节点配置文件】、application.properties【当前nacos端口号、数据库连接等配置】、startup.cmd【可配置当前nacos启动占用资源大小】)

                nginx:代理访问nacos集群

                工程:yml配置文件中配置nginx代理的nacos集群访问地址

十、SpringCloud Alibaba Sentinel

        10.1 概念

                分布式系统的流量防卫兵,作用同hystrix相似,提供限流、降级、熔断等功能。

        10.2 与hystrix比较

                1. hystrix目前处于维护状态,Sentinel由alibab提供,仍在更新

                2. hystrix通过引入jar来使用,无可视化界面,降级、熔断等操作需要通过配置文件、注解来实现;Sentinel通过jar启动,有可视化界面,各类操作可以直接在客户端界面进行操作。

        10.3 安装Sentinel

                1.本地下载 Sentinel相关jar包

                2.终端中启动Sentinel(java -jar sentinel-dashboard-1.8.2.jar )     

                3.访问(http://localhost:8080/)   

              10.4 搭建Sentinel工程
                        10.4.1 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">
    <parent>
        <artifactId>demo-cloud</artifactId>
        <groupId>com.demo.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>sentinel-cloud</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- 引入公共API文件jar -->
        <dependency>
            <artifactId>api-cloud</artifactId>
            <groupId>com.demo.cloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- nacos注册中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- sentinel无法自主实现持久化,需要通过nacos连接数据库实现持久化 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!-- sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>



        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <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-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
                10.4.2 yml配置文件
server:
  port: 9001

spring:
  application:
    name: sentinel-cloud
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719  #默认8719,应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用HttpServer

management:
  endpoints:
    web:
      exposure:
        include: '*'
                10.4.3 启动类
package com.ai.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class SentinelMain {
    public static void main(String[] args) {
        SpringApplication.run(SentinelMain.class, args);
    }
}
                10.4.4 控制层
package com.ai.springcloud.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class SentinelDemo {
    @GetMapping("/testA")
    public String testA() {
        return "测试接口A";
    }

    @GetMapping("/testB")
    public String testB() {
        return "测试接口B";
    }
}
                10.4.5 测试(sentinel是实时的,需要服务有访问才会有显示)

        10.5 流控规则                

                QPS:每分钟请求参数

                并发线程数:线程数

                阈值:数量

                直接:直接降级报错

                关联:例如关联资源关联(/testA),则当A接口达到访问阈值时B接口也会降级报错

                链路:家庭式链路

                快速失败:直接降级报错

                Warm Up:预热,前N秒将访问量控制在默认阈值/3,后续可以达到最大阈值,适用于秒杀活动

                排队等待:超过阈值的接口请求会进行等待,超过等待时间仍未执行才会报错。

                含义:A接口/B接口前2秒会进行预热,最大请求是3,2秒后最大请求可达到10次/秒,超过阈值时B接口报错。

        10.6 熔断规则

                含义:10S内当超过5个请求时,如果有一半的响应时常都超过200ms,则熔断2s

                含义:10S内当超过5个请求时,如果10%的请求出现异常,则熔断2S

                含义:10内当超过5个请求时,如果异常数量超过3个,则熔断2S

        10.7 热点规则(需改造代码)

@RestController
public class SentinelDemo {
    @GetMapping("/testA")
    /*
    1.SentinelResource - 热点规则处理注解
    2.value - 资源名称|方法别名(例:热点规则名为testA,则触发规则时走block_testA方法,热点规则名为/testA,则触发热点规则时走默认兜底方法)
    3.blockHandler - 热点规则兜底方法(降级处理)
    4.fallback - 方法内部异常兜底方法(降级方法)
     */
    @SentinelResource(value = "testA",blockHandler = "block_testA",fallback = "fall_testA")
    public String testA(@RequestParam(value = "p1",required = false) String p1,
                        @RequestParam(value = "p2",required = false) String p2) {
        return "测试接口A";
    }

    @GetMapping("/testB")
    public String testB() {
        return "测试接口B";
    }

    //热点规则兜底方法(返回类型一致、包含原有入参、包含异常对象BlockException)
    public String block_testA (String p1, String p2, BlockException exception){
        return "------testA,热点规则";
    }

    //方法内部异常兜底方法
    public String fall_testA (String p1, String p2, Throwable throwable){
        return "------testA,方法异常";
    }
}

                10.7.1 热点规则兜底方法提取(公共方法)

        10.8 系统规则(用于对所有接口均统一进行规则判定,不常用)

        10.9 持久化(配置数据入库)

                目前sentinel暂无法直接实现持久化,而是通过nacos实现持久化(sentinel -> nacos配置中心 -> 入库)

                10.9.1 新增pom
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
                10.9.2 新增yml
server:
  port: 9001

spring:
  application:
    name: sentinel-cloud
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719  #默认8719,应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用HttpServer
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: sentinel-cloud
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

management:
  endpoints:
    web:
      exposure:
        include: '*'
                10.9.3 新增nacos配置

十一、CAP讲解

        CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。

        CAP至多同时满足两点,及CP、AP。

        一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)

        可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)

        分区容忍性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

        nacos支持CP和AP模式的切换,所以相较于其他控制中心使用更优。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐