第 13 章 网络与分布式系统基础
《计算机系统:系统架构与操作系统的高度集成》
Umakishore Ramachandran & William D. Leahy Jr. 著
13.1 计算机网络概述
计算机网络(Computer Network):
将多台计算机通过通信链路连接起来,实现资源共享和信息交换的系统
网络的基本概念:
节点(Node):计算机、路由器、交换机
链路(Link):连接节点的通信信道(有线/无线)
协议(Protocol):通信规则的集合
网络分类(按覆盖范围):
PAN(个人区域网):蓝牙、NFC,覆盖范围 < 10m
LAN(局域网):以太网、Wi-Fi,覆盖范围 < 1km
MAN(城域网):覆盖一个城市
WAN(广域网):覆盖国家或全球
Internet:全球最大的 WAN
网络拓扑:
总线型:所有节点连接到同一总线(早期以太网)
星型:所有节点连接到中心交换机(现代以太网)
环型:节点形成环形(令牌环)
网状型:节点之间有多条路径(Internet)
网络性能指标:
带宽(Bandwidth):每秒传输的最大数据量(bps)
延迟(Latency):数据从源到目的地的时间(ms)
吞吐量(Throughput):实际传输速率(通常 < 带宽)
丢包率(Packet Loss Rate):丢失的数据包比例
抖动(Jitter):延迟的变化量(对实时应用重要)
13.2 网络协议栈
13.2.1 OSI 参考模型
OSI 七层模型(从上到下):
7. 应用层(Application Layer):
为应用程序提供网络服务
协议:HTTP, HTTPS, FTP, SMTP, DNS, SSH
数据单位:消息(Message)
6. 表示层(Presentation Layer):
数据格式转换、加密/解密、压缩
协议:SSL/TLS(现在通常归入应用层)
数据单位:消息
5. 会话层(Session Layer):
建立、管理、终止会话
协议:RPC, NetBIOS
数据单位:消息
4. 传输层(Transport Layer):
端到端的可靠传输
协议:TCP(可靠), UDP(不可靠)
数据单位:段(Segment)/ 数据报(Datagram)
3. 网络层(Network Layer):
路由和寻址(IP地址)
协议:IP, ICMP, ARP, OSPF, BGP
数据单位:数据包(Packet)
2. 数据链路层(Data Link Layer):
帧传输,错误检测
协议:以太网, Wi-Fi (802.11), PPP
数据单位:帧(Frame)
1. 物理层(Physical Layer):
比特传输(电信号、光信号、无线电波)
标准:RJ45, 光纤, 802.11
数据单位:比特(Bit)
数据封装过程(发送方,从上到下):
应用数据
→ 加传输层头(TCP/UDP头)→ 段
→ 加网络层头(IP头)→ 数据包
→ 加数据链路层头尾(以太网帧头+FCS)→ 帧
→ 转换为比特流传输
数据解封装过程(接收方,从下到上):
比特流
→ 去掉帧头尾 → 数据包
→ 去掉IP头 → 段
→ 去掉TCP/UDP头 → 应用数据
13.2.2 TCP/IP 协议族
TCP/IP 四层模型:
4. 应用层:HTTP, FTP, SMTP, DNS, SSH...
3. 传输层:TCP, UDP
2. 网络层:IP, ICMP, ARP
1. 网络接口层:以太网, Wi-Fi...
IP 地址:
IPv4:32位,点分十进制(192.168.1.1)
IPv6:128位,冒号十六进制(2001:db8::1)
IPv4 地址类别:
A类:1.0.0.0 ~ 126.255.255.255(大型网络)
B类:128.0.0.0 ~ 191.255.255.255(中型网络)
C类:192.0.0.0 ~ 223.255.255.255(小型网络)
私有地址(不可路由到Internet):
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
子网掩码:
192.168.1.100/24
网络地址:192.168.1.0
广播地址:192.168.1.255
主机范围:192.168.1.1 ~ 192.168.1.254
TCP vs UDP:
特性 | TCP | UDP
-------------|------------------|------------------
连接 | 面向连接(三次握手)| 无连接
可靠性 | 可靠(确认+重传) | 不可靠
顺序 | 保证顺序 | 不保证顺序
流量控制 | 是 | 否
拥塞控制 | 是 | 否
速度 | 较慢 | 较快
开销 | 大(20字节头) | 小(8字节头)
适用场景 | 文件传输、HTTP | 视频流、DNS、游戏
TCP 三次握手:
客户端 → SYN(seq=x)→ 服务器
客户端 ← SYN+ACK(seq=y, ack=x+1)← 服务器
客户端 → ACK(ack=y+1)→ 服务器
连接建立!
TCP 四次挥手:
客户端 → FIN → 服务器
客户端 ← ACK ← 服务器
客户端 ← FIN ← 服务器
客户端 → ACK → 服务器
连接关闭!
13.3 套接字编程基础
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
/* ===== TCP 服务器 ===== */
void *handle_client(void *arg) {
int client_fd = *(int *)arg;
free(arg);
char buf[1024];
int n;
/* 接收数据 */
while ((n = recv(client_fd, buf, sizeof(buf)-1, 0)) > 0) {
buf[n] = '\0';
printf("[服务器] 收到: %s", buf);
/* 回显数据 */
send(client_fd, buf, n, 0);
}
printf("[服务器] 客户端断开连接\n");
close(client_fd);
return NULL;
}
void tcp_server(int port) {
/* 1. 创建套接字 */
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) { perror("socket"); return; }
/* 设置地址重用(避免 TIME_WAIT 状态导致绑定失败)*/
int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
/* 2. 绑定地址 */
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr.s_addr = INADDR_ANY /* 监听所有网络接口 */
};
if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind"); close(server_fd); return;
}
/* 3. 监听 */
if (listen(server_fd, 5) < 0) { /* 5 = 等待队列长度 */
perror("listen"); close(server_fd); return;
}
printf("[服务器] 监听端口 %d...\n", port);
/* 4. 接受连接 */
while (1) {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int *client_fd = malloc(sizeof(int));
*client_fd = accept(server_fd,
(struct sockaddr *)&client_addr,
&client_len);
if (*client_fd < 0) { perror("accept"); free(client_fd); continue; }
printf("[服务器] 新连接: %s:%d\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
/* 为每个客户端创建线程 */
pthread_t tid;
pthread_create(&tid, NULL, handle_client, client_fd);
pthread_detach(tid);
}
close(server_fd);
}
/* ===== TCP 客户端 ===== */
void tcp_client(const char *server_ip, int port) {
/* 1. 创建套接字 */
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) { perror("socket"); return; }
/* 2. 连接服务器 */
struct sockaddr_in server_addr = {
.sin_family = AF_INET,
.sin_port = htons(port)
};
inet_pton(AF_INET, server_ip, &server_addr.sin_addr);
if (connect(sock, (struct sockaddr *)&server_addr,
sizeof(server_addr)) < 0) {
perror("connect"); close(sock); return;
}
printf("[客户端] 连接到 %s:%d\n", server_ip, port);
/* 3. 发送和接收数据 */
const char *messages[] = {
"Hello, Server!\n",
"How are you?\n",
"Goodbye!\n"
};
char buf[1024];
for (int i = 0; i < 3; i++) {
/* 发送 */
send(sock, messages[i], strlen(messages[i]), 0);
printf("[客户端] 发送: %s", messages[i]);
/* 接收回显 */
int n = recv(sock, buf, sizeof(buf)-1, 0);
if (n > 0) {
buf[n] = '\0';
printf("[客户端] 收到回显: %s", buf);
}
}
/* 4. 关闭连接 */
close(sock);
printf("[客户端] 连接关闭\n");
}
/* ===== UDP 示例 ===== */
void udp_server(int port) {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr.s_addr = INADDR_ANY
};
bind(sock, (struct sockaddr *)&addr, sizeof(addr));
printf("[UDP服务器] 监听端口 %d...\n", port);
char buf[1024];
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
/* 接收数据报 */
int n = recvfrom(sock, buf, sizeof(buf)-1, 0,
(struct sockaddr *)&client_addr, &client_len);
buf[n] = '\0';
printf("[UDP服务器] 收到来自 %s:%d 的数据: %s\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port), buf);
/* 回复 */
const char *reply = "UDP Reply!";
sendto(sock, reply, strlen(reply), 0,
(struct sockaddr *)&client_addr, client_len);
close(sock);
}
void udp_client(const char *server_ip, int port) {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in server_addr = {
.sin_family = AF_INET,
.sin_port = htons(port)
};
inet_pton(AF_INET, server_ip, &server_addr.sin_addr);
/* 发送数据报(无需建立连接)*/
const char *msg = "Hello UDP!";
sendto(sock, msg, strlen(msg), 0,
(struct sockaddr *)&server_addr, sizeof(server_addr));
printf("[UDP客户端] 发送: %s\n", msg);
/* 接收回复 */
char buf[1024];
int n = recvfrom(sock, buf, sizeof(buf)-1, 0, NULL, NULL);
buf[n] = '\0';
printf("[UDP客户端] 收到: %s\n", buf);
close(sock);
}
/* ===== 简单 HTTP 服务器 ===== */
void simple_http_server(int port) {
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr.s_addr = INADDR_ANY
};
bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
listen(server_fd, 5);
printf("[HTTP服务器] 监听端口 %d...\n", port);
printf(" 访问: http://localhost:%d/\n", port);
int client_fd = accept(server_fd, NULL, NULL);
/* 读取 HTTP 请求 */
char request[4096];
int n = recv(client_fd, request, sizeof(request)-1, 0);
request[n] = '\0';
printf("[HTTP服务器] 收到请求:\n%s\n", request);
/* 发送 HTTP 响应 */
const char *body = "<html><body><h1>Hello, World!</h1>"
"<p>Simple HTTP Server</p></body></html>";
char response[1024];
snprintf(response, sizeof(response),
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Content-Length: %zu\r\n"
"Connection: close\r\n"
"\r\n"
"%s",
strlen(body), body);
send(client_fd, response, strlen(response), 0);
printf("[HTTP服务器] 发送响应\n");
close(client_fd);
close(server_fd);
}
int main() {
printf("=== 套接字编程演示 ===\n\n");
/* 演示 TCP 通信(使用 fork 模拟客户端和服务器)*/
printf("TCP 通信演示:\n");
int port = 8888;
pid_t pid = fork();
if (pid == 0) {
/* 子进程:客户端 */
sleep(1); /* 等待服务器启动 */
tcp_client("127.0.0.1", port);
exit(0);
} else {
/* 父进程:服务器(只处理一个连接)*/
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr.s_addr = INADDR_ANY
};
bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
listen(server_fd, 1);
printf("[服务器] 监听端口 %d...\n", port);
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_fd = accept(server_fd,
(struct sockaddr *)&client_addr,
&client_len);
printf("[服务器] 客户端连接: %s:%d\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
char buf[1024];
int n;
while ((n = recv(client_fd, buf, sizeof(buf)-1, 0)) > 0) {
buf[n] = '\0';
printf("[服务器] 收到: %s", buf);
send(client_fd, buf, n, 0);
}
close(client_fd);
close(server_fd);
int status;
wait(&status);
}
return 0;
}
13.4 分布式系统概念
13.4.1 分布式系统的特征
分布式系统(Distributed System):
多台计算机通过网络协作,对用户呈现为单一系统
分布式系统的特征:
并发性(Concurrency):
多个节点同时执行
需要协调并发访问共享资源
缺乏全局时钟(No Global Clock):
各节点时钟不同步
难以确定事件的全局顺序
解决:逻辑时钟(Lamport 时钟)、向量时钟
故障独立性(Independent Failures):
部分节点故障不影响整体
需要容错机制
异构性(Heterogeneity):
不同硬件、操作系统、编程语言
需要统一的通信协议
分布式系统的挑战:
网络延迟和不可靠性
节点故障
数据一致性
安全性
可扩展性
CAP 定理(Brewer 定理):
分布式系统不能同时满足以下三个特性:
C(Consistency):一致性------所有节点看到相同的数据
A(Availability):可用性------每个请求都能得到响应
P(Partition Tolerance):分区容错------网络分区时仍能工作
实际系统必须在 CA、CP、AP 中选择:
CA:传统关系数据库(MySQL,不支持分区)
CP:ZooKeeper、HBase(一致性优先)
AP:Cassandra、DynamoDB(可用性优先)
13.4.2 远程过程调用(RPC)
c
/* RPC(Remote Procedure Call)概念演示 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* RPC 消息格式 */
typedef struct {
int request_id; /* 请求ID */
char function[32]; /* 函数名 */
int arg1; /* 参数1 */
int arg2; /* 参数2 */
} RPCRequest;
typedef struct {
int request_id; /* 对应的请求ID */
int result; /* 返回值 */
int error; /* 错误码(0=成功)*/
} RPCResponse;
/* RPC 服务器端:实现远程函数 */
int rpc_add(int a, int b) { return a + b; }
int rpc_multiply(int a, int b) { return a * b; }
int rpc_subtract(int a, int b) { return a - b; }
void rpc_server(int port) {
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr.s_addr = INADDR_ANY
};
bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
listen(server_fd, 5);
printf("[RPC服务器] 监听端口 %d\n", port);
int client_fd = accept(server_fd, NULL, NULL);
RPCRequest req;
RPCResponse resp;
while (recv(client_fd, &req, sizeof(req), 0) > 0) {
printf("[RPC服务器] 收到请求: ID=%d, 函数=%s(%d,%d)\n",
req.request_id, req.function, req.arg1, req.arg2);
resp.request_id = req.request_id;
resp.error = 0;
/* 根据函数名调用对应函数 */
if (strcmp(req.function, "add") == 0) {
resp.result = rpc_add(req.arg1, req.arg2);
} else if (strcmp(req.function, "multiply") == 0) {
resp.result = rpc_multiply(req.arg1, req.arg2);
} else if (strcmp(req.function, "subtract") == 0) {
resp.result = rpc_subtract(req.arg1, req.arg2);
} else {
resp.error = -1;
resp.result = 0;
}
printf("[RPC服务器] 返回结果: %d\n", resp.result);
send(client_fd, &resp, sizeof(resp), 0);
}
close(client_fd);
close(server_fd);
}
/* RPC 客户端:调用远程函数(看起来像本地调用)*/
int rpc_sock = -1;
int rpc_request_id = 0;
/* 客户端存根(Stub):将本地调用转换为网络请求 */
int remote_add(int a, int b) {
RPCRequest req = {
.request_id = ++rpc_request_id,
.arg1 = a,
.arg2 = b
};
strncpy(req.function, "add", sizeof(req.function));
send(rpc_sock, &req, sizeof(req), 0);
RPCResponse resp;
recv(rpc_sock, &resp, sizeof(resp), 0);
if (resp.error != 0) {
printf("RPC错误: %d\n", resp.error);
return -1;
}
return resp.result;
}
int remote_multiply(int a, int b) {
RPCRequest req = {
.request_id = ++rpc_request_id,
.arg1 = a,
.arg2 = b
};
strncpy(req.function, "multiply", sizeof(req.function));
send(rpc_sock, &req, sizeof(req), 0);
RPCResponse resp;
recv(rpc_sock, &resp, sizeof(resp), 0);
return resp.result;
}
void rpc_client(const char *server_ip, int port) {
rpc_sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr = {
.sin_family = AF_INET,
.sin_port = htons(port)
};
inet_pton(AF_INET, server_ip, &server_addr.sin_addr);
connect(rpc_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
printf("[RPC客户端] 连接到服务器\n");
/* 调用远程函数(看起来像本地调用!)*/
int result1 = remote_add(3, 5);
printf("[RPC客户端] remote_add(3, 5) = %d\n", result1);
int result2 = remote_multiply(4, 7);
printf("[RPC客户端] remote_multiply(4, 7) = %d\n", result2);
int result3 = remote_add(result1, result2);
printf("[RPC客户端] remote_add(%d, %d) = %d\n", result1, result2, result3);
close(rpc_sock);
}
int main() {
printf("=== RPC 演示 ===\n\n");
int port = 9999;
pid_t pid = fork();
if (pid == 0) {
sleep(1);
rpc_client("127.0.0.1", port);
exit(0);
} else {
rpc_server(port);
wait(NULL);
}
return 0;
}
13.4.3 分布式文件系统
分布式文件系统(Distributed File System):
将文件存储在多台服务器上,对用户呈现为统一的文件系统
NFS(Network File System):
Sun Microsystems 开发(1984)
Unix/Linux 系统广泛使用
工作原理:
客户端挂载远程目录
文件操作通过 RPC 发送到服务器
服务器执行操作并返回结果
挂载示例:
mount -t nfs 192.168.1.100:/shared /mnt/nfs
特点:
透明性:用户感觉不到文件在远程
无状态:服务器不保存客户端状态(简化故障恢复)
缓存:客户端缓存文件数据(提高性能)
HDFS(Hadoop Distributed File System):
为大数据处理设计
架构:
NameNode:存储文件系统元数据(目录结构、文件块位置)
DataNode:存储实际数据块(默认128MB/块)
特点:
高容错:每个数据块默认3个副本
高吞吐量:优化顺序读写(不适合随机访问)
大文件:适合存储GB~TB级别的大文件
写入流程:
1. 客户端向 NameNode 请求写入
2. NameNode 分配 DataNode 列表
3. 客户端将数据写入第一个 DataNode
4. 第一个 DataNode 将数据复制到第二个
5. 第二个复制到第三个
6. 写入完成,通知 NameNode
GFS(Google File System):
Google 内部使用(2003年论文)
HDFS 的设计参考
设计假设:
节点故障是常态(使用廉价商用服务器)
文件通常很大(GB级别)
大多数写操作是追加(Append),而非随机写
高吞吐量比低延迟更重要
13.5 网络操作系统
网络操作系统(Network Operating System):
提供网络服务的操作系统
主要功能:
文件共享(NFS, SMB/CIFS)
打印机共享
用户认证(LDAP, Active Directory)
网络管理
现代网络服务:
DNS(Domain Name System):
将域名转换为IP地址
例:www.google.com → 142.250.80.36
查询过程:
1. 客户端查询本地缓存
2. 查询本地 DNS 服务器
3. 本地 DNS 查询根 DNS 服务器
4. 根 DNS 返回顶级域(.com)DNS 服务器地址
5. 查询顶级域 DNS 服务器
6. 返回权威 DNS 服务器地址
7. 查询权威 DNS 服务器
8. 返回 IP 地址
DHCP(Dynamic Host Configuration Protocol):
自动分配 IP 地址
客户端广播 DHCP Discover
服务器回复 DHCP Offer(提供IP地址)
客户端发送 DHCP Request(接受IP地址)
服务器发送 DHCP ACK(确认)
HTTP/HTTPS:
Web 通信协议
HTTP/1.1:持久连接,管道化
HTTP/2:多路复用,头部压缩,服务器推送
HTTP/3:基于 QUIC(UDP),减少延迟
c
/* DNS 查询演示 */
#include <stdio.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
void dns_lookup_demo() {
printf("=== DNS 查询演示 ===\n\n");
const char *hostnames[] = {
"www.google.com",
"www.baidu.com",
"localhost"
};
for (int i = 0; i < 3; i++) {
printf("查询 %s:\n", hostnames[i]);
struct hostent *he = gethostbyname(hostnames[i]);
if (!he) {
printf(" 查询失败\n");
continue;
}
printf(" 官方名称: %s\n", he->h_name);
/* 打印所有 IP 地址 */
for (int j = 0; he->h_addr_list[j]; j++) {
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, he->h_addr_list[j], ip, sizeof(ip));
printf(" IP地址[%d]: %s\n", j, ip);
}
/* 打印别名 */
for (int j = 0; he->h_aliases[j]; j++) {
printf(" 别名[%d]: %s\n", j, he->h_aliases[j]);
}
printf("\n");
}
}
/* 反向 DNS 查询(IP → 域名)*/
void reverse_dns_demo() {
printf("=== 反向 DNS 查询 ===\n\n");
const char *ips[] = {"8.8.8.8", "1.1.1.1", "127.0.0.1"};
for (int i = 0; i < 3; i++) {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_pton(AF_INET, ips[i], &addr.sin_addr);
char hostname[256];
int ret = getnameinfo((struct sockaddr *)&addr, sizeof(addr),
hostname, sizeof(hostname),
NULL, 0, 0);
if (ret == 0) {
printf("%s → %s\n", ips[i], hostname);
} else {
printf("%s → 查询失败\n", ips[i]);
}
}
}
int main() {
dns_lookup_demo();
reverse_dns_demo();
return 0;
}
本章小结
| 知识点 | 核心内容 | 重要程度 |
|---|---|---|
| 网络概述 | 节点/链路/协议,LAN/WAN,性能指标 | ⭐⭐⭐⭐ |
| OSI七层模型 | 各层功能、协议、数据单位 | ⭐⭐⭐⭐⭐ |
| TCP/IP四层 | 应用/传输/网络/网络接口 | ⭐⭐⭐⭐⭐ |
| IP地址 | IPv4/IPv6,子网掩码,私有地址 | ⭐⭐⭐⭐⭐ |
| TCP vs UDP | 可靠vs不可靠,适用场景 | ⭐⭐⭐⭐⭐ |
| TCP三次握手 | SYN→SYN+ACK→ACK | ⭐⭐⭐⭐⭐ |
| 套接字编程 | socket/bind/listen/accept/connect/send/recv | ⭐⭐⭐⭐⭐ |
| 分布式系统特征 | 并发/无全局时钟/故障独立/异构 | ⭐⭐⭐⭐ |
| CAP定理 | 一致性/可用性/分区容错,三选二 | ⭐⭐⭐⭐⭐ |
| RPC | 远程调用看起来像本地调用,存根机制 | ⭐⭐⭐⭐⭐ |
| NFS/HDFS | 分布式文件系统,透明性,容错 | ⭐⭐⭐⭐ |
| DNS | 域名→IP,递归查询,缓存 | ⭐⭐⭐⭐ |
思考题
- TCP 为什么需要三次握手而不是两次?
- CAP 定理说不能同时满足三个特性,为什么?
- RPC 的"透明性"是什么意思?它有什么局限性?
- HDFS 为什么将每个数据块默认存储3个副本?
- DNS 查询为什么使用 UDP 而不是 TCP?
参考文献:Umakishore Ramachandran & William D. Leahy Jr.,《计算机系统:系统架构与操作系统的高度集成》