分布式架构(分布式ID+分布式事务)

分布式架构

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

=====================

分布式事务产生的场景:

跨JVM进程产生的分布式事务
在这里插入图片描述
单体系统访问多个数据库实例
在这里插入图片描述
多服务访问同一个数据库实例
在这里插入图片描述

CAP理论

在这里插入图片描述

C:一致性,指写操作后的读操作可以读取到最新的数据状态,当数据分布在多个节点上,从任意节点读取到的数据都是最新状态。
写入主数据库后要将数据同步到从数据库
写入主数据库后,在向从数据库同步期间要将从数据库锁定,待同步完成后再释放锁,以免在新数据写入成功后,向从数据库查询到旧的数据

A:可用性,指任何事务操作都可以得到响应结果,且不会出现响应超时或响应错误。
写入主数据库后要将数据同步到从数据库
由于要保证从数据库的可用性,不可将从数据库中的资源进行锁定
即使数据还没有同步过来,从数据库也要返回要查询的数据,哪怕是旧数据,如果连旧数据也没有则可以按照约定返回一个默认的信息,但不能返回错误或响应超时。

P:分区容忍性,网络分区的不同结点出现的网络问题导致节点之间通信失败,此时仍然可以对外提供服务。
尽量使用异步取代同步操作,使用异步方式将数据从主数据库同步到从数据库,这样节点之间能够有效的实现松耦合
添加从数据库节点,其中一个节点挂掉后,其他从节点提供服务。

CAP组合
在这里插入图片描述

Base理论

在这里插入图片描述

========================================

分布式事务解决方案

2PC 两阶段提交
在这里插入图片描述
在这里插入图片描述

XA方案
需要本地数据库支持XA协议
资源锁需要等到两个阶段结束才释放,性能较差
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Seata方案
阿里中间件,分布式事务框架
提供AT模式(2PC)以及TCC模式的分布式事务解决方案
把分布式事务理解为一个包含了若干分支事务的全局事务,全局事务的职责是协调其下管辖的分支事务达成一致
要么一起成功提交,要么一起失败回滚。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
程序实现
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
配置文件
application.yml
application-local.yml
file.conf

dtx-seata-demo-bank1
张三账户减少金额,开启全局事务
远程调用bank2向李四转账

//Dao   MyBatis框架进行
@Mapper
@Component
public interface AccountInfoDao{
	@Update("update account_info set account_blance = account_balance + #{amount} where account_no = #{accountNo}")
	int updateAccountBalnce(@Param("accountNo") String accountNo,@Param("amount") Double amount);
}
//张三扣减金额
public interface AccountInfoService{
	public void updateAccountBalance(String accountNo,Double amount);
}
@Service
@Slf4j
public class AccountInfoServiceImpl implements AccountInfoService{
	@Autowired
	AccountInfoDao accountInfoDao;

	@Autowired
	Bank2Client bank2Client;
	
	@Transactional
	@BlobalTransactional//开启全局事务
	@Override
	public void updateAccountBalance(String accountNo,Double amount{
		//扣除张三的金额
		accountInfoDao.updateAccountBalance(accountNo,amount * -1);
		
		//调用李四的微服务来转账
		String transfer = bank2Client.transfer(amount);
		if("fallback".equals(transfer)){
			//调用李四微服务异常
			throw new RuntimeException("调用李四微服务异常");
		}
	}
}
//FeignClient
@FeignClient(value="seata-demo-bank2",fallback=Bank2ClientFallack.class)//如果调用失败,降级
public interface Bank2Client{
	
	//远程调用李四的微服务
	@GetMapping("/bank2/transfer")
	public String transfer(@RequestParam("amount") Double amout);
}
//调用失败降级
@Component
public class Bank2ClientFallback implements Bank2Client{
	@Override
	public String transfer(Double amount){
		return "fallback";
	}
}
//启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
@EnableFeignClients(basePackages = {"cn.michael.bank1.spring"})//专门扫描客户端的包
public class Bank2Server{
	public static void main(String[] args){
		SpringApplication.run(Bank2Server.class,args);
	}
}

dtx-seata-demo-bank2

//李四账号增加金额
//分支事务,不适用@GlobalTransactional
@Mapper
@Component
public interface AccountInfoDao{
	@Update("UPDATE account_info SET account_balance = account_balance + #{amount} WHERE account_no")
	int updateAccountBalance(@Param("accountNo") String accountNo,@Param("amount") Double amount);
}
public interface AccountInfoService{
	public void updateAccountBalance(String accountNo,Double amount);
}
@Service
@Slf4j
public class AccountInfoServiceImpl implements AccountInfoService{
	@Autowired
	AccountInfoDao accountInfoDao;

	//不使用@GlobalTransactional
	@Transactional
	@Override
	public void updateAccountBalance(String accountNo,Double amount){
		accountaInfoDao.updateAccountBalance(accountNo,amount);
	}
} 

=========================================

分布式ID

在这里插入图片描述
在这里插入图片描述

一、数据库自增

①、创建一个数据库表

stub 字段无意义,只是为了占位,便于插入或者修改数据。并且,给 stub 字段创建了唯一索引,保证其唯一性。

CREATE TABLE `sequence_id` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `stub` char(10) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `stub` (`stub`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

②、通过replace into 来插入数据

插入数据这里,没有使用 insert into 而是使用 replace into 来插入数据,具体步骤是这样的:

  1. 尝试把数据插入到表中
  2. 如果主键或唯一索引字段出现重复数据错误而插入失败时,先从表中删除含有重复关键字值的冲突行,然后再次尝试把数据插入到表中
BEGIN;
REPLACE INTO sequence_id (stub) VALUES ('stub');
SELECT LAST_INSERT_ID();
COMMIT;

优点:实现起来比较简单、ID 有序递增、存储消耗空间小
缺点:支持的并发量不大、存在数据库单点问题(可以使用数据库集群解决,不过增加了复杂度)、ID 没有具体业务含义、安全问题(比如根据订单 ID 的递增规律就能推算出每天的订单量,商业机密啊!)、每次获取 ID 都要访问一次数据库(增加了对数据库的压力,获取速度也慢)

二、数据库号段模式

数据库主键自增这种模式,每次获取 ID 都要访问一次数据库,ID 需求比较大的时候性能问题

可以批量获取,然后存在在内存里面,需要用到的时候,直接从内存里面拿就舒服了!这也就是我们说的 基于数据库的号段模式来生成分布式 ID
数据库的号段模式也是目前比较主流的一种分布式 ID 生成方式。像滴滴开源的Tinyid[1] 就是基于这种方式来做的。不过,TinyId 使用了双号段缓存、增加多 db 支持等方式来进一步优化。

①、创建一个数据表

current_max_id 字段和step字段主要用于获取批量 ID,获取的批量 id 为:current_max_id ~ current_max_id+step
version 字段主要用于解决并发问题(乐观锁),biz_type 主要用于表示业务类型。

CREATE TABLE `sequence_id_generator` (
  `id` int(10) NOT NULL,
  `current_max_id` bigint(20) NOT NULL COMMENT '当前最大id',
  `step` int(10) NOT NULL COMMENT '号段的长度',
  `version` int(20) NOT NULL COMMENT '版本号',
  `biz_type`    int(20) NOT NULL COMMENT '业务类型',
   PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

②、先插入一行数据

INSERT INTO `sequence_id_generator` (`id`, `current_max_id`, `step`, `version`, `biz_type`)
VALUES
 (1, 0, 100, 0, 101);

③、通过 SELECT 获取指定业务下的批量唯一 ID

SELECT `current_max_id`, `step`,`version` FROM `sequence_id_generator` where `biz_type` = 101

在这里插入图片描述
④、不够用的话,更新之后重新 SELECT 即可。

UPDATE sequence_id_generator SET current_max_id = 0+100, version=version+1 WHERE version = 0  AND `biz_type` = 101
SELECT `current_max_id`, `step`,`version` FROM `sequence_id_generator` where `biz_type` = 101

在这里插入图片描述
相比于数据库主键自增的方式,数据库的号段模式对于数据库的访问次数更少,数据库压力更小。
另外,为了避免单点问题,你可以从使用主从模式来提高可用性。

优点:ID 有序递增、存储消耗空间小
缺点:存在数据库单点问题(可以使用数据库集群解决,不过增加了复杂度)、ID 没有具体业务含义、安全问题(比如根据订单 ID 的递增规律就能推算出每天的订单量,商业机密啊!)

三、NoSQL

通过 Redis 的 incr 命令即可实现对 id 原子顺序递增
在这里插入图片描述

为了提高可用性和并发,可以使用 Redis Cluster。Redis Cluster 是 Redis 官方提供的 Redis 集群解决方案(3.0+版本)。

除了 Redis Cluster 之外,也可以使用开源的 Redis 集群方案Codis[2] (大规模集群比如上百个节点的时候比较推荐)。

除了高可用和并发之外, Redis 基于内存,我们需要持久化数据,避免重启机器或者机器故障后数据丢失。Redis 支持两种不同的持久化方式:快照(snapshotting,RDB)、只追加文件(append-only file, AOF)。并且,Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 aof-use-rdb-preamble 开启)。

优点:性能不错并且生成的 ID 是有序递增的
缺点:和数据库主键自增方案的缺点类似

除了 Redis 之外,MongoDB ObjectId 经常也会被拿来当做分布式 ID 的解决方案。
在这里插入图片描述
MongoDB ObjectId 一共需要 12 个字节存储:

  • 0~3:时间戳
  • 3~6:代表机器 ID
  • 7~8:机器进程 ID
  • 9~11:自增值

优点:性能不错并且生成的 ID 是有序递增的
缺点:需要解决重复 ID 问题(当机器时间不对的情况下,可能导致会产生重复 ID)、有安全性问题(ID 生成有规律性)

四、算法UUID

UUID 是 Universally Unique Identifier(通用唯一标识符) 的缩写。UUID 包含 32 个 16 进制数字(8-4-4-4-12)

JDK 就提供了现成的生成 UUID 的方法,一行代码就行了。

//输出示例:cb4a9ede-fa5e-4585-b9bb-d60bce986eaa
UUID.randomUUID()

不同的版本对应的 UUID 的生成规则是不同的

  • 版本 1 : UUID 是根据时间和节点 ID(通常是 MAC 地址)生成
  • 版本 2 : UUID 是根据标识符(通常是组或用户 ID)、时间和节点 ID 生成
  • 版本 3、版本 5 : 版本 5 - 确定性 UUID 通过散列(hashing)名字空间(namespace)标识符和名称生成
  • 版本 4 : UUID 使用随机性或伪随机性生成
    在这里插入图片描述
    JDK 中通过 UUID 的 randomUUID() 方法生成的 UUID 的版本默认为 4
UUID uuid = UUID.randomUUID();
int version = uuid.version();// 4

UUID 可以保证唯一性,因为其生成规则包括 MAC 地址、时间戳、名字空间(Namespace)、随机或伪随机数、时序等元素,计算机基于这些规则生成的 UUID 是肯定不会重复的。

虽然,UUID 可以做到全局唯一性,但是,我们一般很少会使用它。比如使用 UUID 作为 MySQL 数据库主键的时候就非常不合适:

  • 数据库主键要尽量越短越好,而 UUID 的消耗的存储空间比较大(32 个字符串,128 位)
  • UUID 是无顺序的,InnoDB 引擎下,数据库主键的无序性会严重影响数据库性能

优点:生成速度比较快、简单易用
缺点:存储消耗空间大(32 个字符串,128 位)、 不安全(基于 MAC 地址生成 UUID 的算法会造成 MAC 地址泄露)、无序(非自增)、没有具体业务含义、需要解决重复 ID 问题(当机器时间不对的情况下,可能导致会产生重复 ID)

五、算法雪花

Snowflake 是 Twitter 开源的分布式 ID 生成算法。Snowflake 由 64 bit 的二进制数字组成,这 64bit 的二进制被分成了几部分,每一部分存储的数据都有特定的含义:
在这里插入图片描述

  • sign(1bit):符号位(标识正负),始终为 0,代表生成的 ID 为正数
  • timestamp (41 bits):一共 41 位,用来表示时间戳,单位是毫秒,可以支撑 2 ^41 毫秒(约 69 年)
  • datacenter id + worker id (10 bits):一般来说,前 5 位表示机房 ID,后 5 位表示机器 ID(实际项目中可以根据实际情况调整)。这样就可以区分不同集群/机房的节点。
  • sequence (12 bits):一共 12 位,用来表示序列号。序列号为自增值,代表单台机器每毫秒能够产生的最大 ID 数(2^12 = 4096),也就是说单台机器每毫秒最多可以生成 4096 个 唯一 ID。

在实际项目中,一般也会对 Snowflake 算法进行改造,最常见的就是在 Snowflake 算法生成的 ID 中加入业务类型信息。

优点:生成速度比较快、生成的 ID 有序递增、比较灵活(可以对 Snowflake 算法进行简单的改造比如加入业务 ID)
缺点:需要解决重复 ID 问题(ID 生成依赖时间,在获取时间的时候,可能会出现时间回拨的问题,也就是服务器上的时间突然倒退到之前的时间,进而导致会产生重复 ID)、依赖机器 ID 对分布式环境不友好(当需要自动启停或增减机器时,固定的机器 ID 可能不够灵活)。

有很多基于 Snowflake 算法的开源实现比如美团 的 Leaf、百度的 UidGenerator(后面会提到),并且这些开源实现对原有的 Snowflake 算法进行了优化,性能更优秀,还解决了 Snowflake 算法的时间回拨问题和依赖机器 ID 的问题。

并且,Seata 还提出了“改良版雪花算法”,针对原版雪花算法进行了一定的优化改良,解决了时间回拨问题,大幅提高的 QPS。

分布式ID开源框架(百度、滴滴等)

=========================================

分布式 事务解决方案TCC

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
TCC需要主义三种异常处理:空回滚 幂等 悬挂
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

启动类

@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
@EnableAspectAutoProxy //
@EnableFeignClients(basePackages = {"cn.....spring"})
@ComponentScan("xxx.bank1/bank2","org.dromarn.hmily")//要扫描的hmily
public class BankTccServer{
	public static void main(String[] args){
		StringApplication.run(BankTccServer.class,args);
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/409696.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】C++对C语言的关系,拓展及命名空间的使用

文章目录 📝C简述C融合了3种不同的编程方式:C和C语言关系是啥呢?C标准 🌠C应用🌠C语言优点第一个C程序 🌠命名空间🌠命名空间的使用命名空间的定义 🌠怎么使用命名空间中的内容呢&am…

《Docker 简易速速上手小册》第5章 Docker Compose 与服务编排(2024 最新版)

文章目录 5.1 理解 Docker Compose5.1.1 重点基础知识5.1.2 重点案例:部署 Flask 应用和 Redis5.1.3 拓展案例 1:多服务协作5.1.4 拓展案例 2:使用自定义网络 5.2 编排多容器应用5.2.1 重点基础知识5.2.2 重点案例:部署 Flask 应用…

ARMv8-AArch64 的异常处理模型详解之异常处理详解(同步异常和异步异常的分析和处理)

这里写目录标题 一,同步异常的分析1.1 同步异常分析-异常链接寄存器ELR1.2 同步异常分析-异常综合寄存器ESR,Exception Syndrome Register1.3 同步异常分析-错误地址寄存器FAR,Fault Address Register 二, 同步异常的处理示例 Synchronous ex…

wsl添加swap

机器的内存比较少,用wsl 写代码和编译的时候,发现内存不怎么够, 系统的可以分配的内存也不怎么够,需要增加点swap 来解决问题 方法比较简单,配置下.wslconfig 文件,添加下swap 就能解决这个问题 配置文件添…

JAVA的日志技术【详解】

1.使用日志技术的好处 可以将系统执行的信息,方便的记录到指定的位置(控制台、文件中、数据库中)。 可以随时以开关的形式控制日志的启停,无需侵入到源代码中去进行修改。 2.日志技术的体系结构 3.Logback日志框架 logback-co…

第二节:Vben Admin 登录逻辑梳理和对接后端准备

系列文章目录 上一节:第一节:Vben Admin介绍和初次运行 文章目录 系列文章目录前言项目路径的概述一、登录逻辑梳理loginApi接口查看Mock 二、后端程序对接准备关闭Mock 总结 前言 第一节,我们已经配置了前端环境,运行起来了我们…

zabbix监控业务数据

前言 监控系统除了监控os和数据库性能相关的指标外,业务数据也是重点监控的对象。 一线驻场的运维同学应该深有体会,每天需要向甲方或者公司反馈现场的数据情况,正常情况下一天巡检两次,早上上班后和下午下班前各一次。监控项目…

探索水下低光照图像检测性能,基于YOLOv6全系列【n/s/m/l】参数模型开发构建海底生物检测识别分析系统

底这类特殊数据场景下的检测模型开发相对来说比较少,在前面的博文中也有一些涉及,感兴趣的话可以自行移步阅读即可: 试探索水下目标检测,基于yolov5轻量级系列模型n/s/m开发构建海底生物检测系统》 《基于YOLOv5C3CBAMCBAM注意力…

人工智能在测绘行业的应用与挑战

目录 一、背景 二、AI在测绘行业的应用方向 1. 自动化特征提取 2. 数据处理与分析 3. 无人机测绘 4. 智能导航与路径规划 5. 三维建模与可视化 6. 地理信息系统(GIS)智能化 三、发展前景 1. 技术融合 2. 精准测绘 3. 智慧城市建设 4. 可…

【Java程序员面试专栏 算法思维】一 高频面试算法题:排序算法

一轮的算法训练完成后,对相关的题目有了一个初步理解了,接下来进行专题训练,以下这些题目就是汇总的高频题目,本篇主要聊聊排序算法,包括手撕排序算法,经典的TOPK问题以及区间合并,所以放到一篇Blog中集中练习 题目关键字解题思路时间空间快速排序双指针+递归+基准值分…

2024年上半年第一次课

文章目录 一、加入课程QQ群(一)加入QQ群(二)加群要求 二、加入超星学习通(一)安装超星学习通(二)利用学习通签到(三)查看课程内容(四)…

算法分析-面试1-字符串

文章目录 前言一、分类:看看就行了二、字符串API:创建和初始化:查询操作:比较操作:修改操作:截取操作:分割操作:格式化操作:连接操作(Java 8 及以后&#xff…

静态时序分析:SDC约束命令set_load详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 set_load命令用于指定端口(port)或线网(net)的负载电容,该指令的BNF范式(有关BNF范式,可以参考以往文章)为&#…

JAVA毕业设计129—基于Java+Springboot+thymeleaf的物业管理系统(源代码+数据库)

毕设所有选题: https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootthymeleaf的物业管理系统(源代码数据库)129 一、系统介绍 本项目前后端分离,本系统分为管理员、小区管理员、用户三种角色 1、用户: 登…

基于Pytorch的猫狗图片分类【深度学习CNN】

猫狗分类来源于Kaggle上的一个入门竞赛——Dogs vs Cats。为了加深对CNN的理解,基于Pytorch复现了LeNet,AlexNet,ResNet等经典CNN模型,源代码放在GitHub上,地址传送点击此处。项目大纲如下: 文章目录 一、问题描述二、数据集处理…

【GPTs分享】GPTs分享之Write For Me

Write For Me 是一个专门定制的GPT版本,旨在为用户提供高质量的文本内容创作服务。它适用于各种写作需求,从商业计划、学术文章到创意故事等。下面是从简介、主要功能、使用案例、优点和局限性几个方面对Write For Me 的详细介绍。 简介 Write For Me …

MySQL-主从复制

目录 1. 主从复制概述 1.1 如何提升数据库并发能力 1.2 主从复制的作用 2. 主从复制的原理 2.1 原理剖析 三个线程 复制三步骤 复制的问题 2.2 复制的基本原则 3. 一主一从架构搭建 3.1 准备工作 3.2 主机配置文件 3.3 从机配置文件 3.4 主机:建立账户…

每日五道java面试题之spring篇(六)

目录: 第一题 ApplicationContext通常的实现是什么?第二题 什么是Spring的依赖注入?第三题 依赖注入的基本原则第四题 依赖注入有什么优势?第五题 有哪些不同类型的依赖注入实现方式? 第一题 ApplicationContext通常的…

【hashmap】【将排序之后的字符串作为哈希表的键】【获取 HashMap 中所有值的集合】Leetcode 49 字母异位词分组

【hashmap】【将排序之后的字符串作为哈希表的键】【获取 HashMap 中所有值的集合】Leetcode 49 字母异位词分组 解法1 将排序之后的字符串作为哈希表的键解法2 在解法一的基础上加入了getOrDefault ---------------🎈🎈题目链接🎈&#x1f3…

groovy:XmlParser 读 Freeplane.mm文件,生成测试案例.csv文件

Freeplane 是一款基于 Java 的开源软件,继承 Freemind 的思维导图工具软件,它扩展了知识管理功能,在 Freemind 上增加了一些额外的功能,比如数学公式、节点属性面板等。 强大的节点功能,不仅仅节点的种类很多&#xff…