跳到主内容

多租户与隔离

核心能力

多租户与隔离

EnerOS 的多租户模型对应电力运营主体边界:每个租户即一个独立的电网运营责任主体(如省调、地调、虚拟电厂运营商),其数据、Agent、设备、配额完全隔离。租户边界即电网运营责任边界。

电力系统天然是多主体协作场景:国调、分调、省调、地调、县调形成层级;发电集团、电网公司、售电公司、用户形成多边关系。每个主体的数据、控制权限、责任范围必须严格隔离。EnerOS 的多租户模型将这种现实中的边界映射到操作系统层面。

架构总览

┌─────────────────────────────────────────────────────┐
│  租户 A(省调)│  租户 B(地调)│  租户 C(VPP)    │
│  - 拓扑 A     │  - 拓扑 B     │  - 拓扑 C         │
│  - Agent A    │  - Agent B    │  - Agent C        │
│  - 时序 A     │  - 时序 B     │  - 时序 C         │
│  - 配额 A     │  - 配额 B     │  - 配额 C         │
└──────────────────┬──────────────────────────────────┘
                   │ 命名空间隔离
┌──────────────────┴──────────────────────────────────┐
│  eneros-tenant (多租户内核模块)                      │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐            │
│  │ Namespace│ │ Quota    │ │ ACL      │            │
│  │ 命名空间 │ │ 配额管理 │ │ 访问控制 │            │
│  └──────────┘ └──────────┘ └──────────┘            │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐            │
│  │ KMS      │ │ Audit    │ │ Cross    │            │
│  │ 密钥管理 │ │ 审计     │ │ 跨租户   │            │
│  └──────────┘ └──────────┘ └──────────┘            │
└──────────────────┬──────────────────────────────────┘
                   │ cgroup + network namespace
┌──────────────────┴──────────────────────────────────┐
│  资源层:CPU / 内存 / 网络 / 存储                    │
└─────────────────────────────────────────────────────┘

租户模型

use eneros_tenant::{Tenant, TenantId, TenantConfig, TenantTier};

let tenant = Tenant::new(TenantId::from("province_a"))
    .name("A 省电力调度中心")
    .tier(TenantTier::Enterprise)
    .config(TenantConfig {
        max_agents: 100,
        max_devices: 100_000,
        max_ts_throughput: 1_000_000,  // samples/s
        storage_quota_tb: 10,
        api_rate: 1000,                // req/s
        realtime_cpu_cores: 2,
    });

Tenant 字段说明

字段类型说明
idTenantId租户唯一标识(如 “province_a”)
nameString可读名称
tierTenantTier等级(Community / Pro / Enterprise / National)
configTenantConfig资源配额
created_atDateTime创建时间
statusTenantStatusActive / Suspended / Terminated
kms_key_idStringKMS 密钥 ID

TenantTier 等级

等级最大 Agent最大设备适用场景
Community101,000实验室、教学
Pro5010,000配电网、微电网
Enterprise100100,000省调、地调
National10001,000,000国家级电网

命名空间隔离

所有内核资源(拓扑、设备、Agent、时序数据)都带租户命名空间前缀,确保物理隔离:

use eneros_tenant::TenantContext;

// 资源命名空间自动注入
let bus = network.add_bus(Bus::new(1, ...));
// 实际存储 key: "tenant:province_a:bus:1"

// 跨租户访问被拒绝
let other = network.get_bus(TenantId::from("province_b"), 1);
// → PermissionDenied

// 命名空间覆盖所有资源
//   tenant:<id>:topology:<...>
//   tenant:<id>:equipment:<...>
//   tenant:<id>:timeseries:<tag>
//   tenant:<id>:agent:<id>
//   tenant:<id>:audit:<...>

命名空间层级

tenant:province_a:
  ├── topology:network:default
  ├── equipment:line:1
  ├── timeseries:bus_1.voltage
  ├── agent:dispatch_1
  ├── twin:instance:main
  ├── audit:2026-07
  └── kms:key:primary

租户上下文

每个请求/Agent 执行都携带租户上下文,内核自动校验:

use eneros_tenant::TenantContext;

async fn handler(ctx: &TenantContext, req: Request) -> Response {
    // ctx.tenant_id() 自动从 mTLS 证书提取
    let tenant = ctx.tenant();

    // 所有操作自动限定在租户命名空间
    let network = tenant.network().await?;
    let agents = tenant.agents().await?;
    let timeseries = tenant.timeseries().await?;

    // 拓扑操作自动隔离
    let bus = network.get_bus(1).await?;
    // 等价于 network.get_bus_in_namespace(ctx.tenant_id(), 1)

    Response::ok()
}

// API 中间件自动注入租户上下文
async fn tenant_middleware(req: Request, next: Next) -> Response {
    let cert = req.peer_certificate()?;
    let tenant_id = extract_tenant_from_cert(cert)?;
    let ctx = TenantContext::new(tenant_id);
    next.run(ctx, req).await
}

TenantContext 方法

方法返回说明
tenant_id()&TenantId获取租户 ID
tenant()Tenant获取租户对象
has_permission(perm)bool权限检查
quota()Quota获取配额
usage()Usage获取当前使用量
kms() -> KmsKms密钥管理服务

配额管理

按租户维度强制配额,防止单租户耗尽集群资源:

use eneros_tenant::Quota;

let quota = Quota::for_tenant(&tenant_id)
    .agents(100)
    .devices(100_000)
    .ts_throughput(1_000_000)  // samples/s
    .storage(10_tb)
    .api_rate(1000)            // req/s
    .realtime_cpu_cores(2)
    .memory_gb(16)
    .network_mbps(100);

// 内核自动校验配额
tenant.spawn_agent(my_agent).await?;
// 超出配额 → QuotaExceeded

// 实时监控用量
let usage = tenant.usage().await?;
println!("Agent: {}/{}", usage.agents.used, usage.agents.quota);
println!("存储: {:.1}/{:.1} TB", usage.storage.used_tb, usage.storage.quota_tb);
println!("时序吞吐: {:.0}/{:.0} samples/s",
    usage.ts_throughput.current, usage.ts_throughput.quota);

配额资源矩阵

资源计费维度默认配额超出处理
Agent 数量实例数100拒绝创建
设备数100k拒绝创建
时序写入samples/s1M限流
存储TB10拒绝写入
API 调用req/s1000429 限流
实时 CPU2拒绝创建
内存GB16OOM 保护
网络Mbps100限速
Twin forks8拒绝 fork
跨租户调用次/天10000拒绝调用

配额告警

use eneros_tenant::QuotaAlert;

// 配置配额告警
tenant.set_alert(QuotaAlert {
    resource: Resource::Storage,
    threshold: 0.8,  // 80%
    action: AlertAction::Notify { emails: vec!["ops@a.com".into()] },
});

tenant.set_alert(QuotaAlert {
    resource: Resource::TsThroughput,
    threshold: 0.95,  // 95%
    action: AlertAction::AutoScale { factor: 1.5 },
});

资源共享与白名单

某些场景需要跨租户协作(如省地协调),通过显式白名单授权:

// A 省授权 B 省读取部分数据
tenant_a.grant(&tenant_b, Permission::read(&[
    "bus:1:voltage",
    "bus:2:voltage",
    "branch:5:flow",
])).duration(Duration::from_hours(24)).await?;

// B 省在白名单内可访问
let v = tenant_b.cross_read(&tenant_a, "bus:1:voltage").await?;

// 撤销授权
tenant_a.revoke(&tenant_b, Permission::read(&["bus:1:voltage"])).await?;

// 查询授权
let grants = tenant_a.list_grants().await?;
for g in &grants {
    println!("{} → {} : {:?} (剩余 {:?})",
        g.grantor, g.grantee, g.permission, g.expires_in);

Permission 类型

类型含义典型场景
read(tags)读取指定数据省地数据共享
write(tags)写入指定数据协同控制
control(devices)控制指定设备委托控制
query(topology)查询拓扑协调规划
invoke(tools)调用工具共享服务

隔离强度

维度隔离方式强度
数据命名空间前缀 + ACL
计算cgroup v2 + CPU/内存限制
网络per-tenant network namespace
Agent独立进程 + IPC 通信
时序per-tenant LSM tree
密钥per-tenant KMS 密钥
审计per-tenant WORM 日志
实时域per-tenant CPU 隔离

cgroup v2 配置示例

# /sys/fs/cgroup/eneros/tenant_province_a/
#   cpu.max = 200000 100000   (2 核)
#   memory.max = 17179869184  (16 GB)
#   io.max = "8:16 rbps=104857600 wbps=104857600"  (100 MB/s)

多租户运维

use eneros_tenant::Admin;

let admin = Admin::connect(&cluster);

// 列出所有租户
let tenants = admin.list_tenants().await?;
for t in &tenants {
    println!("{}: {:?} - {:?}", t.id, t.tier, t.status);
}

// 创建新租户
let new_tenant = admin.create_tenant(TenantConfig {
    id: TenantId::from("vpp_x"),
    name: "X 虚拟电厂".into(),
    tier: TenantTier::Pro,
    ..Default::default()
}).await?;

// 调整配额
admin.update_quota(&tenant_id, Quota::new().storage(20_tb)).await?;

// 资源使用统计
let usage = admin.usage(&tenant_id).await?;
println!("存储: {:.1}/{:.1} TB", usage.storage.used_tb, usage.storage.quota_tb);
println!("Agent: {}/{}", usage.agents.used, usage.agents.quota);

// 暂停/恢复租户
admin.suspend(&tenant_id).await?;   // 暂停所有 Agent,但保留数据
admin.resume(&tenant_id).await?;    // 恢复运行

// 终止租户
admin.terminate(&tenant_id).await?;  // 删除所有数据,释放资源

租户生命周期

Created → Active ⇄ Suspended → Terminated

           Degraded(配额超限)

跨租户协作示例:省地协调

use eneros_tenant::CrossTenantChannel;

// 建立省地协调通道
let channel = CrossTenantChannel::new(
    &tenant_province,  // 省调
    &tenant_local,     // 地调
    CoordinationProtocol::TieLineControl,
).await?;

// 省调发送协调命令
channel.send(CoordCmd::AdjustTieLine {
    branch: 100,
    target_mw: 200.0,
}).await?;

// 地调接收并执行
while let Ok(cmd) = channel.recv().await {
    match cmd {
        CoordCmd::AdjustTieLine { branch, target_mw } => {
            let decision = DispatchDecision::new()
                .set_generator(local_gen, target_mw);
            ctx.execute(decision).await?;
        }
    }
}

性能指标

操作延迟备注
租户上下文注入< 5μsmTLS 证书提取
命名空间前缀检查< 1μs-
配额校验< 10μs原子计数器
跨租户白名单校验< 20μs缓存命中
租户资源隔离开销< 1%cgroup
跨租户消息延迟< 100μs同集群
KMS 密钥访问< 1ms-
单节点最大租户数1000-
集群最大租户数100,000-

测试环境:4 核 / 8GB / Ubuntu 22.04。

安全合规

多租户隔离满足以下合规要求:

标准要求EnerOS 实现
NERC CIP-005电子安全边界per-tenant network namespace
IEC 62443-4-1安全开发生命周期内置安全模块
GB/T 22239等保 2.0 三级强制访问控制
ISO 27001信息安全管理WORM 审计 + KMS
GDPR数据主体隔离per-tenant 数据加密

配置参数

eneros.toml 中多租户相关配置:

[tenant]
# 是否启用多租户
enabled = true
# 默认租户等级
default_tier = "pro"
# 单节点最大租户数
max_tenants_per_node = 1000
# 是否启用 cgroup 隔离
cgroup_isolation = true
# 是否启用 network namespace
network_isolation = true
# 默认存储配额(TB)
default_storage_quota_tb = 10
# 配额检查间隔(秒)
quota_check_interval_secs = 10
# 跨租户调用默认配额(次/天)
cross_tenant_quota_daily = 10000
# 是否启用 KMS
kms_enabled = true
参数类型默认值说明
enabledbooltrue启用多租户
default_tierenumpro默认租户等级
max_tenants_per_nodeu321000单节点最大租户数
cgroup_isolationbooltruecgroup 隔离
network_isolationbooltrue网络命名空间隔离
default_storage_quota_tbu3210默认存储配额
quota_check_interval_secsu3210配额检查间隔
cross_tenant_quota_dailyu3210000跨租户调用配额
kms_enabledbooltrueKMS 启用

与其他能力的关系

关联能力互动方式
零信任与安全增强租户身份认证
运维自动化租户运维
多智能体协作租户内 Agent 编排
电网拓扑一等公民拓扑按租户命名空间隔离
时序原生操作时序数据按租户 LSM 隔离
安全守卫命令按租户命名空间审计
数字孪生引擎孪生 fork 按租户配额
实时双执行域实时 CPU 按租户隔离

相关文档