3. 平台设计原则:面向租户的多租户架构、数据隔离策略、权限模型(RBAC/ABAC)设计
在自助服务可观测性平台中,多租户架构是支撑企业级规模化运营的基石。平台需要同时服务于多个业务团队(租户),每个租户拥有独立的资源视图、数据边界和操作权限。设计核心在于平衡资源共享效率与租户隔离安全性。
3.1 多租户架构模型
多租户架构通常分为三种模式,每种模式在隔离性、成本和运维复杂度上各有取舍:
| 模式 | 隔离粒度 | 资源效率 | 运维复杂度 | 适用场景 |
|---|---|---|---|---|
| 独立实例(Silo) | 每个租户独占一套完整服务实例 | 低(资源重复) | 高(实例管理) | 金融、合规要求极高的租户 |
| 共享实例(Pool) | 所有租户共享同一套服务实例 | 高(资源复用) | 低(统一运维) | 内部开发测试环境、SaaS 标准版 |
| 混合模式(Bridge) | 核心服务共享,数据存储按租户分区 | 中(平衡) | 中(需路由逻辑) | 大多数企业级可观测性平台 |
推荐实践:采用混合模式作为默认架构。将计算层(查询引擎、告警引擎)共享以降低成本,存储层(时序数据库、日志索引)按租户物理或逻辑分区,确保数据安全。
3.2 数据隔离策略
数据隔离是多租户设计的核心安全防线。根据可观测性数据类型(指标、日志、链路),隔离策略需分层实施:
- 物理隔离:租户使用独立的数据库实例或独立的索引集群。隔离性最强,但成本最高,适用于合规敏感租户。
- 逻辑隔离:共享同一存储集群,通过租户 ID(tenant_id)字段进行数据分区。成本低,但需确保查询路由层强制注入租户上下文。
- 混合隔离:热数据(近期高频查询)采用逻辑隔离以降低成本;冷数据(历史归档)采用物理隔离以满足合规要求。
关键设计点:所有数据写入和查询路径必须经过租户上下文拦截器。该拦截器从认证 中提取租户 ID,自动附加到 SQL 查询、PromQL 查询或日志搜索请求中,防止跨租户数据泄露。
3.3 权限模型设计:RBAC 与 ABAC
权限模型决定了租户内用户能看到什么和能做什么。可观测性平台通常采用 RBAC(基于角色的访问控制)作为基础,并在精细场景下引入 ABAC(基于属性的访问控制)。
3.3.1 RBAC 核心设计
RBAC 通过“用户 → 角色 → 权限”的映射关系简化授权管理。在可观测性平台中,建议预定义以下角色:
| 角色 | 权限范围 | 典型操作 |
|---|---|---|
| 租户管理员 | 租户内全部资源 | 管理用户、配置告警规则、管理数据保留策略 |
| 运维工程师 | 指定服务/环境 | 查看仪表盘、查询日志、创建临时告警 |
| 只读用户 | 指定仪表盘/视图 | 查看预置仪表盘、查看告警通知 |
| 审计员 | 操作日志与访问记录 | 查看用户操作审计、导出审计报告 |
3.3.2 ABAC 扩展场景
当权限控制需要更细粒度时,ABAC 基于用户属性、资源属性和环境条件动态计算权限。典型场景包括:
- 时间窗口限制:仅允许在工作时间(09:00-18:00)执行高危操作(如删除数据源)。
- 环境属性过滤:开发工程师只能查看
environment=dev或environment=staging的指标,不能访问生产环境。 - 数据标签匹配:用户只能访问带有
team=payment标签的仪表盘和告警。
设计陷阱:ABAC 策略引擎会增加查询延迟(每次请求需计算策略)。建议将 ABAC 用于数据行级过滤(如标签过滤),而将功能级权限(如能否创建告警)保留在 RBAC 中,避免性能瓶颈。
3.4 权限模型与数据隔离的协同
多租户架构、数据隔离和权限模型三者必须协同工作,形成完整的访问控制链路:
- 认证阶段:用户登录后,平台从 中解析出
tenant_id和user_id。 - 授权阶段:RBAC 引擎根据用户角色判定是否允许执行请求的操作(如查询、创建、删除)。
- 数据过滤阶段:ABAC 引擎(如启用)根据资源标签和用户属性进一步过滤返回的数据行。
- 存储隔离阶段:查询路由层将
tenant_id注入到存储查询中,确保只访问该租户的数据分区。
// 伪代码:权限与隔离协同流程
function handleRequest(user, request) {
// 1. 认证
tenantId = extractTenantFromToken(user.);
// 2. RBAC 授权
if (!rbacEngine.authorize(user.role, request.action, request.resource)) {
return 403 Forbidden;
}
// 3. ABAC 数据过滤(可选)
filterExpr = abacEngine.buildFilter(user.attributes, request.resource.attributes);
// 4. 注入租户隔离条件
query = request.query + " WHERE tenant_id = " + tenantId;
if (filterExpr) {
query += " AND " + filterExpr;
}
// 5. 执行查询
return storageEngine.execute(query);
}
最佳实践:在平台设计初期,将
tenant_id 作为所有数据模型的必选标签。无论是指标、日志还是链路数据,写入时强制注入租户 ID,查询时强制过滤。这是防止数据泄露最有效的一行代码。