警告
本文使用的公开材料仅能确认 Dark Sky 的后端架构到一定程度,未披露的部分不应外推。本文不涉及 Dark Sky 的移动应用、网站或其他前端产品。本文由 Claude&Codex 协助整理,未经前 Dark Sky 团队确认。相关信息可能存在不准确或过时的情况。请谨慎参考。
引言
Forecast.io 后来更名为 Dark Sky,其核心产品是按经纬度查询的天气 API。Dark Sky 于 2020-03-31 被 Apple 收购,API 服务于 2023-03-31 结束。本文使用的公开材料包括 Wayback Machine 存档、Hacker News 原帖,以及 darkskyapp GitHub 组织下留存的仓库。
本文按以下两条证据边界整理这些材料:
- 每条结论注明材料来源及其覆盖范围;
- 材料未涉及的部分标为「未披露」,不依据相邻证据外推。
2012 年官方 Open Source 文章中「格点数据存成图像」的表述对应早期雷达临近预报链路。该文早于通用 Forecast Data API 发布,文内回指链接也指向介绍 NEXRAD 雷达处理的 How Dark Sky Works。因此,这一表述不能用于判断 GFS、NAM 等数值模式格点的在线存储格式。该存储格式至今未披露。
创始人公开说明的后端组件
2013-03-27,Forecast.io 和 Forecast Data API 发布次日,用户 JonathanHunt 在 Hacker News 发布帖 下询问后端使用的数据库。联合创始人 Adam Grossman(HN 账号 thegrossman)回答:
The top layer of our backend is node.js running behind nginx. We use redis for storage, along with a bunch of flat files for certain things. Under that is a mostly ruby / mysql layer that manages a bunch of C programs for doing various number crunching tasks.
在本文收集的材料中,这是唯一一条创始人对后端组件的直接说明,发布时间对应已经完成重写的通用预报服务。原文可以确认以下组件关系:
这段话未披露 Redis 保存的是 API 结果、模式取值、会话还是元数据,也未披露 flat files 是否保存 GFS、NAM 等模式场,以及 MySQL 的表结构和数据职责。原文用词是 storage,缺少将其进一步描述为格点主库所需的数据对象映射证据。
其他结论依据 darkskyapp GitHub 公开仓库、Chef cookbook、API 文档语义和博客技术文章交叉推断,置信度低于这条直接说明。
对外产品形态
2013-03-26 发布的 Forecast Data API 是从原 Dark Sky 专用接口重写而来,当时官方称接入了 16 个数据源。到 2019 年的 API 文档快照,核心请求仍然是单一形式:
| |
返回内容为当前状况、未来一小时逐分钟预报(视地区可用性)、未来 48 小时逐小时预报、未来一周逐日预报。没有原始模式格点下载接口。
2019 年 API 文档说明,响应中的 flags 字段返回 sources(本次请求实际使用的源 ID 数组)和 nearest-station(最近贡献站点的距离)。2014 版文档中的 v1 还返回 isd-stations、madis-stations、metar-stations、lamp-stations、darksky-stations 等站点 ID 列表。每次请求的数据源组合随位置变化,这一组合只能在请求到达后确定。
数据源清单的变化
v1 时代的 forecast.io/raw 页面列出约 20 个源:
| id | 源 | 覆盖 |
|---|---|---|
darksky | 自研雷达临近预报(NEXRAD + NIMROD) | US / UK / IE |
gfs | NOAA Global Forecast System | 全球 |
nam | NOAA North American Mesoscale | 北美 |
rap | NOAA Rapid Refresh | 北美 |
sref | NOAA/NCEP Short-Range Ensemble Forecast | 北美 |
rtma | NOAA Real-Time Mesoscale Analysis(2.5 km) | 北美 |
cmc | Environment Canada CMC 集合 | 全球 |
naefs | NOAA + EC North American Ensemble | 全球 |
fnmoc | US Navy FNMOC 集合 | 全球 |
metno / metno_ce / metno_ne | 挪威气象局 API 与 GRIB | 全球 / 欧洲 |
datapoint | UK Met Office Datapoint | UK |
lamp | NOAA LAMP(统计后处理) | US |
isd | NOAA Integrated Surface Database | 全球(历史) |
madis | NOAA/ESRL MADIS | 全球(站点) |
metar | 全球 METAR | 全球(站点) |
nwspa / metwarn | 美 / 英预警 | US / UK |
到 2019 年的数据源文档 快照,清单缩减为 13 项:cmc、darksky、ecpa、gfs、hrrr、icon、imo、isd、madis、meteoalarm、nam、nwspa、sref。
变化包括:
- 移除
rap、fnmoc、naefs、metno*、datapoint、lamp、metar; - 新增
hrrr(3 km 快速刷新)和icon(DWD 二十面体全球模式); - 预警源按地区拆分为
nwspa、ecpa、imo、meteoalarm。
官方未披露移除各源的具体依据。
摄取:轮询与推送两条路径
node-sarra 仓库创建于 2017-08,最后更新于 2020-07。该项目是 Sarracenia 的 Node.js 客户端,Sarracenia 是加拿大 ECCC 的 AMQP 推送分发服务。README 说明连接失败后会自动重连,并区分 dev 和 prod 队列及其过期时间,同时指出队列非持久化或断连超过过期窗口时会丢失消息。支持推送的数据源使用 AMQP 订阅,其余数据源的获取方式未披露。
雷达数据使用独立的处理流程,相关公开材料较完整。根据 2011 年的 How Dark Sky Works 和 2013 年的 Cleaning Radar Images:
- 从 NOAA 下载 NEXRAD 原始二进制雷达数据,转成图像;
- 用 FANN C 库训练的 25 神经元网络把回波块分类为信号或噪声,识别出 90% 到 95% 的噪声,剩余部分由人工编写的启发式规则处理,训练集由人工标注;
- 用 OpenCV 光流估计降水区域速度场;
- 将 x 方向速度、y 方向速度和强度变化编码进图像通道下发;
- 每收到新雷达帧,把旧帧外推到当前时刻与实测对比,持续评估误差。
官方给出的处理耗时为:
it takes between 1 and 2 seconds to convert a raw radar data file to a cleaned image, and we dedicate 16 cores worth of virtual servers to the task.
第 3 步不使用多普勒径向速度,Grossman 在 2011 年的 HN 回复 里给的理由是对流单体常常原地生消甚至逆风移动,径向风速对预测移动方向的参考价值有限。
How Dark Sky Works 说明外推和动画由客户端 GPU 执行,服务端只下发编码成图像的速度场。
从格点到点
Dark Sky 未公开完整的点查询代码。现有材料可以确认几个彼此独立的空间处理方法。
站点类数据使用 Delaunay 三角剖分加重心坐标插值。2012-05-31 的 How Dark Sky Calculates Temperature 说明先在站点之间连成三角网,查询点定位到所在三角形后,对三个顶点站点取加权平均;脚注说明使用重心坐标判断点是否落在三角形内,同时直接得到三个顶点的权重系数。对应的开源实现是 delaunay-fast 和 delaunay。
站点近邻查询使用 sphere-knn。README 说明它源自 Dark Sky API 的需求,并自 2012 年 10 月起用于生产。
读取路径还包含一项前置判断。inhabited 的 README 说明它用于快速判断一个位置是否可能有人居住,从而跳过开销较大的 geocoding 查询。此类位置在产品中显示为 Middle of Nowhere。
格点类数据先做偏差订正再融合。2013-07-16 的 New Data Sources: SREF and RTMA 说明 2.5 km 的 RTMA 除了直接参与计算,还用于订正地面站观测:
if your location happens to be 5° warmer (on average) than the nearest ground station, we’ll adjust the station’s temperature upwards by 5° before factoring it into your particular forecast.
forecast.io/raw 页面同时提供 temperature (raw) 和 temperature (bias corrected) 两条曲线,也允许输入任意经纬度和要素,分别查看各数据源的原始时间序列。这些功能说明系统在合成前可以取得各数据源的独立数值,未披露偏差订正结果和各源时间序列是否持久化。
多模式权重按区域动态确定。2013 年 Washington Post 的评测 中,Grossman 说明每个模式先做地理偏差订正,系统按区域持续监测各模式准确率并计算标准误差,请求到达时依据标准误差动态设置权重。权重函数的具体形式未披露。
公开材料支持以下逻辑步骤:
| |
其中偏差订正、区域误差统计和请求时动态加权有公开说明;模式轮次选择、格点读取、插值实现、文件命名和服务边界均未披露。
图像化格点的适用范围
2012-11-20 的 Open Source 是团队开发者 Jay LaPorte 对当时开源出来的五个 Node.js 模块(cache-helpers、pngparse、sphere-knn、string-hash、tz-lookup)的介绍,文中给出四条信息:
- 当时的 Dark Sky API 基本完全由 Node.js 编写,选型理由是「so darned fast and lightweight, we can power the entire API off of a few teensy virtual machines」;
- API 的速度主要来自大量缓存;
- 格点数据存成图像,
pngparse是 API 读取这些图像的模块; - 站点近邻查询使用
sphere-knn,理由是大部分天气数据来自地基雷达站,查询请求位置附近有哪些站点是常见操作。
第三条的适用范围受发布时间和回指链接限制:
Open Source发布于 2012-11-20;- 通用 Forecast Data API 发布于 2013-03-26,官方明确称新 API 在原专用 API 基础上从头重建;
- 文中「We’ve mentioned before」的链接指向 2011 年的 How Dark Sky Works,该文完整讨论 NEXRAD 雷达图像、运动场和客户端外推,没有讨论数值模式预报格点。
因此,现有证据支持将图像存储和 pngparse 归入早期雷达临近预报链路,无法据此判断后来 Forecast Data API 的数值模式格点是否使用 PNG。
其余几个仓库提供的证据及其边界如下:
| 仓库 | 能确认的内容 | 边界 |
|---|---|---|
| pngparse | 从 PNG 文件或 Buffer 读取像素数组,源于早期 Dark Sky API 需求 | 上下文指向雷达 API |
| pbj | 自定义单色位图格式,uint16 LE 宽高加逐 bit 位图,支持 gzip,项目说明称曾代替 PNG 用作存储格式 | 承载的业务对象未披露 |
| elevation | 全球高程格点放在本地二进制文件 elev.bin,按 (y * width + x) * 2 计算偏移做定长随机读取,文件描述符由 cache-helpers.once 只打开一次 | 静态高程层,不随轮次更新 |
| storage-cookbook | 挂载全部 EC2 临时卷并把挂载点写入 node attributes,仅支持 EC2 | 与气象数据路径的关系未披露 |
| zqueue | Redis sorted set 实现的优先队列 | 队列承载的任务类型未披露 |
2013-08-28 的 Project Quicksilver 提供了数值模式与图像之间唯一的直接联系,也是唯一被详细描述过的完整格点生产流程:
- 输入包括 GFS(当时 0.5°)等低分辨率模式、ISD 地面站、MODIS(Terra/Aqua 的地表温度月均高低值、植被覆盖、发射率、反照率)和 USGS GMTED 30 弧秒高程;
- 用神经网络做非线性回归,学习静态地理量到日最高、最低气温偏离量的映射,得到微气候扰动场;官方明确说明该网络的输出不能直接使用,可用的是相对温度差;
- 把扰动场叠加到低分辨率模式场上完成降尺度;
- 用实时地面站观测做整体偏差订正;
- 对每个源重复上述步骤,再做加权平均;
- 输出为 16 bit 灰度 GeoTIFF,每像素最大边长约 3.5 mile,每小时重算一次,交给 MapBox 切瓦片。
Quicksilver 说明模式数据经过了图像化派生处理,输出为文件。文章同时明确说明:
we aren’t using it to provide current temperature data for forecast.io
因此,现有材料无法确认点 API 的温度数据是否来自这条处理流程,输入模式格点在在线 API 中的存储格式也未披露。
另一篇 RGB Temperature 说明不同时刻的天气数值分别编码到 RGB 三个通道,一次传输三个时刻的数据。这条证据属于地图传输层。
不保存历史预报
Dark Sky API FAQ 包含一条直接问答:
Can I get your previous forecasts instead of weather station observations? Unfortunately, we do not have the storage capacity to store previous forecasts. Sorry!
FAQ 对历史数据来源还有一条说明:
Several of our data sources aren’t real-time, and flow into our system after the fact. As a result, our historical data may continue changing for up to two weeks after a time has occurred.
由此可以确认,Time Machine 不返回历史预报归档。FAQ 说明历史报告通常基于观测数据,缺少观测时会由其他来源补齐。这两条 FAQ 未披露当前有效预报的具体保留期限。
缓存
cache-helpers 的 README 明确称它是从 Dark Sky API 中反复出现的缓存模式抽取出来的模块,公开实现包含三种:
| 组件 | 语义 |
|---|---|
once | 首次调用加载并缓存,并发调用合并为一次后端加载 |
timeBasedWithGrace | 软过期未到直接返回缓存;软过期已过硬过期未到,先返回旧值并在后台刷新;硬过期已过则阻塞到新值可用 |
sizeBasedKeyValue | 按容量淘汰的进程内键值缓存 |
README 对两个阈值的解释是「the time until data is out of date」和「the time until data is unacceptably out of date」。timeBasedWithGrace 的语义与 stale-while-revalidate 一致。2017 年公开的 cache 是 Promise 支持的进程内 TTL 缓存,会缓存正在执行的 Promise,使同一进程内的并发请求共享一次后端加载。
这些组件的源码未包含业务对象信息,无法确认数值模式 API 实际缓存了哪些对象。
公开材料可以确认以下对外缓存语义:
- API 文档说明响应返回保守设置的
Cache-Control,取值依据响应中包含的数据确定; - FAQ 说明 minutely 数据每 5 分钟更新,hourly 和 daily 每小时更新,灾害预警实时更新;
exclude=参数文档说明用途是「reducing latency and saving cache space」,说明排除 blocks 可以减少响应缓存占用;- FAQ 说明服务端禁用 CORS,并要求调用方自建代理,调用方可以在代理上缓存响应。
基础设施演进
| 时期 | 形态 | 依据 |
|---|---|---|
| 2011 至 2015 | Linode,约 100 台虚机,自运维 | Grossman Dark Sky Has A New Owner(2015-01-12):「keeping a hundred Linode servers up and running」 |
| 2015 | 与 Applied Invention 合并,团队扩张 | 同一官方公告 |
| 2016 至 2020 | EC2,Chef 管理配置 | Chef cookbook 仓库的创建时间线1 |
| 2020-03-31 | 被 Apple 收购 | Dark Sky 官方公告 |
| 2023-03-31 | API 关停 | Apple 支持文档 |
公开材料显示,2011 年到 2020 年的基础设施主要由长期运行的虚机构成。2016 年后的 cookbook 显示配置由 Chef 管理;本文检查的 darkskyapp 公开仓库中未见容器或 Serverless 相关材料。
公开材料支持的系统边界
- 数值模式来自政府机构,Dark Sky 负责统计后处理和融合。数据源文档列出各政府机构提供的模式;Grossman 说明团队成员没有气象学背景,Jack Turner 将短临方法描述为 numerical & statistical approach,多模式融合方式则见 Washington Post 评测存档。
- 系统不保存历史预报归档,FAQ 直接说明存储容量不足。
- 本文检查的 API 文档和公开仓库未提及专用的地理或时序数据库(PostGIS、InfluxDB、Cassandra 等)。
flags.sources随位置变化、forecast.io/raw 支持任意点抽取、sphere-knn 和 inhabited 服务于查询路径,这四条证据共同支持请求时按点合成的判断。- 分钟级外推和动画由客户端 GPU 执行,流程见 How Dark Sky Works。
- 截至 2026-08-09,在 Google Patents 中以「Dark Sky Company」检索未得到结果。
证据分级
高置信度结论
- 后端组件。 后端包括 nginx、Node.js、Redis storage、flat files、Ruby/MySQL 和 C 计算程序。依据:创始人在上线次日的直接说明。
- 历史预报归档。 Dark Sky 不保存历史预报归档。依据:官方 FAQ。
- 早期雷达格点。 格点以图像形式存储。依据:Open Source 的回指链接和发布时间线。
- 早期雷达 API。 API 主要由 Node.js 实现。依据:2012 年官方说明。
- Quicksilver 输出。 输出采用灰度图和 GeoTIFF。依据:官方技术文章。
- 多模式加权。 系统在请求阶段按区域误差动态设置权重。依据:创始人技术说明。
- 站点近邻查询。 查询使用内存空间索引。依据:sphere-knn 的生产说明。
- 缓存组件。 组件支持后台刷新和并发请求合并。依据:cache-helpers 和 cache 源码。
间接证据支持的结论
- 请求时按点合成。 确认程度为中高。API 文档、raw 页面、sphere-knn 和 inhabited 四条间接证据一致。
- 2016 年后从 Linode 迁到 AWS。 确认程度为中,结论由 cookbook 时间线推断。
未披露
- EC2 临时卷的业务用途。 storage-cookbook 未披露临时卷是否保存气象格点文件。
- pbj 承载的业务对象。 pbj 未披露它是否用于数值模式格点存储。
- Redis 优先队列的生产用途。 zqueue 未披露承载的任务类型。
- 数值模式格点的存储介质。 创始人说明没有给出数据对象与 Redis、flat files、MySQL 之间的映射。
- Forecast Data API 模式格点的存储格式。 现有材料没有支持图像存储的直接证据。
- GRIB 解码工具。 「C programs for number crunching」是唯一线索。
- Redis 的 key 设计和数据结构。 公开材料没有相关信息。
- 多源加权的权重函数。 创始人说明提及基于历史准确率调整,没有给出具体形式。
可复现项目对照
Dark Sky 的模式格点存储未披露。以下两个可复现项目展示了模式格点存储的具体实现。
Pirate Weather 复刻了 Dark Sky 的 API 语法,公开了完整架构:
其中几个数字和选择:原始 GRIB 直接查询约需 20 秒,无法用于在线请求;预处理把 GRIB 合并转成 NetCDF4,按时间维分块并限制有效位数;wgrib2 运行在 Fargate 上,Lambda 的临时存储上限无法满足要求;GFS 和 GEFS 对最近 9 个格点按距离倒数加权;单次请求 1 到 3 秒;历史数据直接读取 S3 上的 ERA5 云原生 Zarr。文档明确说明这套方案未使用传统数据库。
Open-Meteo 每天处理超过 2 TB 模式数据,保存为本地自定义 .om 二进制文件,README 说明文件格式和压缩针对 14 天时间序列这类访问模式优化,公开 API 声称响应时间低于 10 ms。
两个项目均按查询形状设计文件布局,由文件格式和分块承担主要数据访问职责。天气点 API 的典型请求是读取一个空间位置上的多个变量和多个时次。按时间序列方向分块有利于利用页缓存和顺序读取提高吞吐量。
另一种实现可以参照 Tomorrow.io(原 ClimaCell)的专利 US10962680B2,其中描述了四类服务器和「tile layer + cadence」的瓦片化格点存储,支持按瓦片增量重算。这套方案的工程量高于上述两个项目,可作为设计取舍的参照。
仍然未查明的部分
- 最新模式轮次采用原始 GRIB、转换后的数组文件、数据库记录还是内部服务;
- 在线查询是直接读文件、访问共享存储、调用独立格点服务还是查询数据库;
- 最新模式轮次位于本地磁盘、共享文件系统还是对象存储;
pbj是否用于模式格点,还是仅用于雷达掩膜;- 是否有 CDN 前置;
- Apple 收购后 WeatherKit 是否沿用该架构。
上述问题均缺少公开材料。后续可继续检查 Applied Invention 的技术材料,以及 darkskyapp 各仓库的 commit 历史和 issue。
Dark Sky 原团队于 2026-02 发布了新产品 Acme Weather。官方介绍称数据来自数值模式、卫星、地面站和雷达,预报为自研。基础设施细节未披露。
仓库内容见 nodejs、lockrun-cookbook、chef-server、s3_put-cookbook、aws 和 storage-cookbook,创建时间取自 GitHub REST API 元数据。 ↩︎