LLM 推理服务的弹性伸缩与冷启动工程 2026
约 31 分钟9015 字1 次阅读

一、问题的提出:冷启动与弹性伸缩的工程痛点
LLM 推理服务在生产环境里最容易暴露的两个性能问题,第一个是冷启动,第二个是弹性伸缩。冷启动指的是从模型权重加载到第一次成功返回 token 之间的时间窗口,弹性伸缩指的是当请求量波动时把 GPU 资源按比例扩缩到位的过程。这两个问题在 demo 阶段几乎不会暴露,因为 demo 通常只有一个固定规模的部署,访问量也是平的。但一旦进入生产,请求量出现高峰低谷、流量分布跨地域、模型需要热升级或者 GPU 节点会失效回收,问题就会集中爆发。
冷启动的痛点不只是「慢」。模型权重从 NVMe 加载到 HBM 之后,还需要构建 CUDA graph、初始化 KV cache pool、预热 tokenizer 编码路径、跑一遍 dummy pass 让 cuBLAS 算子完成第一次 kernel 选择与 cache warmup。一个 70B 参数的 FP16 模型,单是权重加载就要 14GB 显存占用和大约 30 秒的 PCIe 带宽占用;如果是 405B 模型,BF16 权重达到 810GB,冷启动时间可能超过 5 分钟。这 5 分钟对用户体验是断崖式的,对运维来说是必须用预热池抹平的。
冷启动还有一个被低估的「隐性成本」:GPU 节点在冷启动过程中是「半占用」状态——权重已经加载但还没开始接受请求,CUDA 算子还没 warmup,这时候任何把流量切过来都会得到灾难性的 P99 延迟。这种「半占用」期间,GPU 已经被云厂商计费但没有产生任何业务价值。如果一个生产集群每天要做 50 次冷启动,每次浪费 5 分钟,按 8 卡 H100 每小时 4 美元计算,单是冷启动浪费的成本每月就接近 1.2 万美元。这个数字足以支撑一个 30% warm pool 的全年运营开销。
弹性伸缩的痛点比冷启动更复杂。Kubernetes HPA(Horizontal Pod Autoscaler)默认的 CPU 利用率指标对 LLM 推理是无意义的——LLM 的 GPU 利用率在请求稀疏时已经很高,但延迟却很差。社区后来引入了 vLLM 的 num_requests_waiting 指标,但这个指标的滞后性依然让扩缩容动作落后于真实负载 30-60 秒。当一次突发流量到来,30-60 秒的滞后加上每个新 pod 自身的 2-5 分钟冷启动,结果就是请求队列堆积、SLO 被击穿、用户看到的是「这个 AI 又卡了」。
要解决这两个问题,需要把视角从「单个 pod 的启动时间」提升到「整个推理服务的资源池动态行为」。冷启动是单点延迟,弹性伸缩是系统响应曲线,两者必须在同一个资源池架构里同时设计才能达到工程意义上的「零感知扩容」。这个工程问题不是简单的「多开几个 pod」或者「加一个预热池」就能解决的,它需要从指标体系、调度策略、资源拓扑、负载预测四个层面做系统级协同优化。本文就是要把这套系统级方案拆解成可独立部署、可逐步演进的工程组件。
二、形式化:弹性伸缩问题的四元组
为了把冷启动和弹性伸缩放到统一的工程框架里讨论,我们定义一个四元组 <L, W, S, C>。L 是冷启动延迟(cold start latency),即从触发扩容到第一个 token 输出的 P50 时间。W 是资源浪费率(waste ratio),定义为非高峰时段 GPU 利用率低于阈值时的成本沉没。S 是 SLO 命中率(service level objective),即 P99 延迟满足承诺的比例。C 是单位 token 的边际成本(cost per million tokens),用于衡量算力开销。
四元组之间不是独立的,存在强耦合关系:
L和W是对立的:要降低L,需要预热池常驻空闲 pod,这直接抬高了W;要压低W,需要激进回收空闲 pod,这又会推高L。S和C是对立的:要提高S,需要更多冗余容量应对突发,这又抬高了C;要压低C,必须让 GPU 利用率逼近 100%,这又会牺牲S。L和S通过扩容响应曲线耦合:L越短,S越高,但预热代价越大。
工程上不存在同时优化四个目标的银弹方案。所有号称「零冷启动」「零浪费」的方案,本质都是在四元组的某个子集上做到极致,同时把另外一两个目标托管给基础设施或业务方。例如 warm pool 方案把 L 压到接近零但承担更高的 W;spot instance 方案把 C 压到接近零但承担 L 的不确定性;predictive batching 方案同时优化 W 和 C 但要承担预测错误的代价。
我们在本文里要回答的工程问题是:在给定的四元组预算 <L*, W*, S*, C*> 下,如何在 LLM 推理服务的生产架构里同时实现 cold start 接近 L*、资源浪费低于 W*、SLO 高于 S*、单位成本低于 C*。这是过去三年所有主流推理服务框架(vLLM、SGLang、TensorRT-LLM、Triton、Ray Serve)共同演进的方向。
三、冷启动的算子层真相:HBM 权重加载与 CUDA graph 重建
冷启动不是单一动作,而是一条由 6 个子阶段组成的流水线。理解这条流水线的瓶颈分布是设计任何 warm pool 策略的前提。
阶段 1:磁盘到主存的权重读取。模型权重通常以 safetensors 或 GGUF 格式存储在 NVMe SSD 上。70B 模型 BF16 权重约 140GB,按 PCIe Gen4 x4 通道的 7GB/s 实际带宽计算,单纯读取阶段需要 20 秒。这一阶段最容易优化的方式是把权重放在本地 NVMe 而非网络文件系统(NFS、S3 mount),后者会因网络抖动让读取时间分布方差增加 3-5 倍。
阶段 2:主存到 HBM 的张量复制。把权重从主存复制到 GPU HBM 是冷启动的最大头。H100 的 HBM3 带宽 3TB/s,140GB 复制理论需要 47ms,但实际上因为 PyTorch 张量需要按 layer 分片复制并保留元数据,实际时间通常在 8-15 秒。如果是 MoE 模型(如 Mixtral 8x7B),专家权重是稀疏激活的,可以只加载激活路径上的专家,进一步把这一阶段压到 5 秒内。
阶段 3:CUDA graph 捕获。vLLM 和 TensorRT-LLM 都依赖 CUDA graph 消除 kernel launch overhead。CUDA graph 的捕获过程需要跑一遍 dummy forward pass,触发所有可能的算子路径,这一阶段在 70B 模型上需要 10-20 秒。CUDA graph 一旦捕获就不能跨模型版本复用——任何权重变更、KV cache 配置变更、batch size 变更都必须重捕获,这是 warm pool 失效的常见原因。
CUDA graph 捕获的工程优化有两类。第一类是「静态 shape 缓存」:vLLM 的 CUDA graph 捕获是按 (batch_size, sequence_length) 缓存的,第一次遇到新 shape 会触发一次 10-20 秒的重捕获,第二遇到同 shape 只需要 100ms 加载。生产调优的关键是「预热常用 shape」——warmup 时主动跑一遍 batch=1/2/4/8/16/32 的 dummy pass,让常用 shape 的 CUDA graph 在 warm pool 阶段就准备好,避免第一次真实请求触发重捕获。
第二类是「CUDA graph 复用池」:维护一个跨进程的 CUDA graph cache,把已捕获的 graph 序列化到文件系统,新 pod 启动时直接 load 而不是重捕获。Anyscale 的 Ray Serve 在 vLLM 0.6+ 上做了这个优化,可以让 CUDA graph 捕获时间从 10-20 秒压缩到 1-2 秒。但这种优化的代价是 graph cache 的存储开销——一个完整模型的 graph cache 可能占用 5-10GB 磁盘。
阶段 4:KV cache pool 预分配。vLLM 的 PagedAttention 在服务启动时按 max_num_seqs × max_model_len × num_hidden_layers × head_dim × 2 (K/V) × dtype_size 预分配 KV cache pool。70B 模型在 8 张 H100 上预分配 60GB 左右的 KV cache,这一阶段 2-3 秒。
阶段 5:tokenizer 与多模态编码器初始化。tokenizer 通常是几秒,但多模态模型(如 LLaVA、Qwen-VL)需要单独加载视觉编码器,CLIP ViT-L 的初始化加上投影层需要 5-10 秒。
阶段 6:dummy pass 与算子 warmup。cuBLAS 和 cuDNN 会按算子首次调用顺序做 kernel 选择和 cache 写入。第一次 forward pass 通常比稳态慢 30-50%,这就是为什么很多服务会跑 3-5 次 dummy forward pass 才宣告 ready。
六个阶段累加,70B 模型冷启动总时长通常在 60-90 秒区间。如果是 405B 模型,这个数字会膨胀到 5-8 分钟。要抹平这段延迟,warm pool 是唯一现实方案。
四、弹性伸缩的资源调度:HPA 失效与队列感知 K8s operator
Kubernetes 默认的 HPA 对 LLM 推理服务几乎是无用的,原因有三层。第一层是指标语义错位:HPA 默认看 CPU 利用率,但 LLM 推理的 GPU 利用率在 batch 稀疏时已经 80%+,CPU 利用率却可能只有 20%,用 CPU 触发扩容会让 GPU 早就过载时才开始动作。第二层是滞后窗口过长:HPA 默认 30 秒一次指标采集,每次扩容动作又会延迟 30-60 秒才能让新 pod ready,加上 LLM 自身的冷启动,这个滞后窗口会膨胀到 2-5 分钟。第三层是没有 SLO 反馈:HPA 只看资源利用率,不知道当前的 P99 延迟是多少,无法做延迟驱动的扩容。
社区和工程团队的应对方案是部署自定义的 LLM-aware autoscaler。这种 operator 通常基于 KEDA(Kubernetes Event-Driven Autoscaling)或自研 controller,核心指标从 GPU 利用率转向 queue_depth(等待处理的请求数)、prefill_queue_latency(prefill 阶段排队时间)、kv_cache_utilization(KV cache pool 使用率)。vLLM 暴露的 /metrics 端点已经提供这些指标,operator 每 5 秒采集一次,按 SLO 反推目标副本数。
扩容策略上常见三种范式。第一种是「队列长度阈值」:queue_depth > 100 触发扩容,queue_depth < 10 触发缩容。优点是直观,缺点是阈值需要按业务反复调优。第二种是「延迟反推」:P99 TTFT > 800ms 触发扩容,按 P99 / SLO_target 比例计算扩容副本数。这种范式更贴近 SLO,但实现复杂且对指标质量要求高。第三种是「预测驱动」:根据历史流量曲线预测未来 5 分钟负载,提前扩容。这种范式对周期性流量(白天/夜间、工作日/周末)非常有效,但对突发流量(营销事件、热点新闻)反应滞后。
生产实践中三种范式通常组合使用。队列长度做快速反应(5-15 秒级),延迟反推做精细调节(30-60 秒级),预测驱动做提前布局(5-30 分钟级)。任何只用单一范式的方案在面对真实业务波动时都会暴露短板。
工程实现细节上,KEDA 的 LLM-aware scaler 通常用 Prometheus 作为指标源。Scaler 通过 PromQL 查询 vllm:num_requests_waiting、vllm:gpu_cache_usage_perc、vllm:time_to_first_token_seconds 三个指标,按业务定义的 SLO 反推目标副本数。反推公式形如:desired_replicas = ceil(current_replicas * (current_metric / target_metric)),但要注意 cooldown 窗口(默认 300 秒)防止抖动。生产调优时 cooldown 通常需要缩短到 60-120 秒,因为 LLM 推理的负载变化比传统微服务快得多。
五、Spot/Preemptible 利用:中断感知路由与有状态恢复
Spot 实例(AWS)或 Preemptible 实例(GCP)的成本通常是按需实例的 30-40%,这对 LLM 推理这种 GPU 密集型服务的 TCO 影响巨大。但 spot 实例随时可能被云厂商回收(提前 30 秒到 2 分钟通知),这意味着直接部署 LLM 推理服务会面临频繁中断。
工程上要把 spot 实例纳入推理服务的资源池,必须解决三个核心问题。第一是中断感知:pod 收到 spot interruption notice 后必须在 30 秒内优雅退出,否则会被强制 kill,权重加载和 KV cache 都会丢失。vLLM 和 SGLang 都实现了 graceful shutdown handler,会在退出前把当前 batch 的请求完成、把 streaming 响应结束。
第二是有状态恢复:被中断的 pod 上的请求不能丢,必须被路由到其他 pod 重试。这要求推理服务实现 request-level retry with idempotency。LLM 推理本身是天然幂等的(同样的 prompt 生成同样的 output,至少在 temperature=0 时),所以 retry 在语义上是安全的。但 streaming 响应需要 server-sent events 重连,客户端需要保存最后接收的 token index 用于断点续传。
第三是拓扑感知:spot 实例的中断不是随机的,是按云厂商的容量调度策略发生的——通常是某个 AZ 的整个实例类型同时被回收。这意味着路由层必须能感知「这个 AZ 的 spot 池即将被清空」并提前把流量迁移到其他 AZ。生产系统通常维护一个 spot health score,路由层根据 score 动态调整权重。
混合按需 + spot 的资源池架构在生产中通常按 30/70 拆分:30% 按需实例承担基线流量,70% spot 实例承担弹性流量。按需实例的冷启动是确定的(云厂商保证容量),spot 实例的冷启动是不确定的(可能被回收)。这种拆分让 C 显著降低,但 L 的尾部会拉长,因为偶尔会有 spot 中断导致的请求重试。
六、Predictive batching:从概率预测到请求合批的放大器
Predictive batching 的核心思想是利用流量预测模型把未来 5-30 秒可能到达的请求做预先合批,让 GPU 在到达时已经处于高利用率状态。这是 cold start 之外的另一条放大器路径,因为它同时压低 W(资源浪费)和 C(单位成本),代价是增加了 L 的方差(预测错误时延迟会拉长)。
预测模型的选择通常不是 deep learning,而是简单的指数加权移动平均(EWMA)+ 周期的组合。LLM 流量的周期特征非常强——工作日 vs 周末、上午 vs 下午、整点 vs 半点——简单的 STL 分解就能捕获 80% 的方差。生产系统通常用 Prophet 或更轻量的 ARIMA,把预测窗口设为 30 秒,预测输出是未来 30 秒的「期望到达率」(requests per second)。
合批策略的关键参数是 max_batch_size 和 max_wait_ms。max_batch_size 决定了 GPU 利用率的天花板——batch=1 时 GPU 利用率 20%,batch=32 时 GPU 利用率 70%+。max_wait_ms 决定了延迟的底线——等待 100ms 凑 batch 的代价是所有请求都被额外加了 100ms 延迟。生产调参的核心是 max_wait_ms 应该等于 P99 TTFT 的可接受额外预算的 50%。
预测错误的处理是另一个工程难点。如果预测未来 30 秒有 100 RPS,但实际只来 30 RPS,那么 batch 会因为 timeout 而提前发出,每个请求都承担了满 max_wait_ms 的延迟。生产实践是用置信区间替代点预测:当预测的不确定性高时(晚间、周末、流量模式变化),减小 max_wait_ms;当预测的不确定性低时(工作日下午、流量模式稳定),放大 max_wait_ms。
实现细节上,predictive batching 通常在网关层(API Gateway)和推理服务之间插入一个 batcher 中间件。Batcher 维护两个队列:input queue(正在等待合批的请求)和 dispatch queue(已经凑齐 batch 准备送入推理服务的请求)。Batcher 的核心状态机是:(1) 收到新请求 → 入 input queue;(2) 每 10ms 检查一次 input queue;(3) 如果队列长度 ≥ max_batch_size 或者队首请求等待时间 ≥ max_wait_ms → 把当前队列内容打包成 batch → 送入 dispatch queue → 推理服务消费 dispatch queue。
更进一步的优化是 hierarchical batching:把 batcher 按请求的优先级分桶(高优先级请求用小 batch + 小 wait time,低优先级请求用大 batch + 大 wait time)。这种分层让 SLO 敏感的核心请求不被长尾请求拖累,而成本敏感的后台请求可以激进合批。Meta 的 Llama 3 inference architecture 公开博客里详细讨论了这种分层 batching 的生产收益:SLO 命中提升 12%,单位成本下降 18%。
最后一个工程关键点是 batcher 的观测性。Batcher 自身需要暴露 batch_size_distribution、wait_time_distribution、prediction_error(预测 RPS vs 实际 RPS 的差值)三个核心指标。SRE 用这三个指标诊断「为什么 batch 效率下降」「为什么延迟方差增加」这类常见问题。
七、Warm pool 设计:跨节点的 GPU 预热池拓扑与换班策略
Warm pool 是抹平冷启动延迟的核心架构。设计一个生产级 warm pool 需要考虑四个维度:节点拓扑、容量配比、换班策略、故障隔离。
节点拓扑。Warm pool 的 GPU 节点必须分布在多个 AZ 和多个故障域,避免单点故障让整个 warm pool 失效。生产部署通常跨 3 个 AZ,每个 AZ 有 N 个 warm pod,N 按峰值 QPS / 单 pod 容量计算,再加 30% 的冗余。Warm pod 与按需 pod 之间的网络拓扑也需要优化——warm pod 必须能快速接收路由流量,跨 AZ 的网络延迟会额外增加 1-3ms 的 TTFT。
更精细的拓扑设计会把 warm pool 按 GPU 类型分组:H100 节点组成 high-tier warm pool(承担大模型推理),A100 节点组成 low-tier warm pool(承担小模型推理)。这种分层让 warm pool 的资源利用率最大化——H100 不能被小模型请求浪费(A100 足够),反之亦然。
容量配比。Warm pool 的「温度」决定它的成本开销。100% warm(所有 pod 随时 ready)的资源浪费是按需 pod 的 100%;50% warm(半数 pod 待机)的资源浪费是 50%;0% warm(无 warm pool,回到冷启动)的资源浪费是 0% 但 L 是 5-10 分钟。生产实践根据流量的周期性选 30-70% 的 warm 比例:流量稳定时选 30%,流量波动大时选 70%。
容量配比的动态调整是进阶工程。生产系统通常维护一个 warm pool autoscaler,根据过去 1 小时的流量曲线自动调整 warm 比例。例如:检测到 23:00-07:00 是低流量时段,warm 比例从 50% 降到 30%;检测到 14:00-16:00 是高峰前奏,warm 比例从 50% 提到 70%。这种动态配比让 warm pool 的成本开销和 SLA 保障同时优化。
换班策略。Warm pod 不能永远常驻,否则内存泄漏、算子 cache 污染、CUDA context 老化会逐步降低推理质量。生产系统通常每 24-48 小时执行一次「换班」:新 pod 启动并 warmup,老 pod 优雅退出并释放资源。换班过程不能让流量中断,所以是滚动式——一次只换 1/N 的 pod。换班策略还需要和模型升级周期对齐——模型升级时整个 warm pool 需要整体重建。
换班过程中最容易出问题的是「老 pod 上的 in-flight 请求」。如果直接 kill 老 pod,正在 streaming 的请求会被截断。生产系统用「优雅 drain」机制:先从 LB 后端摘除老 pod(停止新请求进入)→ 等待 30 秒让 in-flight 请求完成 → kill 老 pod。如果 30 秒后仍有 in-flight 请求,触发强制 kill 但记录 metric,下次换班前分析原因。
故障隔离。Warm pod 本身的故障(CUDA OOM、推理死锁、显存泄漏)必须被健康检查捕获。Kubernetes 的 liveness probe 默认看 HTTP 200,但 LLM 推理服务可能在「假活」状态——端口在响应但所有推理都失败。生产系统用 application-level health check:定期发一个 dummy prompt,要求 P99 TTFT < 100ms 且能正确返回,否则标 unhealthy 并触发换班。
更进一步的故障隔离是「GPU-level circuit breaker」:监控 GPU 的 Xid 错误(NVIDIA driver 报告的硬件错误码)、ECC 错误(显存位翻转)、温度异常。一旦某个 GPU 在 1 小时内出现 ≥ 3 次 Xid,自动把这个 pod 标 unhealthy 并触发换班。这种主动隔离避免了「半坏的 GPU 拖慢所有请求」的灾难模式。
八、讨论:与已有方案的对比 + 局限
本文讨论的弹性伸缩与冷启动工程方案,并不是孤立发明的技术,而是过去三年业界经验的系统化整理。对比几个有代表性的方案:
| 方案 | L(冷启动) | W(浪费) | S(SLO) | C(成本) |
|---|---|---|---|---|
| 纯按需 + HPA | 5-10 分钟 | 30-40% | 差 | 高 |
| Warm pool 100% | < 10 秒 | 80-100% | 好 | 极高 |
| Spot + 重试 | 30 秒-2 分钟 | 50-60% | 中 | 低 |
| Predictive batching | 30 秒 | 20-30% | 中好 | 中低 |
| Warm pool + Spot 混合 | 10-30 秒 | 50-70% | 好 | 中 |
每个方案都有明确的权衡。Warm pool 100% 是「用钱买确定性」,适合 SLA 严格的 ToB 场景;Spot + 重试 是「用风险换成本」,适合成本敏感的 ToC 场景;Predictive batching 是「用预测换效率」,适合流量周期稳定的内部工具场景。
本文方案的局限主要有三点。第一是预测模型对突发流量的无力——一次未预期的热点事件会让所有预测方案全部失效,只能靠临时扩容应急。第二是 warm pool 的隐性成本——除了 GPU 资源,还有 HBM 占用、网络带宽、CUDA context 内存,这些成本在云厂商账单上不会单独列出,但 TCO 影响很大。第三是 spot 实例的中断模式不可控——某些云厂商在某些时段会集中回收 spot 实例,这种「批量回收」会让混合池策略瞬间失效。
九、给 SRE 的可观测性清单
生产级 LLM 推理服务的可观测性必须包含以下指标。建议每个指标都按 pod / node / AZ / cluster 四个维度聚合。
冷启动指标:
cold_start_duration_seconds{pod, model_version, gpu_type}:每个 pod 的冷启动总时长分布(P50/P95/P99)cold_start_stage_breakdown{pod, stage}:六阶段子时长分布(权重读取 / CUDA graph / KV pool / tokenizer / dummy pass)warm_pool_hit_ratio{time_window}:warm pool 命中比例(流量被路由到 warm pod 的比例)
弹性指标:
hpa_lag_seconds{event}:从指标异常到扩容动作的时间差queue_depth{pod, queue_type}:prefill / decode 队列长度kv_cache_utilization{pod}:KV cache pool 使用率replica_count{desired, current}:期望副本数 vs 实际副本数(检测扩容滞后)
SLO 指标:
ttft_seconds{quantile, model_version}:TTFT P50/P95/P99itl_seconds{quantile, model_version}:ITL(inter-token latency)request_error_rate{error_type}:按错误类型分类(OOM / timeout / 5xx)
成本指标:
gpu_utilization{pod, gpu_id}:单卡利用率(区分 compute / memory / PCIe)spot_interruption_count{az, instance_type, time_window}:spot 中断频率cost_per_million_tokens{model_version}:单位 token 成本
SRE 团队建议每周做一次四元组 <L, W, S, C> 趋势复盘,识别哪个维度在恶化,并对症下药。
一句话摘要:LLM 推理服务的弹性伸缩与冷启动工程本质上是在四元组
<L, W, S, C>之间寻找帕累托最优,warm pool 抹平冷启动、spot instance 压低成本、predictive batching 提升利用率,三者必须按业务 SLO 预算组合才能达到「零感知扩容」的工程理想。
参考文献
- Kwon, W., et al. (2023). Efficient Memory Management for Large Language Model Serving with PagedAttention. SOSP '23.
- Sheng, Y., et al. (2024). SGLang: Efficient Execution of Structured Language Model Programs. arXiv:2312.07104.
- NVIDIA (2024). TensorRT-LLM: A High-Performance LLM Inference Library. NVIDIA Technical Report.
- Amazon Web Services (2024). EC2 Spot Instances Best Practices for Machine Learning Workloads. AWS Whitepaper.
- Kubernetes Autoscaling Special Interest Group (2024). KEDA: Kubernetes Event-Driven Autoscaling. CNCF Sandbox Project.
- Anyscale (2024). Ray Serve: Production-Ready Model Serving Framework. Anyscale Documentation.
- vLLM Project (2024). vLLM Metrics and Monitoring Guide. vLLM Official Documentation.
- Google Cloud (2024). Preemptible VM Instances and GPU Workload Patterns. GCP Architecture Center.
- Pope, R., et al. (2023). Efficiently Scaling Transformer Inference. MLSys '23.
- Microsoft DeepSpeed Team (2023). DeepSpeed-Inference: Enabling Efficient Inference for Transformer Models. arXiv:2207.00032.
- Meta AI (2024). Llama 3 Inference Architecture and Scaling. Meta Engineering Blog.
- Databricks (2024). LLM Serving on Databricks: Autoscaling and Cold Start Optimization. Databricks Documentation.
- Yu, G., et al. (2022). Prophet: Forecasting at Scale. The American Statistician.
- Hamilton, J. D. (1994). Time Series Analysis. Princeton University Press.