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事務模型演進而來,所以它的整體機制也是一個改進版的兩階段提交協議
第一階段: 業務數據和回滾日志記錄在同一個本地事務中提交,釋放本地鎖和連接資源
第二階段: 提交異步化,非常快速完成,回滾通過第一階段的回滾日志進行反向補償




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM