在大数据处理场景下,调度系统要管几十个甚至上百个团队的任务,每个团队都有自己的数据、资源和访问权限。如果管理不好,就会出现数据泄漏、任务互相干扰、资源争抢这些问题。Apache DolphinScheduler 作为一个成熟的调度平台,天生就支持多租户,但很多人不知道怎么用好它。今天我们就从实际落地的角度,聊聊多租户权限管理的最佳实践,全程不绕弯子,直接上干货。

一、为什么多租户权限管理这么重要

想象一下,你在一家大型互联网公司,数据平台上有搜索团队、推荐团队、广告团队。每个团队都有几十个任务,共享同一个服务器的资源,但数据绝对不能混。如果没有权限隔离,小明不小心删了隔壁团队的临时表,或者误改了别人的任务配置,那后果很严重。多租户就是让每个团队拥有自己的“小天地”,只能看到自己的项目、任务和数据,互不干扰。DolphinScheduler 把这套机制做得挺完善,但前提是你得知道怎么配。

二、DolphinScheduler的权限体系都有啥

DolphinScheduler 的权限分成三层:租户(Tenant)、用户(User)、队列(Queue)。租户是核心,它对应操作系统的一个用户(一般是 Linux 用户),用来执行任务。用户是真正登录系统的人,一个用户可以属于多个租户,但一个任务只能在一个租户下运行。队列负责管理资源,比如 YARN 的队列,控制内存和 CPU 分配。

2.1 租户、用户、队列

  • 租户:每个租户代表一个业务团队或者项目。创建租户时需要指定一个操作系统用户名和队列。这个 OS 用户必须有权限访问执行任务需要的文件和数据。
  • 用户:就是具体的账号。你可以给用户分配一个默认租户,也可以让用户在不同项目里使用不同的租户。
  • 队列:通常对应 YARN 的队列名称。DolphinScheduler 会把任务提交到这个队列,从而限制资源使用量。

2.2 资源与项目权限

除了租户隔离,DolphinScheduler 还支持项目和资源的细粒度权限。项目是一组任务的集合,你可以把某个项目授权给某人,让他只有“查看”或“编辑”权限。资源包括脚本、配置文件、数据源等,也能按租户或者用户授权。所以实际使用中,你既要管好租户,也要管好项目和资源权限,二者缺一不可。

三、最佳实践:怎么配置才靠谱

下面我会结合两个真实场景,告诉你具体怎么操作。所有示例都以 Python 作为唯一技术栈,通过调用 DolphinScheduler 的 REST API 来管理租户和权限。

3.1 场景一:金融数据团队隔离

金融部门有风险控制和反洗钱两个小组。每个小组有独立的任务和数据目录。我们需要创建两个租户 risk_tenantaml_tenant,分别对应不同的 Linux 用户和 YARN 队列。然后创建用户,把每个用户绑定到对应的租户上,并给用户分配项目权限。

3.2 场景二:跨部门共享资源

有时候不同部门需要共用同一个数据源,比如一张公共维表。如果每个部门都独立创建数据源,既浪费又难维护。这时候可以创建一个公共租户 common_tenant,专门用来管理共享资源,然后给其他部门的用户授予对这个租户下资源的“查看”权限。这样既能隔离任务,又能共享数据。

3.3 代码示例:用Python管理租户和权限

下面是一个完整的 Python 脚本,展示如何通过 DolphinScheduler 的 REST API 创建租户、用户、分配项目权限。请确保你的 DolphinScheduler 服务已经启动,API 端口默认为 12345。

import requests
import json

# 配置信息
BASE_URL = "http://your-dolphinscheduler-host:12345/dolphinscheduler"
TOKEN = "your-login-token"  # 需要先登录获取token

headers = {
    "token": TOKEN,
    "Content-Type": "application/json"
}

# 1. 创建租户
def create_tenant(tenant_code, tenant_name, os_user, queue_id):
    """
    创建租户
    :param tenant_code: 租户编码,唯一
    :param tenant_name: 租户名称
    :param os_user: 操作系统用户名,需提前在调度服务器上创建
    :param queue_id: 队列ID,需要先创建队列并获取ID
    """
    url = f"{BASE_URL}/tenants"
    data = {
        "tenantCode": tenant_code,
        "tenantName": tenant_name,
        "osUser": os_user,
        "queueId": queue_id
    }
    resp = requests.post(url, json=data, headers=headers)
    if resp.status_code == 201:
        print(f"租户 {tenant_code} 创建成功")
        return resp.json().get("data").get("id")
    else:
        print(f"创建租户失败: {resp.text}")
        return None

# 2. 创建用户
def create_user(user_name, user_password, tenant_id, email="user@example.com", phone=""):
    """
    创建用户
    :param user_name: 用户名
    :param user_password: 密码
    :param tenant_id: 默认租户ID
    """
    url = f"{BASE_URL}/users"
    data = {
        "userName": user_name,
        "userPassword": user_password,
        "tenantId": tenant_id,
        "email": email,
        "phone": phone
    }
    resp = requests.post(url, json=data, headers=headers)
    if resp.status_code == 201:
        print(f"用户 {user_name} 创建成功")
        return resp.json().get("data").get("id")
    else:
        print(f"创建用户失败: {resp.text}")
        return None

# 3. 给用户授权项目
def grant_project_access(user_id, project_code, perm_type="READ"):
    """
    授予用户对某个项目的权限
    :param user_id: 用户ID
    :param project_code: 项目编码
    :param perm_type: 权限类型:READ(查看)、EDIT(编辑)、ALL(所有)
    """
    url = f"{BASE_URL}/projects/{project_code}/grant"
    data = {
        "userId": user_id,
        "perm": perm_type
    }
    resp = requests.post(url, json=data, headers=headers)
    if resp.status_code == 200:
        print(f"用户 {user_id} 成功获得项目 {project_code} 的 {perm_type} 权限")
    else:
        print(f"授权失败: {resp.text}")

# 假设已经知道队列ID为1(需要先手动创建队列)
queue_id = 1

# 创建风险控制租户
risk_tenant_id = create_tenant("risk_tenant", "风险控制租户", "riskuser", queue_id)
# 创建反洗钱租户
aml_tenant_id = create_tenant("aml_tenant", "反洗钱租户", "amluser", queue_id)

# 创建用户并绑定租户
user_zhang = create_user("zhangsan", "pass123", risk_tenant_id)
user_li = create_user("lisi", "pass456", aml_tenant_id)

# 假设项目“risk_proj”和“aml_proj”已经通过界面创建,这里给用户授予权限
if user_zhang:
    grant_project_access(user_zhang, "risk_proj", "EDIT")  # 张三可以编辑风险项目
if user_li:
    grant_project_access(user_li, "aml_proj", "EDIT")      # 李四可以编辑反洗钱项目

print("权限配置完成!")

这段代码就是最基础的多租户管理流程。实际使用时,你还需要处理登录获取 token、异常重试等细节。但核心思想就是把租户、用户、项目权限关联起来,形成隔离又可控的访问体系。

四、优缺点和应用场景分析

优点

  • 租户隔离彻底:每个任务跑在独立的操作系统用户下,文件和进程都无法互相影响。
  • 队列控制资源:通过 YARN 队列,可以限制每个租户最大资源使用量,避免一个团队把集群打满。
  • 权限粒度可选:既支持粗粒度的租户隔离,也支持细粒度的项目/资源授权,灵活性高。

缺点

  • 运维成本高:需要先在每个调度节点上创建好操作系统用户,否则租户无法工作。
  • 队列配置复杂:如果没配置好 YARN 队列,租户隔离就没有意义,任务可能抢资源。
  • 学习曲线:对新手来说,理解租户、用户、队列三者的关系需要一点时间。

适用场景

  • 金融、医疗、政府等对数据安全要求极高的行业。
  • 大型互联网公司的数据平台,多个业务线共用集群。
  • 需要给外部客户提供调度服务的 SaaS 平台。

五、注意事项

  1. 操作系统用户必须事先创建:DolphinScheduler 不会自动创建 Linux 用户,你需要手动在每个 worker 节点上用 useradd 创建对应的用户,并保证这些用户有权访问任务依赖的文件。
  2. 队列名称要统一:如果你的集群是 YARN 模式,队列名称必须在资源管理器里已经存在,否则任务会提交失败。
  3. 权限不要给得太粗:默认管理员账户不能随便共享,最好按照“最小权限原则”来分配,每个用户只给完成工作所需的最低权限。
  4. 资源目录隔离:建议为每个租户分配独立的资源目录(比如 HDFS 上的 /data/tenant/{tenant_code}),并在创建租户时把 OS 用户的 home 目录指向那个位置。
  5. 定期审计:可以写一个脚本定期检查用户权限是否合适,避免离职人员还留着权限。

六、总结

多租户权限管理是大数据调度中绕不开的一块硬骨头,但 DolphinScheduler 提供了比较完整的解决方案。只要把租户、用户、队列这三驾马车配好,再配合项目和资源的细粒度控制,就能搭建出一个既安全又灵活的调度环境。关键还是实际动手去配,别光看文档。建议你先在一个测试集群上按照上面的 Python 示例跑一遍,心里就有底了。记住,权限隔离不是为了限制业务,而是为了让团队更放心地共享资源。