Springcloud_alibaba学习笔记

文章目录

  • 0. 简介
    • 区别
    • 特点
    • 组件
  • 1. 环境搭建
  • 2. Nacos
    • a.作为服务注册中心
      • 启动
      • Nacos Client简单上手
      • 服务间通信(和之前一样)
        • 应用搭建
        • Controller
        • 具体实现
          • RestTemplate+Ribbon:
          • OpenFeign
    • b.作为统一配置中心
      • Config Client简单上手
      • Controller
      • Nacos中创建配置
      • Nacos config
      • 自动刷新
      • 细节
        • 1、配置集(Data ID)
        • 2、配置分组(Group)
        • 3、命名空间(Namespace)
        • 4、最佳实践
    • c.配置持久化
    • d. 高可用(集群)
      • nacos高可用
  • 3. Sentinel
    • 3.1 简介
    • 3.2 概念&原理
      • 资源(Recourse)
      • 规则(Rule)
      • 流量控制
      • 流量控制设计理念
      • 服务降级&熔断
      • QPS(每秒请求数)
      • RT(响应时间)
    • 3.3 使用
      • Sentinel Dashboard
      • Sentinel
    • 3.4 五大规则
      • 1. 流控规则
        • 并发线程数规则设置
        • JMeter
        • 高级选项
          • a.流控模式
          • b.流控效果
      • 2. 降级规则
        • 熔断策略
        • @SentinelResource
      • 3. 热点规则
      • 4. 系统规则
      • 5. 授权规则

0. 简介

区别

Spring Cloud vs Spring Cloud Alibaba

Spring官网原文:

Spring Cloud Alibaba provides a one-stop solution for distributed application development. It contains all the components required to develop distributed applications, making it easy for you to develop your applications using Spring Cloud.

With Spring Cloud Alibaba, you only need to add some annotations and a small amount of configurations to connect Spring Cloud applications to the distributed solutions of Alibaba, and build a distributed application system with Alibaba middleware.

翻译:

阿里云为分布式应用开发提供了一站式解决方案。它包含了开发分布式应用程序所需的所有组件,使您可以轻松地使用springcloud开发应用程序。

有了阿里云,你只需要添加一些注解和少量的配置,就可以将Spring云应用连接到阿里的分布式解决方案上,用阿里中间件搭建一个分布式应用系统。

  • spring cloud 用来解决微服务系统中(分布式系统)解决方案
  • spring cloud alibaba 用来解决微服务系统中解决方案

特点

spring cloud alibaba 特点

  • 服务降级和流量控制(Flow Control and Service Degradation),注意服务熔断也属于服务降级:由sentinel替换hystrix
  • 服务注册与发现(Service Registration and discovery;服务注册中心):nacos替换eureka和consul
  • 分布式配置(Distributed Configuration):nacos替换config(alibaba的统一配置中心和服务注册中心和为了一个),无需手动刷新配置,nacos可以自动完成配置刷新
  • 事件驱动(Event-Driven):事件驱动利用RocketMQ替换bus
  • 消息总线(Message Bus):消息总线(异步处理)
  • 分布式事务(Distributed Transaction):Seata
  • Dubbo RPC:集成Dubbo实现服务间通信,Dubbo RPC替换RestTemplate和OpenFeign

组件

  • 服务注册与发现组件 eureka consul nacos
  • 服务间通信组件 restTemplate+ribbon,Openfeign restTemplate+ribbon,Openfeign
  • 服务降级和熔断 hystrix hystrix dashboard sentinel
  • 服务网关组件 gateway gateway
  • 统一配置中心组件 消息总线组件 config bus nacos

1. 环境搭建

维护springcloud依赖 -Hoxton.SR6

维护springcloud alibaba依赖 -2.2.1

集成springboot父项目 -2.2.5

a. 创建一个新的project (empty project)

b. 检查SDK配置版本;检查Maven配置

c. 创建父项目,并删除/src

d. 父项目依赖管理pom.xml


<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.0modelVersion>

    <groupId>org.examplegroupId>
    <artifactId>SpringCloudAlibaba_parentartifactId>
    <version>1.0-SNAPSHOTversion>

    
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.2.5.RELEASEversion>
    parent>

    
    <properties>
        <spring.cloud-version>Hoxton.SR6spring.cloud-version>
        <spring.cloud.alibaba.version>2.2.1.RELEASEspring.cloud.alibaba.version>
    properties>

    
    <dependencyManagement>
        <dependencies>
            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-dependenciesartifactId>
                <version>${spring.cloud-version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
            
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-alibaba-dependenciesartifactId>
                <version>${spring.cloud.alibaba.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
        dependencies>
    dependencyManagement>

project>

注意pomimport这个写法:虽然当前项目是我们的父项目,但还要再引入一个spring-cloud-dependencies父项目,所以采用这种写法。往常在引用依赖时写法就是:, ,这样写引入的都是jar包。而这里的写法产生的效果是:类似引入了一个pom清单(记录各种组件的版本),把spring-cloud-dependencies这个父项目的pom引入到当前pom。

2. Nacos

作用:服务注册中心(重点) + 统一配置中心。

这里主要学习Nacos作为服务注册中心的使用和细节。

a.作为服务注册中心

启动

Nacos作为服务注册中心,和Consul一样,是一款软件。所以需要安装Nacos,安装包下载地址:

https://github.com/alibaba/nacos/releases,进入后点击Asserts进行下载。

Springcloud_alibaba学习笔记_第1张图片

在bin目录中启动nacos:

sh startup.sh -m standalone

访问http://localhost:8848/nacos,查看可视化管理页面,登陆账号密码都是谁"nacos"

Springcloud_alibaba学习笔记_第2张图片

MacosBigSur版本nacos启动失败解决方法

Nacos Client简单上手

  • 创建独立springboot应用
@SpringBootApplication
@EnableDiscoveryClient  // 可省略:原来是consul server,现在是nacos server
public class NacosClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(NacosClientApplication.class, args);
    }
}
  • 依赖
    • spring-boot-web
    • nacos client
    • 无需健康检查(actuator),nacos已经内部实现了
    <dependencies>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        dependency>
    dependencies>
  • 配置文件
server.port=8989
# 微服务服务名 唯一 全部大写
spring.application.name=NACOSCLIENT

# nacos server的总地址
spring.cloud.nacos.server-addr=localhost:8848

# nacos server服务注册地址(所以这行不配置也会默认使用已配置的nacos server的总地址)
#spring.cloud.nacos.discovery.server-addr=${spring.cloud.nacos.server-addr}

# 指定向nacos server注册的服务名(同上)
#spring.cloud.nacos.discovery.service=${spring.application.name}

启动入口类,登陆nacos管理页面,发现服务注册成功:

Springcloud_alibaba学习笔记_第3张图片

服务间通信(和之前一样)

SpringCloud服务间通信回顾:

  1. RESTful (HTTP) 推荐
  2. RPC

使用Rest通信的方式:

  1. RestTemplate(最原生)
  2. RestTemplate + Ribbon(实现负载均衡)
  3. OpenFeign(本地接口,HTTP伪客户端,解决服务路径写死问题)

Nacos的服务间通信与之前的Eureka和Consul基本一致。

应用搭建

开发一个用户服务(Users)和一个商品服务(Products):

  • 入口类
    • @SpringBootApplication
    • @EnableDiscoveryClient
  • 依赖
    • spring-boot-web
    • nacos-client
  • 配置文件
    • server.port
    • application.name
    • nacos.server-addr=localhost:8848

实际测试中发现,不写nacos的server地址,服务同样可以被注册到服务注册中心,猜测是引入了nacos-client依赖后会默认将服务注册到localhost:8848。

Controller

商品服务

@RestController
public class ProductController {

    private static final Logger log = LoggerFactory.getLogger(ProductController.class);

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

    @GetMapping("/product")
    public String product(Integer id) {
        log.info("id = " + id);
        return "调用商品服务,id = " + id + ",当前提供服务的端口为: " + port;
    }
}

用户服务(大致框架)

@RestController
public class UserController {

    private static final Logger log = LoggerFactory.getLogger(UserController.class);

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

    @GetMapping("/invoke")
    public String invokeProduct(Integer id) {
        log.info("调用用户服务...");
        return "调用用户服务成功!";
    }
}

具体实现

  1. RestTemplate
    1. new RestTemplate().getForObject(url, String.class)
  2. RestTemplate + Ribbon
    1. DiscoveryClient
    2. LoadBalanceClient
    3. @LoadBalance
  3. OpenFeign(集成RestTemplate + Ribbon)
RestTemplate+Ribbon:

BeansConfig.java

@Configuration
public class BeansConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

UserController.java

@RestController
public class UserController {

    private static final Logger log = LoggerFactory.getLogger(UserController.class);

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

    @Autowired
    private DiscoveryClient discoveryClient;    // 服务发现客户端

    @Autowired
    private LoadBalancerClient loadBalancerClient;  // 负载均衡客户端

    @Autowired
    private RestTemplate restTemplate;  // 这是具有负载均衡功能的RestTemplate

    @GetMapping("/invoke")
    public String invokeProduct(Integer id) {
        log.info("调用商品服务...");
        // 1. RestTemplate
        // String result = new RestTemplate().getForObject("http://localhost:9090/product?id=123", String.class);
        // 2. RestTemplate + Ribbon (Load Balance):Nacos client已经包含了这个依赖
        // Ribbon: a.DiscoveryClient b.LoadBalanceClient c.@LoadBalance

        // a.DiscoveryClient
        // List instances = discoveryClient.getInstances("PRODUCTS");
        // for (ServiceInstance instance : instances) {
        //     log.info("服务主机:{} 服务端口:{} 服务uri:{}", instance.getHost(), instance.getPort(), instance.getUri());
        // }

        // b. LoadBalanceClient
        // ServiceInstance instance = loadBalancerClient.choose("PRODUCTS");// 已经进行负载均衡后的节点(轮询)
        // String result = new RestTemplate().getForObject(instance.getUri() + "/product?id=21", String.class);

        // c. @LoadBalanced注解,直接具有负载均衡
        String result = this.restTemplate.getForObject("http://PRODUCTS/product?id=123", String.class);
        log.info("商品服务调用结果:{}", result);
        return "调用商品服务成功:[" + result + "]";
    }
}

记录一个坑:@LoadBalanced注解使用后无法直接在uri中使用服务名找到对应集群机器的ip。

报错:500, I/O error on GET request for “http://PRODUCTS/product”: Network is unreachable (connect failed); nested exception is java.net.SocketException: Network is unreachable (connect failed)

分析:在发请求时还是拿着"http://PRODUCTS/product",而不是把服务ID转化成ip地址,说明@LoadBalanced注解没有生效

原因:Ribbon版本原因

链接:

  1. 在使用Eureka的时候,@LoadBalanced注解无效,无法通过服务名获取注册中心服务的URL的问题记录
  2. UnknownHostException: xxx restTemplate无法通过服务名调用服务/@LoadBalanced注解失效
  3. nacos作为注册中心,resttemplate使用负载均衡调用服务失败的问题
  4. 在使用Zookeeper以及Consul的时候,@LoadBalanced注解无效,无法通过服务名获取注册中心的URL的问题记录

我的解决:

为商品服务(需要进行通信的服务)的配置中加入instance-id

spring.cloud.discovery.client.simple.local.instance-id=PRODUCTS

上面就是就是使用RestTemplateRestTemplate+Ribbon进行服务间通信的回顾,我们发现虽然实现了负载均衡,在最后一种使用@LoadBalanced注解的方式中也把路径中的ip改为了服务名,但依然存在路径写死的问题。

OpenFeign
  • 为用户服务引入openfeign依赖spring-cloud-starter-openfeign

  • 为用户服务入口类加上注解@EnableFeignClients

  • 在用户服务中创建接口/feignclients/ProductClient.java

    @FeignClient("PRODUCTS")
    public interface ProductClient {
    
        @GetMapping("/product")
        public String product(@RequestParam("id") Integer id);
    }
    
  • 为UserController注入ProductClient

    @RestController
    public class UserController {
    
        private static final Logger log = LoggerFactory.getLogger(UserController.class);
    
        @Value("${server.port}")
        private int port;
    
        @Autowired
        private DiscoveryClient discoveryClient;    // 服务发现客户端
    
        @Autowired
        private LoadBalancerClient loadBalancerClient;  // 负载均衡客户端
    
        @Autowired
        private RestTemplate restTemplate;  // 这是具有负载均衡功能的RestTemplate
    
        @Autowired
        private ProductClient productClient;    // 注入feign客户端
    
        @GetMapping("/invoke")
        public String invokeProduct(Integer id) {
            log.info("调用商品服务...");
            // 1. RestTemplate
            // String result = new RestTemplate().getForObject("http://localhost:9090/product?id=123", String.class);
            // 2. RestTemplate + Ribbon (Load Balance):Nacos client已经包含了这个依赖
            // Ribbon: a.DiscoveryClient b.LoadBalanceClient c.@LoadBalance
    
            // a.DiscoveryClient
            // List instances = discoveryClient.getInstances("PRODUCTS");
            // for (ServiceInstance instance : instances) {
            //     log.info("服务主机:{} 服务端口:{} 服务uri:{}", instance.getHost(), instance.getPort(), instance.getUri());
            // }
    
            // b. LoadBalanceClient
            // ServiceInstance instance = loadBalancerClient.choose("PRODUCTS");// 已经进行负载均衡后的节点(轮询)
            // String result = new RestTemplate().getForObject(instance.getUri() + "/product?id=21", String.class);
    
            // c. @LoadBalanced注解,直接具有负载均衡
            // String result = this.restTemplate.getForObject("http://PRODUCTS/product?id=123", String.class);
    
            // 3. OpenFeign
            String result = productClient.product(999);
            log.info("商品服务调用结果:{}", result);
            return "调用商品服务成功:[" + result + "]";
        }
    

    测试发现可以用户服务可以成功调用商品服务,并具有负载均衡策略。

b.作为统一配置中心

Nacos作为统一配置中心,管理配置文件的方式是在自己所在服务器上形成一个版本库(有版本控制),因此不需要再去创建远程配置仓库。

Config Client简单上手

  • 创建独立springboot应用
@SpringBootApplication
@EnableDiscoveryClient
public class NacosClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(NacosClientApplication.class, args);
    }
}
  • 依赖

    • spring-boot-web
    • nacos client
  • 配置文件

server.port=8888
spring.application.name=CONFIGCLIENT

# nacos server的总地址
spring.cloud.nacos.server-addr=localhost:8848
  • 启动服务,在客户端可以发现已经注册成功

Controller

配置文件中定义变量name

name=XiaoMing
@RestController
public class DemoController {

    private static final Logger log = LoggerFactory.getLogger(DemoController.class);

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

    @GetMapping("/demo")
    public String demo() {
        log.info("Demo OK!");
        return "Demo OK! name: " + this.name;
    }
}

Nacos中创建配置

image-20200728211633327

注意Nacos中的配置文件都是独立的,没有config组件使用的公共配置文件,所以每个配置文件的文件名称必须写全。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C0kZd4RP-1650549322384)(https://cdn.jsdelivr.net/gh/zewei94yomi/ImageLoader@master/uPic/p7SeNZ.png)]

至此我们已经把原本client的配置都放到了nacos配置中心里,在client端可以删除application.properties,但我们还需要为client配置关于配置中心的信息/配置,即告诉client如何去nacos配置中心获取自己的配置。

Nacos config

引入nacos-config依赖


<dependency>
    <groupId>com.alibaba.cloudgroupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>

创建本地配置文件bootstrap.properties(配置配置中心地址),不能命名为application.properties

# 方式一:
# 远程配置中心的地址
spring.cloud.nacos.config.server-addr=localhost:8848
# 去哪个组获取配置
spring.cloud.nacos.config.group=DEFAULT_GROUP
# 需要拉取的配置文件名
spring.cloud.nacos.config.name=configclient-prod
# 配置文件后缀
spring.cloud.nacos.config.file-extension=properties
# 方式二:
# 远程配置中心的地址
spring.cloud.nacos.server-addr=localhost:8848
# 去指定nacos地址读取配置
spring.cloud.nacos.config.server-addr=${spring.cloud.nacos.server-addr}
# 读取配置的分组
spring.cloud.nacos.config.group=DEFAULT_GROUP
# 指定读取文件后缀
spring.cloud.nacos.config.file-extension=properties
# 指定读取文件的前缀
spring.application.name=configclient
# 指定读取文件的具体环境
spring.profiles.active=prod

自动刷新

默认情况下nacos已经实现了自动配置刷新功能,如果需要刷新配置直接在控制器中加入@RefreshScope注解即可

为Controller加上注解@RefreshScope后,远端配置修改后会自动刷新:

修改前name=XiaoMing,我们在Nacos中修改为name=XiaoMing999

Springcloud_alibaba学习笔记_第4张图片

我们直接再次访问http://localhost:8888/demo,发现配置name已经自动刷新

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qYzBHosH-1650549322386)(https://cdn.jsdelivr.net/gh/zewei94yomi/ImageLoader@master/uPic/rMMhOn.png)]

细节

Nacos的配置中心的配置获取,主要通过 Namespace、group、Data ID能够定位到一个配置集。

1、配置集(Data ID)

在系统中,一个配置文件通常就是一个配置集,一个配置集可以包含了系统的各种配置信息,例如,一个配置集可能包含了数据源、线程池、日志级别等配置项。每个配置集都可以定义一个有意义的名称,就是配置集的ID即Data ID。

配置集中包含的一个个配置内容就是配置项。它代表一个具体的可配置的参数与其值域,通常以 key=value 的形式存在。例如我们常配置系统的日志输出级别(logLevel=INFO|WARN|ERROR) 就是一个配置项。

2、配置分组(Group)

配置分组是对配置集进行分组,通过一个有意义的字符串(如 Buy 或 Trade )来表示,不同的配置分组下可以有相同的配置集(Data ID)。当您在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。配置分组的常见场景:可用于区分不同的项目或应用,例如:学生管理系统的配置集可以定义一个group为:STUDENT_GROUP。

注 :默认情况下使用 DEFAULT_GROUP 组。

3、命名空间(Namespace)

命名空间(namespace)可用于进行不同环境的配置隔离。例如可以隔离开发环境、测试环境和生产环境,因为它们的配置可能各不相同,或者是隔离不同的用户,不同的开发人员使用同一个nacos管理各自的配置,可通过namespace隔离。不同的命名空间下,可以存在相同名称的配置分组(Group) 或 配置集。

4、最佳实践

Nacos抽象定义了Namespace、Group、Data ID的概念,具体这几个概念代表什么,取决于我们把它们看成什么,这里推荐给大家一种用法:

Namespace:代表不同环境,如开发、测试、生产环境。

Group:代表某项目,如XX医疗项目、XX电商项目

DataId:每个项目下往往有若干个工程,每个配置集(DataId)是一个工程的主配置文件
————————————————
版权声明:本文为CSDN博主「Jay-zhan」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_38978094/article/details/104172300

c.配置持久化

持久化:管理的配置信息的持久化

注意:Nacos默认存在配置信息的持久化,默认的持久化方式是使用内嵌数据库(Derby:不方便观察数据存储的基本情况),但是官方建议在生产情况下,将配置信息存入MySQL数据库。

数据源:在0.7版本之前,在单机模式时nacos使用嵌入式数据库(derby)实现数据的存储;0.7版本增加了支持mysql数据源能力(Nacos到目前只支持了MySQL数据库)。

关于为什么要做配置持久化

  • Nacos通过集中式存储来保证数据的持久化,同时也为Nacos集群部署奠定了基础
  • 如果以之前的方式启动Nacos,如果想搭建Nacos集群,那各个节点中的数据唯一性就是最大的问题
  • Nacos此时采用了单一数据源,直接解决了分布式和集群部署中的一致性问题

具体步骤:

# 1.说明
- 在0.7版本之前,在单机模式时nacos使用嵌入式数据库(derby)实现数据的存储,不方便观察数据存储的基本情况。
	0.7版本增加了支持mysql数据源能力,具体的操作步骤:
	1.安装数据库,版本要求:5.6.5+
	2.初始化mysql数据库,数据库初始化文件:nacos-mysql.sql
	3.修改conf/application.properties文件,增加支持mysql数据源配置(目前只支持mysql),添加mysql数据源的url、用户名和密码。

# 2.安装mysql数据库5.6.5+以上版本(略)
- 添加官方的yum源创建并编辑mysql-community.repo文件
	vi /etc/yum.repos.d/mysql-community.repo
- 粘贴以下内容到源文件中
    [mysql57-community]
    name=MySQL 5.7 Community Server
    baseurl=http://repo.mysql.com/yum/mysql-5.7-community/el/7/$basearch/
    enabled=1
    gpgcheck=0
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql

- 安装mysql
	yum install mysql-community-server -y

- 启动mysql数据库
    systemctl start mysqld

- 修改mysql数据库密码
	grep 'temporary password' /var/log/mysqld.log
	mysqladmin -u root -p password 回车 输入原始密码 在输入新的密码
- 登录mysql
    mysql -uroot -p'Root!Q2w'
- 修改远程连接
	grant all privileges on *.* to 'root'@'%' identified by 'Root!Q2w' with grant option;
    flush privileges;

# 3.修改配置文件
	spring.datasource.platform=mysql
    db.num=1
    db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?		
    	characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
			&useUnicode=true&useSSL=false&serverTimezone=UTC
	db.user=root
	db.password=Root!Q2w

d. 高可用(集群)

因为集群搭建太麻烦,这里略过,直接复制笔记。

nacos高可用

# 集群 cluster : 统一种软件服务的多个节点对一个系统提供服务称之为这个软件服务集群  tomcat集群  mysql集群  redis集群 es集群...
	集群解决问题:
						1.并发访问压力
						2.单节点故障问题
# 1.nacos集群架构图
- https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html

Springcloud_alibaba学习笔记_第5张图片

# 2.集群搭建注意事项
- 注意: 
	a.3个或3个以上Nacos节点才能构成集群。
	b.要求虚拟机内存分配必须大于2G以上

# 3.集群规划
-	node cluster:
	10.15.0.3 8845 nacos01
	10.15.0.3 8846 nacos02
	10.15.0.3 8847 nacos03
	10.15.0.3 9090 nginx
	10.15.0.3 3306 mysql

# 4.搭建nacos集群
	1).将nacos安装包从新解压缩
	2).开启nacos mysql持久化
		 注意:数据库中不能存在原始数据
	3).修改nacos conf目录中cluster.conf文件添加所有集群节点
		10.15.0.3:8845
		10.15.0.3:8846
		10.15.0.3:8847			
	4).将修改后nacos复制三份 
		注意:修改为不同端口信息
	
	5).分别启动三台机器
		./startup.sh

# 5.安装Nginx
- 0.安装必要依赖
	yum install -y gcc pcre-devel zlib-devel
- 1.下载Nginx
	http://nginx.org/en/download.html

- 2.将Nginx上传到linux中,并解压缩
	 tar -zxvf nginx-1.11.1.tar.gz

- 3.查看Nginx安装目录
	[root@localhost nginx-1.11.1]# ls
	auto  CHANGES  CHANGES.ru  conf  configure  contrib  html  LICENSE  man  README  src

- 4.在Nginx安装目录中执行如下命令:(指定安装位置)
	./configure --prefix=/usr/nginx

- 5.执行上述命令后,执行如下命令:
	make && make install

# 6.配置nginx conf配置文件
	a.加入如下配置:
	upstream  nacos-servers {
    	server 10.15.0.3:8845;
		server 10.15.0.3:8846;
		server 10.15.0.3:8847;
	}
	b.修改
	location / {
      proxy_pass http://nacos-servers/;
  	}

# 7.启动nginx进行测试即可

3. Sentinel

3.1 简介

Springcloud_alibaba学习笔记_第6张图片

作用:Alibaba开源的组件,用来对现有的微服务系统进行保护(替换Hystrix)

解决服务雪崩==》服务熔断

Sentinel takes “flow” as the breakthrough point, and works on multiple fields including flow control, circuit breaking and load protection to protect service reliability.

Sentinel以“流量”为突破口,在流量控制、断路、负载保护等多个领域进行工作,保障服务可靠性。

特性:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。

Springcloud_alibaba学习笔记_第7张图片

3.2 概念&原理

资源(Recourse)

资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用"资源"来描述代码块。
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

规则(Rule)

围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

流量控制

流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:

Springcloud_alibaba学习笔记_第8张图片

流量控制设计理念

流量控制有以下几个角度:
资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
运行指标,例如 QPS、线程池、系统负载等;
控制的效果,例如直接限流、冷启动、排队等。
Sentinel的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

服务降级&熔断

在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。

Hystrix 通过线程池的方式,来对依赖(在我们的概念中对应”资源“)进行了隔离。

优点:

  • 资源和资源之间做到了最彻底的隔离

缺点:

  • 增加了线程切换的成本(thread context switching)

  • 需要预先给各个资源做线程池大小的分配

Sentinel 对这个问题采取了几种手段:

  1. 通过并发线程数进行限制
    和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
  2. 通过响应时间对资源进行降级
    除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。
  3. 系统负载保护
    Sentinel 同时从系统的维度提供保护,防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。
    针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。

“3.2 资源-概念&原理”摘自https://zhuanlan.zhihu.com/p/64786381,更多sentinel的原理与源码解读请查看此链接。

QPS(每秒请求数)

Query Per Second:系统每秒的请求数,如5/s,代表平均每秒5个请求

RT(响应时间)

Response Time:响应时间

3.3 使用

Sentinel包含两个开源组件:

  1. Sentinel(实现流量控制、服务熔断、服务降级),相当于Hystrix
  2. Sentinel Dashboard(实现仪表盘功能),相当于Hystrix Dashboard,不同点:Hystrix Dashboard只能监控;Sentinel Dashboard可以监控同时操控(服务降级…)。

两者必须一起使用,Sentinel做流量控制,Dashboard做规则配置,这样的坏处是两者必须耦合,好处是规则配置无需硬编码,只需在dashboard上修改配置,规则就会立即生效而无需重启服务和组件。

Sentinel Dashboard

  1. 下载Sentinel Dashboard,github:https://github.com/alibaba/Sentinel/tags,下载dashboard的jar,sentinel-dashboard-1.7.2.jar

  2. 运行sentinel-dashboard-1.7.2.jar:

    java -jar -Dserver.port=9191 sentinel-dashboard-1.7.2.jar
    

    springboot的默认启动端口为8080,如果8080被占用那么这个java程序就无法启动成功,所以最好指定一个端口。

    如果在服务器上运行,服务器必须安装JDK8.0+,并配置环境变量

  3. 访问dashboard管理界面:http://localhost:9191/

    账号密码都是sentinel

    Springcloud_alibaba学习笔记_第9张图片

Sentinel

  1. 启动Nacos

  2. 开发创建一个demo的Springboot应用

    1. 引入依赖

      1. spring-boot-starter-web
      2. spring-cloud-starter-alibaba-nacos-discovery
      3. 这里为了方便起见,没有引入nacos config的依赖,而是把配置文件放在本地
    2. 配置文件

      # Application
      server.port=8998
      spring.application.name=SENTINEL
      # Nacos server
      spring.cloud.nacos.server-addr=localhost:8848
      
    3. 暴露接口

      @RestController
      public class DemoController {
      
          private static final Logger log = LoggerFactory.getLogger(DemoController.class);
      
          @GetMapping("/demo")
          public String demo() {
              log.info("demo ok!!!");
              return "demo ok!!!";
          }
      }
      
    4. 测试,访问http://localhost:8998/demo,成功

  3. 在微服务中引入sentinel组件

    
    <dependency>
        <groupId>com.alibaba.cloudgroupId>
        <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
    dependency>
    
  4. 配置配置文件,使sentinel可以连接到dashboard

    # Sentinel Dashboard
    # 开启sentinel保护,默认开启
    spring.cloud.sentinel.enabled=true
    # 指定sentinel dashboard的web地址(连接dashboard),这里使用的是HTTP的通信方式(效率低)
    spring.cloud.sentinel.transport.dashboard=localhost:9191
    # 指定sentinel组件与sentinel dashboard组件的通信地址,这里使用的是TCP的通信方式(效率高),默认8719
    spring.cloud.sentinel.transport.port=8719
    
  5. 至此,微服务启动后就可以被sentinel保护。注意,服务必须被调用后才能在dashboard中查看到。

3.4 五大规则

这里重点介绍记录前三种规则,文档链接:https://github.com/alibaba/Sentinel/wiki

Springcloud_alibaba学习笔记_第10张图片

1. 流控规则

https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6

流量控制(flow control)

其原理是监控应用流量的 QPS 并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

QPS:

  • 当每秒请求数超过指定阀值时,对当前请求进行限流
  • 决定请求数(外部)

并发线程数:

  • 补充概念:假设不考虑线程池的概念,原则上Tomcat服务器接收到一个请求时就会为其创建一个线程来处理请求。但是假设某一时刻有10个请求被服务器接收,但未必需要10个线程来处理(宏观上是平行,但微观上还是串行),单个线程处理请求速度非常快,也许几个线程就可以处理完。
  • 当服务器中创建线程数超过指定阀值时,对当前请求进行限流
  • 决定并发线程数(内部)
  • 压力测试工具(秒杀系统):Apache JMeter

并发线程数规则设置

使用QPS作为流控规则非常容易测试,只需要频繁刷新浏览器来发送请求即可,而设置并发线程数则测试比较困难,需要借助工具JMeter。

Springcloud_alibaba学习笔记_第11张图片

JMeter

  1. 下载:https://jmeter.apache.org/

  2. Linux/Mac,直接打开/bin/jmeter

  3. 在Test Plan下创建一个Thread Group

  4. 配置线程组

    Springcloud_alibaba学习笔记_第12张图片

  5. 配置HTTP请求

  6. 添加监听器(HTTP请求的结果树)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IyqWbqxB-1650549322393)(https://cdn.jsdelivr.net/gh/zewei94yomi/ImageLoader@master/uPic/vRR6zg.png)]

  7. 测试

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BGztRYXt-1650549322394)(https://cdn.jsdelivr.net/gh/zewei94yomi/ImageLoader@master/uPic/gZhwVR.png)]

高级选项

a.流控模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jh7sg0NY-1650549322394)(https://cdn.jsdelivr.net/gh/zewei94yomi/ImageLoader@master/uPic/xPZysj.png)]

  1. 直接:当配置资源在运行过程中超过当前配置规则的阀值之后,它做的处理是什么

  2. 关联模式:当配置资源在运行过程中超过当前配置规则的阀值之后,它所关联的资源做什么处理。注意关联的顺序,是设置的“关联资源”影响“当前资源”。被关联的资源无论怎样接受请求,都不会被影响。比如下载面的例子中,对/demo无论发送多少请求都不会被流控,而当对/login的qps超过2时,/demo会被sentinel进行流控。

    Springcloud_alibaba学习笔记_第13张图片
  3. 链路模式(存在问题):当配置资源在运行过程中超过当前配置规则的阀值之后,它链路中的资源做什么处理。链路模式类似关联模式,只是它的关联顺序是正向关联。

注意:这里超过阀值,指的是“超过阀值后的请求”,做什么处理

b.流控效果

注意:流控效果只适用于QPS限流

  1. 快速失败:当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。

  2. Warm Up:即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

    通常冷启动的过程系统允许通过的 QPS 曲线如下图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tQo2CBlc-1650549322395)(https://cdn.jsdelivr.net/gh/zewei94yomi/ImageLoader@master/uPic/f9BeCf.jpg)]

  3. 排队等待:始终匀速通过,严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。详细文档可以参考 流量控制 - 匀速器模式。这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

2. 降级规则

https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7

熔断降级(Degrade Service)

熔断:为了避免微服务架构中的服务雪崩现象

除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用自动进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。

熔断策略

Springcloud_alibaba学习笔记_第14张图片
  1. 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

    image-20200802142932522

  2. 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值 ,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BIHQKCdV-1650549322396)(https://cdn.jsdelivr.net/gh/zewei94yomi/ImageLoader@master/uPic/image-20200802143052470.png)]

  3. 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JhAAWzOC-1650549322397)(https://cdn.jsdelivr.net/gh/zewei94yomi/ImageLoader@master/uPic/image-20200802143303114.png)]

@SentinelResource

@GetMapping("/sentinel/test1")
@SentinelResource(value = "aa",blockHandler = "fallBack",fallback = "fall")
public String test1(int id){
    log.info("sentinel test1");
    if(id<0)		
      	throw new RuntimeException("非法参数!!!");
    }
    return "sentinel test1 :"+id;
}
//降级异常处理
public String fallBack(int id,BlockException e){
    if(e instanceof FlowException){
      	return "当前服务已被流控! "+e.getClass().getCanonicalName();
    }
    return "当前服务已被降级处理! "+e.getClass().getCanonicalName();
}
//异常处理
public String fall(int id){
  	return "当前服务已不可用!";
}

3. 热点规则

https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81

热点参数(Param Flow)

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。(控制颗粒度更小)

Springcloud_alibaba学习笔记_第15张图片

Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。

4. 系统规则

https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81

Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

5. 授权规则

https://github.com/alibaba/Sentinel/wiki/%E9%BB%91%E7%99%BD%E5%90%8D%E5%8D%95%E6%8E%A7%E5%88%B6

也叫黑白名单控制

很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单控制)的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。(类似电脑的防火墙)

参考:

  1. Nacos服务—配置中心
  2. 阿里Sentinel原理解析

你可能感兴趣的:(分布式系统,SpringCloud,微服务,springcloud)