SpringCloud2020总结

官网文档传送门:

SpringCloud脑图链接

SpringCloud: https://spring.io/projects/spring-cloud/

这个网址是各springcloud组件的配置介绍,自己搭建组件环境可以考虑看这个。

Seata: https://seata.io/zh-cn/docs/overview/what-is-seata.html

分布式事务解决的框架,文档介绍很详细,推荐。

Nacos: https://nacos.io/zh-cn/docs/what-is-nacos.html

那个替代Eureka和Config的男人。

Sentinel:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D

在Hystrix基础上增加了流控规则和持久化,alibaba体系的一员。

SpringCloud和SpringBoot之间的版本依赖
在这里插入图片描述

微服务模块

  1. 建module
  2. 改POM
  3. 写YML
  4. 主启动
  5. 业务类
    顺序

SpringCloud脑图链接

SpringCloud Alibaba详解

SpringCloud Alibaba入门简介

  1. 为什么会出现SpringCloud alibaba?
    Spring Cloud Netflix 项目进入维护模式
    Spring Cloud Netflix Projects Entering Maintenance Mode
  2. SpringCloud alibaba带来了什么?

是什么

官网:
https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md
诞生:
2018.10.31, Spring Cloud Alibaba 正式入驻了 Spring Cloud 官网孵化器,并在 Maven 中央仓库发布了第一个版本。
Spring-Cloud-Alibaba项目由阿里巴巴的开源组件和多个阿里云产品组成,旨在实现和公开众所周知的Spring框架模式和抽象,为使用阿里巴巴产品的Java开发者带来Spring-Boot和Spring-Cloud的好处。

能干什么

* 服务限流降级:默认支持 Servlet、Feign、RestTemplate、Dubbo、和RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级骨子额,还支持查看限流降级 Metrics 控制。
* 服务注册于发现:适配 Spring Cloud 服务注册于发现标准,默认集成 Ribbon 支持
* 分布式配置管理:支持分布式系统中的外部话配置,配置更改时自动刷新。
* 消息驱动能力:基于Spring Cloud Stream 为微服务应用构建消息驱动能力。
* 阿里云对象存储:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用,任何时间、任何低调存储和访问任意类型的数据。
* 分布式任务调度:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务,网格任务支持海量任务均匀分配到所有 Worker (schedulerx-client) 执行。

去哪里下

https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

怎么使用

bashhttps://spring.io/projects/spring-cloud-alibaba#overview
  1. SpringCloud alibaba学习资料获取!
    SpringCloud脑图链接

SpringCloud Alibaba Nacos服务注册和配置中心

Nacos简介
为什么叫nacos?

前面四个字母分别表示 Naming 和 Configuration 的前两个字母, 最后一个s 为 Service

是什么?

一个更易于构建云原生运用的动态服务发现、配置管理和服务管理平台
Nacos: Dynamic Naming and Configuration Service
Nacos 就是注册中心+ 配置中心   等价于  Nacos = Eureka + Config + Bus

能做什么?

替代 Eureka 做服务注册中心
替代 Config 做服务配置中心

去哪里下载?

https://github.com/alibaba/nacos
官方文档
https://nacos.io/en-us/
https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html

各种注册中心比较
在这里插入图片描述
安装并运行Nacos
下载地址:https://github.com/alibaba/nacos/releases
下载:nacos-server-版本号.zip
解压运行startup.cmd
使用http://127.0.0.1:8848/nacos/index.html访问
用户名:nacos 密码:nacos


替代Eureka作为服务中心演示

官方文档

https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html

基于 Nacos 的服务提供者

  • POM 配置信息
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
  • YML 配置
server:
  port: 9001

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

management:
  endpoints:
    web:
      exposure:
        include: '*'  #监控
  • 主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9001.class,args);
    }
}
  • 业务类
@RestController
public class PaymentController {
    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/payment/nacos/{id}")
    public String getPayment(@PathVariable("id") Integer id){
        return "nacos registry,serverPort: "+ serverPort+"\t id"+id;
    }
}
  • 测试
    启动 nacos

再次新建相同的服务9002
在这里插入图片描述
基于 Nacos 的服务消费者

  • POM 配置信息
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
  • YML 配置
server:
  port: 83

spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

#消费者将要去访问的微服务名称(成功注册进nacos的微服务提供者),在这配置了访问的服务,业务类就不用在定义常量了
service-url:
  nacos-user-service: http://nacos-payment-provider
  • 主启动
@SpringBootApplication
@EnableDiscoveryClient
public class OrderNacosMain83 {
    public static void main(String[] args) {
        SpringApplication.run(OrderNacosMain83.class,args);
    }
}
  • 配置类
@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}
  • 业务类
@Slf4j
public class OrderNacosController {
    @Value("service-url.acos-user-service")
    private String serverURL;
    @Resource
    private RestTemplate restTemplate;

    @GetMapping("/consumer/payment/nacos/{id}")
    public String paymentInfo(@PathVariable("id") Long id){
        return restTemplate.getForObject(serverURL+"/payment/nacos/"+id,String.class);
    }
}

Nacos支持cp和ap之间的切换

C 是所有节点在同一时间看到的数据是一致的,而A的定义是所有的请求都会受到相应。


何时选择使用何种模式?

一般来说,
如果不需要存储级别的信息且服务实例是通过 nacos-client 注册的,并且能够保持心跳上报,那么久可以选择AP 模式,当前主流的服务如: spring cloud 和 dubbo 服务,都适用于AP 模式,AP为了方服务的可能性而减弱了一致性,因此AP模式先只支持注册临时实例。

如果需要在服务级别编辑或者存储配置信息,那么CP是必须的, K8S 服务和 DNS 服务则不适用于 CP 模式。

CP 模式下则支持注册持久化实例,此时则是 Raft 协议为集群模式运行, 该模式下注册实实例之前必须先注册服务。如果服务不存在,则会返回错误

curl -X PUT
'$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'

替代Config做服务配置中心

  • POM
<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
  • YML
    bootatrap.yml
#nacos配置
server:
  port: 3377
spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos作为注册中心
      config:
        server-addr: localhost:8848 #Nacos作为配置中心
        file-extension: yaml #指定yaml格式的配置
        group: DEV_GROUP
        namespace: 20d08909-60b8-40de-b14f-95ec77507117
#${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file.extension}
# nacos-config-client-dev.yaml

application.yml

spring:
  profiles:
    active: dev #表示开发环境
    #active: test #表示测试环境
    #active: info

在这里插入图片描述

  • 启动类
@SpringBootApplication
@EnableDiscoveryClient
public class NacosConfigClientMain3377 {
    public static void main(String[] args) {
        SpringApplication.run(NacosConfigClientMain3377.class,args);
    }
}
  • 业务类
@RestController
@RefreshScope //支持Nacos的动态刷新
@Slf4j
public class ConfigClientController {
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/config/info")
    public String getConfigInfo(){
        log.info("getConfigInfo");
        return configInfo;
    }
}

在 Nacos 中添加配置信息
修改下 Nacos 中的yaml 配置文件,再次调用查看配置的接口,就会发现配置已经刷新

Nacos 作为配置中心 - 分类配置

	spring.profiles.active: dev #指定环境
	spring.cloud.nacos.config.group: DEV_GROUP #指定分组
    spring.cloud.nacos.config.namespace: 20d08909-60b8-40de-b14f-95ec77507117 #指定空间

集群和持久化配置

使用Nginx对Nacos集群(更改mysql数据源)进行反向代理
更改服务中nacos的地址变成nginx地址

SpringCloud Alibaba Sentinel 实现熔断与限流

官网
https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
是什么
一句话解释, 之前我们讲过的Hystrix
去哪下
https://github.com/alibaba/Sentinel/releases
能干什么
在这里插入图片描述
怎么玩

https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D

java -jar 名称
默认端口8080
登录账号密码均为: sentinel

启动Nacos 8848
启动Sentinel 8080

sentienl 采用的是懒加载

  • POM
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--     sentinel-datasource-nacos 后续持久化用   -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </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.hzy.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
  • YML
server:
  port: 8401
spring:
  application:
    name: cloudalibaba-sentinel-server
  cloud:
    nacos:
#      服务注册中心
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
#        配置Sentinel dashboard地址
        dashboard: localhost:8080
#        默认8719端口,如果被占用+1
        port: 8719
      # 流控规则持久化到nacos
      datasource:
        dsl:
          nacos:
            server-addr: localhost:8848
            data-id: ${spring.application.name}
            group-id: DEFAULT_GROUP
            data-type: json
            rule-type: flow

#图形化监控
management:
  endpoints:
    web:
      exposure:
        include: "*"

@SentinelResource注解可以配置

SentinelResource 定义了value,
entryType,resourceType,blockHandler,fallback,defaultFallback等属性。

属性说明

value

资源名称,必需项,因为需要通过resource name找到对应的规则,这个是必须配置的。
entryType

entry 类型,可选项,
有IN和OUT两个选项,默认为 EntryType.OUT。

public enum EntryType {
    IN("IN"),
    OUT("OUT");
}

blockHandler

blockHandler 对应处理 BlockException 的函数名称,可选项。
blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,
参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。
blockHandlerClass

blockHandler 函数默认需要和原方法在同一个类中,如果希望使用其他类的函数,
则需要指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
fallback

fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。
fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。
fallbackClass

fallbackClass的应用和blockHandlerClass类似,fallback 函数默认需要和原方法在同一个类中。
若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
defaultFallback(since 1.6.0)

如果没有配置defaultFallback方法,默认都会走到这里来。
默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑。
默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。
若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。
exceptionsToIgnore(since 1.6.0)

用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

在这里插入图片描述

一旦我们重启应用,sentinel 规则将消失,生产环境需要将配置规则进行持久化

将想留配置规则持久化经Nacos 保存, 只需要刷新 服务提供者的一个rest地址, sentinel 控制台的
流控规则就能看到, 只要Nacos 里面的配置不删除,针对服务提供者的 sentinel 上的控流规则
spring:
  application:
    name: order-service-nacos
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.1.3:8848
    sentinel:
      transport:
        # 默认8719, 如果被占用了会自动从8719开始一次+1, 直至找到未被占用的端口为止
        port: 8719
        # sentinel dashboard d地址
        dashboard: 192.168.1.3:8080
      datasource:
        ds1:
          nacos:
            server-addr: 192.168.1.3:8848
            dataId: order-service-nacos
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

在nacos上编辑
在这里插入图片描述

Seata简介

为了解决分布式事务的问题!

单机没有问题

单体应用被拆分成微服务应用, 原来的三个模块被拆分为独立的三个应用,分别使用三个独立的数据源,

业务操作需要调用三个服务来完成,此时每个服务内部的数据一致性由本地事务来保证,但是全局的数据一致性没有办法保证。

Seata 是一款开源的分布式事务解决方案,致力于在微服务的分布式事务处理
https://seata.io/zh-cn

分布式事务处理过程的一个ID + 三个组件模型
  • Transaction ID XID (全局唯一的事务ID)
  • 3组件概念
Transaction Coordinator(TC):事务协调者, 维护全局和分支事务的状态,驱动全局事务提交或回滚。
Transaction Manager (TM) :事务管理器, 定义全局事务的范围:开始全局事务、提交或回滚全局事务。
Resource Manager (RM) :资源管理器, 管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

处理过程

  1. TM 向 TC 申请开启一个全局事务,全局事务叉棍见成功过并且申城一个全局唯一的 XID;

  2. XID 在微服务调用链路的上下文中传播;

  3. RM 向 TC 注册分支事务, 将其纳入 XID 对应全局事务的管辖;

  4. TM 向 TC发起针对 XID 的全局提交或者回滚决议;

  5. TC 调度 XID 管辖的全部分支事务完成提交或者回滚请求

去哪里下载
官方下载
怎么玩?

本地 @Transactional
全局 @GlobalTransactional

SEATA 的分布式交易解决方案

在这里插入图片描述0.9版本以后可以使用集群

AT 模式如何做到对业务的无侵入
一阶段加锁,二阶段提交,二阶段回滚

雪花算法

分布式ID
在复杂分布式系统中,往往需要对大量的数据进行唯一标识
此时一个能够生成全局唯一ID的系统是非常必要的
ID生成规则部分硬性要求

  1. 全局唯一
  2. 趋势递增
  3. 单调递增
  4. 信息安全
  5. 含时间戳

ID号生成系统的可用性要求

  • 高可用(发一个分布式ID的请求,服务器就要保证99.999%的情况下给我创建一个唯一分布式ID)
  • 低延迟(发一个分布式ID的请求,服务器要快,极速)
  • 高QPS(假如并发一口气10万个创建分布式ID请求同时杀过来,服务器要顶的住并且一下子成功创建10万个分布式ID)

一般通用解决方案

  • UUID(UUID.randomUUID().toString();加上4个短线36个字符)
UUID会导致入库性能变差
1. 无序,无法预测他的生成顺序,不能生成递增有序的数字。(官方推荐ID越短越好,UUID很长,所以不是很推荐)
2. 主键,ID作为主键时在特定的环境会存在一些问题。
3. 索引,B+树索引的分裂。(mysql的索引是通过B+树来实现的,因为是无序的,所以每一次UUID数据的插入都会对主键地域的B+树的进行很大的修改,插入完全无序,不但会导致一些中间节点产生分裂,也会白白创造出很多不饱和的节点,这样大大减低了数据库插入的性能)
  • 数据库自增主键
单机
REPLACE INTO的含义是插入一条数据,如果表中唯一索引的值遇到冲突,则替换老数据。
插入语法:REPLACE INTO 表名(字段) VALUES(值);
集群分布式(不合适)
1. 系统水平扩展比较困难,避免ID冲突,需要思考步长,间隔。
2. 数据库压力还是很大,每次获取ID都得读写一次数据库,非常影响性能,不符合分布式ID里面的延迟低和要高QPS的规则,在高并发下,去数据库中获取ID,是非常影响性能的。
  • 基于Redis生成全局id策略
因为Redis是单线程的天生保证原子性,可以使用原子操作INCR和INCRBY来实现
集群分布式(需要维护5台Redis集群,5台以上就会重复ID,不合适)
注意:在Redis集群情况下,同样和MySQL一样需要设置不同的增长步长,同时key一定要设置有效期
可以使用Redis集群来获取更高的吞吐量。
假如一个集群有5台Redis,可以初始化每台Redis的值分别是1,2,3,4,5,然后步长都是5。

snowflake雪花算法

概述
在这里插入图片描述结构
雪花算法的几个核心组成部分:
在这里插入图片描述号段解析:
在这里插入图片描述SnowFlake可以保证:
所有生成的ID按时间趋势递增
整个分布式系统内不会产生重复ID(因为有datacenterId和workerId来做区分)

得出可以使用到2039-09-07

public static void main(String[] args) {
        System.out.println("11111111111111111111111111111111111111111".length());
        long time=2199023255551L;
        Date date=new Date();
        date.setTime(time);
        System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(date));
    }

源码
雪花算法GitHub地址

hutool工具包GitHub地址

实战
引入特定的hutool工具包

package com.hzy.demo;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.IdUtil;

import javax.annotation.PostConstruct;

public class IdGeneratorSnowflake {
    private long workerId=0;
    private long datacenterId=1;
    private Snowflake snowflake= IdUtil.createSnowflake(workerId,datacenterId);
    @PostConstruct//初始化加载
    public void init(){
        try {
            workerId= NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());
            System.out.println("当前机器的workerId:{}"+workerId);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("当前机器的workerId获取失败");
            System.out.println(e);
            workerId=NetUtil.getLocalhostStr().hashCode();
        }
    }
    public synchronized long snowflakeId(){
        return snowflake.nextId();
    }
    public synchronized long snowflakeId(long workerId,long datacenterId){
        Snowflake snowflake=IdUtil.createSnowflake(workerId,datacenterId);
        return snowflake.nextId();
    }

}
package com.hzy.demo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SnowflakeDemo {
    public static void main(String[] args) {
        IdGeneratorSnowflake idGeneratorSnowflake=new IdGeneratorSnowflake();
        ExecutorService threadPool= Executors.newFixedThreadPool(5);
        for (int i = 0; i < 20; i++) {
            threadPool.submit(()->{
                System.out.println(idGeneratorSnowflake.snowflakeId());
            });
        }
        threadPool.shutdown();
    }
}

优缺点
在这里插入图片描述如果真的出现时钟回拨(基本不可能)
百度开源的分布式唯一ID生成器UidGenerator
Leaf–美团点评分布式ID生成系统

发布了21 篇原创文章 · 获赞 7 · 访问量 436

猜你喜欢

转载自blog.csdn.net/weixin_42998267/article/details/105555230
今日推荐