Spring Cloud Alibaba自学笔记

Nacos

Nacos 服务注册与发现

image-20210512203457657

github地址

直接下载解压,启动

startup.cmd -m standalone

访问

http://192.168.1.4:8848/nacos/index.html

功能

  • 服务发现与管理
  • 配置管理

服务注册

添加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

配置

spring:
  application:
    name: nacos-discovery-consumer
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        metadata:
           name: lengleng

server:
  port: 8050

开启服务

@EnableDiscoveryClient //启用服务注册与发现
@SpringBootApplication
public class NacosDiscoveryConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(NacosDiscoveryConsumerApplication.class, args);
    }
}

观察nacos控制台查看是否被注册进去

远程方法调用

注册RestTemplate

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

使用

@RestController
public class DemoController {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private LoadBalancerClient loadBalancerClient;


    @GetMapping("/demo")
    public String test01(String name) {
        ServiceInstance choose = loadBalancerClient.choose("nacos-discovery-provider");
        URI uri = choose.getUri();
        return restTemplate.getForObject(uri+"/demo?name=" + name, String.class);
    }


}

Nacos负载均衡、服务上下线、权重信息

服务上下线

通过在控制面版进行控制

image-20210512205246141

负载均衡

@Bean
@LoadBalanced  //默认集成了ribbon  可以实现负载均衡
public RestTemplate restTemplate() {
    return new RestTemplate();
}

直接使用服务名去调用


@GetMapping("/demo")
public String test01(String name) {
    //nacos默认集成了 rabbion  因此可以直接使用服务名去调用  来实现负载均衡
    return restTemplate.getForObject("http://nacos-discovery-provider/demo?name=" + name, String.class);
}

权重

管理台进行设置,通过编辑按钮进行设置

image-20210512205638203

元数据

上图可以看到有元数据一列,来区分不同的服务节点

获取元数据

@GetMapping("/test")
public String test(String name) {
    //获取元数据   感知节点信息

    RibbonLoadBalancerClient.RibbonServer ribbonServer = (RibbonLoadBalancerClient.RibbonServer) loadBalancerClient.choose("nacos-discovery-provider");
    NacosServer nacosServer = (NacosServer) ribbonServer.getServer();

    //第一次 使用rabbion选择了一个provider  获取它的元数据
    System.out.println("-->" + nacosServer.getMetadata());
    // 这里选择了两次的  provider服务

    //第二次又通过rabbion 调用了一次provider  进行具体业务处理
    return restTemplate.getForObject( "http://nacos-discovery-provider/demo?name=" + name, String.class);
    // 灰度  灰度发布
}

Nacos整合Feign、Webflux

Feign

Feign是从Netflix中分离出来的轻量级项目,能够在类接口上添加注释,成为一个REST API客户端。

通常使用的是open feign

Spring Cloud在netflix fegn的基础上扩展了支持SpringMVC注释,并通过自动配置为Spring Boot应用程序提供集成。

添加依赖


<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

配置

spring:
  application:
    name: nacos-discovery-consumer-feign
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        metadata:
           name: lengleng

server:
  port: 8052

启用feign

@EnableFeignClients  //feign注解
@EnableDiscoveryClient
@SpringBootApplication
public class NacosDiscoveryConsumerFeignApplication {

    public static void main(String[] args) {


        SpringApplication.run(NacosDiscoveryConsumerFeignApplication.class, args);
    }
}
@RestController
public class DemoController {
    @Autowired
    private DemoFeignService demoFeignService;

    @GetMapping("/test")
    public String test(String name) {
        return demoFeignService.demo(name);
    }
}

远程接口

@FeignClient("nacos-discovery-provider")
public interface DemoFeignService {
    @GetMapping("/demo")
    String demo(@RequestParam("name") String name);
}

Webflux

image-20210512210340827

添加依赖

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

配置


spring:
  application:
    name: nacos-discovery-consumer-webflux
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        metadata:
           name: lengleng

server:
  port: 8053

使用

    @Bean
    @LoadBalanced
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }


@RestController
public class DemoController {
    @Autowired
    private WebClient.Builder webclientBuilder;

    @GetMapping("/test")
    public Mono<String> test(String name) {
        return webclientBuilder.build()
                .get()
                .uri("http://nacos-discovery-provider/demo?name=" + name)
                .retrieve()
                .bodyToMono(String.class);
    }
}

Nacos整合gateway

Spring Cloud Gateway是Spring Cloud 的一个全新项目,该项目是基于Spring 5.0,Spring Boot 2.0和ProjectReactor等技术开发的网关,它旨在为微服务架构提供—种简单有效的统一的API路由管理方式。

Spring Cloud Gateway 作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且基于Filter 链的方式提供了网关基本的功能,例如︰安全、监控、埋点和限流等。

image-20210512210547992

配置

添加依赖

不需要引用web模块

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

配置

spring:
  application:
    name: nacos-discovery-gateway-server
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        metadata:
          name: lengleng
    gateway:
      routes:
        - id: nacos-discovery-provider   #provider服务的名称
          uri: lb://nacos-discovery-provider #nacos注册名称
          predicates: #谓词:
            - Path=/provider/** #接收的请求
          filters:
            - StripPrefix=1 # 去掉前缀

server:
  port: 8054

Nacos配置中心

配置中心的功能

添加依赖

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

配置bootstrap.yml

# 需要在bootstrap.yml 中进行配置server-addr  由他的声明周期来决定  而不能使用application.yml文件进行配置
spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yml # 指定文件类型 nacos-config-client.yml   默认是properties
  profiles:
    active: dev #指定文件后缀来指定环境  nacos-config-client-dev.yml
server:
  port: 8055

# 要去加载nacos-config-client-dev.yml文件  读取其中的属性  可以由配置中心进行配置

使用

@RefreshScope  //声明是可以进行刷新的  也就是配置文件发生了更改 它可以感知的到
@RestController
public class DemoController {
    @Value("${test:空test}")
    public String str;

    @GetMapping("/test/config")
    public String test() {
        return str;
    }
}

动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。

配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。

Nacos提供了一个简洁易用的UI(控制台样例Demo)帮助您管理所有的服务和应用的配置。Nacos还提供包括配置版本踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,帮助您更安全地在生产环境中管理配置变更和降低配置变更带来的风险。

服务id即dataId生成的策略

image-20210512211301646

image-20210512211357592

配置文件加载

profile

读取日志

2019-03-03 12:44:29.040  INFO 23952 --- [-127.0.0.1_8848] o.s.c.a.n.c.NacosPropertySourceBuilder   : Loading nacos data, dataId: 'nacos-config-client-load.yml', group: 'DEFAULT_GROUP'

2019-03-03 12:44:29.044  INFO 23952 --- [-127.0.0.1_8848] o.s.c.a.n.c.NacosPropertySourceBuilder   : Loading nacos data, dataId: 'nacos-config-client-load-dev.yml', group: 'DEFAULT_GROUP'

后加载的会覆盖掉前面的配置信息

  • 优先使用配置是 applicationname-profile
  • 不存在时读取 applicationname

    # 需要在bootstrap.yml 中进行配置server-addr  由他的声明周期来决定  而不能使用application.yml文件进行配置
    spring:
    application:
    name: nacos-config-client
    cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yml # 指定文件类型 nacos-config-client.yml   默认是properties
        group: PIGX #组
    profiles:
    active: dev #指定文件后缀来指定环境  nacos-config-client-dev.yml
    server:
    port: 8055
    
    # 要去加载nacos-config-client-dev.yml文件  读取其中的属性  可以由配置中心进行配置
    
    

GROUP

  • 默认没有组 都是放在DEFAULT_GROUP(即DEFAULT_GROUP 是默认的组)

会在新建配置时指定组

image-20210512211925041

匹配顺序

组—-profile

namespace

image-20210512212121371

# 需要在bootstrap.yml 中进行配置server-addr  由他的声明周期来决定  而不能使用application.yml文件进行配置
spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yml # 指定文件类型 nacos-config-client.yml   默认是properties
        group: PIGX #组
        namespace: b47c4714-f86e-4234-ad21-1e7fe654f5d5

  profiles:
    active: dev #指定文件后缀来指定环境  nacos-config-client-dev.yml
server:
  port: 8055

# 要去加载nacos-config-client-dev.yml文件  读取其中的属性  可以由配置中心进行配置

namespace需要通过命名空间ID进行指定

加载顺序

namespace—-组—-profile

共享配置文件

spring:
  application:
    name: nacos-config-client-load
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yml
        namespace: b47c4714-f86e-4234-ad21-1e7fe654f5d5
        group: PIGX
        # 方式一 常用
        ext-config:
          - data-id: common.yml
        	group: PIGX
        	refresh: true
        # 方式二   只会加载DEFAULT_GROUP中的配置文件  不会传递group  会传递namespace
        shared-dataids: common.yml
        refreshable-dataids: common.yml #支持刷新


server:
  port: 8056

加载顺序

  • common.yml group:DEFAULT_GROUP shared配置的
  • commom.yml group:PIGX ext-config配置的
  • nacos-config-client-load.yml group:PIGX 默认的

后加载的文件属性会覆盖掉前面加载的

数据持久

修改conf/application.properties文件,增加支持mysql数据源配置(目前只支持mysql),添加mysql数据源的url、用户名和密码。

spring.datasource.platform=mysql

db.num=1
db.url.0=jdbc:mysql://11.162.196.16:3306/nacos_devtest?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=nacos_devtest
db.password=youdontknow

初始化mysql数据库,数据库初始化文件:nacos-mysql.sql

常用表格说明

  • config_info:存储配置文件信息 xx.yml
  • his_config_info:保存配置文件的修改记录 历史信息
  • users: 登录用户信息
  • tenant_info: namespace信息

集群

image-20210512105310286

通过Nginx进行请求转发

在nacos的解压目录nacos/的conf目录下,有配置文件cluster.conf,请每行配置成ip:port。(请配置3个或3个以上节点)

# ip:port
127.0.0.1:13333
127.0.0.1:14444
127.0.0.1:15555

启动

./startup.sh -p 13333
./startup.sh -p 14444
./startup.sh -p 15555

通过-p指定端口

配置nginx

nacos.conf

upstream cluster{
	server 127.0.0.1:13333;
	server 127.0.0.1:14444;
	server 127.0.0.1:15555;
}
server{
	listen 11111;
	server_name localhost;
	
	location / {
		proxy_pass http://cluster;
	}
}

启动nginx

集群已经搭建好了

访问

localhost:11111/nacos

然后在项目中配置

spring:
  application:
    name: nacos-config-client-load
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:11111
        file-extension: yml
server:
  port: 8056

Sentinel

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

  • Windows平台安装包下载

可以从https://github.com/alibaba/Sentinel/releases下载sentinel-dashboard-$version.jar包。

使用如下命令启动控制台:

java -Dserver.port=8718 -Dcsp.sentinel.dashboard.server=localhost:8718 -Dproject.name=sentinel-dashboard -Dcsp.sentinel.api.port=8719 -jar D:\sentinel\sentinel-dashboard-1.8.0.jar

1

其中-Dserver.port=8718用于指定Sentinel控制台端口为8718F:\software\sentinel\sentinel-dashboard-1.8.0.jar为下载的包路径地址。

up-d3e4965511f73cee8ec905740129e7f063a

打开控制台

Sentinel提供了一个可视化的操作平台,安装好之后,在浏览器中输入(http://localhost:8718 (opens new window))就可以访问了,默认的用户名和密码都是sentinel(我使用的是1.8.0版本)

sentinel

懒加载的只有当有流量访问的时候才会工作

连接

添加依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.1.1.RELEASE</version>
</dependency>

配置

server:
  port: 18080

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
      datasource:
        ds1:
          file:
            file: classpath:flowrule.json
            data-type: json
            rule-type: flow
        ds2:
          nacos:
            server-addr: localhost:8848
            dataId: sentinel-core-example
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow
  application:
    name: sentinel-core-example

限流

方式一 根据URL限流

@RestController
public class DemoController {
    // 设置阈值为1   每秒只能访问1次
    //流量多的时候会报错Blocked by Sentinel(flow limiting) 
    @GetMapping("/hello")
    public String hello() {
        return "hello sentinel";
    }
}

对hello请求进行限流

自定义降级策略

public class DemoUrlBlockHandler implements UrlBlockHandler {
    @Override
    public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {
        httpServletResponse.getWriter().println("error url");
    }
}

配置类

通过配置类进行绑定

@Configuration
public class SentinelConfig {
    @PostConstruct
    public void init() {
        WebCallbackManager.setUrlBlockHandler(new DemoUrlBlockHandler());
        WebCallbackManager.setRequestOriginParser(new IpRequestOriginParser());
    }
}

方式二 通过资源名限流

resource下面挂了一个resource资源 对资源进行限流

/*
@GetMapping("/resource")
//通过@SentinelResource指定资源名
@SentinelResource("resource")  //需指定具体的资源  否则会报错500
public String resource() {
    return "hello resource";
}
*/
// 方式一
@GetMapping("/resource")
@SentinelResource(value = "resource", blockHandler = "exHandler") //默认找本类下的方法
public String resource() {
    return "hello resource";
}
public String exHandler(BlockException ex) {
    return "exHandeler error";
}
// 方式二   通过blockHandlerClass指定类  通过blockHandler指定方法
@GetMapping("/resource1")
@SentinelResource(value = "resource1", blockHandler = "exHandler", blockHandlerClass = {ExceptionUtil.class})
public String resource1() {
    return "hello resource";
}

处理异常的类

public class ExceptionUtil {
    public static String exHandler(BlockException ex) {
        return "exHandler error";
    }
}

黑白名单控制

配置类

@Configuration
public class SentinelConfig {
    @PostConstruct
    public void init() {
        WebCallbackManager.setUrlBlockHandler(new DemoUrlBlockHandler());
        WebCallbackManager.setRequestOriginParser(new IpRequestOriginParser());//定义判断标准是什么
    }
}
public class IpRequestOriginParser implements RequestOriginParser {
    /** 根据IP
     * Parse the origin from given HTTP request.
     *
     * @param request HTTP request
     * @return parsed origin
     */
    @Override
    public String parseOrigin(HttpServletRequest request) {
        return request.getRemoteAddr();  //生产上不要这么使用
    }
}

接口

@RestController
public class SecurityController {
    @GetMapping("/white")
    public String white() {
        return "hello white";
    }
    @GetMapping("/black")
    public String black() {
        return "hello black";
    }
}

再sentinel面板中的授权规则进行设置

不符合规则的会触发降级操作

热点限流

image-20210512133245207

按照不同的参数进行划分

@RestController
public class ParamController {
    @GetMapping("/param")
    @SentinelResource(value="/param",blockHandler = "exHandler")
    public String param(String type) {
        return "success";
    }
    public String exHandler(String type, BlockException ex) {
        return "exHandler error";
    }
}

热点限流只对resource生效,对普通的请求路径是不生效的,因此要使用热点限流的功能一定要使用@SentinelResource功能进行标注

在sentinel面板中的簇点链路中的/param请求下的param资源进行热点操作

其中参数索引以0开始,type参数的参数索引为0

当不带参数的时候进行访问,一切正常

带param参数访问的时候,会触发降级,执行降级策略。带其他的参数也不会触发降级

自适应限流

超过阈值进行处理,所有请求服务挂起block掉,不超过不进行处理

在sentinel控制台系统规则面板进行设置。新增系统规则

阈值类型

  • LOAD:瞬间处理的进程数,一般设置为CPU个数*0.7
  • RT:服务的平均响应时间,单位为毫秒。超过指定时间的服务都被挂起
  • 线程数:
  • 入口QPS:
  • CPU使用率:0.7

规则持久化

重启应用后我们设置的规则就没了。

目前支持file,nacos,zk,apollo,redis这五种类型

file

在resource文件夹设置规则

flowrule.json

[
  {
    "resource": "hello",
    "count": 1,
    "grade": 1,
    "limitApp": "default",
    "strategy": 0,
    "controlBehavior": 0
  }
]

一条限流规则主要由下面的几个因素构成,我们可以组成这些元素来实现不同的限流效果

  • resource:资源名,即限流规则的作用对象
  • count:限流阈值
  • grade:限流阈值类型(QPS或并发线程数)1:QPS 0:线程数
  • limitApp:流控针对的调用来源,若为default则不区分调用来源
  • strategy:调用关系限流策略。接口是链路的一直往后调用,是否整个链路都限流
  • controlBehavior:流量控制效果(直接拒绝、WarmUP、均速排队)

配置

server:
  port: 18080

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
      datasource:
        ds1:
          file:
            file: classpath:flowrule.json
            data-type: json
            rule-type: flow
  application:
    name: sentinel-core-example

Nacos

添加依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <version>1.7.0</version>
</dependency>

配置

server:
  port: 18080

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
      datasource:
        ds2:
          nacos:
            server-addr: localhost:8848
            dataId: sentinel-core-example
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow
  application:
    name: sentinel-core-example

整合Feign

https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel

提供方

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-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>
@RestController
public class DemoController {

    @GetMapping("/feign")
    public String feign() {
        return "hello sentinel feign";
    }
}

配置

server:
  port: 18082

spring:
  application:
    name: sentinel-feign-provider
  cloud:
    nacos:
      server-addr: localhost:8848

消费方

@RestController
public class DemoController {
    @Autowired
    private DemoFeignClient feignClient;

    @GetMapping("/hello")
    public String hello() {
        return feignClient.feign();
    }
}

@Component
public class DemoFeginClientFallback implements DemoFeignClient {
    @Override
    public String feign() {
        return "error";
    }
}

@FeignClient(value = "sentinel-feign-provider", fallback = DemoFeginClientFallback.class)
public interface DemoFeignClient {
    @GetMapping("/feign")
    String feign();
}
server:
  port: 18081

spring:
  application:
    name: sentinel-feign-comsumer
  cloud:
    nacos:
      server-addr: localhost:8848
@EnableFeignClients
@SpringCloudApplication
public class SentinelFeignProvierApplication {

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

}

整合gateway

官网

sentinel-api-gateway-common-arch

  • GatewayFlowRule:网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。
  • ApiDefinition:用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以定义一个 API 叫 my_api,请求 path 模式为 /foo/**/baz/** 的都归到 my_api 这个 API 分组下面。限流的时候可以针对这个自定义的 API 分组维度进行限流。

Seata分布式事务

官方文档地址

Seata是阿里开源的一个分布式事务框架。 Seata主要有两种分布式事务实现方案,AT及TCC

  • AT模式主要关注多 DB 访问的数据一致性,当然也包括多服务下的多 DB 数据访问一致性问题
  • TCC 模式主要关注业务拆分,在按照业务横向扩展资源时,解决微服务间调用的一致性问题
  1. 下载seata-server并运行,下载地址

  2. 每个服务加上seata的依赖

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        <version>2.1.1.RELEASE</version>
    </dependency>
    
    1. 加上file.conf,并修改service的vgroup
    2. 指明配置中心—–加上registry.conf配置
  3. 数据库导入表