多租户基础:多租户模型、资源类型与租户隔离需求

核心原理:什么是多租户

多租户(Multi-Tenancy)是一种软件架构模式,指单个软件实例同时服务多个租户(Tenant),每个租户拥有独立的数据、配置和用户体系,但在物理或逻辑层面共享同一套基础设施。租户可以是企业、部门、项目组,甚至是一个外部客户。多租户的核心价值在于通过资源共享降低运维成本和硬件开销,但代价是租户之间必然产生资源争抢——这正是本课程要解决的核心问题。

理解多租户需要先区分三个层次:基础设施层(物理机、虚拟机、容器)、平台层(数据库实例、中间件、应用运行时)和应用层(业务代码、API、前端)。不同层次的多租户实现方式不同,资源争抢的表现和隔离手段也截然不同。例如,在基础设施层,两个租户可能共享同一台物理机的CPU核;在平台层,两个租户可能共享同一个数据库连接池;在应用层,两个租户可能共享同一个JVM堆内存。

关键认知:多租户不等于虚拟化。虚拟化是资源抽象技术,多租户是业务架构模式。一个多租户系统可以运行在虚拟机、容器或裸金属之上,但租户隔离的边界和粒度由架构设计决定,而非底层虚拟化技术自动提供。
多租户模型与资源争抢关系 租户 A(企业客户) 用户数:5000 业务:交易系统 SLA:P99 < 50ms 租户 B(中小客户) 用户数:300 业务:报表分析 SLA:P99 < 500ms 租户 C(内部项目) 用户数:50 业务:数据训练 SLA:无严格限制 共享资源池(物理/虚拟化层) CPU 核 8核 @ 3.2GHz 超线程开启 内存 64GB DDR4 NUMA 双节点 存储 IO NVMe SSD x4 RAID 10 网络 10GbE 双网卡 VLAN 隔离 争抢点 CPU 抢占 IO 排队 租户 A 的高并发交易可能抢占 CPU 时间片,导致租户 B 的报表任务延迟 租户 C 的大规模数据训练可能占满磁盘 IO,影响所有租户的读写延迟

资源类型:四大核心争抢维度

多租户环境中的资源争抢主要集中在四个维度,每个维度都有其独特的争抢机制和影响特征:

资源类型 争抢表现 典型瓶颈 影响范围
CPU 时间片抢占、上下文切换频繁、CPU 缓存命中率下降 计算密集型任务(如数据加密、复杂查询) 所有共享同一 CPU 核的租户
内存 内存不足触发 swap、GC 频繁、OOM Killer 误杀 大对象分配、缓存膨胀、连接数过多 同一物理机/容器组内的租户
IO 磁盘队列深度增加、读写延迟飙升、IOPS 下降 大量随机读写、日志刷盘、数据备份 共享同一存储卷或磁盘的租户
网络 带宽占用、TCP 重传率上升、连接数耗尽 大文件传输、流媒体、数据同步 共享同一网卡或网络链路的租户

值得注意的是,资源争抢往往不是孤立的。例如,当租户 A 发起大量磁盘读写时,IO 等待会导致其线程阻塞,进而占用更多内存缓冲,同时 CPU 需要处理更多的中断请求——这种级联效应使得问题定位变得复杂。这也是为什么本课程后续章节会强调全链路监控和根因分析的重要性。

租户隔离需求:从“不干扰”到“可量化”

租户隔离需求可以划分为四个递进层次,不同业务场景对隔离强度的要求差异巨大:

  1. 数据隔离(最低要求):租户之间不能访问彼此的数据,这是多租户的底线。通常通过数据库 Schema 分离、行级权限控制或加密方案实现。
  2. 性能隔离(核心需求):一个租户的突发流量不应导致其他租户的服务质量下降。这需要配额管理、优先级调度和资源限制机制。
  3. 故障隔离(高要求):某个租户的代码缺陷、死循环或内存泄漏不应拖垮整个系统。这需要进程隔离、容器隔离或微服务拆分。
  4. 安全隔离(合规需求):租户之间的网络流量、内存数据、磁盘残留都不能被其他租户探测到。这涉及加密、专用网络和物理隔离。
常见误区:很多团队认为“只要用了容器就实现了租户隔离”。实际上,容器默认只提供进程级隔离,CPU、内存、IO 的配额都需要额外配置。如果只是简单地 docker run 而不设置 --cpus、--memory 等参数,所有容器共享宿主机全部资源,争抢问题依然存在。

案例场景:一个典型的争抢事故

某 SaaS 平台同时服务三个租户,部署在 8 核 64GB 的物理机上,使用 Kubernetes 管理容器。某天下午 14:00 开始,租户 A 的营销活动导致其订单量暴涨 10 倍,CPU 使用率从 20% 飙升至 95%。结果:

  • 租户 B 的实时报表接口 P99 延迟从 120ms 恶化到 2.3s,大量超时
  • 租户 C 的批量数据同步任务执行时间从 30 分钟延长到 4 小时
  • 系统日志显示 CPU 上下文切换次数从每秒 2 万次飙升到 18 万次

根因分析后发现,租户 A 的 Pod 没有设置 CPU 请求(requests)和限制(limits),Kubernetes 默认允许其使用宿主机所有空闲 CPU。租户 B 和 C 的 Pod 虽然设置了 requests,但未设置 limits,导致在 CPU 竞争时无法获得保障。修复方案是:

# 租户 A 的 Pod 配置(限制其 CPU 使用)
resources:
  requests:
    cpu: "2"
    memory: "8Gi"
  limits:
    cpu: "4"
    memory: "16Gi"

# 租户 B 的 Pod 配置(保障其最低资源)
resources:
  requests:
    cpu: "2"
    memory: "4Gi"
  limits:
    cpu: "4"
    memory: "8Gi"

同时启用了 Kubernetes 的 ResourceQuota 和 LimitRange,确保每个租户命名空间内的资源总和不超过预设配额。调整后,租户 B 的 P99 延迟恢复到 150ms 以内,租户 C 的任务执行时间回到 35 分钟左右。

误区与复盘:隔离方案设计的常见陷阱

从上述案例可以总结出多租户隔离设计中的几个高频误区:

  • 误区一:只做“软隔离”不做“硬隔离”。应用层的限流和熔断是必要的,但不能替代内核层的 cgroup 限制。软隔离在正常情况下有效,但遇到极端流量时可能被突破。
  • 误区二:静态配额无法应对动态负载。固定分配 CPU 核数会导致资源利用率低(租户空闲时其他租户也无法使用),而完全不限制又会导致争抢。需要结合弹性配额和优先级调度。
  • 误区三:忽略 IO 和网络的隔离。很多团队只关注 CPU 和内存,但磁盘 IO 和网络带宽的争抢同样致命。需要配置 IO 权重(如 cgroup blkio)和网络 QoS(如 TC 或 CNI 插件)。
  • 误区四:没有建立“争抢预案”。当争抢发生时,如何快速定位是哪个租户、哪个 Pod、哪个进程导致的?需要提前建立监控指标(如 CPU throttling 时间、IO 等待队列长度)和告警阈值。