📚 第一章 网络基础知识
📄 一句话概括

二层看 MAC、三层看 IP,四到七层看的是内容:端口号、URL、Cookie。 看得越深,能力越强,代价是性能与加密的墙。

📝 本节和前面几节的关系

1.9.5 的路由器「只管把包送到」,这一层开始管「送给谁、怎么分」。 这一节讲的是负载均衡器的原理,1.9.7 讲网关。

一、看内容意味着什么

每往上一层,能看的东西就多一层:

层 看什么 能做的决定
二层 MAC 往哪个口转发
三层 IP 往哪个网段转发
四层 端口号 是 HTTP 还是数据库
七层 URL、Cookie、头 按用户、按路径分发

第三行是「四层」的分水岭:只看端口号就能分出「这是网页、这是数据库、这是邮件」, 这已经能支撑大部分分流需求了。 而且四层不需要解析应用协议,性能高得多。 第四行才是「七层」的价值: 按 URL 把 /api 转给一组服务器、/static 转给另一组;按 Cookie 做灰度发布。 这些都必须看到应用层内容才能做到。 代价是必须完整解析,而且加密之后看不到了。

二、三种分发算法

同样三台服务器,三种算法给出三种分布:

算法 依据 分布
轮询 按顺序挨个发 S1:4/S2:4/S3:4
最少连接 看谁当前连接少 S1:6/S2:4/S3:2
源地址哈希 同一用户固定一台 S1:1/S2:5/S3:6

三种数字都不一样,正好说明各管一件事: 轮询保证「次数均匀」,哈希保证「同一用户总是同一台」。 后者对「有会话状态」的应用是必须的——否则第一次登录在 S1、第二次请求到 S2,会话就丢了。 第二行那个「最少连接」看起来最聪明,但它有代价: 必须实时统计连接数,这本身有开销;而且短连接场景下统计是滞后的—— 刚分给 S1 的请求还没建立连接,统计里看不出来。 所以真实负载均衡器通常是「加权轮询 + 健康检查」的组合。 第三行那个哈希有个明显的坑:服务器数量一变,几乎所有用户的落点都会变, 缓存全失效、会话全丢。 这就是「一致性哈希」被发明出来的原因——它把「增删一台机器」的影响限制在一小部分 key 上。

三、看得越深,代价越大

三层代价,一层比一层硬:

代价 表现 缓解
性能 要解析、要缓冲 硬件卸载
加密 TLS 之后看不到内容 在网关处解密
状态 要记住会话 会话同步/粘性

第二行是今天最现实的一道墙:七层设备要看 URL,就必须先解密。 所以它变成了「TLS 的终点」——客户端到它这一段是加密的,它到后端那一段可能又是加密的。 这也意味着「七层设备能看到你所有的明文」,所以它同时是一个巨大的信任点与风险点。 第三行那个「状态」是可用性的隐患:多台七层设备之间要同步会话,否则用户换一台就掉登录。 同步本身又是一条要保证的链路——这就是「设备越聪明,架构越复杂」的典型例子。 所以选型的原则很简单:能用四层解决就别上七层。 按 IP 或端口能分清的,就不必去解析 HTTP。

四、动手 Demo:四到七层交换机,其实是「按内容分发」

模拟三种分发算法,看十个请求怎么落到三台服务器上。 三台的容量故意设成 6/4/2,才能看出「最少连接」的差别。

import zlib

caps = {'S1': 6, 'S2': 4, 'S3': 2}
reqs = ['u%d' % i for i in range(12)]

rr = {k: 0 for k in caps}
for i, _ in enumerate(reqs):
    rr[list(caps)[i % 3]] += 1

lc = {k: 0 for k in caps}
for _ in reqs:
    k = min(lc, key=lambda x: (lc[x] / caps[x], lc[x]))
    lc[k] += 1

hh = {k: 0 for k in caps}
names = list(caps)
for r in reqs:
    hh[names[zlib.crc32(r.encode()) % 3]] += 1

for tag, d in (('轮询', rr), ('最少连接', lc), ('源地址哈希', hh)):
    print('%-10s %s' % (tag, '/'.join('%s:%d' % (k, d[k]) for k in caps)))

实跑输出:

--------------------------------------------------------------------
四到七层交换机,其实是「按内容分发」
--------------------------------------------------------------------
**二层看 MAC、三层看 IP,四到七层看的是「内容」**——**端口号、URL、Cookie,甚至 HTTP 头。**

下面模拟三种常见的分发算法,看流量分布:

  算法           依据                         分布
  -------------------------------------------------------------
  轮询           **按顺序挨个发**             S1:4/S2:4/S3:4
  最少连接       **看谁当前连接少**           S1:6/S2:4/S3:2
  源地址哈希     **同一用户固定落到一台**     S1:1/S2:5/S3:6

**三行的数字都不一样,正好说明三种算法各管一件事**:
**轮询保证「次数均匀」,哈希保证「同一用户总是同一台」。**
**后者对「有会话状态」的应用是必须的**:**否则第一次登录在 S1、第二次请求到 S2,会话就丢了。**

**「最少连接」看起来最聪明,但它需要实时统计连接数**,
**这本身就有开销,而且短连接场景下统计滞后。**
**所以真实负载均衡器通常是「加权轮询 + 健康检查」的组合。**

轮询是 4/4/4(12 个请求平均分),最少连接是 6/4/2(按 6:4:2 的容量比例分), 哈希是 1/5/6(按 crc32 取模,分布不均)。 哈希那一行最能说明问题:它保证「同一个 key 总落同一台」,但不保证「负载均匀」。 十二个 key 分到三台,本来就是随机的,偏成这样很正常。 所以哈希适合「要粘性」的场景,不适合「要均衡」的场景。 最少连接那一行能分出 6/4/2,是因为把容量写进了比较式: lc[x] / caps[x] 表示「当前负载占容量的比例」,取最小的那台。 如果三台容量相同,它就退化成「平均分」。

30 秒实验

  1. 把 caps 三台都改成 4,再跑一遍——看最少连接是不是变成 4/4/4。
  2. 把 reqs 从 12 个改成 100 个,看哈希那一行会不会更均匀。
  3. 想一下:如果服务器从 3 台变成 4 台,哈希那一行会有多少 key 换台?

常见误区

  1. 以为四层与七层只是「快慢」的差别。 能力不同:四层只能看端口,七层能看 URL 与 Cookie。
  2. 以为负载均衡就是「平均分」。 哈希与最少连接都不平均, 因为它们的目的一开始就不是「平均」。
  3. 以为七层设备总是更好。 它要解密、要解析、要保持状态,能用四层解决就别上七层。
自测三问(点开对答案) 1. 四层与七层设备分别看什么? —— **四层看端口号,七层看 URL、Cookie、HTTP 头等内容。**看得越深能力越强, 代价是性能与加密的墙。 2. 为什么「源地址哈希」不适合要求负载均衡的场景? —— **它保证「同一 key 落同一台」,但不保证均匀。**而且服务器数量一变,几乎所有 key 都会换台。 3. 七层设备最大的现实障碍是什么? —— **TLS 加密之后看不到内容。** 所以它必须成为解密终点,这既是性能开销, 也是巨大的信任与风险点。

下一节讲最后一个设备:网关——它不只是转发,它要翻译。

相关笔记