Skip to content
Published on

网络工程与安全完全指南:从 TCP/IP 到服务网格、AI 服务网络

分享
Authors

目录

  1. 网络基础: OSI & TCP/IP
  2. 套接字编程: asyncio & aiohttp
  3. 服务网格: Istio & Envoy
  4. 网络安全: TLS & Zero Trust
  5. CDN & 边缘计算
  6. AI 服务网络: gRPC & SSE
  7. 抓包分析实战
  8. 测验

1. 网络基础

OSI 7 层模型

OSI(Open Systems Interconnection)模型是把网络通信抽象为 7 个层次的参考模型。

名称协议示例PDU
7ApplicationHTTP, DNS, SMTPMessage
6PresentationTLS, JPEG, ASCIIMessage
5SessionNetBIOS, RPCMessage
4TransportTCP, UDPSegment
3NetworkIP, ICMPPacket
2Data LinkEthernet, 802.11Frame
1Physical线缆、光纤Bits

TCP/IP 协议栈

实际的互联网使用比 OSI 更简化的 4 层 TCP/IP 模型。

  • Application Layer:HTTP/2、HTTP/3、DNS、TLS
  • Transport Layer:TCP(可靠性)、UDP(速度)
  • Internet Layer:IPv4、IPv6、ICMP
  • Link Layer:Ethernet、Wi-Fi

HTTP/2 与 HTTP/3 的区别

HTTP/1.1 在一个连接上一次只能处理一个请求,因此会出现队头阻塞(Head-of-Line, HOL blocking)。

HTTP/2 的改进点:

  • 多路复用:在一个 TCP 连接上同时处理多个流
  • 头部压缩:用 HPACK 算法消除重复的头部
  • 服务器推送:无需客户端请求即可主动推送资源
  • 二进制分帧:使用二进制帧而非文本

HTTP/3 & QUIC: HTTP/3 运行在 QUIC(基于 UDP)之上而非 TCP,因此连 TCP 层面的队头阻塞也一并解决了。

HTTP/1.1:  [Req1][Res1][Req2][Res2]  (顺序)
HTTP/2:    [Req1, Req2, Req3][Res1, Res2, Res3]  (多路复用,单一 TCP)
HTTP/3:    [Req1, Req2, Req3][Res1, Res2, Res3]  (多路复用,独立 QUIC)

DNS 的工作原理

查询 api.example.com 时的流程:

  1. 检查浏览器缓存
  2. 检查 OS 缓存(/etc/hosts)
  3. 向 Recursive Resolver(ISP DNS)发起查询
  4. 按 Root NS → .com TLD NS → example.com Authoritative NS 的顺序层层查询
  5. 返回 A 记录(IPv4)或 AAAA 记录(IPv6)

TLS 1.3 握手

TLS 1.3 相比旧版本减少了往返次数,新连接为 1-RTT,重连为 0-RTT 即可建立会话。

Client                          Server
  |--- ClientHello (密钥交换) --->|
  |<-- ServerHello + Certificate-|
  |<-- + EncryptedExtensions -----|
  |--- Finished ----------------->|
  |<-> 加密数据交换 <------>|

2. 套接字编程

Python asyncio TCP 服务器

import asyncio

async def handle_client(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
    addr = writer.get_extra_info('peername')
    print(f"连接建立: {addr}")

    try:
        while True:
            data = await reader.read(1024)
            if not data:
                break
            message = data.decode('utf-8').strip()
            print(f"收到: {message} from {addr}")

            # 回显响应
            response = f"Echo: {message}\n"
            writer.write(response.encode('utf-8'))
            await writer.drain()
    except asyncio.IncompleteReadError:
        pass
    finally:
        print(f"连接关闭: {addr}")
        writer.close()
        await writer.wait_closed()

async def main():
    server = await asyncio.start_server(
        handle_client, '0.0.0.0', 8888
    )
    addr = server.sockets[0].getsockname()
    print(f"服务器已启动: {addr}")

    async with server:
        await server.serve_forever()

if __name__ == '__main__':
    asyncio.run(main())

使用 aiohttp 的异步 HTTP 客户端

import asyncio
import aiohttp
from typing import List

async def fetch_url(session: aiohttp.ClientSession, url: str) -> dict:
    async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response:
        return {
            'url': url,
            'status': response.status,
            'body': await response.text()
        }

async def fetch_all(urls: List[str]) -> List[dict]:
    connector = aiohttp.TCPConnector(
        limit=100,          # 最大并发连接数
        limit_per_host=10,  # 每个主机的最大连接数
        keepalive_timeout=30
    )
    async with aiohttp.ClientSession(connector=connector) as session:
        tasks = [fetch_url(session, url) for url in urls]
        return await asyncio.gather(*tasks, return_exceptions=True)

# 执行
urls = [f"https://httpbin.org/get?id={i}" for i in range(20)]
results = asyncio.run(fetch_all(urls))

gRPC 与 REST 对比

项目gRPCREST
协议HTTP/2HTTP/1.1 or HTTP/2
序列化Protocol Buffers(二进制)JSON(文本)
流式传输支持双向流式传输有限(SSE、WebSocket 需另行搭建)
类型安全强类型(.proto 模式)弱类型
延迟相对更高
浏览器支持需要 grpc-web原生支持

3. 服务网格

Istio 架构

Istio 以边车(sidecar)模式把 Envoy 代理注入每个 Pod,从而控制服务间通信。

  • Control Plane(Istiod):管理配置、签发证书、下发流量策略
  • Data Plane(Envoy Sidecar):处理实际流量、采集指标、实施 mTLS

VirtualService 配置示例

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ml-inference-vs
  namespace: production
spec:
  hosts:
    - ml-inference-svc
  http:
    - match:
        - headers:
            x-model-version:
              exact: 'v2'
      route:
        - destination:
            host: ml-inference-svc
            subset: v2
          weight: 100
    - route:
        - destination:
            host: ml-inference-svc
            subset: v1
          weight: 90
        - destination:
            host: ml-inference-svc
            subset: v2
          weight: 10

负载均衡算法

  • Round Robin:按顺序分散(默认值)
  • Least Connections:选择活跃连接数最少的服务器
  • Weighted Round Robin:基于权重分散
  • IP Hash:以客户端 IP 固定到特定服务器(会话保持)
  • Consistent Hashing:在分布式缓存环境下增减服务器时,将重新分布降到最低

服务发现

在 Kubernetes 环境中,由 CoreDNS 负责服务发现。以 service-name.namespace.svc.cluster.local 的格式访问服务。


4. 网络安全

TLS 证书链

Root CA (最上层证书机构,内置于浏览器/操作系统)
  └── Intermediate CA (中间证书机构)
        └── Leaf Certificate (实际的服务器证书)

每张证书都由上一级 CA 的私钥签名,从而形成信任链。

mTLS(Mutual TLS)

普通 TLS 只由服务器一方出示证书。mTLS 则要求客户端也出示证书,实现双向认证。

普通 TLS:  Client[验证服务器证书]Server
mTLS:      Client[双向验证证书]Server

在服务网格中,mTLS 会自动加密并认证边车代理之间的通信。

Nginx TLS 配置

server {
    listen 443 ssl http2;
    server_name api.example.com;

    ssl_certificate     /etc/ssl/certs/server.crt;
    ssl_certificate_key /etc/ssl/private/server.key;

    # 仅允许 TLS 1.2 以上
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;

    # HSTS (1 年)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;

    location /api/ {
        proxy_pass http://backend_pool;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Zero Trust 架构

Zero Trust 的核心原则:"永不信任,始终验证(Never Trust, Always Verify)"

  • 基于身份的访问控制:以用户/服务身份而非 IP 地址进行认证
  • 最小权限原则:只允许访问必要的资源
  • 持续验证:会话期间也持续评估信任等级
  • 微分段(Micro-segmentation):把网络划分为更小的区域,阻断横向移动

JWT & OAuth 2.0

JWT(JSON Web Token)由三部分组成: Header.Payload.Signature

OAuth 2.0 授权码流程(Authorization Code Flow):

  1. 客户端重定向到 Authorization Server
  2. 用户完成认证后,签发 Authorization Code
  3. 后端用 Code 换取 Access Token
  4. 用 Access Token 调用 Resource Server API

5. CDN & 边缘计算

CDN 工作原理

CDN(Content Delivery Network)通过在全球各地的 PoP(Point of Presence)缓存内容,降低延迟。

缓存策略:

  • Cache-Control: max-age=86400:在浏览器与 CDN 上缓存 1 天
  • Cache-Control: no-cache:始终向源服务器重新验证
  • ETag / Last-Modified:用条件请求确认内容是否有变化

Cloudflare Workers 示例

export default {
  async fetch(request, env) {
    const url = new URL(request.url)

    // 在边缘节点路由 AI 推理
    if (url.pathname.startsWith('/inference/')) {
      const modelId = url.searchParams.get('model') || 'default'

      // 路由到最近的 GPU 集群
      const region = request.cf.region
      const backendUrl = selectBackend(region, modelId)

      return fetch(backendUrl, {
        method: request.method,
        headers: request.headers,
        body: request.body,
      })
    }

    // 静态资源缓存
    const cache = caches.default
    const cachedResponse = await cache.match(request)
    if (cachedResponse) return cachedResponse

    const response = await fetch(request)
    // 只缓存成功响应
    if (response.status === 200) {
      const responseToCache = response.clone()
      await cache.put(request, responseToCache)
    }
    return response
  },
}

6. AI 服务网络

用 gRPC 做 ML 模型服务

Protocol Buffers 定义:

syntax = "proto3";
package inference;

service InferenceService {
  rpc Predict(PredictRequest) returns (PredictResponse);
  rpc StreamPredict(PredictRequest) returns (stream PredictResponse);
}

message PredictRequest {
  string model_name = 1;
  repeated float input_data = 2;
  map<string, string> metadata = 3;
}

message PredictResponse {
  repeated float output_data = 1;
  float confidence = 2;
  int64 latency_ms = 3;
}

Python gRPC 服务器:

import grpc
from concurrent import futures
import inference_pb2
import inference_pb2_grpc
import numpy as np
import time

class InferenceServicer(inference_pb2_grpc.InferenceServiceServicer):
    def Predict(self, request, context):
        start = time.time()
        input_array = np.array(request.input_data)

        # 实际模型推理(示例)
        output = input_array * 2.0

        latency = int((time.time() - start) * 1000)
        return inference_pb2.PredictResponse(
            output_data=output.tolist(),
            confidence=0.95,
            latency_ms=latency
        )

    def StreamPredict(self, request, context):
        # 流式响应(可用于 LLM 生成 token 等场景)
        tokens = ["你", "好", "!", " gRPC", " 流式传输", "。"]
        for token in tokens:
            yield inference_pb2.PredictResponse(
                output_data=[float(ord(c)) for c in token],
                confidence=0.9,
                latency_ms=10
            )

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    inference_pb2_grpc.add_InferenceServiceServicer_to_server(
        InferenceServicer(), server
    )
    server.add_insecure_port('[::]:50051')
    server.start()
    print("gRPC 服务器已启动: 端口 50051")
    server.wait_for_termination()

用 SSE 做 LLM 实时流式传输

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import asyncio
import json

app = FastAPI()

async def llm_token_generator(prompt: str):
    """以 SSE 格式流式发送 LLM token"""
    # 实际环境中应使用 LLM 库
    tokens = prompt.split() + ["[完成]"]
    for i, token in enumerate(tokens):
        data = json.dumps({"token": token, "index": i})
        yield f"data: {data}\n\n"
        await asyncio.sleep(0.05)  # 模拟 token 生成延迟
    yield "data: [DONE]\n\n"

@app.get("/stream")
async def stream_llm(prompt: str = "你好"):
    return StreamingResponse(
        llm_token_generator(prompt),
        media_type="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "X-Accel-Buffering": "no",  # 关闭 Nginx 缓冲
        }
    )

7. 抓包分析实战

tcpdump 基本命令

# 在特定网卡上抓取 HTTP 流量
sudo tcpdump -i eth0 -w capture.pcap port 80 or port 443

# 只过滤 TCP 握手(SYN 包)
sudo tcpdump -i any 'tcp[tcpflags] & tcp-syn != 0'

# 与特定主机的通信
sudo tcpdump -i eth0 host 10.0.0.1 -n

# 监控 DNS 查询
sudo tcpdump -i any udp port 53 -v

# gRPC(HTTP/2)流量
sudo tcpdump -i eth0 port 50051 -w grpc_trace.pcap

用 curl 做网络调试

# 查看 TLS 证书信息
curl -vI https://api.example.com 2>&1 | grep -A 20 "SSL connection"

# 确认是否使用了 HTTP/2
curl --http2 -I https://api.example.com

# 测量响应时间
curl -o /dev/null -s -w \
  "DNS: %{time_namelookup}s\nTCP: %{time_connect}s\nTLS: %{time_appconnect}s\nTotal: %{time_total}s\n" \
  https://api.example.com

# 测试 gRPC 端点(grpcurl)
grpcurl -plaintext localhost:50051 list
grpcurl -plaintext -d '{"model_name": "bert", "input_data": [1.0, 2.0]}' \
  localhost:50051 inference.InferenceService/Predict

网络性能指标

  • RTT(Round-Trip Time):数据包往返时间,用 ping 测量
  • Throughput:单位时间的传输数据量,用 iperf3 测量
  • Packet Loss:丢包率,在不稳定的 UDP 环境中尤为重要
  • Jitter:RTT 的抖动,对实时流式传输很重要
# 测量网络带宽
iperf3 -s  # 服务器
iperf3 -c server_ip -t 30 -P 4  # 客户端(4 个并行流)

测验

Q1. 请说明 TCP 三次握手与四次挥手的过程。

答案

三次握手(建立连接):

  1. Client → Server: SYN (seq=x)
  2. Server → Client: SYN-ACK (seq=y, ack=x+1)
  3. Client → Server: ACK (ack=y+1)

四次挥手(断开连接):

  1. Client → Server: FIN
  2. Server → Client: ACK
  3. Server → Client: FIN
  4. Client → Server: ACK (经过 TIME_WAIT 状态后彻底断开)

解析:断开连接需要四步,是因为服务器收到 FIN 之后可能仍有数据要发送。客户端发出 ACK 之后会维持 TIME_WAIT 状态 2MSL(Maximum Segment Lifetime)的时长,以处理延迟到达的数据包。

Q2. 请说明 HTTP/2 的多路复用如何解决 HTTP/1.1 的队头阻塞问题。

答案:HTTP/2 在一个 TCP 连接上同时传输多个流。每个流都有独立的 ID,某一个流的处理被延迟,也不会影响到其他流。

解析:HTTP/1.1 虽然支持流水线(pipelining),但响应必须按请求顺序返回,前面的响应一慢,后面的响应也要跟着等待(队头阻塞)。HTTP/2 通过按帧交错传输解决了这一问题,但 TCP 层面的队头阻塞,要到 HTTP/3(QUIC)才彻底解决。

Q3. 请说明 mTLS 与普通 TLS 的区别,以及它在服务网格中的作用。

答案:普通 TLS 只验证服务器证书,而 mTLS(Mutual TLS)要求客户端也出示证书,实现双向认证。

解析:在服务网格(如 Istio)中,mTLS 由边车代理(Envoy)自动处理。每个服务都会被签发一张带有唯一 SPIFFE ID 的 X.509 证书,服务间通信时据此完成相互认证与加密。这样即使在内部网络中,也能防止窃听、伪造和中间人攻击。

Q4. 请说明为什么 gRPC 比 REST API 更适合 ML 模型服务。

答案:gRPC 使用 Protocol Buffers 做二进制序列化,基于 HTTP/2 多路复用,并支持双向流式传输,因此在 ML 服务场景中更为优化。

解析:在传输大体量张量数据时,Protocol Buffers 生成的负载体积比 JSON 小 3-5 倍。通过服务器端流式传输,可以把 LLM 生成的 token 实时传给客户端。此外,.proto 模式清晰定义了 API 契约,在 ML 流水线集成时能保证类型安全。

Q5. 请说明 CDN 缓存失效(invalidation)策略的种类及其权衡。

答案:主要策略包括基于 TTL 的过期、基于版本的 URL、通过 API 的即时失效,以及基于代理键(标签)的失效。

解析

  • 基于 TTL:实现简单,但在过期之前可能会提供陈旧内容
  • 版本化 URL(style.v2.css):既保持缓存命中率,又能立即更新,缺点是 URL 管理更复杂
  • 即时失效 API:能快速生效,但会产生 CDN 费用,且存在传播延迟(数十秒)
  • 代理键(Surrogate Key):可以一次性使一组相关内容失效(如 Cloudflare Cache Tags)

在实际运维中,通常组合使用:静态资源(JS/CSS)用版本化 URL,API 响应用短 TTL + 即时失效。