zoukankan      html  css  js  c++  java
  • SpringCloud Alibaba微服务原理与实战-读书笔记

    概述

    主要包含以下组件

    Sentinel 流量控制和服务降级
    Nacos 服务注册与发现
    Nacos 分布式配置中心
    RocketMQ 消息驱动
    Seate 分布式事务
    Dubbo RPC通信
    OSS 阿里云对象存储

    springboot自动装配原理

    eg:将redis整合到springboot中:
    1.添加starter依赖:spring-boot-starter-data-redis
    2.在application.properties中配置redis数据源
    3.使用@Autowried引入redisTemplate
    4.使用
    当使用@Autowried注入redisTemplate实例时.说明IOC容器中已经存在RedisTemplate,这是Springboot自动装配而来的
    所以,存在一个机制,这个机制的实现基于某种约定或者规范,只要Starter组件符合SpringBoot中自动装配的规范,就能实现自动装配

    自动装配的实现

    自动装配在SpringBoot中是通过@EnableAutoConfiguration注解开启的,这个注解声明在@SpringBootApplication中

    @Enable注解:主要作用是把相关组件的Bean转配到IOC容器中
    @Enable注解对JavaConfig进一步完善,常见的@Enable注解有
    @EnableWebMvc和@EnableScheduling等

    每个@Enable类的注解都包含@Import

    @ImportSelector的作用


    自动装配的核心是扫描约定目录下的文件进行解析,解析完成后把得到的Configuration配置类通过ImportSelector进行导入,从而完成Bean的自动装配过程

    SpringFactoriesLoaderss是Spring内部提供的一种预定俗成的加载方式,类似于Java中的SPI,它会扫描classpath下的METE-INF/spring.factories文件,这个文件的数据由key=value方式存储



    Conditional条件注解



    • springboot中的@Conditional做了一些扩展


    手工实现一个starter

    1.命名规范:
    官方: spring-boot-starter-模块名称
    自定义: 模块名称-spring-boot-starter
    官方命名模块名称放最后,自定义模块名称放前面
    2.创建一个工程,命名为redis-spring-boot-starter
    3.添加jar包依赖

    <dependency>
          <groupId>org.redisson</groupId>
          <artifactId>redisson</artifactId>
          <version>3.11.1</version>
    </dependency>
    

    4.定义属性

    @ConfigurationProperties(prefix = "gp.redisson")
    public class RedissonProperties {
    
        private String host = "localhost";
        private String password;
        private int port = 6379;
        private int timeout;
        private boolean ssl;
    
        public String getHost() {return host;}
        public void setHost(String host) {this.host = host;}
        public String getPassword() {return password;}
        public void setPassword(String password) {this.password = password;}
        public int getPort() {return port;}
        public void setPort(int port) {this.port = port;}
        public boolean isSsl() {return ssl;}
        public void setSsl(boolean ssl) {this.ssl = ssl;}
        public int getTimeout() {return timeout;}
        public void setTimeout(int timeout) {this.timeout = timeout;}
    }
    

    5.定义需要自动装配的配置类,主要是把RedissonClient装配到IOC容器
    @ConditionalOnClass(Redisson.class)表示只有classpath下存在Redisson这个类,RedissonAutoConfiguration 才会实现自动装配

    @Configuration
    @ConditionalOnClass(Redisson.class)
    @EnableConfigurationProperties(RedissonProperties.class)
    public class RedissonAutoConfiguration {
        @Autowired
        RedissonProperties redissonProperties;
        @Bean
        RedissonClient redissonClient(){
           Config config=new Config();
           String prefix="redis://";
           if(redissonProperties.isSsl()){
               prefix="rediss://";
           }
           SingleServerConfig singleServerConfig=config.useSingleServer()
                   .setAddress(prefix+redissonProperties.getHost()+":"+redissonProperties.getPort())
                   .setConnectTimeout(redissonProperties.getTimeout());
           if(!StringUtils.isEmpty(redissonProperties.getPassword())){
               singleServerConfig.setPassword(redissonProperties.getPassword());
           }
           return Redisson.create(config);
        }
    }
    

    6.在resource下创建METE-INF/spring.factories文件,使得SpringBoot程序可以扫描到该文件完成自动装配

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
      com.gupaoedu.book.RedissonAutoConfiguration
    

    7.使用的时候,直接添加依赖

      <groupId>com.gupaoedu.book</groupId>
      <artifactId>redis-spring-boot-starter</artifactId>
      <version>1.0-SNAPSHOT</version>
    

    8.添加属性

    gp.redisson.host=192.168.56.111
    gp.redisson.port=6379
    

    springboot集成dubbo

    • 生产者
      1.启动方法要加上@DubboComponentScan
      2.服务加上@Service注解,该注解是dubbo包下的,不是spring的
      3.添加dubbo依赖
    <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-spring-boot-starter</artifactId>
                <version>2.7.5</version>
    </dependency>
    

    4.加上配置文件

    dubbo.application.name=springboot-provider
    dubbo.protocol.name=dubbo
    dubbo.protocol.port=20880
    dubbo.registry.address=N/A
    
    • 消费者
    声明服务时使用@Reference注解获取一个远程代理对象
    @Reference(url = "dubbo://127.0.0.1:20880/com.gupaoedu.book.dubbo.IHelloService")
    private IHelloService helloService;
    
    
    • dubbo使用nacos作为注册中心
      1.依赖nacos组件
    <dependency>
                <groupId>com.alibaba.boot</groupId>
                <artifactId>nacos-discovery-spring-boot-starter</artifactId>
                <version>0.2.4</version>
            </dependency>
    

    2.dubbo注册地址加上nacos协议
    dubbo.registry.address=nacos://192.168.56.111:8848
    3.启动类加上Dubbo注解
    @DubboComponentScan

    • dubbo使用nacos作为注册中心
      1.依赖nacos组件
    <dependency>
                <groupId>com.alibaba.boot</groupId>
                <artifactId>nacos-discovery-spring-boot-starter</artifactId>
                <version>0.2.4</version>
            </dependency>
    

    2.dubbo注册地址加上nacos协议
    dubbo.registry.address=nacos://192.168.56.111:8848
    3.启动类加上Dubbo注解
    @DubboComponentScan

    • springcloud使用nacos作为注册中心
      1.引入服务发现依赖
    <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
    </dependency>
    

    2.配置
    spring.cloud.nacos.discovery.server-addr=192.168.56.111:8848

    Nacos服务注册与发现实现原理

    nacos源码分析

    • 服务注册
    • 服务地址获取
    • 服务地址变化感知
      spring-cloud-common中有个ServiceRegistry接口,是服务注册的标准
    package org.springframework.cloud.client.serviceregistry;
    
    public interface ServiceRegistry<R extends Registration> {
        void register(R registration);
    
        void deregister(R registration);
    
        void close();
    
        void setStatus(R registration, String status);
    
        <T> T getStatus(R registration);
    }
    

    其中一个实现类是NacosServiceRegistry
    在spring-cloud-commons包的META-INF/spring.factories中包含自动装配信息

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
      com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration,
      com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration,
      com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,
      com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientAutoConfiguration,
      com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration
    org.springframework.cloud.bootstrap.BootstrapConfiguration=
      com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration
    

    sentinel微服务熔断和限流

    1.限流规则配置

    public class FlowRuleInitFunc implements InitFunc{
        @Override
        public void init() throws Exception {
            List<FlowRule> rules=new ArrayList<>();
            FlowRule rule=new FlowRule();
            rule.setCount(1);
            rule.setResource("hello");
            rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
            rule.setLimitApp("default");
            rules.add(rule);
            FlowRuleManager.loadRules(rules);
        }
    }
    

    2.请求方法设置限流注解,增加限流后返回的方法

    @RestController
    public class HelloController {
    
        @SentinelResource(value = "hello",blockHandler = "blockHandlerHello")
        @GetMapping("/say")
        public String hello(){
            return "hello ,Mic";
        }
        public String blockHandlerHello(BlockException e){
            return "被限流了";
        }
    }
    

    3.在META-INF.services增加限流类,设置扩展点

    com.gupaoedu.book.springcloud.sentinel.springcloudsentinelsample.FlowRuleInitFunc
    

    4.添加限流依赖

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

    5.将一类url归类为一个

    @Service
    public class CustomerUrlCleaner implements UrlCleaner{
        @Override
        public String clean(String originUrl) {
            if(StringUtils.isEmpty(originUrl)){
                return originUrl;
            }
            if(originUrl.startsWith("/clean/")){
                return "/clean/*";
            }
            return originUrl;
        }
    }
    
    • Sentinel集成Nacos动态流控规则
      1.nacos配置
    [{
        "resource":"/dynamic",
        "limitApp":"default",
        "grade":1,
        "count":1,
        "strategy":0,
        "controlBehavior":0,
        "clusterMode":false
    }]
    

    2.项目配置文件中配置

    spring:
      application:
        name: spring-cloud-sentinel-dynamic
      cloud:
        sentinel:
          transport:
            dashboard: 127.0.0.1:7777
          datasource:
            - nacos:
                server-addr: 192.168.56.111:8848
                data-id: ${spring.application.name}-sentinel-flow
                group-id: DEFAULT_GROUP
                data-type: json
                rule-type: flow
    

    3.在sentinel控制台可以看到规则

    现在不支持在控制台修改规则同步到nacos
    可以通过修改源码,对控制台的curd操作的结果保存到nacos实现将控制台的规则持久化到nacos中

    Sentinel工作原理

    分布式事务

    分布式事务指事务的参与者,支持事务的服务器分别位于不同的节点上
    分布式事务常见解决方案:
    1.两阶段提交协议

    第一阶段是事务准备阶段
    第二阶段是事务提交或者回滚阶段
    准备阶段:事务管理器(TM)通知资源管理器(RM)准备分支事务,记录事务日志,并告知事务管理器准备结果
    提交/回滚阶段:如果所有资源管理器(RM)在准备阶段都明确返回成功,则事务管理器向所有资源管理器发起事务提交指令完成数据变更,反之,如果任何一个资源管理器明确返回失败,则事务管理器向所有资源管理器发送事务回滚指令
    缺点: 同步阻塞,过于保守(任意一个节点失败都会回滚)
    事务协调者单点故障:如果协调者第二阶段出现故障,那么其他参与者会处于锁定状态
    脑裂导致数据不一致: 在第二阶段中,事务协调者向所有参与者发送commit请求
    发生局部网络异常导致只有一部分参与者收到commit请求,这部分参与者收到请求后会执行commit操作,但是未收到commit请求的节点由于事务无法提交
    导致数据出现不一致问题

    2.三阶段提交协议
    比二阶段多一个询问阶段
    事务协调者向参与者发送事务执行请求,询问是否可以执行指令

    Base理论

    通过牺牲数据的强一致性来获取高可用性
    Base Avaliable(基本可用): 出现故障时,允许损失一部分功能可用性,保证核心功能可用
    Soft State(软状态) : 允许系统中数据存在中间状态,这个状态不影响系统可用性,就是允许系统中不同节点的数据副本存在延时
    Eventually Consistent(最终一致性):中间状态数据经过一段时间之后达到最终数据一致性

    分布式事务常见解决方案

    1. TCC补偿型方案(属于两段式)(关键字:事先冻结):



    2.基于可靠性消息的最终一致性方案(基于中间件实现)


    支付服务的本地事务与发送消息这个操作的原子性问题:
    1.先发送消息,再执行数据库事务
    会出现消息发送成功但是本地事务更新失败的情况
    2.先执行数据库事务,再发送消息
    出现mq响应超时导致异常,从而将本地事务回滚,但消息可能已经发送成功,也存在数据不一致问题



    最大努力通知型


    分布式事务框架seata

    AT模式

    分为三大模块:TM(事务管理器) RM(资源管理器) TC(事务控制器),
    TM: 负责向TC注册一个全局事务,并生成一个全局唯一的XID
    在AT模式下,每个数据库资源被当做一个RM,在业务层面通过JDBC标准接口访问RM时,Seata会对所有的请求进行拦截,每个本地事务提交时,RM会向TC注册一个分支事务

    Saga模式

    把一个业务流程中的长事务分为多个本地短事务,业务流程中每个参与者都提交真实的提交给本地短事务,
    当其中一个参与者事务执行失败,则通过补偿机制补偿前面已经成功的参与者


    常见两种协调方式

    1. 事件/编排式
    2. 命令/协调式

    Seata AT实现原理

    AT模式是基于XA事务模型演进而来,所以它的整体机制也是一个改进版的两阶段提交协议
    第一阶段: 业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源
    第二阶段: 提交异步化,非常快速完成,回滚通过第一阶段的回滚日志进行反向补偿



  • 相关阅读:
    HTTPS 深入浅出
    Elasticsearch Analyzer 的内部机制
    Elasticsearch 查看token分析过程
    elasticsearch教程大全
    【DDD】领域驱动设计实践 —— 框架实现
    阿里盒马领域驱动设计实践
    kubernetic
    安装k8s dashboard
    单机版kubernetes1.13安装
    Kubernetes踩坑记录
  • 原文地址:https://www.cnblogs.com/Baronboy/p/15384815.html
Copyright © 2011-2022 走看看