微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

springcloud

SpringCloud

早期,所有东西,后台前台等等都在一个工程打成war包

容易单点挂掉,并发能力弱,代码耦合度高

扩展,不好扩展,要么都并发,但后台不需要,造成浪费

好处:维护简单

 

基于http协议,这是和dubbo的本质区别,dubbo的核心是基于RPC:远程过程调用

 

分布式,垂直拆分:功能拆分

        水平拆分:分层  web层、service、mapper

方便水平扩展

方便独立优化

解耦合

提高并发

缺点:增加成本,重复开发

 

SNAPSTOP 快照版本,随时修改

M:mileStone M1第一个里程碑版本

SR:service RELEASE 第一个正式版本  GA

 

后台分离  ;用户后台用户前台 、订单前台、订单前台 互相调用

解决代码冗余

缺点:调用关系错综复杂、维护困难

 

SOA:注册中心,容器   服务的提供者和调用者都注册注册中心中

 

微服务架构

粒度很小,每一个服务对应唯一的业务能力

面向服务:restfulPI接口,跟语言无关

自治:服务之间互不干扰,各自独立

 

前后端分离:提供统一的rest接口

数据库分离:各自数据源

 部署独立, 服务之间有调用,但是重启服务互不影响,利于持续集成和交付,每个服务都是独立的组件,可复用,可替换,渐低耦合,利于维护

 

Spring cloud 、 dubbo(阿里)

 

服务之间调用方式:

1、 RPC  远程过程调用自定义数据格式  dubbo

2、 HTTP  网络传输协议,基于tcp,规定了数据格式 Spring cloud

缺点:消息封装臃肿,优点:服务的提供和调用没有技术限定,自由灵活,可以rest风格。

 

 

 

HTTp客户端工具: 处理响应请求

HTTPclient

OKHttp

URLConnection

 

Jackson

工具类  ObjectMapper 可以序列化,反序列化

 Private static final ObjectMapper mapper=new ObjectMapper();

序列化: mapper .writeValueAsstring(user)

反序列化mapper .readValue(response,User.class)

 

spring的restTemplate模板工具类,实现了序列化和反序列化

 

 

微服务

Spring Cloud  

 

核心组件:   都在Netflix下

1、Eureka  :服务治理组件。包含服务注册中心、服务注册和发现机制的实现

2、Zuul:网关组件,提供智能路由,访问过滤功能

3、Ribbon: 客户端负载均衡的服务调用组件(客户端负载

4、Feign :服务调用,给与Ribon和Hystrix的声明式服务调用组件(声明式服务调用

5、Hystrix:容错管理组件,实现断路器,帮助服务中延迟,为故障提供容错能力。

 

Eureka使用,创建模块 ,提供者,调用者,Eureka模块注册中心

区别于zookeper不用装在linux

Eureka Server 进入自我保护机制

防止误杀服务机制,个别客户端心跳失联,认为是客户端问题,剔除客户端。

大量客户端失联,认为网络问题,进入自我保护机制。恢复心跳,自动退出自我保护机制。

 

Renew:服务续约,每隔30秒发送一次心跳来续约。

eviction 服务剔除,Eureka客户端连续90秒没有向Eureka服务器发送服务续约,即心跳,剔除服务。

Cancel:服务下线

 

原理:

Eureka server  集群部署,异步数据同步,数据最终一致性

Service  provider  提供者  注册到eureka

Service  consumer  消费者 获取注册服务列表,消费服务

 

Eureka模块注册中心

server:
  port: 10086
spring:
  application:
    name: wxb-eureka  #作为微服务名称注入到eureka容器
eureka:
  client:
    service-url:
      defaultZone: http://localhost:10086/eureka #http://localhost:${server.port}/eureka

 

 

启动类加注解

@EnableEurekaServer//启用eureka组件服务端

 

 

 

 

提供者加依赖eureka客户端依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

配置文件

spring:
  datasource:
    url: jdbc:MysqL://localhost:3306/mybatis1?serverTimezone=UTC
    username: root
    password: wxb123456
  application:
    name: service-provider #作为微服务的名称

eureka:
  client:
    service-url:
      defaultZone: http://localhost:10086/eureka

 

引导类 注解启用

//@EnableEurekaClient//启用客户端eureka
@EnablediscoveryClient//发现的客户端

 

List instances=discoveryClient.getInstances(service-provider )

ServiceInstance   instance=Instances.get(0)

(“http://”+Instance.getHost()+”:”+instance.getPort()+”/user/”+id,User.class)

 

 

register-with-eureka: true #认就是true
instance:
  lease-expiration-duration-in-seconds: 10  #10秒过期时间
  lease-renewal-interval-in-seconds: 5 # 5秒一次心跳 心跳时间

 

服务端配置文件

server:
  enable-self-preservation: false  #关闭自我保护状态
  eviction-interval-timer-in-ms: 5000 #提出无效连接的间隔时间

@autowired

discovertClient  discovertClient 拉取所有服务信息

 

 

 

 

Ribbon 负载均衡    客户端负载均衡

提供了认的负载均衡算法:轮询、随机

也可以自定义负载均衡算法  加权轮询

用法

 

1、引入依赖(消费方) :eureka  已经依赖了  配置文件

2、加上@loadBalanced

@Bean
@LoadBalanced//开启负载均衡
public RestTemplate restTemplate(){
    return new RestTemplate();

 

3、认轮询

 

负载均衡算法=rest接口第几次请求数%服务器集群总数量 = 实际调用服务器位置下标,每次服务重启后rest接口计数从1开始

Ribbon负载均衡策略:

轮询:对所有的服务器节点按顺序分配,每个服务器的概率是等同的

 

加权轮询:对每个服务器加了权重比利,性能强劲的服务器的权重就高一些,性能弱的权重随机

重试

最低并发

可用过滤

响应时间加权重

区域权重

 

Hystrix  熔断,微服务的一种保护机制

为每个依赖调度分配一个小的线程池,如果线程池已满调用会立即被拒绝,认不采用排队,加速失败判定时间。

用户请求将不在访问服务,而是通过线程池中的空闲线程来访问服务,如果线程已满,或者请求超时,则降级处理

服务降级处理:优先保证核心服务,非核心服务不可用和弱可用

 

请求失败,不会阻塞,不会无休止等待或直到系统崩溃,而是会至少看到一个执行结果,例如返回有好的提示信息

服务降级会导致请求失败,不会导致阻塞,最多影响这个请求,不会影响其他服务没有响应。

触发hystrix服务降级条件:1、线程池已满  2、请求超时

 

使用:(在customers  服务调用方 配置)

 

降级:

1、引入依赖  引入启动器

2、配置文件(可以不加)

设置Hystrix的超时时间

认是1秒,开发环境够用

生产环境的话,修改:timeoutInMilliseconds: 6000ms

 

3、启动类加注解@EnableCicuitBreaker    //开启熔断

4、两个方法产生关联 加注解@HystrixCommand(fallbackMethod=”熔断方法名”)  使用全局的熔断方法可以改成@HystrixCommand  

5、局部的熔断,熔断和被熔断方法的返回值和参数列表一致

Public  String 熔断方法名 (Long   id){

  Return “服务正忙,稍后再试”;

}

 

想要制定熔断方法为全局的

在类上面加注解@defaultProperties(defaultFallback=”熔断方法名”)

多个熔断方法,全局的:返回值和被熔断的方法一致,参数列表为空

Public  String 熔断方法名 (){

  Return “服务正忙,稍后再试”;

}

 

 

消费者consumers引导类上注解好几个,可以使用组合注解

@SpringBootApplication
@EnablediscoveryClient//发现的客户端
@EnableCircuitBreaker//开启熔断器

可以用组合注解代替

@Spring CloudApplication

 

服务熔断:熔断器,断路器

可以弹性容错,情况好转之后,可以自动重连

先是拒绝所有后续请求,一段时间后,允许部分请求,调用成功则恢复,否则继续断开

熔断:

熔断器的三个状态:

1、闭合状态

2、打开状态:对请求计数,失败请求百分比达到阈值,触发熔断,认阈值50%,请求次数不低于20次

3、半开状态 open之后,休眠时间:5秒,进入半开,若请求都是健康的,关闭熔断器。否则继续休眠计时

 

可以修改参数:

出发熔断的最小次数认20、熔断失败的请求最小占比,50%、休眠时间,认5秒

 

流程:

1、每次调用创建hystrixcommand,依赖调用封装在run方法,执行execute同步或异步调用

2、调用是否缓存,缓存直接返回结果,没有缓存,判断熔断器是否打开

3、打开熔断器,getfallback降级逻辑

4、没打开熔断器,判断线程池/队列/信号量是否跑满,满了进入fallback降级逻辑

5、没跑满调用hystrixcommand的run方法,执行依赖逻辑,没有出现异常,继续,否则fallback降级,没有超时返回调用结果,超时进入fallback降级。

 

两种资源隔离方式

1、线程池隔离模式  线程池存储请求,处理请求,设置超时时间,为每一个线程申请线程池,消耗资源,可以应对突发洪流(处理不完,放入线程池慢慢处理)

2、信号量隔离模式  使用原子计数器/信号量 来记录当前多少个线程运行,请求到来先判断计数器数值,超过设置的最大线程个数,放弃新的请求,不超过,计数器+1,请求返回计数器-1,无法应对突发洪流

Feign

伪装,把rest请求进行隐藏,伪装成类似于springmvc的controller一样,不用拼接url、参数,一切交给feign

 

使用:

常见一个接口,在接口上加一些注解即可

Springcloud中feign支持springmvc注解,整合了Ribbon和eureka

 

1、引入依赖  openfeign

2、引导类上加注解 @EnableFeignClients  //启用feign组件

去掉

/*@Bean
@LoadBalanced//开启负载均衡
public RestTemplate restTemplate(){
    return new RestTemplate();

*/

不用再注入restemplate。去掉之前的hystrix的熔断代码

1、创建一个接口  xxxclient

2、加上注解@ FeignClient(“微服务的名称”)

3、接口中加上方法

4、注入接口到controller中  

 

有feign,关闭了Hystrix熔断,使用需要手动开启

Feign:

 Hystrix:

   Eanabled: true

 

Feign使用熔断

新建一个类xxxfallback 实现 xxxclient接口,实现熔断方法

接口的注解修改为:

@ FeignClient(value=“微服务的名称”,fallback=”xxxfallback ”)

 

把xxxfallback类上面加上 @Component  注入容器

 

Zuul网关

路由: 分发不同的微服务

负载均衡:同一个微服务的不同实例

 

保证对外服务的安全性,需要实现对外访问的权限控制,每个微服务都需要,破坏了restfulapi的无状态特点

无法直接服用既有接口

使用网关,所有请求都先经过zuul网关

具备服务路由,负载均衡,权限控制

核心:是一系列的过滤器

功能:身份认证与安全、审查与监控、动态路由、压力测试、静态响应处理、负载均衡、多区域弹性

 

创建zuul模块

配置文件

server:
  port: 10001
spring:
  application:
    name: wxb-zuul
zuul:
  routes:
    service-provider: #路由名称,随便起,习惯上写服务名
      path: /service-provider/**
      url: http://localhost:8080  #路由到 http://localhost:8080这个地址

 

启动类加注解 @EnableZuulProxy  //启用zuul组件

 

多个路径,负载均衡

需要把zuul注入到eureka中

1、添加eureka依赖

2、配置文件

加上eureka.client.service-url-defaultZone: http://localhost:100086/eureka

3、启用eureka  @EnablediscoveryClient

4、

server:
  port: 10001
spring:
  application:
    name: wxb-zuul
zuul:
  routes:

 service-provider: #路由名称,随便起,习惯上写服务名
      path: /service-provider/**

       ServiceId: service-provider


   

 

或者  常用

  routes:
     service-provider:  /service-provider/**   #可以随便改/user/**

     service-consumer: /consumer/**

 

或者不写,访问路径直接自己加上 localhost:10001service-provider/user/1  即可

 

还可以加  /api  区分是否请求经过网关  可以不要(专业性)

routes:
     service-provider:  /service-provider/**   #可以随便改/user/**

     service-consumer: /consumer/**

Prefix: /api

路径前面必须加/api才能访问

 

Zuul过滤器:请求拦截

流程:

请求--》pre  类型过滤器---》route filter--》post filters  ---响应

Pre、routing 出现异常的话---》error filter--post filter-》响应  error filter 本身异常,执行postfilter--响应

 

post filter 本身异常--》error filter--》响应

 

自定义

1、一个类loginFilter  继承 ZuulFilter 接口,重写四个方法  类上加@component 放入spring容器

public abstract String filterType();  return “pre”;
//执行顺序,返回值越小,执行顺序越高

public abstract int filterOrder();   return  10;

//是否执行该过滤器:true:执行

boolean shouldFilter();  return true;
//编写过滤器逻辑
Object run() throws ZuulException{

Return  null;//什么都不做

//初始化zuul网关的 上下文对象

Requestcontest con=Requestcontest.getCurrentContext();  

 

//获取对象

Request  rr=Con.getRequest();

//获取参数

String  ss=Rr.getParameter(“”)

Con.setSentZuulResponse(false)    //不转发请求

//设置状态码,401,身份未认证

Con.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED)

Con.setResponseBody(“request error”)  //设置响应提示

}

 

2、过滤器类型 : pre routing、post、error

 

声明式:直接装配  和 编程式

 

 

 

 

 

 

浏览器browser---》consumer-----》provider

Consumer、provider都去注册中心Eureka,provider可能调用别的provider、redisMysqL、elasticSearch等等   Consumer还可能调用别的provider

 

Eureka的时候 项目的返回从Json变为了Xml

SpringBoot项目中集成了EurekaServer,又需要jackson-dataformat-xml这个依赖 ,

可以将实体转换为xml也可以转换为json,根据发起请求的request头中Accept,application/xml在最后匹配json的*/ *前面,优先级高过json,所以返回了XML

解决:在请求的Mapping上加上produces = { “application/json;charset=UTF-8” }

 

Ribbon 客户端的负载均衡

Provider以集群的方式启动

增加端口号;1000\2000\3000 三个provider

1、Eclipse 直接修改配置文件的端口,main方法启动,在dashboerd看不到,

  或者启动一个端口之后 Run As--》run configurations--》选择项目--》new configuration---》

选择arguments标题栏,program arguments中输入 --server.port=需要的端口号即可

2、Idea 不修改配置文件,在edit configuration 中 点击 copy configuration

在environment 选项下面,program arguments中写: --server.port=需要的端口号即可

 

Feign:声明式远程调用

 

// 表示当前接口和一个provider对应,springboot-provider指定要调用的微服务名称
@FeignClient("springboot-provider")
public interface EmployeeRemoteService {

 

主启动类加注解@EnableFeignClients

 

400:参数类型不匹配,需要的参数没有传参,违反数据校验规则

Common和provider传参都需要加注解     

用来获取请求参数的注解@RequestParam @PathVariable @RequestBody不能省略,

简单类型

@RequestMapping("/provider/get/emp/list/remote")
List<Employee> getListRemote(@RequestParam("keyword") String keyword);

复杂类型:

@requestBody(Employee employee)

 

Hystrix:熔断、降级

微服务很多,多个调用一个微服务,被调用的微服务超时,都开始等待

一个问题蔓延至整个系统。

 

CAP

一致性+可用性+P:分区容错性(必须的) 一致性+可用性(保证一个

雪崩:某个服务出现故障,导致服务级联调用而引发雪崩

 

Provider的提供方案:

熔断:一段时间内侦测到多个类似错误,会强迫之后的多个调用快速失败,不在访问远程服务器,防止应用不断尝试,让程序继续执行,防止超时出现

 

使用ResultEntity作为返回值类型,成功失败返回同一个类型,result属性判断成功还是失败,失败:message   成功:data返回数据

 

Consumer的提供方案:

降级:防止用户一直等待,使用降级方式,调用FallBack(返回友好提示,不会去处理请求) 

              例如: 当前请求人数过多,请稍后重试

 

dubbo可以整合hystrix

 

<!--provider熔断-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

 

主启动类上面加注解:// 开启断路器功能 @EnableCircuitBreaker

// @HystrixCommand 指定当前方法出问题指定另一个备用方法
@HystrixCommand(fallbackMethod = "getEmpWithCircuitBreakerBackUp")
@RequestMapping(value = "/provider/get/emp/circuit/breaker",produces = { "ap

 

public ResultEntity<Employee> getEmpWithCircuitBreakerBackUp(@RequestParam("sinal") String sinal){

 

 

Consumer 客户端降级

1、实现consumer端 实现服务降级功能  

2、实现fallbackFactory接口时,要传入@FeignClient标记的接口类型
3、在create() 方法中返回@FeignClient标记的接口类型的对象,当provider调用失败
*               会执行这个对象的对应方法

 

public class MyFallBackFactory implements FallbackFactory<EmployeeRemoteService> {
    public EmployeeRemoteService create(final Throwable throwable) {

 

 

@FeignClient(value = "springboot-provider",fallbackFactory = MyFallBackFactory.class)
public interface EmployeeRemoteService {

 

feign:
  hystrix:
    enabled: true    # 开启降级

 

监控: provider

1、加入监控依赖  spring-boot-starter-actuator

 

2、配置application.yml

management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

 

3、创建监控工程

加入依赖

spring-cloud-starter-netflix-hystrix-dashboard

在主启动类上面加注解

// 启用仪表盘
@EnableHystrixDashboard

配置文件配置:

server:
  port: 8000
spring:
  application:
    name: springcloud-dashboard

监控访问地址:http://localhost:8000/hystrix

使用:

1、直接查看数据(provider)访问地址:localhost:1000/actuator/hystrix.stream    (1000是provider的端口号)  不方便,因为一直在监控,数据不断增加

2、第二种访问  http://localhost:8000/hystrix ,在页面输入localhost:1000/actuator/hystrix.stream   ,Delay设置毫秒,Title标题,使用认值即可

 

 

Zuul网关:提供给一个统一的入口

没有的话,直接访问provider,有网关的话

请求到达网关

 

1、客户端直接请求不同的微服务,增加复杂性

2、存在跨域请求www.a.com  www.b.com  浏览器跨域存在阻碍(出于安全考虑)

3、认证复杂,登陆问题:1、共享session 2、单点登录

4、难以重构,可能需要新的微服务

 

Zuul: 请求的路由  、 过滤

请求---》zuul----》请求特征---》微服务名称-----》Eureka---》具体的微服务

依赖:  spring-cloud-starter-netflix-eureka-client

spring-cloud-starter-netflix-zuul

配置文件

server:
  port: 9000

spring:
  application:
    name: springcloud-zuul
eureka:
  client:
    service-url:
      defaultZone: http://localhost:5000/eureka/

启动类:

// 开启zuul网关代理
@EnableZuulProxy

初步访问:服务名称最好小写,访问也要小写

http://localhost:9000/微服务名称/目标为服务具体功能地址

例如:http://localhost:9000/springcloud-feign-consumer/feign/consumer/test/fallback?signal=1

可以是自定义路由规则,代替微服务名称(不想暴露微服务名称

配置文件中配置:

zuul:
  routes:
    employee:
      service-id: springcloud-feign-consumer
      path: /my/**

此时通过:微服务名称

http://localhost:9000/springcloud-feign-consumer/feign/consumer/test/fallback?signal=1

和  路由

http://localhost:9000/my/feign/consumer/test/fallback?signal=1

都可以访问。

可以设置禁用服务名称访问

ignored-services:           # 禁用服务名称访问  ,忽略所有  ignored-services: '*'
  -  springcloud-feign-consumer

还可以在禁用的基础上增加前缀

ignored-services:  ‘*’       // 所有微服务都不可以通过名称访问

prefix: /bbb   

 

还可以

server:
  port: 9000
  servlet:
    context-path: /aaa         # 属于springboot 的application tomcat 访问之前加此路径

 

这是通过zuul访问的规则路径

 

还可以不通过zuul直接:http://localhost:7000/feign/consumer/test/fallback?signal=1  来访问

 

请求---》gateway(过滤器)-----》微服务

转发只允许在自己工程内部才可以

重定向可以访问新的资源

 

ZuulFilter

 

线程本地化技术  threadLocal

一个请求访问另一个请求:session域、application域等(横向)

一个线程内部:可以直接调用方法,通过传参;还可以通过threadlocal技术先set()  使用再 get()

 

springcloud要基于springboot开发

 

Springcloud分布式架构一站式解决方案,可以天然基于spring全家桶开发

dubbo 熔断降级需要hystrix

 

阿里的Nacos加入spring,官方推荐Nacos代替eureka作为注册中心

 

Idea项目工程导入eclipse

找到项目——复制,删除idea特征,留下maven特征(src+Pom.xml目录)通过eclipse的import --》maven  已存在的项目即可,最好把项目复制到工作区,maven导入的不会复制项目再工作区。

 

 

 

Seata   分布式事务解决方

全局的数据一致性问题

http://seata.io/zh-cn/    1+3

全局唯一的事务ID  transation ID  XID

三组件:

Transation Coordinator  TC   事务协调者  驱动全局事务的提交回滚

Transation Manager    TM   事务管理器  开始全局事务的提交回滚

Resource  Manager    RM  资源管理器  管理分支事务,驱动分支事务提交回滚

 

1、TM向TC申请开启一个全局事务@GlobalTransactional,创建成功并生成一个全局唯一XID

2、XID在微服务调用的上下文中传播

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

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

5、TC调度XID下辖的全部分支事务完成提交或回滚

 

下载网址:https://github.com/seata/seata/releases

使用:本地@Transational  全局@GlobalTransational

 

下载使用1.1.0版本

1、备份file.conf配置文件

2、修改自定义事务组名称+事务存储模式为DB+数据库连接信息

3、修改service模块和store模块

 

 

先启动nacos-server.cmd

再启动seata-server.bat

三个微服务:订单==库存==账户

用户下单==》创建一个订单==》远程调用库存服务扣减库存==》远程调用账户扣减余额==》订单状态修改成已完成。

跨越三个数据库,两次远程调用,必然存在分布式事务问题

 

 

@GlobalTransactional

没有加注解,超时超时之后,出现超时异常,库存减少,钱减少,但是订单显示未完成。

Feign有超时重试机制,可能多次扣减。

 

@GlobalTransactional(name = "wxb-create-order",rollbackFor = Exception.class)

异常:统统回滚   异常之后,没有插入写操作

 

Seata原理

Tc:seata服务器

Tm:@GlobalTransactional 事务发起者

Rm:一个数据库就是一个rm  事务的参与方

 

认AT模式:无侵入自动补偿,阿里云 GTS

TCC模式:可与AT混用,更灵活

SAGA模式:长事务,每个参与者都提交本地事务。无锁,高性能,不保证隔离性

XA模式(开发中)

 

一阶段

Seata拦截业务sql,,业务更新前,before images  前置镜像

执行业务sql,更新业务数据

更新之后,after images 后置镜像 生成行锁(locK_table表)

所有操作再一个数据库事务完成

二阶段

顺利,seata把一阶段的的快照数据和行锁删除,解锁,清理数据

异常:二阶段回滚,回滚一阶段已经执行的业务sql,反向补偿,before images 还原数据,之前还需要校验脏写,如果有,转人工处理。还原之后,删除before images、after images   和行锁   删除un_log 表数据

 

 

 

Cap理论

不能同时满足c、a、p(必须保证)

一致性:强一致性,每次读写返回的值都是最新的,结果一致。

可用性:发出请求总能得到数据,不一定是最新数据

分区容错性:分布式系统,不同的节点,遇到分区故障,可以满足一致性和可用性,不能同步,但是也可以容忍。除非网络全部故障。

CA:放弃分区容错,一个整体应用,不是分布式,单体架构

CP:放弃可用性,保证一致性  例如 zookeeper,redis

AP:保证可用性  例如eureka,淘宝,最终一致性。

 

强一致性:复制是同步的

弱一致性:复制是异步的,即使过了不一致时间窗口期,读取的也不一定是最新值,存在问题。12306买票

 

最终一致性:弱一致性的特殊形式,没有更新的条件,最终访问的是最后的值。

随着时间推移,数据最终一致。

 

一般采用ap  保证可用性,采用最终一致性。

 

Base理论

BA:基本可用  和高可用的区别:基本可用(故障时)可以适当延长响应时间。

S:柔性状态  数据存在中间状态,同步中,正在同步。

E:最终一致性  一段时间后,数据必须一致。

 

分布式事务协议

二阶段提交2PC 常用方案    协调者一个 和  参与者 多个

1、准备阶段  投票阶段  可以不可以提交,记录日志,没有提交事务  ,同意/终止

2、提交阶段  所有参与者返回同意,发出commit请求,发送ack 完成,协调者收到所有的ack,完成事务。如果返回消息是 终止,或者超时未返回,撤销事务,告诉所有的参与者根据一阶段日志 ,回滚事务。无论成功与否,事务在二阶段都会完成。

优点:数据强一致性。

缺点:事务节点都是阻塞型  底层是锁 占用资源   需要补充超时机制,否则失联会一直阻塞。数据一致性问题,协调者或者某个参与者宕机,协调者发出消息,但是唯一接收消息的参与者宕机,即使再选举出新的协调者,事务的状态不确定。

 

三阶段提交 3PC  二阶段的改进

引入超时机制、插入准备阶段,保证提交之前各个节点状态一致。

多了先询问能不能操作执行,再执行事务,不提交,反馈之后再提交。

1、cancommit  询问  返回yes/no    no/超时  直接中断事务。

2、Precommit  协调者根据参与者反馈进行操作  事务预提交,执行事务操作,但不提交事务,记录事务日志。返回ack,等待最终指令。

3、执行提交。二阶段  失败 (no/超时)中断事务  协调者撤销请求,回滚。

 

缺点:第三阶段:超时之后,会继续事务提交,造成数据不一致。

 

 

分布式方案:

1、TCC

2、全局消息

3、分布式事务 seata

 

TCC  事务补偿机制  二阶段提交(强一致性)

byteTcc(停止更新)

Try尝试    锁定资源

confirm确认  执行业务,释放锁

Cancel 取消  出问题,释放锁

 

库存、订单

一、Try:库存100,要购买2   先检查库存是否足够,冻结购买的库存2,创建订单,状态为待确认。

二、Confirm/cancle:根据try的服务是否正常 ,执行confirm或cancel,如果执行confirm或cancel失败,会一直重试。(保证了数据的强一致性)并发性一般。

 

存在性能瓶颈、业务耦合度较高,增加开发成本

数据最终一致性(基于confirm和cancle幂等性)

可靠性:集群解决单点故障

 

Seata  at模式和tcc模式

AT模式:基于本地ACID事务的关系型数据库

TCC模式:不依赖底层数据库数据库日志表、成功批量清理回滚日志、失败自动补偿,数据回滚。

自定义的prepare、commit、rollback逻辑

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐