分布式学习

1. 列举三个非冯·诺依曼计算结构

非冯结构是指不遵循传统冯·诺依曼体系的计算架构,包括:

  • 数据流结构(Dataflow Architecture):指令执行取决于数据的可用性而不是程序计数器。

  • 神经网络结构(Neural Network Architecture):模拟生物神经元连接,用于人工智能。

  • 量子计算结构(Quantum Computing Architecture):利用量子比特和量子叠加原理进行计算。


2. 简述同步通信

同步通信指通信双方在数据传输过程中必须同时处于活动状态,例如:

  • 发送方发出数据后等待接收方响应

  • 接收方只有在发送方传输时才能接收;

  • 常见于阻塞式消息传递,如 MPI_SendMPI_Recv


3. 简述云计算中的基础服务模型

云计算有三种基本服务模型:

模型 名称 功能
IaaS Infrastructure as a Service 提供虚拟机、存储、网络等基础资源(如AWS EC2、阿里云ECS)
PaaS Platform as a Service 提供应用开发运行平台(如Google App Engine、Microsoft Azure)
SaaS Software as a Service 提供在线应用服务(如Gmail、Office 365)

4. 简述Flynn分类法

Flynn分类法根据指令流和数据流的数量将计算机系统分为四类:

分类 含义 示例
SISD 单指令流单数据流 传统单核处理器
SIMD 单指令流多数据流 GPU
MISD 多指令流单数据流 稀有,用于容错系统
MIMD 多指令流多数据流 多核多线程系统、分布式系统

5. 举例说明MPI中标签的作用

**MPI标签(Tag)**用于区分不同类型的消息,防止通信混乱。

假设进程 P 向进程 Q 发送两类消息:

// 进程 P
MPI_Send(&data1, count, MPI_INT, dest=Q, tag=100, comm);
MPI_Send(&data2, count, MPI_INT, dest=Q, tag=200, comm);

// 进程 Q
MPI_Recv(&recv1, count, MPI_INT, source=P, tag=100, comm, status);
MPI_Recv(&recv2, count, MPI_INT, source=P, tag=200, comm, status);

作用:标签 100200 确保数据 data1data2 不会混淆。


6. 简述虚拟机和容器的异同

比较项 虚拟机(VM) 容器(Container)
启动速度 慢(分钟级) 快(秒级)
占用资源 多(完整OS) 少(共享宿主OS)
隔离性 强(硬件层) 相对弱(内核级)
应用场景 多系统环境 微服务、快速部署
虚拟化层 Hypervisor Docker Engine / Containerd

7. 简述云计算的三种存储方式

  1. 对象存储(Object Storage)

    • 面向非结构化数据,如图片、音频、备份。

    • 如 Amazon S3、阿里云 OSS。

  2. 块存储(Block Storage)

    • 类似硬盘,适合数据库、虚拟机挂载。

    • 如 Amazon EBS、阿里云云盘。

  3. 文件存储(File Storage)

    • 提供标准文件系统访问,适合共享访问。

    • 如 Amazon EFS、阿里云 NAS。


8. 简述什么是 Cache 一致性问题

Cache一致性问题是指在多处理器系统中,每个CPU都有自己的缓存,如果多个缓存中同一变量副本不一致,可能导致程序结果错误。

示例:

  • CPU1 缓存了变量 X=1,CPU2 更新为 X=2

  • 如果CPU1未刷新,就会读取过时数据。

常用解决方案:

  • MESI 协议(修改-独占-共享-无效)

  • 总线监听(Bus Snooping)

9. 任务并行 vs 数据并行

类型 含义 示例
任务并行 各处理单元执行不同任务,操作不同数据 多线程同时执行输入、处理、输出
数据并行 各处理单元执行相同操作,处理不同数据 多核同时对不同数组片段求平方

10. 负载均衡 / 通信 / 同步

  • 负载均衡:将任务在各节点上平均分配,避免某些过载、某些空闲。

  • 通信:节点间交换数据,例如发送接收消息(如 MPI)。

  • 同步:进程/线程间协调执行时序,如 barrier、锁等。


11. 并发 / 并行 / 分布式计算对比

特性 并发计算 并行计算 分布式计算
核心思想 多任务交替 多任务同时 多节点协作
硬件需求 单/多核 多核/多处理器 多主机网络
通信 同步/共享内存 同步/共享内存 网络通信
示例 单核多线程 多核计算矩阵 云平台运行搜索引擎

12. 冯诺依曼瓶颈及解决

  • 问题:处理器与内存间数据传输速率差距导致带宽瓶颈

  • 解决方法

    • 多级缓存

    • 指令预取、乱序执行

    • 使用哈佛结构分开指令/数据总线


13. 缓存映射的三种方式

类型 映射策略 特点
直接映射 每块内存映射到唯一缓存位置 实现简单,冲突多
全相联映射 任意内存块可映射至任何缓存行 命中率高,硬件复杂
组相联映射 缓存分组,每块映射至某组内任一行 折中方案,常用

14. 分布式 vs 共享式存储系统

类型 特点 示例
共享式 所有节点访问同一存储 多核服务器共享内存
分布式 存储分布在多个节点上 HDFS、Ceph 等

15. 阿达姆定律(Amdahl’s Law)

并行化程序的加速比受限于其串行部分

公式:
S=1(1−P)+PNS = \frac{1}{(1 - P) + \frac{P}{N}}S=(1−P)+NP​1​
其中:

  • SSS:加速比

  • PPP:可并行部分比例

  • NNN:处理器数量


16. Foster 并行化方法步骤

  1. 分解(Decomposition)

  2. 分配(Assignment)

  3. 通信(Communication)

  4. 合成/调度(Agglomeration & Mapping)


17. 缓存 / 一致性问题 / 伪共享

  • 缓存:位于CPU与内存之间的高速缓冲。

  • 缓存一致性问题:多核对同一变量副本操作,导致数据不一致。

  • 伪共享:不同线程使用同一缓存行内不同变量,仍引起无效失效。


18. 矩阵向量乘三种实现对比

实现 特点
行划分 每线程处理矩阵某几行
列划分 每线程处理输入向量的某几列
块划分 分块组合行列划分,适合大规模计算

19. parallel for 中静态 vs 动态线程分配

分配方式 含义 适用情况
静态 预先划分任务段 均匀负载
动态 空闲线程动态领取任务 不均匀任务(load imbalance)

20. Flynn 分类法四类

类型 特征 示例
SISD 单指令单数据 传统CPU
SIMD 单指令多数据 GPU
MISD 多指令单数据 容错系统(少见)
MIMD 多指令多数据 多核/集群系统

21. 流水线 vs 多发射

  • 流水线:将指令划分为阶段(如取指/译码/执行),指令重叠执行

  • 多发射(超标量):同周期多指令发射执行,提升吞吐率。


21. 忙等待 / 互斥量 / 信号量 / 临界区

  • 忙等待:循环检测资源,无睡眠。

  • 互斥量:互斥访问资源(lock/unlock)。

  • 信号量:支持计数、资源控制(P/V操作)。

  • 临界区:程序中访问共享资源的代码段。


22. 点对点通信 vs 集合通信

类型 含义 示例
点对点通信 单对单通信 MPI_Send / MPI_Recv
集合通信 多个进程参与,如广播、规约 MPI_Bcast / MPI_Reduce

23. 事务的4个特性

特性 全称 描述
A Atomicity(原子性) 事务中的操作要么全部执行,要么全部不执行,不能只执行一部分。
C Consistency(一致性) 执行前后数据库必须保持一致,符合数据完整性约束。
I Isolation(隔离性) 多个事务并发执行时,彼此之间不会互相干扰。
D Durability(持久性) 一旦事务提交,其结果就永久保存在数据库中,即使宕机也不会丢失。

举个实际场景总结一下:
假设你从支付宝给朋友转账:

**原子性:**转账过程要么钱成功转出并到账,要么完全失败,不能只扣钱不收钱。
**一致性:**总金额在转账前后保持不变。
**隔离性:**并发转账不会影响彼此账户的最终状态。
**持久性:**转账成功后,即使系统宕机,钱也不会“消失”或“回滚”

24.ACID 一致性和CAP一致性

ACID 一致性 —— 数据库事务的一致性
✅ 定义:
事务执行前后,数据库必须从一个一致的状态变为另一个一致的状态,满足所有数据完整性约束(如主键唯一、外键、触发器、检查约束等)。
✅ 核心目标:
保证事务内部的逻辑正确性,防止数据出现非法状态

25.CAP 一致性 —— 分布式系统中的一致性

所属领域:分布式系统(如微服务、分布式数据库)中的 CAP 定理
✅ CAP 定理三要素:
C(Consistency)一致性:对分布式系统各个节点对外的表现是一致的
A(Availability)可用性:每个请求都能收到响应(不一定是最新数据)。
P(Partition tolerance)分区容错性:系统能容忍网络分区(节点通信失败)而继续运行。

✅ CAP 中的一致性含义:
指强一致性(Strong Consistency),即:在网络正常或出现分区的情况下,所有用户访问到的数据是最新的、完全一致的。

✅ 举例说明:
有两个节点 A 和 B,当你向 A 写入了数据,立刻再从 B 读取时也必须返回这条最新数据,否则就是不一致。

26.数据冒险是什么

✅ 正确理解 Read After Write (RAW)

它是数据冒险(Data Hazard) 中最常见的一种,准确地说:

Read After Write:指一个指令试图读取某个寄存器(或内存位置),但这个寄存器正在被前一条尚未完成写入的指令所更新


举个例子说明:

1. ADD R1, R2, R3   ; R1 = R2 + R3
2. SUB R4, R1, R5   ; R4 = R1 - R5
  • 第 1 条指令正在把计算结果写入寄存器 R1

  • 第 2 条指令马上就要读取 R1,但是 R1 还没写好!

  • 这就造成了 Read After Write(RAW) Hazard


❗为什么叫 Read After Write?

因为第二条指令要 Read(读),但它依赖的值 需要在前面的指令 Write(写)之后才正确,因此叫:

Read(第二条) after Write(第一条)


⚠️ 为什么不能翻成“读后写”?

“读后写”会给人一种先读再写的错觉,好像程序顺序是:

读 -> 写

但实际是指:

第一条:写
第二条:读
→ 第二条读太早 → 冒险!

所以准确的理解应该是“写之后才可读”,而不是“读了之后再写”


✅ 更准确的翻译:

  • Read After Write:应翻译为 “写后读”

  • 表达了这个依赖关系:必须先写完,才能读


延伸:数据冒险的三种基本类型

类型 简称 示例 描述
Read After Write RAW 读用到前面尚未写好的值 ✅ 最常见
Write After Read WAR 写被排在读之前 异常情况
Write After Write WAW 两个写竞争 通常影响结果一致性

27. 简述一下raft 是啥,写出领导者选举的伪代码

领导者选举(Leader Election)相关算法
最常见的是:

算法 关键特点 场景
Bully Algorithm 编号高者优先,向高编号发起选举,收到回应则放弃 同步网络,编号唯一
Ring Algorithm 按环传递选举消息,编号最大者当选 节点构成环形结构
Raft Election 基于任期(term)、多数投票,心跳维持领导地位 实现简单、一致性强
以 Raft 为例(常考):
Leader Election 流程图(简化版)
        +--------------------+
        |   Follower         |
        | (Timeout reached)  |
        +---------+----------+
                  |
                  v
        +--------------------+
        |   Candidate        |
        |  - Increment term  |
        |  - Vote for self   |
        |  - Send RequestVote|
        +---------+----------+
                  |
        +---------+----------+
        | Majority votes?    |
        |   Yes        No    |
        v                    v
+---------------+     +-------------+
|   Leader      |     | Back to     |
| (Send heart-  |     | Follower    |
|   beats)      |     +-------------+
+---------------+

✅ C语言实现:模拟 Raft RequestVote

#include 
#include 
#include 

// ---------- 定义结构体 ----------

typedef struct {
    int term;           // 候选人当前任期
    int candidateId;    // 候选人 ID
    int lastLogIndex;   // 候选人最后一条日志索引
    int lastLogTerm;    // 候选人最后一条日志任期
} RequestVoteRequest;

typedef struct {
    int term;           // 当前节点任期
    bool voteGranted;   // 是否投票
} RequestVoteResponse;

typedef struct {
    int id;
    int currentTerm;
    int votedFor;          // -1 表示尚未投票
    int lastLogIndex;
    int lastLogTerm;
} RaftNode;

// ---------- 判断日志是否更新 ----------
// 若 a 日志比 b 更新,返回 true
bool isLogUpToDate(int candidateTerm, int candidateIndex, int localTerm, int localIndex) {
    if (candidateTerm > localTerm) return true;
    if (candidateTerm == localTerm && candidateIndex >= localIndex) return true;
    return false;
}

// ---------- 模拟处理 RequestVote 请求 ----------
RequestVoteResponse handleRequestVote(RaftNode *node, RequestVoteRequest req) {
    RequestVoteResponse resp;
    resp.term = node->currentTerm;
    resp.voteGranted = false;

    if (req.term < node->currentTerm) {
        // 候选人任期太旧,拒绝投票
        return resp;
    }

    // 若请求 term 更大,更新当前节点任期,并重置投票
    if (req.term > node->currentTerm) {
        node->currentTerm = req.term;
        node->votedFor = -1;
    }

    // 如果还没投票或者之前就投给这个 candidate
    // 并且候选人日志不落后
    if ((node->votedFor == -1 || node->votedFor == req.candidateId) &&
        isLogUpToDate(req.lastLogTerm, req.lastLogIndex, node->lastLogTerm, node->lastLogIndex)) {
        node->votedFor = req.candidateId;
        resp.voteGranted = true;
    }

    resp.term = node->currentTerm;
    return resp;
}

// ---------- 测试主函数 ----------
int main() {
    // 模拟 follower 节点
    RaftNode follower = {
        .id = 1,
        .currentTerm = 3,
        .votedFor = -1,
        .lastLogIndex = 5,
        .lastLogTerm = 3
    };

    // 模拟候选人发送投票请求
    RequestVoteRequest request = {
        .term = 4,
        .candidateId = 2,
        .lastLogIndex = 5,
        .lastLogTerm = 3
    };

    // 处理请求
    RequestVoteResponse response = handleRequestVote(&follower, request);

    // 输出结果
    printf("Follower Term: %d\n", follower.currentTerm);
    printf("Vote Granted to Candidate %d: %s\n", request.candidateId,
           response.voteGranted ? "YES" : "NO");

    return 0;
}

28. “电梯调度:事件优先 vs 时间优先”

这个问题其实很经典,常用于考察事件驱动 vs 时间驱动调度模型的理解。

✅ 电梯控制问题中的两种调度策略:
模型 描述
事件优先模型 电梯状态变化由外部事件触发(如按钮被按)。适用于低负载、响应快的场景。
时间优先模型 定期轮询电梯状态进行调度(如每秒检查一次状态)。适用于状态稳定但响应延迟。
通常参考点:

实时性要求高 → 事件优先
系统结构简单、可预测 → 时间优先
✅ 二、电梯调度:事件驱动 vs 时间驱动模型

场景题型:给定电梯调度场景,选择合适模型并解释原因

模型类型 优点 缺点 适用场景
事件驱动模型 响应快、资源高效 实现复杂 按键触发、请求频繁的系统
时间驱动模型 实现简单 易浪费资源、延迟高 状态稀疏、周期任务

答题模板(事件 vs 时间):

在本场景下,电梯响应的关键为用户输入(如按钮按下),且要求快速响应,因此应采用事件优先模型。此模型可在每次事件触发时直接调度处理,避免定期轮询所带来的资源浪费与响应延迟。

28. 行存储 和 列存储 分别是啥意思

“行存储”和“列存储”是数据库中两种数据物理存储方式。它们的最大区别在于:是按行还是按列来组织和存储数据。下面我给你通俗又系统地解释一下:


✅ 什么是行存储(Row-Oriented Storage)

存储方式:

一整行的数据作为一个整体存储在一起。

例如,有这样一张表:

ID Name Age Gender
1 Alice 23 F
2 Bob 30 M

在行存储中,物理存储是这样的(按行):

[1, Alice, 23, F], [2, Bob, 30, M]

✅ 特点:

  • 适合事务型操作(OLTP),例如插入/更新/删除整行。
  • 每次访问都能获得一行完整信息,适合频繁的随机访问。

✅ 什么是列存储(Column-Oriented Storage)

每一列的数据存储在一起。
上述表的数据在列存储中会变成这样:

ID:     [1, 2]
Name:   [Alice, Bob]
Age:    [23, 30]
Gender: [F, M]

✅ 特点:

  • 适合分析型操作(OLAP),例如统计、聚合、筛选某一列。
  • 只读取相关列即可,大大减少 I/O。
  • 通常配合压缩算法,节省空间。
特性 行存储(Row Store) 列存储(Column Store)
数据组织方式 按行存储整条记录 按列存储每个字段
适合场景 高并发写入、快速读取整行数据(OLTP) 快速聚合分析、少列访问(OLAP)
查询优化 快速读取一整行 快速读取某几列,列压缩效率高
示例系统 MySQL(InnoDB)、PostgreSQL ClickHouse、Amazon Redshift、HBase

你要查“所有用户的平均年龄”

  • 行存储要把所有行读出来(包括姓名、性别等),然后提取年龄列

  • 列存储只读年龄列即可,更快、更省资源


I/请求投票RPC RequestI/请求投票RPC Response type RequestVoteRequest struct {type RequestVoteResponse struct { termint自己当前的任期号termint川自己当前任期号 candidateld int // 自己的IDvoteGranted bool //自己会不会投票给这 lastLoglndex int//自己最后一个日志号//个candidate lastLogTermint //自己最后一个日志的任期


✅ 可能含义 1:Raft 中的任期(Term)变化与时钟模型

Raft 中“时钟题”一般是围绕:

  • 任期(term)的变化规则

  • 各节点间时间(选举超时、心跳超时)的关系

  • 事件发生顺序:如谁先成为 Candidate、是否会分裂投票


常见题型:Raft 时钟题例子

给定多个节点的超时时间和网络延迟,请判断哪个节点最可能先成为 Leader?是否会发生分裂投票?如何避免?

解题思路:
  1. 超时时间短的节点更可能最早成为 Candidate。

  2. **分裂投票(split vote)**发生在多个 Candidate 几乎同时发起选举。

  3. 引入随机超时是防止分裂投票的重要机制。


✅ 示例题(考试常见):

Raft 集群中有 3 个节点 A、B、C,其选举超时分别为 150ms、200ms、250ms。若网络没有延迟,谁最可能成为 Leader?为什么?

答案

  • A 最先超时,先发起投票。

  • 如果 B、C 接收到请求且没投过票,A 会赢得多数选票 → 成为 Leader。


✅ 可能含义 2:Lamport 时钟 / 向量时钟题

如果“RA 时钟题”不是 Raft 的简写,也可能是:

分布式系统考试里经典的“逻辑时钟”题,用来判断事件的先后关系

题型特点:

  • 给出一组事件、节点间通信

  • 要你给每个事件分配 Lamport 时钟值

  • 或者用向量时钟判断“是否并发”、“谁先发生”

示例:Lamport 时钟

事件 A1 → A2
A1 发消息给 B2
→ 问各事件的 Lamport 时钟是多少?


✅ 总结:RA 时钟题常考点

类型 涉及内容 考察点
Raft 任期时钟题 超时、term 增长、选举过程 选举机制是否正确、防止 split vote
Lamport 时钟 事件编号、消息传递 逻辑因果顺序
向量时钟 多节点时间戳数组 并发性判断(是否存在先后关系)

29. 超时例题

Raft 集群中有 3 个节点 A、B、C,选举超时分别是:

  • A:150ms

  • B:200ms

  • C:250ms

网络无延迟。问:谁最可能成为 Leader?为什么?


✅ 关键概念:Raft 中的选举超时

Raft 中每个节点在 “Follower 状态” 时会启动一个“选举超时计时器”:

  • 如果超时时间到了还没有收到来自 Leader 的心跳(AppendEntries),它就认为 Leader 挂了,会:

    • 转为 Candidate

    • 启动一次选举


✅ 步骤解析(无网络延迟):

  1. 150ms 到达时:

    • A 的选举超时先触发 → A 转为 Candidate

    • A 向 B 和 C 发送 RequestVote 请求

  2. B 和 C 的状态:

    • 当前任期一致(假设都是 term=1)

    • 没有投过票(votedFor == null

    • 如果 A 的日志不落后 → 会投票给 A

  3. A 获得了 自己 + B 或 C 的票数 = 2 票

    • 超过半数(3 个节点的一半是 2)

    • → A 成为 Leader


❗为什么不会发生分裂投票?

因为 A 先触发,B 和 C 还没超时,也就是说:

  • B、C 都还是 Follower 状态

  • 都愿意投票给第一个发来 RequestVote 的 Candidate(A)


如果网络有延迟或超时很接近怎么办?

假设 A、B 几乎同时超时(如 A=150ms,B=151ms),就可能出现:

  • A 和 B 同时发起选举、都给自己投票

  • A 请求到 C 时,C 可能已经投给 B

  • → 三个节点各自一票 / 或 2:1 分裂

这种情况就叫 分裂投票(split vote)


原因
谁先超时 谁先变成 Candidate,先发起投票
谁能赢选举 谁先获得多数投票(> N/2)
如何得票 其他节点还没投票,并且你日志不落后
如何避免冲突 随机选举超时(避免多个节点同时选)

如果你想,我可以给你扩展出多个变种题(比如有日志不一致、网络延迟、有节点宕机的情况),帮助你训练这类题目的答题思维。要来几道练练吗?


30.三阶段提交(3PC)的三个阶段

1️⃣ 阶段一:CanCommit(询问阶段
协调者向所有参与者发送 “Can you commit?”
参与者检查自己是否可以提交(如资源锁是否可用),然后回复 Yes/No。
(这里跟 2PC 的 prepare 阶段类似)
2️⃣ 阶段二:PreCommit(预提交阶段)
如果所有参与者都回复 Yes:
协调者发送 PreCommit 给所有参与者,要求进入预提交状态(写 WAL 日志、锁定资源,但暂不真正执行 Commit)。
参与者执行预提交,写入日志,并回复 ACK。
(2PC 在这里会直接 Commit,而 3PC 多了一个过渡状态)

3️⃣ 阶段三:DoCommit(正式提交阶段)
协调者收到所有参与者的 ACK 后,发送 DoCommit。
参与者正式执行 Commit,释放锁,并反馈已提交。
如果在阶段 2 或 3 发生网络异常,超时后可以通过超时和超时恢复来避免阻塞。

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