分布式相关概念

分布式原理

1. CAP理论


CAP 理论是分布式系统中的一个基本理论,它由计算机科学家 Eric Brewer 在 2000 年提出。CAP 代表一致性(Consistency)、可用性(Availability)、分区容错性(Partition Tolerance)三个概念的首字母缩写。

  1. 一致性(Consistency): 所有节点看到的数据是一致的。在任何给定时间,所有节点的数据都是相同的,不会出现数据冲突或不一致的情况。在强一致性系统中,当一个写操作完成后,所有节点都能立即读取到最新的数据。

  2. 可用性(Availability): 系统保证在有限时间内对请求做出响应,并返回有效的结果。即使系统中的部分节点发生故障,仍能保证可用的服务。

  3. 分区容错性(Partition Tolerance): 系统能够容忍网络中的某些节点或通信链路的故障,即便发生网络分区(部分节点之间无法通信)的情况,系统仍能够继续工作。

CAP 理论指出,在分布式系统设计中,无法同时满足这三个特性,只能在一致性、可用性和分区容错性之间进行权衡。在网络分区(网络故障)的情况下,必须选择放弃一致性或者放弃可用性之一,以确保系统的分区容错性。这就意味着在分布式系统中,必须根据实际需求和场景来权衡选择。

CP 架构:对于 CP 来说,放弃可用性,追求一致性和分区容错性。

我们熟悉的 ZooKeeper,就是采用了 CP 一致性,ZooKeeper 是一个分布式的服务框架,主要用来解决分布式集群中应用系统的协调和一致性问题。其核心算法是 Zab,所有设计都是为了一致性。在 CAP 模型中,ZooKeeper 是 CP,这意味着面对网络分区时,为了保持一致性,它是不可用的。

AP 架构:对于 AP 来说,放弃强一致性,追求分区容错性和可用性,这是很多分布式系统设计时的选择,后面的 Base 也是根据 AP 来扩展的。

ZooKeeper 相对的是 Eureka,Eureka 是 Spring Cloud 微服务技术栈中的服务发现组件,Eureka 的各个节点都是平等的,几个节点挂掉不影响正常节点的工作,剩余的节点依然可以提供注册和查询服务,只要有一台 Eureka 还在,就能保证注册服务可用,只不过查到的信息可能不是最新的版本,不保证一致性。

2. BASE 理论


BASE 理论是对分布式系统中数据一致性与可用性之间的折中原则的描述。它是对 ACID 特性相对的一种理念,主要用于描述分布式系统在面对网络分区和并发访问时的行为。

BASE 包含以下三个核心概念:

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

  2. Soft state(软状态): ACID中的原子性可以理解为一种"硬状态",软状态则是在一定时间内,允许出现中间状态,比如临时的不一致状态。

  3. **Eventually consistent(最终一致性):**虽然无法保证强一致性,但是在软状态结束以后,最终达到数据一致。

与 ACID 理论相对应,BASE 理论更侧重于分布式系统的可用性,允许系统在一定程度上放宽对一致性的要求。在大规模的分布式系统中,通过牺牲强一致性来实现可用性和分区容忍性,BASE 理论提供了一种更加灵活的设计思路。

3. Paxos 算法


Paxos 算法是分布式系统领域中用于解决一致性问题的一种算法,由 Leslie Lamport 在 1989 年提出。Paxos 算法解决了分布式系统中的一致性问题,特别是在存在故障和网络延迟的情况下,如何保证多个节点之间就某个值达成一致。

Paxos 算法的核心目标是在存在网络分区或节点故障的情况下,确保节点之间就某个值(提议)达成一致的算法。它主要包含三个阶段:

  1. 提议阶段(Prepare Phase): 提议者(Proposer)向接收者(Acceptor)发送准备请求(prepare request),请求接收者承诺不再接受编号小于当前提案编号的提案。

  2. 承诺阶段(Promise Phase): 接收者在接收到准备请求后,如果接收者还没有接受过编号大于当前提案编号的提案,就会向提议者发送承诺(promise),表示可以接受提案,并保证不再接受编号小于当前提案编号的提案。

  3. 接受阶段(Accept Phase): 如果提议者收到了大多数接收者的承诺,那么提议者就可以向接收者发送接受请求(accept request),并要求接收者接受该提案。

Paxos 算法通过这三个阶段的协调和通信,最终实现了多个节点对某个值达成一致。它能够处理网络分区、消息丢失、延迟等情况下的一致性问题,但是由于算法本身较为复杂,实现和理解上有一定的困难。然而,Paxos 算法为分布式系统中一致性问题提供了一种理论基础和解决思路。

4. Raft算法

Raft 是一种分布式一致性算法,旨在解决分布式系统中的一致性问题。它被设计为易于理解和实现,是一种领导者选举算法,适用于构建分布式一致性的系统,比如分布式数据库或分布式存储系统。

核心概念:

  1. 领导者选举

    • Raft 将节点分为三种角色:领导者(Leader)、跟随者(Follower)和候选人(Candidate)。领导者负责处理客户端的请求,并且在没有故障的情况下,每个任期只有一个领导者。
    • 当领导者宕机或失去连接时,跟随者可以发起新一轮的领导者选举。选举的过程包括投票、候选人的提议等。
  2. 日志复制

    • Raft 使用日志来记录系统状态的变化。领导者负责接收客户端的写请求,并将这些请求追加到其日志中。然后领导者会通知跟随者复制这些日志条目。
    • 当大多数节点(多数派)确认已经复制了这些日志条目后,领导者可以提交这些日志条目,并应用到状态机中,确保所有节点状态的一致性。

特点和优势:

  1. 可理解性

    • Raft 相对于其他分布式一致性算法(比如Paxos)更容易理解和实现,其算法设计更加直观和清晰。
  2. 容错性

    • Raft 在节点故障时能够快速进行领导者选举,并保持系统的可用性和一致性。
  3. 性能

    • Raft 能够提供良好的性能,并且在网络分区或节点宕机等情况下也能快速地恢复一致性。
  4. 应用范围广泛

    • Raft 算法被广泛应用于构建分布式存储系统、分布式数据库、分布式计算系统等领域。

Raft 算法致力于解决分布式一致性问题,通过领导者选举和日志复制等机制保证了分布式系统的一致性、可用性和容错性。其相对简单且清晰的设计使其成为分布式系统领域中的重要算法之一。

4. Quorum 选举机制


Quorum 选举机制是一种在分布式系统中用于达成共识或选举领导者的方法。它通常基于投票机制,确保在多个节点之间达成多数派(quorum)的共识,以决定某个操作的执行或者领导者的选举。

在 Quorum 选举机制中,多数派的概念非常重要。多数派表示系统中节点数量的一半加一(n/2 + 1),它是一种决策的阈值,确保了共识的达成。在一个典型的使用场景中,如果节点数为奇数,多数派的节点数将大于一半,确保了在节点间的投票中有足够的节点支持某项操作或者选举结果。

例如,对于一个由 5 个节点组成的系统,需要至少3个节点(即5的一半再加1)达成一致才能进行操作或选举领导者。如果只有两个节点同意,则不足以形成多数派,操作或选举将无法进行。

Quorum 选举机制在分布式系统中具有重要意义,因为它确保了系统在进行重要决策时能够达成一致,同时对抗了少数节点可能带来的错误或故障。这种机制被广泛应用于分布式数据库、分布式一致性算法(比如 Paxos 或 Raft)以及分布式存储系统等场景中。

5. ZooKeeper保证数据一致性


在分布式场景中,ZooKeeper的应用十分广泛,比如数据发布和订阅、命名服务、配置中心、注册中心、分布式锁等。

ZooKeeper提供了一个类似于 Linux 文件系统的数据类型,和基于 Watcher 机制的分布式事件通知,这些特性都依赖于 ZooKeeper 的高容错数据一致性协议。

那么,在分布式场景下,ZooKeeper 是如何实现数据一致性的呢?

5.1 Zab 协议

ZooKeeper 是通过 Zab 协议来保证分布式事务的最终一致性。Zab(ZooKeeper Atomic Broadcast,ZooKeeper 原子广播协议)支持崩溃恢复,基于该协议,ZooKeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间数据一致性。

系统架构图如下:

分布式相关概念_第1张图片

在 ZooKeeper 集群中,所有客户端的请求都是写入到 Leader 进程中的,然后,由 Leader 同步到其他节点,称为 Follower。在集群数据同步的过程中,如果出现 Follower 节点崩溃或者 Leader 进程崩溃时,都会通过 Zab 协议来保证数据一致性。

Zab 协议的具体实现可以分为以下两部分:

  • 消息广播阶段

​ Leader 节点接受事务提交,并且将新的 Proposal 请求广播给 Follower 节点,收集各个节点的反馈,决定是否进行 Commit,在这个过程中,也会使用到 Quorum 选举机制。

  • 崩溃恢复阶段

​ 如果在同步过程中出现 Leader 节点宕机,会进入崩溃恢复阶段,重新进行 Leader 选举,崩溃恢复阶段还包含数据同步操作,同步集群中最新的数据,保持集群的数据一致性。

整个 ZooKeeper 集群的一致性保证就是在上面两个状态之前切换,当 Leader 服务正常时,就是正常的消息广播模式;当 Leader 不可用时,则进入崩溃恢复模式,崩溃恢复阶段会进行数据同步,完成以后,重新进入消息广播阶段。

5.2 Zab 协议中的 Zxid

Zxid 是 Zab 协议的一个事务编号,Zxid 是一个 64 位的数字,其中低 32 位是一个简单的单调递增计数器,针对客户端每一个事务请求,计数器加 1;而高 32 位则代表 Leader 周期年代的编号。

这里 Leader 周期的英文是 epoch,可以理解为当前集群所处的年代或者周期,对比另外一个一致性算法 Raft 中的 Term 概念。在 Raft 中,每一个任期的开始都是一次选举,Raft 算法保证在给定的一个任期最多只有一个领导人。

分布式相关概念_第2张图片

Zab 协议的实现也类似,每当有一个新的 Leader 选举出现时,就会从这个 Leader 服务器上取出其本地日志中最大事务的 Zxid,并从中读取 epoch 值,然后加 1,以此作为新的周期 ID。总结一下,高 32 位代表了每代 Leader 的唯一性,低 32 位则代表了每代 Leader 中事务的唯一性。

5.3 Zab 流程分析

Zab 的具体流程可以拆分为消息广播、崩溃恢复和数据同步三个过程

5.3.1 消息广播

客户端的写请求进来之后,Leader 会将写请求包装成 Proposal 事务,并添加一个递增事务 ID,也就是 Zxid,Zxid 是单调递增的,以保证每个消息的先后顺序

广播这个 Proposal 事务,Leader 节点和 Follower 节点是解耦的,通信都会经过一个先进先出的消息队列,Leader 会为每一个 Follower 服务器分配一个单独的 FIFO 队列,然后把 Proposal 放到队列中

Follower 节点收到对应的 Proposal 之后会把它持久到磁盘上,当完全写入之后,发一个 ACK 给 Leader

当 Leader 收到超过半数 Follower 机器的 ack 之后,会提交本地机器上的事务,同时开始广播 commit, Follower 收到 commit 之后,完成各自的事务提交

5.3.2 崩溃恢复

消息广播通过 Quorum 机制,解决了 Follower 节点宕机的情况,但是如果在广播过程中 Leader 节点崩溃呢?

这就需要 Zab 协议支持的崩溃恢复,崩溃恢复可以保证在 Leader 进程崩溃的时候可以重新选出 Leader,并且保证数据的完整性。

崩溃恢复和集群启动时的选举过程是一致的,也就是说,下面的几种情况都会进入崩溃恢复阶段:

  • 初始化集群,刚刚启动的时候
  • Leader 崩溃,因为故障宕机
  • Leader 失去了半数的机器支持,与集群中超过一半的节点断连

崩溃恢复模式将会开启新的一轮选举,选举产生的 Leader 会与过半的 Follower 进行同步,使数据一致,当与过半的机器同步完成后,就退出恢复模式, 然后进入消息广播模式。

Zab 中的节点有三种状态,伴随着的 Zab 不同阶段的转换,节点状态也在变化:

状态 说明
following 当前节点是跟随者,服从Leader节点的命令
leading 当前节点是Leader,负责协调事务
election/looking 节点处于选举状态
5.3.3 数据同步

崩溃恢复完成选举以后,接下来的工作就是数据同步,在选举过程中,通过投票已经确认 Leader 服务器是最大Zxid 的节点,同步阶段就是利用 Leader 前一阶段获得的最新Proposal历史,同步集群中所有的副本。

5.4 Zab 与 Paxos 算法的联系与区别

Paxos 的思想在很多分布式组件中都可以看到,Zab 协议可以认为是基于 Paxos 算法实现的,先来看下两者之间的联系:

  • 都存在一个 Leader 进程的角色,负责协调多个 Follower 进程的运行
  • 都应用 Quorum 机制,Leader 进程都会等待超过半数的 Follower 做出正确的反馈后,才会将一个提案进行提交
  • 在 Zab 协议中,Zxid 中通过 epoch 来代表当前 Leader 周期,在 Paxos 算法中,同样存在这样一个标识,叫做 Ballot Number

两者之间的区别是,Paxos 是理论,Zab 是实践,Paxos 是论文性质的,目的是设计一种通用的分布式一致性算法,而 Zab 协议应用在 ZooKeeper 中,是一个特别设计的崩溃可恢复的原子消息广播算法。

Zab 协议增加了崩溃恢复的功能,当 Leader 服务器不可用,或者已经半数以上节点失去联系时,ZooKeeper 会进入恢复模式选举新的 Leader 服务器,使集群达到一个一致的状态。

6. 区块链共识问题

区块链是一种分布式数据库技术,以块(block)的形式按照时间顺序链接起来,形成一个不断增长的、不可篡改的记录链(chain)。每个区块包含了一批交易数据以及与前一个区块相关联的加密学证明,确保数据的安全性和完整性。

关键特征包括:

  1. 分布式性:区块链数据被存储在许多不同的计算机节点上,而不是集中存储在单个地点。

  2. 不可篡改性:区块链的设计使得一旦数据被记录在链上,就很难更改。因为每个区块都包含了前一个区块的哈希值,改变一个区块会导致链中后续所有区块的哈希值变化,从而很容易被检测到。

  3. 去中心化:区块链通常不依赖于中央权威机构,而是由网络中的参与者共同管理和验证交易。

  4. 加密安全:使用密码学技术确保数据的安全性,例如公钥加密和哈希函数等。

区块链最著名的应用之一是加密货币,比特币就是第一个成功应用区块链技术的加密货币。除了加密货币,区块链还在金融、供应链管理、投票系统、数字身份验证等领域得到广泛应用,因为它的特性能够提供可靠的数据存储、去中心化的信任机制和安全性。

6.1 共识机制

当谈论区块链和共识机制时,常见的几种方法包括:

  1. Proof of Work (PoW)

    • 原理:PoW是比特币和一些其他加密货币所采用的共识机制。参与者(也称为矿工)通过解决数学难题来验证交易并创建新的区块。解决这些难题需要大量计算能力,因此矿工需要进行大量的计算来获得机会创建区块并获得奖励。
    • 优点:安全性高,防止双重支付和篡改数据。
    • 缺点:需要大量的计算能力和能源消耗高。
  2. Proof of Stake (PoS)

    • 原理:PoS是一种不同的共识机制,它不需要矿工进行大量计算,而是根据持有的加密货币数量来决定创建新区块的权益。持币者(称为验证者)将一定数量的代币作为抵押,通过随机选择方式来确定谁有权利创建新区块。
    • 优点:能源效率高,因为不需要大量计算。持有者有利益去保护网络安全。
    • 缺点:可能存在“富者愈富”的情况,即持有更多代币的人可能更容易获得奖励。
  3. Delegated Proof of Stake (DPoS)

    • 原理:DPoS是PoS的变种,它引入了代表制度,持币者可以通过投票选举代表来代表他们验证交易和创建区块。这些代表(通常是一些超级节点)负责网络的验证和维护。
    • 优点:提高了网络的效率,因为由少数节点代表大多数持币者参与验证和创建区块。
    • 缺点:相比于PoS,DPoS可能更加中心化,因为只有一部分节点被选为超级节点,而其他持币者的权利有限。

这些共识机制都有各自的优缺点,选择使用哪种机制通常取决于区块链项目的特定需求、安全性要求和社区的共识。

6.2 拜占庭将军问题

拜占庭将军问题是计算机科学中的一个经典问题,它涉及分布式系统中的可靠性和容错性。这个问题描述了这样一种情况:一群拜占庭将军(或节点)围攻一座城市,他们需要达成共识来决定是否发起进攻或者撤退,但其中一些将军可能是叛徒,并试图误导其他将军做出错误的决定。

在这个问题中,将军们需要达成一致的决策,但叛徒的存在使得这个共识过程变得困难。拜占庭将军问题的目标是找到一种算法或机制,使得即使在存在叛徒的情况下,系统中的忠诚节点仍能就某个提议达成一致的决策。

解决这个问题需要满足一些条件:

  • 所有忠诚的将军必须达成一致的决策。
  • 系统需要对叛徒进行容错,即使存在叛徒,系统也能做出正确的决策。
  • 忠诚的将军不能被错误的信息误导。

这个问题对于分布式系统和区块链等领域具有重要意义,因为在这些系统中,节点可能会受到故障或者攻击,而拜占庭将军问题提出了如何在这种环境下达成共识的挑战。解决这个问题的一些算法被用于设计拜占庭容错的分布式共识算法,确保在存在恶意节点的情况下依然能够保持系统的正确性。

6.3 共识方法

当谈论区块链和共识机制时,常见的几种方法包括:

  1. Proof of Work (PoW)

    • 原理:PoW是比特币和一些其他加密货币所采用的共识机制。参与者(也称为矿工)通过解决数学难题来验证交易并创建新的区块。解决这些难题需要大量计算能力,因此矿工需要进行大量的计算来获得机会创建区块并获得奖励。
    • 优点:安全性高,防止双重支付和篡改数据。
    • 缺点:需要大量的计算能力和能源消耗高。
  2. Proof of Stake (PoS)

    POS(Proof of Stake,权益证明)类似现实生活中的股东大会机制,拥有股份越多的人拥有越多的投票权,也就越容易获取记账权。

  3. Delegated Proof of Stake (DPoS)

    采用 DPOS(Delegated Proof of Stake,委托权益证明)机制的典型代表是 EOS,如果说 POS 类似股东大会,比较的是谁持有的股份多,那么 DPOS 类似于公司董事会制度,在 DPOS 共识制度下,会选出一定数量的代表,来负责生产区块。

7. 分布式事务概述

7.1 概念

在分布式系统下,一个业务跨越多个服务或数据源,每个服务都是一个分支事务,要保证所有分支事务最终状态一致,这样的事务就是分布式事务。

7.2 分布式事务的解决方案

分布式事务的解决方案,典型的有两阶段和三阶段提交协议、 TCC 分段提交,和基于消息队列的最终一致性设计。

  • 两阶段提交(2PC,Two-phase Commit Protocol)是非常经典的强一致性、中心化的原子提交协议,在各种事务和一致性解决方案中,都能看到两阶段提交的应用。

  • 三阶段提交:是在两阶段提交之上扩展的提交协议,主要是为了解决两阶段提交协议的阻塞问题,从原来的两个阶段扩展为三个阶段,增加了超时机制。

  • TCC分段提交:TCC是一个分布式事务的处理模型,将事务过程拆分为Try、Confirm、Cancel 三个步骤,在保证强一致性的同时,最大限度提高系统的可伸缩性和可用性。

  • 基于消息队列的最终一致性:

    异步化在分布式系统设计中随处可见,基于消息队列的最终一致性就是一种异步事务机制,在业务中广泛应用。

    在具体实现上,主要有本地消息表和第三方可靠消息队列等。

    下面介绍一下本地消息表:本地消息表的方案最初是由 ebay 的工程师提出,核心思想是将分布式事务拆分成本地事务进行处理,通过消息日志的方式来异步执行。

    本地消息表是一种业务耦合的设计,消息生产方需要额外建一个事务消息表,并记录消息发送状态,消息消费方需要处理这个消息,并完成自己的业务逻辑,另外会有一个异步机制来定期扫描未完成的消息,确保最终一致性。

7.3 分布式事务有哪些开源组件

分布式事务开源组件应用比较广泛的是蚂蚁金服开源的 Seata,也就是 Fescar,前身是阿里中间件团队发布的 TXC(Taobao Transaction Constructor)和升级后的 GTS(Global Transaction Service)。

Seata 的设计思想是把一个分布式事务拆分成一个包含了若干分支事务(Branch Transaction)的全局事务(Global Transaction)。分支事务本身就是一个满足 ACID 的 本地事务,全局事务的职责是协调其下管辖的分支事务达成一致,要么一起成功提交,要么一起失败回滚。

在 Seata 中,全局事务对分支事务的协调基于两阶段提交协议,类似数据库中的 XA 规范,XA 规范定义了三个组件来协调分布式事务,分别是 AP 应用程序、TM 事务管理器、RM 资源管理器、CRM 通信资源管理器。

8. 两阶段提交和三阶段提交

两阶段提交(2PC)和三阶段提交(3PC)都是用于在分布式系统中实现事务一致性的协议。它们的目标都是确保跨多个节点或服务的事务操作能够要么全部提交(达成一致),要么全部回滚,以维护数据的一致性。

两阶段提交(2PC):

  • 阶段1 - 准备阶段(Prepare Phase)

    1. 协调者(Coordinator)向所有参与者(Participants)发送准备请求,并等待它们的响应。
    2. 参与者收到请求后,执行事务操作,并将准备就绪的消息或“同意”响应返回给协调者。
  • 阶段2 - 提交或回滚阶段(Commit or Rollback Phase)

    1. 如果所有参与者都准备就绪,协调者向所有参与者发送提交请求,并等待它们的响应。
    2. 参与者收到提交请求后,如果事务执行成功,则提交事务并发送“提交完成”响应;如果执行失败,则回滚事务并发送“回滚完成”响应。
  • 特点:2PC存在单点故障(协调者故障可能导致阻塞)、同步阻塞(在阶段2需要等待所有参与者的响应)、存在潜在的两阶段提交问题(即可能出现参与者在已经同意事务后出现问题无法提交的情况)。

三阶段提交(3PC):

三阶段提交是对两阶段提交的改进,旨在减少一些2PC的缺点。

  • 阶段1 - CanCommit 阶段

    1. 协调者向参与者发送 CanCommit 请求。
    2. 参与者执行事务操作,如果准备就绪,则发送“Yes”响应,否则发送“No”响应。
  • 阶段2 - PreCommit 阶段

    1. 协调者收到所有“Yes”响应后,向所有参与者发送 PreCommit 请求。
    2. 参与者收到请求后,事务进入预提交状态,但不立即执行提交。
  • 阶段3 - DoCommit 阶段

    1. 协调者收到所有 PreCommit 响应后,向所有参与者发送 DoCommit 请求。
    2. 参与者收到请求后,执行最终提交并向协调者发送“已提交”响应。

区别和联系:

  1. 同步阻塞:2PC需要在第二阶段等待所有参与者响应,而3PC引入了一个预提交阶段,减少了同步阻塞的时间。
  2. 单点故障:两阶段提交存在单点故障问题,而三阶段提交在第二阶段引入了超时机制来解决协调者单点故障问题。
  3. 数据传输量:3PC引入了额外的消息来解决2PC的一些问题,因此可能会产生更多的网络开销。
  4. 引入超时机制:在 2PC 中,只有协调者拥有超时机制,如果在一定时间内没有收到参与者的消息则默认失败,3PC 同时在协调者和参与者中都引入超时机制。

9. MySQL如何实现XA规范

XA(eXtended Architecture)是用于实现分布式事务的标准之一,它定义了事务管理器(Transaction Manager)和资源管理器(Resource Manager)之间的接口和协议。MySQL 实现了 XA 接口以支持分布式事务。

9.1 MySQL有哪些一致性日志?

MySQL InnoDB 引擎中和一致性相关的有重做日志(redo log)、回滚日志(undo log)和二进制日志(binlog)。

  • redo 日志,重做日志,每当有操作执行前,在数据真正更改前,会先把相关操作写入 redo 日志。这样当断电,或者发生一些意外,导致后续任务无法完成时,待系统恢复后,可以继续完成这些更改。
  • undo 日志,也叫回滚日志,记录事务开始前数据的状态,当一些更改在执行一半时,发生意外而无法完成,就可以根据撤消日志恢复到更改之前的状态。
  • binlog 日志是 MySQL sever 层维护的一种二进制日志,是 MySQL 最重要的日志之一,它记录了所有的 DDL 和 DML 语句,除了数据查询语句 select、show 等,还包含语句所执行的消耗时间。
    binlog 与 InnoDB 引擎中的 redo/undo log 不同,binlog 的主要目的是复制和恢复,用来记录对 MySQL 数据更新或潜在发生更新的 SQL 语句,并以事务日志的形式保存在磁盘中。binlog 主要应用在 MySQL 的主从复制过程中,MySQL 集群在 Master 端开启 binlog,Master 把它的二进制日志传递给 slaves 节点,在从节点回放来达到 master-slave 数据一致的目的。

9.2 XA规范是如何定义的?

XA 是由 X/Open 组织提出的分布式事务规范,XA 规范主要定义了事务协调者(Transaction Manager)和资源管理器(Resource Manager)之间的接口。

事务协调者(Transaction Manager),因为 XA 事务是基于两阶段提交协议的,所以需要有一个协调者,来保证所有的事务参与者都完成了准备工作,也就是 2PC 的第一阶段。如果事务协调者收到所有参与者都准备好的消息,就会通知所有的事务都可以提交,也就是 2PC 的第二阶段。

在前面的内容中我们提到过,之所以需要引入事务协调者,是因为在分布式系统中,两台机器理论上无法达到一致的状态,需要引入一个单点进行协调。协调者,也就是事务管理器控制着全局事务,管理事务生命周期,并协调资源。

资源管理器(Resource Manager),负责控制和管理实际资源,比如数据库或 JMS 队列。
目前,主流数据库都提供了对 XA 的支持,在 JMS 规范中,即 Java 消息服务(Java Message Service)中,也基于 XA 定义了对事务的支持。

9.3 XA事务的执行流程

XA 事务是两阶段提交的一种实现方式,根据 2PC 的规范,XA 将一次事务分割成了两个阶段,即 Prepare 和 Commit 阶段。
Prepare 阶段,TM 向所有 RM 发送 prepare 指令,RM 接受到指令后,执行数据修改和日志记录等操作,然后返回可以提交或者不提交的消息给 TM。如果事务协调者 TM 收到所有参与者都准备好的消息,会通知所有的事务提交,然后进入第二阶段。
Commit 阶段,TM 接受到所有 RM 的 prepare 结果,如果有 RM 返回是不可提交或者超时,那么向所有 RM 发送 Rollback 命令;如果所有 RM 都返回可以提交,那么向所有 RM 发送 Commit 命令,完成一次事务操作。

9.4 MySQL对XA规范的实现

MySQL支持XA事务规范,这包括内部XA和外部XA两种情况。

  1. 内部 XA

    • 在MySQL的InnoDB存储引擎中,当开启binlog(二进制日志)时,MySQL会同时维护binlog日志和InnoDB的redo log,确保这两个日志的一致性。这时MySQL会使用XA事务,保证了这两个日志的同步。
    • 但是需要澄清的是,这并不是内部XA的唯一场景。内部XA不仅仅指的是InnoDB在单个MySQL实例上的操作,也可以指一个MySQL实例上的多个存储引擎(如MyISAM、InnoDB等)之间的事务操作。
  2. 外部 XA

    • 外部XA是指典型的分布式事务,涉及多个数据库、多个数据库实例或者多个应用系统。
    • MySQL提供了对外部XA事务的支持,可以通过使用XA START/END/PREPARE/COMMIT等SQL语句来管理分布式事务。这些命令可以用于协调多个外部资源管理器(如不同的数据库)的事务操作。

10. TCC事务模型

10.1 概述

TCC(Try-Confirm-Cancel)的概念来源于 Pat Helland 发表的一篇名为“Life beyond Distributed Transactions:an Apostate’s Opinion”的论文。
TCC 提出了一种新的事务模型,基于业务层面的事务定义,锁粒度完全由业务自己控制,目的是解决复杂业务中,跨表跨库等大颗粒度资源锁定的问题。TCC 把事务运行过程分成 Try、Confirm / Cancel 两个阶段,每个阶段的逻辑由业务代码控制,避免了长事务,可以获取更高的性能。

  • Try 阶段:调用 Try 接口,尝试执行业务,完成所有业务检查,预留业务资源。
  • Confirm 或 Cancel 阶段:两者是互斥的,只能进入其中一个,并且都满足幂等性,允许失败重试。

Confirm 操作:对业务系统做确认提交,确认执行业务操作,不做其他业务检查,只使用 Try 阶段预留的业务资源。
Cancel 操作:在业务执行错误,需要回滚的状态下执行业务取消,释放预留资源。

Try 阶段失败可以 Cancel,如果 Confirm 和 Cancel 阶段失败了怎么办?
TCC 中会添加事务日志,如果 Confirm 或者 Cancel 阶段出错,则会进行重试,所以这两个阶段需要支持幂等;如果重试失败,则需要人工介入进行恢复和处理等。

10.2 TCC事务模型的优缺点

实际开发中,TCC 的本质是把数据库的二阶段提交上升到微服务来实现,从而避免数据库二阶段中长事务引起的低性能风险。

所以说,TCC 解决了跨服务的业务操作原子性问题,比如下订单减库存,多渠道组合支付等场景,通过 TCC 对业务进行拆解,可以让应用自己定义数据库操作的粒度,可以降低锁冲突,提高系统的业务吞吐量。
TCC 的不足主要体现在对微服务的侵入性强,TCC 需要对业务系统进行改造,业务逻辑的每个分支都需要实现 try、Confirm、Cancel 三个操作,并且 Confirm、Cancel 必须保证幂等。
另外 TCC 的事务管理器要记录事务日志,也会损耗一定的性能。

10.3 与2PC/XA两阶段提交的区别

  • 2PC/XA 是数据库或者存储资源层面的事务,实现的是强一致性,在两阶段提交的整个过程中,一直会持有数据库的锁。
  • TCC 关注业务层的正确提交和回滚,在 Try 阶段不涉及加锁,是业务层的分布式事务,关注最终一致性,不会一直持有各个业务资源的锁。

TCC 的核心思想是针对每个业务操作,都要添加一个与其对应的确认和补偿操作,同时把相关的处理,从数据库转移到业务中,以此实现跨数据库的事务。

11. 分布式ID的实现方案

  1. UUID(Universally Unique Identifier)
    • 使用标准的 UUID 算法(比如 UUIDv4),基于随机数生成唯一的标识符。UUID 是一种128位的唯一标识符,通常基于时间戳和随机数生成。
  2. Snowflake 算法
    • Twitter 的 Snowflake 算法使用了一个64位的整数作为唯一 ID,其中包括了时间戳、机器标识和序列号。通过时间戳和节点标识生成唯一 ID,具有一定的顺序性。
  3. Redis 的 INCR 操作
    • 使用 Redis 的 INCR 操作,利用 Redis 的自增特性来生成唯一递增的 ID。可以将 Redis 中的键作为计数器来实现。

雪花算法的时钟回拨:
因为服务器的本地时钟并不是绝对准确的,在一些业务场景中,比如在电商的整点抢购中,为了防止不同用户访问的服务器时间不同,则需要保持服务器时间的同步。为了确保时间准确,会通过 NTP 的机制来进行校对,NTP(Network Time Protocol)指的是网络时间协议,用来同步网络中各个计算机的时间。
如果服务器在同步 NTP 时出现不一致,出现时钟回拨,那么 SnowFlake 在计算中可能出现重复 ID。除了 NTP 同步,闰秒也会导致服务器出现时钟回拨,不过时钟回拨是小概率事件,在并发比较低的情况下一般可以忽略。关于如何解决时钟回拨问题,可以进行延迟等待,直到服务器时间追上来为止。

12. 分布式锁概述

12.1 如何理解分布式锁?

我们都知道,在业务开发中,为了保证在多线程下处理共享数据的安全性,需要保证同一时刻只有一个线程能处理共享数据。
Java 语言给我们提供了线程锁,开放了处理锁机制的 API,比如 Synchronized、Lock 等。当一个锁被某个线程持有的时候,另一个线程尝试去获取这个锁会失败或者阻塞,直到持有锁的线程释放了该锁。

分布式场景下解决并发问题,需要应用分布式锁技术。分布式锁的目的是保证在分布式部署的应用集群中,多个服务在请求同一个方法或者同一个业务操作的情况下,对应业务逻辑只能被一台机器上的一个线程执行,避免出现并发问题。

12.2 分布式锁的常见实现

  • 基于关系型数据库
    基于关系型数据库实现分布式锁,是依赖数据库的唯一性来实现资源锁定,比如主键和唯一索引等。
    以唯一索引为例,创建一张锁表,定义方法或者资源名、失效时间等字段,同时针对加锁的信息添加唯一索引,比如方法名,当要锁住某个方法或资源时,就在该表中插入对应方法的一条记录,插入成功表示获取了锁,想要释放锁的时候就删除这条记录。

  • 基于 Redis 缓存
    相比基于数据库实现分布式锁,缓存的性能更好,并且各种缓存组件也提供了多种集群方案,可以解决单点问题。
    常见的开源缓存组件都支持分布式锁,包括 Redis、Memcached 及 Tair。以常见的 Redis 为例,应用 Redis 实现分布式锁,最直接的想法是利用 setnx 和 expire 命令实现加锁。
    在 Redis 中,setnx 是「set if not exists」如果不存在,则 SET 的意思,当一个线程执行 setnx 返回 1,说明 key 不存在,该线程获得锁;当一个线程执行 setnx 返回 0,说明 key 已经存在,那么获取锁失败,expire 就是给锁加一个过期时间。

  • 基于 ZooKeeper 实现
    ZooKeeper 有四种节点类型,包括持久节点、持久顺序节点、临时节点和临时顺序节点,利用 ZooKeeper 支持临时顺序节点的特性,可以实现分布式锁。
    当客户端对某个方法加锁时,在 ZooKeeper 中该方法对应的指定节点目录下,生成一个唯一的临时有序节点。

    判断是否获取锁,只需要判断持有的节点是否是有序节点中序号最小的一个,当释放锁的时候,将这个临时节点删除即可,这种方式可以避免服务宕机导致的锁无法释放而产生的死锁问题。
    下面描述使用 ZooKeeper 实现分布式锁的算法流程,根节点为 /lock:

    客户端连接 ZooKeeper,并在 /lock 下创建临时有序子节点,第一个客户端对应的子节点为 /lock/lock01/00000001,第二个为 /lock/lock01/00000002;
    其他客户端获取 /lock01 下的子节点列表,判断自己创建的子节点是否为当前列表中序号最小的子节点;
    如果是则认为获得锁,执行业务代码,否则通过 watch 事件监听 /lock01 的子节点变更消息,获得变更通知后重复此步骤直至获得锁;
    完成业务流程后,删除对应的子节点,释放分布式锁。

13. Redis实现分布式锁

一般来说,生产环境可用的分布式锁需要满足以下几点:

  • 互斥性:互斥是锁的基本特征,同一时刻只能有一个线程持有锁,执行临界操作
  • 超时释放:超时释放是锁的另一个必备特征,可以对比MySQL InnoDB 引擎的 innodb_lock_wait_timeout 配置,通过超时释放,防止不必要的线程等待和资源浪费
  • 可重入性:在分布式环境下,同一个节点上的同一个线程如果获取了锁以后,再次请求还是可以成功
  • 高性能和高可用:加锁和解锁的开销要尽可能的小,同时也需要保证高可用,防止分布式锁失效
  • 支持阻塞和非阻塞:对比 Java 语言的 wait() 和 notify() 等操作,这个一般是在业务代码中实现,比如在获取锁是通过 while (true) 或者轮询来实现阻塞操作

使用 setnx 实现分布式锁

Redis 支持 setnx 指令,只在 key 不存在的情况下,将 key 的值设置为 value,若 key 已经存在,则 setnx 命令不做任何动作。使用 setnx 实现分布式锁的方案,获取锁的方法很简单,只要以该锁为 key,设置一个随机的值即可。如果 setnx 返回 1,则说明该进程获得锁;如果 setnx 返回 0,则说明其他进程已经获得了锁,进程不能进入临界区;如果需要阻塞当前进程,可以在一个循环中不断尝试 setnx 操作。

分布式锁的高可用

上面分布式锁的实现方案中,都是针对单节点 Redis 而言的,在生产环境中,为了保证高可用,避免单点故障,通常会使用 Redis 集群。

集群下分布式锁存在哪些问题

集群环境下,Redis 通过主从复制来实现数据同步,Redis 的主从复制(Replication)是异步的,所以单节点下可用的方案在集群的环境中可能会出现问题,在故障转移(Failover) 过程中丧失锁的安全性。
由于 Redis 集群数据同步是异步的,假设 Master 节点获取到锁后在未完成数据同步的情况下,发生节点崩溃,此时在其他节点依然可以获取到锁,出现多个客户端同时获取到锁的情况。

Redlock 算法的流程

Redlock 算法是在单 Redis 节点基础上引入的高可用模式,Redlock 基于 N 个完全独立的 Redis 节点,一般是大于 3 的奇数个(通常情况下 N 可以设置为 5),可以基本保证集群内各个节点不会同时宕机。
假设当前集群有 5 个节点,运行 Redlock 算法的客户端依次执行下面各个步骤,来完成获取锁的操作:

客户端记录当前系统时间,以毫秒为单位;
依次尝试从 5 个 Redis 实例中,使用相同的 key 获取锁,当向 Redis 请求获取锁时,客户端应该设置一个网络连接和响应超时时间,超时时间应该小于锁的失效时间,避免因为网络故障出现的问题;
客户端使用当前时间减去开始获取锁时间就得到了获取锁使用的时间,当且仅当从半数以上的 Redis 节点获取到锁,并且当使用的时间小于锁失效时间时,锁才算获取成功;
如果获取到了锁,key 的真正有效时间等于有效时间减去获取锁所使用的时间,减少超时的几率;
如果获取锁失败,客户端应该在所有的 Redis 实例上进行解锁,即使是上一步操作请求失败的节点,防止因为服务端响应消息丢失,但是实际数据添加成功导致的不一致。

在 Redis 官方推荐的 Java 客户端 Redisson 中,内置了对 RedLock 的实现。

14. RPC 远程服务调用

RPC(Remote Procedure Call,远程过程调用),指的是一种计算机通信协议,允许程序调用另一个地址空间(通常是另一台机器上)的程序或函数,就像调用本地函数一样,而无需程序员显式编写远程调用的细节。RPC使得分布式系统中的不同部分能够像调用本地函数一样进行通信和交互。

一些与Java相关的RPC框架包括:

  1. Java RMI(Remote Method Invocation):Java远程方法调用,允许Java程序在不同的Java虚拟机之间进行远程调用。它是Java语言本身提供的远程调用机制。
  2. Apache Dubbo:Dubbo是一种高性能、轻量级的开源RPC框架,支持多种协议,并提供服务治理、负载均衡、容错等功能。
  3. gRPC:虽然不是Java特有的,但gRPC支持多种语言,包括Java。它是一个高性能的开源RPC框架,使用HTTP/2作为传输协议,并支持多种语言的客户端和服务器。
  4. Spring Cloud的Feign:Feign是Spring Cloud中的一个声明式的HTTP客户端,它简化了开发者编写基于HTTP的客户端代码的过程,通过注解和接口定义远程服务调用。

优点

  • 分布式通信:允许在不同机器之间进行函数调用,方便构建分布式系统。
  • 抽象性:隐藏了底层的网络通信和细节,使得远程调用看起来像是本地调用。
  • 模块化:允许系统拆分成独立的服务模块,提高了系统的可维护性和扩展性。

缺点

  • 网络开销:远程调用需要经过网络传输,可能存在网络延迟和开销。
  • 可靠性:网络通信可能会面临中断、超时等问题,需要考虑消息丢失和重传的问题。
  • 复杂性:实现RPC需要考虑序列化、反序列化、异常处理、服务注册等一系列问题,增加了系统的复杂性。

15. 为什么微服务需要使用API网关?

API网关在微服务架构中扮演着重要的角色,以下是它的几个关键作用:

  1. 服务路由和负载均衡

    • 微服务架构中存在大量的服务,API网关可以作为入口点,根据请求的URL或其他标识,将请求路由到正确的微服务。它可以根据路由规则实现负载均衡,将请求均匀地分发到多个实例中,提高系统整体的性能和可用性。
  2. 安全控制

    • API网关可以作为安全屏障,实施认证、授权和访问控制策略。它可以集中管理认证和授权机制,确保只有经过认证的用户才能访问特定的服务,并且可以对不同服务的访问权限进行细粒度的控制。
  3. 监控和日志

    • API网关可以收集和记录所有请求和响应的日志信息,包括请求时间、来源、目的地、状态码等。这些信息有助于监控服务的运行状况、发现问题和故障,并进行故障排除。
  4. 协议转换和数据转换

    • 微服务可能使用不同的通信协议和数据格式。API网关可以处理不同的协议和格式,将外部请求转换为适合特定服务的格式,并将服务的响应转换为外部客户端所需的格式,实现数据的转换和适配。
  5. 缓存和性能优化

    • API网关可以缓存某些请求或响应,减少对后端服务的请求压力,提高系统的性能和响应速度。它可以在网关层面实现一些优化,减少对后端服务的重复请求。
  6. 简化客户端接口

    • API网关可以提供统一的、规范的接口给客户端,隐藏了底层的服务细节。通过网关,客户端只需与网关交互,无需了解后端服务的具体信息和复杂性。

网关的缺点

  1. 单点故障
    • API网关作为入口点,成为系统的单点故障可能性较高,一旦网关出现故障,整个系统的可用性将受到影响。
  2. 性能瓶颈
    • 所有外部请求都需要经过API网关,可能会成为性能瓶颈,特别是在高并发的情况下,网关需要处理大量请求。
  3. 增加复杂性
    • 引入了额外的中间层,增加了系统的复杂性和管理成本,特别是在配置、维护和扩展方面需要额外的工作。
  4. 部署和扩展
    • 需要考虑网关的部署和扩展问题,特别是随着微服务数量的增加,网关的管理和扩展也变得更加复杂。

微服务网关选型
在微服务领域,有许多开源网关实现,应用比较多的是 Spring Cloud Zuul 和 Spring Cloud Gateway。

Spring Cloud Zuul

Spring Cloud Zuul 是 Spring Cloud Netflix 项目的核心组件之一,是 Netflix 开发的一款提供动态路由、监控、弹性、安全的网关服务。
Zuul 分为 1.x 和 2.x 两个大版本,1.x 版本是基于 Servlet 构建的,采用的是阻塞和多线程方式。1.x 版本在 Spring Cloud 中做了比较好的集成,但是性能不是很理想。后来 Netflix 宣布开发 2.x 版本,目前已经更新到了 2.x 版本,不过 Spring Cloud 官方并没有集成,而是开发了自己的 Spring Cloud Gateway。

Spring Cloud Gateway

Spring Cloud Gateway 是 Spring Cloud 体系的第二代网关组件,基于 Spring 5.0 的新特性 WebFlux 进行开发,底层网络通信框架使用的是 Netty。
Spring Cloud Gateway 可以替代第一代的网关组件 Zuul。Spring Cloud Gateway 可以通过服务发现组件自动转发请求,集成了 Ribbon 做负载均衡,支持使用 Hystrix 对网关进行保护,当然也可以选择其他的容错组件,比如集成阿里巴巴开源的 Sentinel,实现更好的限流降级等功能。

16. 如何实现服务的注册与发现?

16.1 为什么需要服务注册和发现?

分布式系统下微服务架构的一个重要特性就是可以快速上线或下线,从而可以让服务进行水平扩展,以保证服务的可用性。
假设有一个电商会员服务,随着业务发展,服务器负载越来越高,需要新增服务器。如果没有服务注册与发现,就要把新的服务器地址配置到所有依赖会员模块的服务,并相继重启它们,这显然是不合理的。
服务注册与发现就是保证当服务上下线发生变更时,服务消费者和服务提供者能够保持正常通信。
有了服务注册和发现机制,消费者不需要知道具体服务提供者的真实物理地址就可以进行调用,也无须知道具体有多少个服务者可用;而服务提供者只需要注册到注册中心,就可以对外提供服务,在对外服务时不需要知道具体是哪些服务调用了自己。

16.2 服务注册与发现的原理

首先,在服务启动时,服务提供者会向注册中心注册服务,暴露自己的地址和端口等,注册中心会更新服务列表。服务消费者启动时会向注册中心请求可用的服务地址,并且在本地缓存一份提供者列表,这样在注册中心宕机时仍然可以正常调用服务。

如果提供者集群发生变更,注册中心会将变更推送给服务消费者,更新可用的服务地址列表。

16.3 常见的服务注册与发现组件

  1. Zookeeper
    • Apache ZooKeeper是一个分布式的开源协调服务,常用于服务注册与发现、分布式锁、配置管理等。它提供了简单的文件系统模型和高性能的通知机制,可用于构建可靠的分布式系统。
  2. Eureka(Netflix OSS)
    • Eureka是Netflix开源的一款服务注册与发现组件,被设计用于云端中的负载均衡和中间层故障转移。虽然它更常用于基于Spring Cloud的微服务架构中,但也可以作为服务注册和发现的独立组件使用。
  3. Nacos
    • 阿里巴巴开源的Nacos是一个动态服务发现、配置管理和服务管理平台。它提供了服务注册、配置管理、服务发现、服务路由和流量管理等功能,支持多种语言和框架。

一致性对比:

在讨论分布式系统时,一致性是一个绕不开的话题,在服务发现中也是一样。CP 模型优先保证一致性,可能导致注册中心可用性降低,AP 模型优先保证可用性,可能出现服务错误。

为了保证微服务的高可用,避免单点故障,注册中心一般是通过集群的方式来对外服务,比如 ZooKeeper 集群。
ZooKeeper 核心算法是 Zab,实现的是 CP 一致性,所以 ZooKeeper 作为服务发现解决方案,在使用 ZooKeeper 获取服务列表时,如果 ZooKeeper 正在选主,或者 ZooKeeper 集群中半数以上机器不可用时,那么将无法获得数据。

在 Spring Cloud Eureka 中,各个节点都是平等的,几个节点挂掉不影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。只要有一台 Eureka 还在,就能保证注册服务可用,只不过查到的信息可能不是最新的版本,不保证一致性。

Spring Cloud Nacos 在 1.0.0 版本正式支持 AP 和 CP 两种一致性协议,可以动态切换。

对于服务注册和发现场景来说,一般认为,可用性比数据一致性更加重要。针对同一个服务,即使注册中心的不同节点保存的服务提供者信息不相同,会出现部分提供者地址不存在等,不会导致严重的服务不可用。对于服务消费者来说,能消费才是最重要的,拿到可能不正确的服务实例信息后尝试消费,也要比因为无法获取实例信息而拒绝服务好。

17. 分布式调用跟踪

在复杂的分布式系统中,一个请求可能会经过多个不同的服务和组件,分布式调用跟踪技术可以帮助追踪请求在系统中的传播路径,并且记录各个组件的响应时间、耗时、错误信息等重要数据,以便于排查问题、性能优化和分析系统的行为。

Zipkin是一个开源的分布式跟踪系统,用于收集、存储和可视化分布式系统中的调用链路和跟踪数据。它可以帮助开发人员追踪请求的路径,定位系统中的性能问题和瓶颈。

18. 分库分表

单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。

数据库的拆分(Sharding)是指根据不同的策略将一个大型数据库拆分成多个较小的数据库单元,以提高性能、可扩展性和并发处理能力。主要有水平拆分(Horizontal Sharding)和垂直拆分(Vertical Sharding)两种方式。

水平拆分(Horizontal Sharding):水平拆分是指按照某个规则将数据行拆分到多个数据库中,通常是按照某个列或者规则进行划分。例如,按照用户ID、时间范围、地理位置等将数据行分布到不同的数据库中。

垂直拆分(Vertical Sharding):垂直拆分是指将数据库中的表按照某种关系或者业务逻辑拆分成不同的表或者数据库,通常是按照表中的列进行拆分。例如,将一个大表按照列的关联性拆分成多个小表。

分库分表后引入的问题

  • 分布式事务问题:对业务进行分库之后,同一个操作会分散到多个数据库中,涉及跨库执行 SQL 语句,也就出现了分布式事务问题。
    比如数据库拆分后,订单和库存在两个库中,一个下单减库存的操作,就涉及跨库事务。关于分布式事务的处理,可以使用分布式事务中间件,实现 TCC 等事务模型;也可以使用基于本地消息表的分布式事务实现。
  • 跨库关联查询问题:分库分表后,跨库和跨表的查询操作实现起来会比较复杂,性能也无法保证。在实际开发中,针对这种需要跨库访问的业务场景,一般会使用额外的存储,比如维护一份文件索引。另一个方案是通过合理的数据库字段冗余,避免出现跨库查询。

19. 限流算法

限流算法是在分布式系统中用来控制流量并保护系统免受过载的影响的重要工具。以下是一些常见的限流算法:

  1. 固定窗口计数器算法(Fixed Window Counter)
    • 将时间划分为固定的窗口,例如每秒一个窗口。在每个窗口期间内,计数请求的数量。当请求超出阈值时,拒绝后续请求。
  2. 滑动窗口计数器算法(Sliding Window Counter)
    • 类似于固定窗口计数器,但是窗口不是固定的,而是随时间滑动。这种方式可以更平滑地限制流量,而不会出现严格的窗口边界。
  3. 令牌桶算法(Token Bucket)
    • 令牌桶算法维护一个令牌桶,桶中存放着令牌,每个令牌代表一个允许通过的请求。系统按照一定速率往桶里添加令牌,当请求到达时,如果桶中有足够的令牌,则允许通过并取走一个令牌;如果没有令牌,则拒绝请求或等待直到有足够的令牌。
  4. 漏桶算法(Leaky Bucket)
    • 漏桶算法将请求看作是水滴,它以恒定的速率将请求处理,并将多余的请求放在一个“桶”中。如果“桶”已满,则拒绝多余的请求。这种算法使得请求以固定的速率处理,防止突发性请求造成的压力。

20. 负载均衡算法

负载均衡算法用于在多个服务器或节点间分发工作负载,以确保各个节点能够有效地处理请求,提高系统的性能和可靠性。以下是一些常见的负载均衡算法:

  1. 轮询(Round Robin)

    • 将请求依次分配给每个节点,循环往复。每个请求按照顺序分发给不同的节点,适用于节点性能相近的情况。
  2. 加权轮询(Weighted Round Robin)

    • 类似于轮询算法,但给不同节点分配不同的权重,使得性能更高的节点能够处理更多的请求。
  3. 随机算法(Random)

    • 随机选择一个节点来处理请求,适用于节点性能相差不大且请求相对均匀的场景。
  4. 最少连接(Least Connections)

    • 将请求分配给当前连接数最少的节点。这种方式可以避免请求集中在少数节点上,适用于长连接或处理时间较长的场景。
  5. IP哈希(IP Hash)

    • 根据请求的源IP地址进行哈希计算,然后将相同哈希结果的请求发送到同一节点。这种方法可以确保同一客户端的请求始终发送到同一个节点,适用于需要保持会话一致性的场景。
  6. 最优响应时间(Least Response Time)

    • 根据节点的实时负载情况和响应时间选择最优节点。这需要实时监控节点的负载和性能指标来进行决策。
  7. 最少流量(Least Traffic)

    • 分配请求到当前流量最小的节点,确保整个系统的网络流量尽量均衡。
  8. 一致性哈希(Consistent Hashing)

    • 根据请求的键值对将请求映射到节点,通过哈希环的方式确定请求应该由哪个节点处理。这种算法在节点动态变化时能够更好地保持负载均衡。

21. 分布式日志系统

在分布式场景下,除了不方便查看集群日志以外,传统日志收集都存在哪些问题?

  • 无法实现日志的快速搜索:传统的查找是基于文件的,搜索效率比较低,并且很难对日志文件之间的关系进行聚合,无法从全局上梳理日志,也很难进行调用链路的分析。

  • 日志的集中收集和存储困难:当有上千个节点的时候,日志是分布在许多机器上的,如果要获取这些日志的文件,不可能一台一台地去查看,所以这就是很明显的一个问题。

  • 日志分析聚合及可视化:由于日志文件分布在不同的服务器上,因此进行相关的分析和聚合非常困难,也不利于展开整体的数据分析工作。

除了这些,还有日志安全问题,以电商场景为例,很多业务日志都是敏感数据,比如用户下单数据、账户信息等,如何管理这些数据的安全性,也是一个很关键的问题。

ELK 日志系统

ELK 是一个流行的日志管理解决方案,它由三个开源工具组成:Elasticsearch、Logstash 和 Kibana。

  1. Elasticsearch

    • Elasticsearch 是一个分布式搜索和分析引擎,专门用于存储和检索大量数据。它以实时、高可用和可扩展的特性而闻名,能够快速地索引、搜索和分析海量数据。
  2. Logstash

    • Logstash 是一个用于日志收集、处理和转发的工具。它能够从各种来源收集数据,包括日志文件、消息队列、数据库等,然后进行清洗、结构化和转换,最终将数据发送到Elasticsearch等存储和分析平台。
  3. Kibana

    • Kibana 是一个用于数据可视化和分析的工具。它提供了一个直观的界面,可以通过图表、图形和仪表板等方式对Elasticsearch中的数据进行查询、分析和展示。用户可以通过Kibana创建定制化的可视化报表和仪表板,实时监控系统的状态和趋势。

ELK 日志系统通常用于以下方面:

  • 日志收集和分析:通过Logstash收集各种来源的日志数据,并将其存储到Elasticsearch中,然后使用Kibana对数据进行可视化和分析。
  • 实时监控:借助Kibana的仪表板和图表功能,实时监控系统的运行状态、性能指标和日志信息。
  • 故障排查和分析:通过Elasticsearch强大的搜索和分析能力,快速定位和解决问题。
  • 安全审计:对系统的访问和操作进行记录、分析和审计,以保证系统的安全性。

ELK 日志系统提供了一个强大的日志管理平台,可以帮助组织更好地理解和利用日志数据,从而优化系统性能、改善用户体验和提高安全性。

你可能感兴趣的:(分布式)