EMR Serverless 队列本质是可调度计算资源池,核心承载三大核心职能:控制资源使用边界、支撑作业并发运行、实现配额精细化管理,同时兼具资源划分、计算能力、计费三重核心属性,其最佳实践需围绕类型选择、计费配置、管理规则、容量规划、监控运维等维度展开。
EMR Serverless 提供公共队列与独占队列两类,需根据业务对资源稳定性、成本的需求差异选择,核心差异与适用场景如下:
维度 | 公共队列 | 独占队列 |
|---|---|---|
资源归属 | 所有租户共享 | 用户专属 |
付费模式 | 完全按量后付费 | 固定预付费(包年包月)/ 预付费 + 弹性后付费 |
资源稳定性 | 高并发 / 资源紧张时可能申请失败、任务变慢 | 固定资源强保障,弹性资源有上限限制 |
支持功能 | 仅支持 Spark SQL、Spark Jar、Presto SQL、Ray Job 作业 | 含公共队列所有功能,额外支持创建 Spark/Presto/Ray 专用计算组 |
适用场景 | 成本敏感、非核心业务、资源需求波动小的场景 | 核心业务、强资源保障需求、需专用计算组的场景 |
MAX(100%×固定CU数,256CU),需提前评估峰值需求。说明
合理选择资源规格与计费模式,是降低成本、匹配任务特性的关键,核心配置如下:
以 “CU” 为基本资源单位,默认规格与适配场景明确,需根据任务类型选择:
三种计费模式对应不同成本逻辑,需结合业务资源使用规律选择:
计费模式 | 适用场景 | 说明 |
|---|---|---|
完全按量付费(公共队列) | 资源使用不规律、单次任务时长短、无固定峰值的场景 | 仅统计作业运行 CU 时,排队时间不计费;避免过度配置单作业资源导致费用浪费 说明 相同作业会因指定资源的大小差异而导致费用波动。 |
包年包月(独占队列) | 资源需求稳定、长期运行(如 7×24 小时流式任务) | 按购买时长(1-36 个月)和固定 CU 数付费,长期使用比按量更划算,需精准评估最小必要资源 |
包年包月 + 按量付费 | 有基础稳定资源需求,且存在周期性峰值的场景 | 固定资源保障基础负载,弹性资源应对峰值;弹性部分后付费,需控制峰值不超过弹性上限 说明 独占队列的弹性部分不得超过 MAX(100% * 固定CU数,256CU)。 |
使用主账号或子账号,点击创建队列进入队列资源开通页面,即可根据需求购买相应规格队列。
购买时长:1个月、2个月、3个月、6个月、1年、2年、3年。
自动续费:无论购买何种时长,自动续费周期均为每月。若独占队列未续费,队列将在账单到期后次日12:00关停,并在关停15天后释放资源。释放前可手动续费恢复资源,释放后将不再保存队列信息。
队列资源:在创建队列时,支持用户选择可用区。鉴于资源库存保障以及多级房容灾等方面的考虑,建议用户选择多可用区。
资源规格:EMR Serverless支持CPU资源和GPU资源。在创建队列时,用户可选择CPU资源、GPU资源或CPU与GPU混合资源。CPU资源具备1:2、1:4、1:8的资源规格;GPU资源方面,用户可选择所需的GPU机型及数量。
队列权限:队列权限用以限制不同用户在不同队列上的权限。当前支持两种角色:Developer 与 Admin。主账号默认是Admin权限,子账号的队列权限需要授予。当前不支持子账号申请权限,需要账号主动授予。
权限点 | 角色 | ||
|---|---|---|---|
权限名称 | 说明 | Admin | Developer |
GetQueue | 允许获取某个队列的状态和配置 | ✔️ | ✔️ |
UpdateQueue | 允许修改队列的状态和配置,表示该用户可以修改队列的 CPU、Memory 配置,以及开启、停止队列 | ✔️ | |
ExecuteOnQueue | 允许在队列中提交作业 | ✔️ | ✔️ |
MonitorQueue | 允许查看在该队列上执行的当前和过去查询以及该队列的使用统计信息 | ✔️ | ✔️ |
ListJob | 允许查看该队列中的所有任务 | ✔️ | ✔️ |
KillJob | 允许 Kill /删除该队列中的任务 | ✔️ | |
ModifyJob | 允许编辑该队列中的任务 | ✔️ | |
DeleteQueue | 允许删除该队列 | ✔️ | |
All | 允许对某个队列的完全控制权限,包含对其授权的权限 | ✔️ | |
容量规划的目标是通过合理的资源分配,实现业务的稳定运行。避免 “资源不足导致任务 pending” 或 “资源闲置浪费”。
EMR Serverless 场景的容量规划必须从负载特征出发,将业务服务水平目标(SLO)映射为“并发数与资源水位目标”。不同类型任务的特征、SLO 目标差异显著,对应容量配置方向不同:
负载类型 | 核心特征 | SLO 目标 | 容量配置方向 |
|---|---|---|---|
批处理(如夜间数据同步) | 定时提交(如 0:00 开始)、短时运行、时长有长尾(部分作业耗时远超中位数) | 固定窗口内完成(如 2 小时内跑完 120 个作业)、可容忍 1-2 次重试 | 按 “峰值并发 × 单作业资源” 配置上限,加 20%-50% 安全缓冲;控制队列利用率在 80%-90% |
常驻 / 流式 / 微批 | 7×24 小时运行、高频发起(分钟级)、速率稳定 | 低抖动(延迟波动≤10%)、高可用(可用性≥99.9%)、延迟达标(如处理延迟≤5s) | 设较高 “最小容量”(避免资源回收导致重启),预留 10%-20% 冗余应对流量波动 |
交互式(Adhoc/Notebook) | 请求短(秒 - 分钟级)、峰值随机(如业务高峰时分析师集中查询) | 响应时间≤1 分钟、无排队等待 | 小粒度并发配额(如单用户最大并发 5 个作业)、作业级限流;配置较短资源回收时间,提高资源复用率 |
容量建模的核心是把业务并发与每作业的资源规模乘起来,再加上安全缓冲,得到队列的上限配置;下限则由最小保障与启动overhead目标共同决定。
动态分配能够在峰时拉起更多 Executor,在低谷快速回收,但如果边界配置不当,会引发任务pending。建议:
# 启用动态分配,并设定边界与空闲回收 spark.dynamicAllocation.enabled=true spark.dynamicAllocation.minExecutors=16 # 结合常驻并发 × 每作业 Executor 的下限 spark.dynamicAllocation.initialExecutors=32 # 结合典型并发的中位数 spark.dynamicAllocation.maxExecutors=256 # 上限受队列配额与并发上限约束 spark.dynamicAllocation.executorIdleTimeout=60s spark.dynamicAllocation.schedulerBacklogTimeout=1s # 并行度与 Shuffle 分区:避免过高/过低 spark.sql.shuffle.partitions=200 spark.default.parallelism=200 # 与 Executor 数量和核数匹配
用户可通过队列监控功能,判断当前队列容量是否能够满足业务需求。
开通队列后,用户可以在资源队列列表中选择相应的队列,进入监控界面。监控界面将显示队列的整体作业数量、作业资源使用情况,用户在监控列表中最多可查看近7天的队列资源使用情况。
其中,作业状态及其对应含义如下:
在计算组列表中选择相应计算组:
EMR Serverless已接入云监控,用户也可登录云监控,打开EMR Serverless,查看EMR Serverless队列、计算组粒度的监控指标,并配置告警规则。
下面以三类场景给出计算过程、推荐容量与参数建议。
spark.dynamicAllocation.enabled=true spark.dynamicAllocation.minExecutors=60 # 约 240 vCPU / 每 Executor 4 vCPU spark.dynamicAllocation.initialExecutors=120 spark.dynamicAllocation.maxExecutors=468 # 约 1872 vCPU / 每 Executor 4 vCPU spark.dynamicAllocation.executorIdleTimeout=60s spark.sql.shuffle.partitions=600
spark.dynamicAllocation.enabled=true spark.dynamicAllocation.minExecutors=50 spark.dynamicAllocation.initialExecutors=60 spark.dynamicAllocation.maxExecutors=60 spark.dynamicAllocation.executorIdleTimeout=120s spark.streaming.backpressure.enabled=true spark.sql.shuffle.partitions=200
说明
流式场景优先保证最小容量与稳定性,避免频繁回收与重均衡。
spark.dynamicAllocation.enabled=true spark.dynamicAllocation.minExecutors=10 spark.dynamicAllocation.initialExecutors=20 spark.dynamicAllocation.maxExecutors=25 spark.dynamicAllocation.executorIdleTimeout=30s spark.sql.shuffle.partitions=100