花2万块买的教程!java编程入门到精通

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 花2万块买的教程!java编程入门到精通

背景知识

CAP定理

CAP定理,又被叫作布鲁尔定理。对于设计分布式系统来说(不仅仅是分布式事务)的架构师来说,CAP就是你的入门理论。

• C (一致性):对某个指定的客户端来说,读操作能返回最新的写操作。对于数据分布在不同节点上的数据上来说,如果在某个节点更新了数据,那么在其他节点如果都能读取到这个最新的数据,那么就称为强一致,如果有某个节点没有读取到,那就是分布式不一致。

• A (可用性):非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。可用性的两个关键一个是合理的时间,一个是合理的响应。合理的时间指的是请求不能无限被阻塞,应该在合理的时间给出返回。合理的响应指的是系统应该明确返回结果并且结果是正确的,这里的正确指的是比如应该返回50,而不是返回40。

• P (分区容错性):当出现网络分区后,系统能够继续工作。打个比方,这里个集群有多台机器,有台机器网络出现了问题,但是这个集群仍然可以正常工作。

BASE理论

BASE 理论指的是基本可用 Basically Available,软状态 Soft State,最终一致性 Eventual Consistency,核心思想是即便无法做到强一致性,但应该采用适合的方式保证最终一致性,是对CAP中AP的一个扩展。

BASE,Basically Available Soft State Eventual Consistency 的简写:

BA:Basically Available 基本可用,分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用。

S:Soft State 软状态,允许系统存在中间状态,而该中间状态不会影响系统整体可用性。

E:Consistency 最终一致性,系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。

BASE 理论本质上是对 CAP 理论的延伸,是对 CAP 中 AP 方案的一个补充。

柔性事务

不同于 ACID 的刚性事务,在分布式场景下基于 BASE 理论,就出现了柔性事务的概念。要想通过柔性事务来达到最终的一致性,就需要依赖于一些特性,这些特性在具体的方案中不一定都要满足,因为不同的方案要求不一样;但是都不满足的话,是不可能做柔性事务的。

幂等操作

在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,支付流程中第三方支付系统告知系统中某个订单支付成功,接收该支付回调接口在网络正常的情况下无论操作多少次都应该返回成功。

为什么需要分布式事务

随着业务的发展及服务的SOA化,一些大的操作往往由不同的小操作组成,而这些小的操作分布在不同的服务器上,分布式事务需要保证这些小操作要么全部成功,要么全部失败。从本质上来说,分布式事务是为了保证不同数据库的数据一致性。可能应用分布式事务的场景有:

  1. 数据库分库分表

当数据库单表数据达到千万级别,就要考虑分库分表,那么就会从原来的一个数据库变成多个数据库。例如如果一个操作即操作了01库,又操作了02库,而且又要保证数据的一致性,那么就要用到分布式事务。

  1. 应用SOA化

所谓的SOA化,就是业务的服务化。例如电商平台下单操作就会产生调用库存服务扣减库存和订单服务更新订单数据,那么就会设计到订单数据库和库存数据库,为了保证数据的一致性,就需要用到分布式事务。

两套协议、四类常见方案

两套协议是指两阶段提交协议2PC和三阶段提交协议3PC

四类常见方案这里我们介绍以下分布式事务解决方案:Tcc、可靠消息最终一致性、最大努力通知、Saga

两套协议

两阶段提交协议2PC

两阶段提交(2PC) 是 Oracle Tuxedo 系统提出的 XA 分布式事务协议的其中一种实现方式。

XA协议中有两个重要角色:事务协调者事务参与者

漫话图解

2PC协议有两个阶段:Propose和Commit. 在无failure情况下的2PC协议流程的画风是这样的:

• Propose阶段:

○ coordinator: “昨夜验人有惊喜, 今天都投票出六娃”

○ voter1/voter2/voter3: “好的女王大人!”

• Commit阶段

○ coordinator: “投六娃”

○ voter1/voter2/voter3: “投了女王大人!” (画外音: 六娃扑街)

图1: 2PC, coordinator提议通过, voter{1,2,3}达成新的共识

如果有至少一个voter (比如voter3)在Propose阶段投了反对票, 那么propose通过失败. coordinator就会在Commit(or abort)阶段跟所有voter说, 放弃这个propose.

图2: 2PC, coordinator提议没有通过, voter{1,2,3}保持旧有的共识

具体流程

分布式事务中2PC的具体流程是这样的:

第一阶段

• 顺利的情况

  1. 事务协调者的节点会首先向所有的参与者节点发送 Prepare(预备) 请求。
  2. 在接到 Prepare(预备) 请求之后,每一个参与者节点会各自执行与事务有关的数据更新,写入Undo Log和Redo Log。
  3. 参与者执行成功,暂时不提交事务,向事务协调节点返回done(完成)消息。
  4. 进入第二阶段

• 出错时

在XA的第一阶段,如果某个事务参与者反馈失败消息,说明该节点的本地事务执行不成功,必须回滚。

  1. 事务协调者的节点会首先向所有的参与者节点发送 Prepare(预备) 请求。
  2. 在接到 Prepare(预备) 请求之后,每一个参与者节点会各自执行与事务有关的数据更新,写入Undo Log和Redo Log。
  3. 参与者执行失败,返回失败消息。
  4. 协调者中断事务

中断事务

任何一个参与者向协调者反馈了 No 响应,或者在等待超时之后,协调者尚无法接收到所有参与者的反馈响应,那么就会中断事物。

  1. 发送回滚请求。协调者向所有参与者节点发出 Rollback 请求。
  2. 事物回滚。参与者收到Rollback请求之后,会利用其在阶段一种记录的 Undo 信息来执行事务回滚操作,并在完成回滚之后释放在整个事物执行期间占用的资源。
  3. 反馈事物回滚结果。参与者在完成事物回滚之后,向协调者发送 Ack 消息。
  4. 中断事务

第二阶段

在XA分布式事务的第二阶段,如果事务协调节点在之前所收到都是正向返回,那么它将会向所有事务参与者发出Commit请求。

接到Commit请求之后,事务参与者节点会各自进行本地的事务提交,并释放锁资源。当本地事务完成提交后,将会向事务协调者返回“完成”消息。

当事务协调者接收到所有事务参与者的“完成”反馈,整个分布式事务完成。

优缺点

优点

2PC是强一致(要打个问号)协议:

  1. 预备、提交两个阶段保证了事务是原子的
  2. 2PC是允许读-写隔离的,这意味着某个字段的变更在事务协调者提交之前是不可见的。

缺点

  1. 同步阻塞:当参与事务者存在占用公共资源的情况,其中一个占用了资源,其他事务参与者就只能阻塞等待资源释放,处于阻塞状态。
  2. 单点故障:一旦事务管理器出现故障,整个系统不可用
  3. 数据不一致:在阶段二,如果事务管理器只发送了部分 commit 消息,此时网络发生异常,那么只有部分参与者接收到 commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。
  4. 不确定性:当协事务管理器发送 commit 之后,并且此时只有一个参与者收到了 commit,那么当该参与者与事务管理器同时宕机之后,重新选举的事务管理器无法确定该条消息是否提交成功。

三阶段提交协议3PC

漫话图解

简单的说来, 3PC就是把2PC的Commit阶段拆成了PreCommit和Commit两个阶段. 通过进入增加的这一个PreCommit阶段, voter可以得到Propose阶段的投票结果, 但不会commit; 而通过进入Commit阶段, voter可以盘出其他每个voter也都打算commit了, 从而可以放心的commit.

换言之, 3PC在2PC的Commit阶段里增加了一个barrier(即相当于告诉其他所有voter, 我收到了Propose的结果啦). 在这个barrier之前coordinator掉线的话, 其他voter可以得出结论不是每个voter都收到Propose Phase的结果, 从而放弃或选出新的coordinator; 在这个barrier之后coordinator掉线的话, 每个voter会放心的commit, 因为他们知道其他voter也都做同样的计划.

图3: 3PC, coordinator提议通过, voter{1,2,3}达成新的共识

具体流程

阶段一CanCommit

  1. 事务询问:Coordinator 向各参与者发送 CanCommit 的请求,询问是否可以执行事务提交操作,并开始等待各参与者的响应;
  2. 参与者向 Coordinator 反馈询问的响应:参与者收到 CanCommit 请求后,正常情况下,如果自身认为可以顺利执行事务,那么会反馈 Yes 响应,并进入预备状态,否则反馈 No。

阶段二PreCommit

执行事务预提交:如果 Coordinator 接收到各参与者反馈都是Yes,那么执行事务预提交:

  1. 发送预提交请求:Coordinator 向各参与者发送 preCommit 请求,并进入 prepared 阶段;
  2. 事务预提交:参与者接收到 preCommit 请求后,会执行事务操作,并将 Undo 和 Redo 信息记录到事务日记中;
  3. 各参与者向 Coordinator 反馈事务执行的响应:如果各参与者都成功执行了事务操作,那么反馈给协调者 ACK 响应,同时等待最终指令,提交 commit 或者终止 abort,结束流程;

中断事务:如果任何一个参与者向 Coordinator 反馈了 No 响应,或者在等待超时后,Coordinator 无法接收到所有参与者的反馈,那么就会中断事务。

  1. 发送中断请求:Coordinator 向所有参与者发送 abort 请求;
  2. 中断事务:无论是收到来自 Coordinator 的 abort 请求,还是等待超时,参与者都中断事务。

阶段三doCommit

执行提交

  1. 发送提交请求:假设 Coordinator 正常工作,接收到了所有参与者的 ack 响应,那么它将从预提交阶段进入提交状态,并向所有参与者发送 doCommit 请求;
  2. 事务提交:参与者收到 doCommit 请求后,正式提交事务,并在完成事务提交后释放占用的资源;
  3. 反馈事务提交结果:参与者完成事务提交后,向 Coordinator 发送 ACK 信息;
  4. 完成事务:Coordinator 接收到所有参与者 ack 信息,完成事务。

中断事务:假设 Coordinator 正常工作,并且有任一参与者反馈 No,或者在等待超时后无法接收所有参与者的反馈,都会中断事务

  1. 发送中断请求:Coordinator 向所有参与者节点发送 abort 请求;
  2. 事务回滚:参与者接收到 abort 请求后,利用 undo 日志执行事务回滚,并在完成事务回滚后释放占用的资源;
  3. 反馈事务回滚结果:参与者在完成事务回滚之后,向 Coordinator 发送 ack 信息;
  4. 中断事务:Coordinator 接收到所有参与者反馈的 ack 信息后,中断事务。

优缺点

• 优化单点故障:相比二阶段提交,三阶段提交降低了阻塞范围,在等待超时后协调者或参与者会中断事务。避免了协调者单点问题。阶段 3 中协调者出现问题时,参与者会继续提交事务。

• 一致性问题:

四种方案

Saga

1987年普林斯顿大学的Hector Garcia-Molina和Kenneth Salem发表了一篇Paper Sagas,讲述的是如何处理long lived transaction(长活事务)。Saga是一个长活事务可被分解成可以交错运行的子事务集合。其中每个子事务都是一个保持数据库一致性的真实事务。

分布式事务执行过程中,依次执行各参与者的正向操作,如果所有正向操作均执行成功,那么分布式事务提交。如果任何一个正向操作执行失败,那么分布式事务会去退回去执行前面各参与者的逆向回滚操作,回滚已提交的参与者,使分布式事务回到初始状态。

Saga 模式用一种非常纯朴的方式来处理一致性:补偿。上图左侧是正常的事务流程,当执行到 T3 时发生了错误,则开始执行右边的事务补偿流程,反向执行T3、T2、T1 的补偿服务,其中 C3 是 T3 的补偿服务、C2 是 T2 的补偿服务、C1 是 T1 的补偿服务,将T3、T2、T1 已经修改的数据补偿掉。

Tcc

TCC是Try、Confirm、Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作:预处理Try、确认Confirm、撤销Cancel。

• Try操作做业务检查及资源预留,

• Confirm做业务确认操作,

• Cancel实现一个与Try相反的操作即回滚操作。

TM首先发起所有的分支事务的try操作,任何一个分支事务的try操作执行失败,TM将会发起所有分支事务的Cancel操作,若try操作全部成功,TM将会发起所有分支事务的Confirm操作,其中Confirm/Cancel 操作若执行失败,TM会进行重试。

分支事务失败的情况:

TCC分为三个阶段:

  1. Try 阶段是做业务检查(一致性)及资源预留(隔离),此阶段仅是一个初步操作,它和后续的Confirm 一起才能 真正构成一个完整的业务逻辑。
  2. Confirm 阶段是做确认提交,Try阶段所有分支事务执行成功后开始执行 Confirm。通常情况下,采用TCC则 认为 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。若Confirm阶段真的出错了,需引 入重试机制或人工处理。
  3. Cancel 阶段是在业务执行错误需要回滚的状态下执行分支事务的业务取消,预留资源释放。通常情况下,采 用TCC则认为Cancel阶段也是一定成功的。若Cancel阶段真的出错了,需引入重试机制或人工处理。

TM事务管理器可以实现为独立的服务,也可以让全局事务发起方充当TM的角色,TM独立出来是为了成为公用组件,是为了考虑系统结构和软件复用。

TM在发起全局事务时生成全局事务记录,全局事务ID贯穿整个分布式事务调用链条,用来记录事务上下文, 追踪和记录状态,由于Confirm 和cancel失败需进行重试,因此需要实现为幂等,幂等性是指同一个操作无论请求 多少次,其结果都相同。

可靠消息最终一致性

可靠消息最终一致性方案是指当事务发起方执行完成本地事务后并发出一条消息,事务参与方(消息消费者)一定能够接收消息并处理事务成功,此方案强调的是只要消息发给事务参与方最终事务要达到一致。

此方案是利用消息中间件完成,如下图:

事务发起方(消息生产方)将消息发给消息中间件,事务参与方从消息中间件接收消息,事务发起方和消息中间件之间,事务参与方(消息消费方)和消息中间件之间都是通过网络通信,由于网络通信的不确定性会导致分布式事务问题。

因此可靠消息最终一致性方案要解决以下几个问题:

  1. 本地事务与消息发送的原子性问题

本地事务与消息发送的原子性问题即:事务发起方在本地事务执行成功后消息必须发出去,否则就丢弃消息。即实现本地事务和消息发送的原子性,要么都成功,要么都失败。本地事务与消息发送的原子性问题是实现可靠消息最终一致性方案的关键问题。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
6天前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
|
8天前
|
安全 Java 编译器
JDK 10中的局部变量类型推断:Java编程的简化与革新
JDK 10引入的局部变量类型推断通过`var`关键字简化了代码编写,提高了可读性。编译器根据初始化表达式自动推断变量类型,减少了冗长的类型声明。虽然带来了诸多优点,但也有一些限制,如只能用于局部变量声明,并需立即初始化。这一特性使Java更接近动态类型语言,增强了灵活性和易用性。
89 53
|
7天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
4天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
6天前
|
存储 缓存 安全
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见。本文介绍了使用 `File.createTempFile` 方法和自定义创建临时文件的两种方式,详细探讨了它们的使用场景和注意事项,包括数据缓存、文件上传下载和日志记录等。强调了清理临时文件、确保文件名唯一性和合理设置文件权限的重要性。
16 2
|
7天前
|
Java UED
Java中的多线程编程基础与实践
【10月更文挑战第35天】在Java的世界中,多线程是提升应用性能和响应性的利器。本文将深入浅出地介绍如何在Java中创建和管理线程,以及如何利用同步机制确保数据一致性。我们将从简单的“Hello, World!”线程示例出发,逐步探索线程池的高效使用,并讨论常见的多线程问题。无论你是Java新手还是希望深化理解,这篇文章都将为你打开多线程的大门。
|
7天前
|
安全 Java 编译器
Java多线程编程的陷阱与最佳实践####
【10月更文挑战第29天】 本文深入探讨了Java多线程编程中的常见陷阱,如竞态条件、死锁、内存一致性错误等,并通过实例分析揭示了这些陷阱的成因。同时,文章也分享了一系列最佳实践,包括使用volatile关键字、原子类、线程安全集合以及并发框架(如java.util.concurrent包下的工具类),帮助开发者有效避免多线程编程中的问题,提升应用的稳定性和性能。 ####
33 1
|
10天前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
10天前
|
设计模式 安全 Java
Java编程中的单例模式深入解析
【10月更文挑战第31天】在编程世界中,设计模式就像是建筑中的蓝图,它们定义了解决常见问题的最佳实践。本文将通过浅显易懂的语言带你深入了解Java中广泛应用的单例模式,并展示如何实现它。
|
安全 Java 程序员
4月7日云栖精选夜读:给 Java 学习者的超全教程整理
作为Java程序员的我们,应该不仅对这门语言有所了解,而且我们在平常编程时也需要使用众多的库。比如小编知道的,如果要学习Java Web的话,SSH(Spring, Struts和Hibernate)肯定得会吧,或者至少了解基本的原理吧。
2760 0