- 后端
- 数据分析
- 数据可视化
- 数据库
【免费下载链接】cube
📊 Cube Core is open-source semantic layer for AI, BI and embedded analytics
Cube 开源语义层(Cube Core)通过@cubejs-backend/redshift-driver为 Amazon Redshift 提供纯 JavaScript 数据库驱动支持。本文以 packages/cubejs-redshift-driver/CHANGELOG.md 为主体脉络,梳理该驱动自 2021 年引入以来的关键里程碑(UNLOAD 直出 S3、IAM 认证、Spectrum 外部表内省、schema 查询修复等),并结合 RedshiftDriver.ts、RedshiftIAMCredentialsProvider.ts 与 env.ts 中的源码实现,讲解每个能力的底层原理、环境变量与配置方法。读完本文,你将掌握 Redshift 驱动的核心能力边界、关键环境变量的作用与取值约束,并能读懂其版本演进规律,为实际部署与排障提供依据。
一、驱动定位:Cube 语义层中的 Redshift 接入层
在 Cube 的架构中,数据库驱动负责将语义层编译出的查询下推到目标数据源,并完成元数据(schema/table/column 结构)的发现。Redshift 驱动的官方定位是"Pure Javascript Redshift driver"(见 README.md),即不依赖原生编译模块、纯 JavaScript 实现的驱动包。
从源码结构看,该包由 4 个文件组成:
- RedshiftDriver.ts:驱动主类,继承自 PostgreSQL 驱动;
- RedshiftCredentialsProvider.ts:凭证提供者接口与明文凭证实现;
- RedshiftIAMCredentialsProvider.ts:基于 AWS SDK 的 IAM 临时凭证实现;
- index.ts:包导出入口。
关键设计是继承自PostgresDriver(见 RedshiftDriver.ts#L57)。由于 Redshift 的查询协议兼容 PostgreSQL 线协议,驱动可以复用 postgres 驱动的连接池、查询执行、流式读取等能力,只在 Redshift 有差异的地方做覆盖。这也是 CHANGELOG 中大量变更同时出现在redshift-driver与postgres-driver下的原因——例如 1.6.12 版本的连接池迁移(#10389)和 1.6.34 版本的连接错误信息优化(#10679)均由 postgres 驱动底层能力提升传导而来。
二、读懂 CHANGELOG:3654 行变更记录的阅读方法
该 CHANGELOG 文件共 3654 行,记录了从 v0.27.25(2021-06-01)到 v1.7.42(2026-09-18)的完整版本历史。文件头注明遵循 Conventional Commits 规范(原文为外部链接,本文仅作说明),由 lerna 等 monorepo 发布工具自动生成。
阅读时需要注意两类条目的区别:
Version bump only占位条目:绝大多数版本(如 1.7.42、1.7.41、1.7.40 等)仅有"Version bump only for package @cubejs-backend/redshift-driver"这一行说明,表示该版本下此包没有代码级变更,只是跟随整个 Cube monorepo 统一发版。这类条目是仓库发布节奏的记录,不含技术内容。Features/Bug Fixes实质条目:带**redshift-driver:**前缀或影响该包能力的实质变更。统计整个文件,Features/Bug Fixes/Performance Improvements等分类标题共出现 55 处,其中直接标注redshift-driver的实质变更约 12 条,是本文分析的主线。
将这些实质变更按时间排列,可以得到驱动能力的演进主线:
| 版本 | 日期 | 变更内容 | 能力影响 |
|---|---|---|---|
| 0.27.25 | 2021-06-01 | 引入 Redshift 驱动(基于 postgres-driver);支持 UNLOAD 直接导出到 S3 | 驱动诞生,具备数据导出能力 |
| 0.27.26 | 2021-06-01 | publishConfig 设为 public | 包可公开发布到 npm |
| 0.28.20 | 2021-08-15 | 不加载用户自定义类型(user defined types) | 规避 Redshift 与 PostgreSQL 的pg_type差异 |
| 1.0.3 | 2024-10-22 | 优化testConnection(),仅建连不执行真实查询 | 降低健康检查成本(Redshift 查询计费) |
| 1.1.1 | 2024-10-31 | 支持外部 schema/表(如 Spectrum)的内省 | 元数据发现覆盖外部表 |
| 1.2.10 | 2025-02-24 | 修复外部(Spectrum)表tableColumnTypes为空的问题 | 外部表可用于预聚合建表 |
| 1.2.26 | 2025-03-21 | 使用 Redshift 专用 schema 查询(#9363,关闭 #3876) | 修复非当前用户 schema 不可见问题 |
| 1.3.59 | 2025-08-26 | 使用正确的列类型查询,尊重fetchColumnsByOrdinalPosition(#9915) | 修正列顺序/类型获取 |
| 1.6.12 | 2026-02-16 | 支持 IAM 认证(#10391);postgres 驱动迁移到自研连接池 | 免密码认证 + 连接池升级 |
| 1.6.34 | 2026-04-14 | 支持按预聚合配置独立数据源;连接错误信息优化 | 多数据源精细化配置 |
| 1.7.37 | 2026-09-10 | 迁移 TypeScript 6.0.3;所有驱动支持具名 ESM 导出 | 类型系统与模块体系升级 |
下文按能力维度展开这些变更背后的源码实现。
三、基于 PostgreSQL 协议的继承与 Redshift 差异化适配
RedshiftDriver继承PostgresDriver(RedshiftDriver.ts#L57),因此 PostgreSQL 的查询执行、预处理语句、流式读取等机制被整体复用。但 Redshift 并非完全兼容 PostgreSQL,驱动针对差异点做了多处理:
3.1 元数据查询的专属 SQL
Redshift 中部分系统表行为与 PostgreSQL 不同,驱动通过覆盖查询语句适配:
informationSchemaQuery()(RedshiftDriver.ts#L143-L152):从information_schema.columns读取列元数据,并排除pg_catalog、pg_internal、information_schema、mysql、performance_schema、sys、INFORMATION_SCHEMA等系统 schema(常量IGNORED_SCHEMAS)。createSchemaIfNotExists()(RedshiftDriver.ts#L160-L166):这是 1.2.26 版本"Redshift-specific schema query"(#9363)修复的体现。注释说明:在 Redshift 中,非当前用户拥有的 schema 不会出现在常规information_schema中,需要通过pg_namespace表查询,否则用户即使被授予了在既有预聚合 schema 中建表的权限,也可能因 schema 无法被发现而导致建表失败。getSchemasQuery()(RedshiftDriver.ts#L212-L219)与getSchemas()(RedshiftDriver.ts#L227-L233):使用 Redshift 专有的SHOW SCHEMAS FROM DATABASE语句,该语句能同时返回常规 schema 与外部(Spectrum)schema,再过滤系统 schema。
3.2 表名长度与参数数量限制
createTable()(RedshiftDriver.ts#L298-L311):Redshift 表名最长127 个字符(PostgreSQL 是 63 个),超限时抛出明确错误,并提示在 Cube 定义中使用sqlAlias属性缩短表名。注意这里刻意不调用super.createTable(),因为父类含 63 长度检查。checkValuesLimit()(RedshiftDriver.ts#L288-L296):Redshift 服务端对参数化查询的参数数量存在兼容性缺陷,超过32767 个参数值时会报there is no parameter $-32768。驱动在stream()与queryResponse()两个入口统一拦截,抛出更有意义的错误信息。
3.3 连接测试不做真实查询
AWS Redshift 没有专门的连接检查语句,而且查询即使是系统表也会计费。1.0.3 版本(#8847)将testConnection()优化为仅从连接池获取并释放连接(RedshiftDriver.ts#L318-L321),不执行任何 SQL,从而在保证健康检查能力的同时避免产生查询费用。
3.4 不加载用户自定义类型
0.28.20 版本"Don't load user defined types"的对应实现是loadUserDefinedTypes()空方法(RedshiftDriver.ts#L396-L398),注释说明 Redshift 的pg_type表不存在typcategory列,无法复用 PostgreSQL 的加载逻辑,因此留待后续实现。从代码结构看,该能力是预聚合等场景的类型映射辅助函数。
四、UNLOAD:将查询结果直接导出到 S3
0.27.25 版本(2021-06-01)在引入驱动的同时带来了"Support UNLOAD (direct export to S3)",这是 Redshift 驱动最具差异化价值的能力:利用 Redshift 的UNLOAD语句,将表/查询结果以 CSV+GZIP 格式导出到 S3,供 Cube 的导出与外部系统使用。
4.1 配置前提:exportBucket
导出的前提是配置了 S3 导出桶,由getExportBucket()(RedshiftDriver.ts#L339-L394)读取环境变量构建:
| 环境变量 | 说明 | 必填 |
|---|---|---|
CUBEJS_DB_EXPORT_BUCKET_TYPE | 存储类型,Redshift 仅支持s3,其他值直接抛错 | 是 |
CUBEJS_DB_EXPORT_BUCKET | S3 桶名 | 是 |
CUBEJS_DB_EXPORT_BUCKET_AWS_REGION | S3 桶所在区域 | 是 |
CUBEJS_DB_EXPORT_BUCKET_AWS_KEY | AWS Access Key | 二选一(见下) |
CUBEJS_DB_EXPORT_BUCKET_AWS_SECRET | AWS Secret Key | 二选一 |
CUBEJS_DB_REDSHIFT_UNLOAD_ARN | 用于 UNLOAD 的 IAM Role ARN(unloadArn) | 二选一 |
CUBEJS_DB_EXPORT_BUCKET_CSV_ESCAPE_SYMBOL | 导出 CSV 的转义符号 | 否 |
这些变量的定义见 env.ts#L880-L963。校验规则(源码getExportBucket中)为:三个必填键缺一即抛错;若未设置unloadArn,则keyId与secretKey必须齐全——即凭证要么走 AK/SK,要么走 IAM Role。
4.2 UNLOAD 执行流程源码拆解
unload()方法(RedshiftDriver.ts#L421-L520)的执行链路:
- 读取表列类型,拼出
SELECT col1, col2, ... FROM tableName子查询; - 用
crypto.randomBytes(10).toString('hex')生成随机导出路径,避免冲突; - 构造导出选项:
REGION、HEADER(含表头)、FORMAT CSV、GZIP、MAXFILESIZE(取options.maxFileSize,单位为 MB); - 执行
UNLOAD (...) TO 's3://bucket/path/',凭证部分按unloadArn是否存在选择iam_role '...'或CREDENTIALS 'aws_access_key_id=...;aws_secret_access_key=...'; - 通过 PostgreSQL 协议监听
notice消息,解析形如UNLOAD completed, 0 record(s) unloaded successfully.的消息提取导出行数(见 RedshiftDriver.ts#L453-L468)——行数为 0 时直接返回空结果,不再访问 S3; - 行数大于 0 时,调用
extractUnloadedFilesFromS3()从 S3 拉取导出文件,返回{ exportBucketCsvEscapeSymbol, csvFile, types }供上层消费; finally中移除 notice 监听并释放连接。
isUnloadSupported()(RedshiftDriver.ts#L417-L419)返回!!this.config.exportBucket,即上层可通过该开关判断当前数据源是否具备导出能力。
五、IAM 认证:免密码接入与临时凭证管理
1.6.12 版本(2026-02-16,#10391)为驱动引入 IAM 认证。这是对 Redshift 运维场景的重要补充:生产环境通常不希望将数据库密码直接写入环境变量,而希望基于 AWS 身份体系自动签发临时凭证。
5.1 触发条件与凭证提供者选择
构造函数(RedshiftDriver.ts#L99-L125)中的选择逻辑:
若设置了 CUBEJS_DB_REDSHIFT_CLUSTER_IDENTIFIER,且未设置 CUBEJS_DB_PASS 与 config.password → 使用 RedshiftIAMCredentialsProvider(IAM 临时凭证) 否则 → 使用 RedshiftPlainCredentialsProvider(明文 user/password)即只要提供了 cluster identifier 且没有显式密码,驱动即自动切换到 IAM 认证,无需额外开关。
5.2 IAM 凭证提供者的实现要点
RedshiftIAMCredentialsProvider.ts 基于@aws-sdk/client-redshift的GetClusterCredentialsWithIAMCommand实现:
- 必需的三个配置(RedshiftIAMCredentialsProvider.ts#L35-L50):
CUBEJS_DB_REDSHIFT_AWS_REGION、CUBEJS_DB_REDSHIFT_CLUSTER_IDENTIFIER、CUBEJS_DB_NAME,缺失任一直接抛错; - 跨账户支持:配置
CUBEJS_DB_REDSHIFT_ASSUME_ROLE_ARN时使用fromTemporaryCredentials做角色切换,并可附带CUBEJS_DB_REDSHIFT_ASSUME_ROLE_EXTERNAL_ID作为外部 ID(RedshiftIAMCredentialsProvider.ts#L56-L63); - 有效期与刷新:
DurationSeconds设为 1800 秒(源码注释指出默认 15 分钟、最长 1 小时),凭证缓存到期前1 分钟(REFRESH_BUFFER_MS = 60 * 1000)即视为过期并触发刷新(RedshiftIAMCredentialsProvider.ts#L74-L97); - 并发保护:使用
inflightRefresh字段保证多请求并发时只发起一次凭证刷新,其余请求复用同一 Promise,避免凭证风暴; - 连接注入:
createConnection()(RedshiftDriver.ts#L127-L130)在建连前异步获取{ user, password }并注入连接配置,因此 IAM 与明文两种模式对上层查询逻辑完全透明。
对应环境变量定义见 env.ts#L1462-L1510,其中还包括CUBEJS_DB_REDSHIFT_WORKGROUP_NAME(Redshift Serverless workgroup 名)的定义,说明该设计同时考虑了 Serverless 形态的接入。
六、外部表(Spectrum)元数据内省
Redshift Spectrum 允许对 S3 上的外部数据直接查询,但外部表不会出现在常规information_schema中(与 PostgreSQL 的元数据机制不兼容)。1.1.1 版本(#8849)引入外部 schema/表内省,1.2.10 版本(#9251)修复外部表tableColumnTypes为空的问题,使外部表能够参与 Cube 的元数据发现与预聚合。
6.1 元数据结构合并
tablesSchema()(RedshiftDriver.ts#L173-L198)先将常规 schema 通过information_schema构建出DatabaseStructure,再调用getSchemas()拿全量 schema 列表,两者求差得到外部 schema 集合,逐个通过 Redshift 专有语句补全:
SHOW TABLES FROM SCHEMA db.schema(tablesForExternalSchema,RedshiftDriver.ts#L201-L203);SHOW COLUMNS FROM TABLE db.schema.table(columnsForExternalTable,RedshiftDriver.ts#L205-L207)。
同理,getTablesForSpecificSchemas()与getColumnsForSpecificTables()(RedshiftDriver.ts#L235-L272)在父类查询结果上计算"缺失的 schema/表",再走外部表补查,保证增量加载 schema 时外部表也能被发现。
6.2 tableColumnTypes 兜底
tableColumnTypes()(RedshiftDriver.ts#L400-L415)先尝试常规information_schema.columns查询;若结果为空,则判定目标表可能是 Spectrum 外部表,拆分schema.table后走SHOW COLUMNS FROM TABLE补查,并将列类型通过toGenericType()映射为 Cube 通用类型。这是 1.2.10 修复的核心逻辑:此前外部表在此路径返回空数组,导致依赖列类型的功能(如 UNLOAD 的 SELECT 拼接)无法工作。
七、查询正确性、多数据源与工程化演进
7.1 列类型查询与列顺序修正
1.3.59 版本(#9915)修复了列类型查询未尊重fetchColumnsByOrdinalPosition的问题。该参数控制列元数据是否按物理顺序返回,修复后 Redshift 驱动使用正确的查询语句保证列顺序与表定义一致,避免因列错位导致的类型映射错误(该能力由 0.27.25 时期"fixes column order"(#6068)的基础演进而来)。
7.2 预聚合专用数据源配置
1.6.34 版本(#10587)支持"pre-aggregation-specific data source configuration"。对应实现中,getEnv(..., { dataSource, preAggregations })的调用方式贯穿整个驱动(见 RedshiftDriver.ts#L99-L110 及getInitialConfiguration),意味着环境变量可针对预聚合场景单独命名(环境变量 key 由 dataSource 与 preAggregations 组合派生,见 env.ts 中的keyByDataSource逻辑),实现主数据源与预聚合数据源的分离配置。
7.3 readOnly 差异与连接池
getInitialConfiguration()(RedshiftDriver.ts#L277-L286)返回readOnly: false,源码注释说明原因:UNLOAD 导出需要列类型(涉及建表语义),无法在只读模式下工作——这与 0.27.35 版本"MySQL/PostgreSQL 默认 readOnly"的变更形成对比,Redshift 因导出能力而保持非只读。此外 1.6.12 版本随 postgres 驱动迁移到自研 Pool 实现(#10389),getDefaultConcurrency()返回默认并发5(RedshiftDriver.ts#L63-L65),capabilities()声明支持增量 schema 加载(RedshiftDriver.ts#L522-L526)。
7.4 TypeScript 6 与 ESM 导出
1.7.37 版本(2026-09-10)完成两项工程化升级:全仓库迁移到 TypeScript 6.0.3(为 TypeScript 7 做准备,#11767),以及所有驱动支持具名 ESM 导出(#11838)。前者统一了类型系统基线,后者使import { RedshiftDriver } from '@cubejs-backend/redshift-driver'这类具名导入在 ESM 环境下可靠工作。
八、环境变量速查表
综合源码 RedshiftDriver.ts 与 env.ts,Redshift 驱动的全部关键环境变量归纳如下:
| 环境变量 | 作用 | 取值约束 |
|---|---|---|
CUBEJS_DB_NAME | Redshift 数据库名 | IAM 认证必填 |
CUBEJS_DB_USER/CUBEJS_DB_PASS | 明文账号密码 | 与 IAM 认证互斥 |
CUBEJS_DB_REDSHIFT_CLUSTER_IDENTIFIER | Provisioned 集群标识 | IAM 认证必填 |
CUBEJS_DB_REDSHIFT_AWS_REGION | IAM 认证所需区域 | IAM 认证必填 |
CUBEJS_DB_REDSHIFT_WORKGROUP_NAME | Serverless workgroup 名 | Serverless 场景 |
CUBEJS_DB_REDSHIFT_ASSUME_ROLE_ARN | 跨账户角色 ARN | 可选 |
CUBEJS_DB_REDSHIFT_ASSUME_ROLE_EXTERNAL_ID | 角色外部 ID | 可选 |
CUBEJS_DB_REDSHIFT_UNLOAD_ARN | UNLOAD 的 IAM Role ARN | 与 AK/SK 二选一 |
CUBEJS_DB_EXPORT_BUCKET_TYPE | 仅支持s3 | 配置导出必填 |
CUBEJS_DB_EXPORT_BUCKET | S3 桶名 | 配置导出必填 |
CUBEJS_DB_EXPORT_BUCKET_AWS_REGION | 桶区域 | 配置导出必填 |
CUBEJS_DB_EXPORT_BUCKET_AWS_KEY/..._SECRET | S3 AK/SK | 与 unloadArn 二选一 |
CUBEJS_DB_EXPORT_BUCKET_CSV_ESCAPE_SYMBOL | CSV 转义符号 | 可选 |
所有变量均支持按 dataSource 与 preAggregations 组合派生 key(如多数据源、预聚合专用配置),具体规则由keyByDataSource在 env.ts 中统一实现。
九、结语:从版本历史看驱动演进规律
纵观@cubejs-backend/redshift-driver的 CHANGELOG,其演进呈现清晰的三条主线:
- 能力从"能用"到"好用":先解决接入(0.27.25 引入、UNLOAD),再解决生产问题(IAM 免密、Spectrum 外部表、schema 可见性、连接测试计费);
- 与 postgres 驱动深度耦合:大量底层改进(连接池、错误信息、TypeScript、ESM)在 postgres 驱动侧完成,Redshift 驱动通过继承自动获得,体现了"协议兼容 + 差异化覆盖"的驱动架构设计;
- 发布节奏快而稳定:绝大多数版本为
Version bump only,反映 monorepo 统一发版机制下,单包变更被精准收敛到实质条目,便于追踪。
对使用者而言,本文第 8 节的环境变量表与第 4、5、6 节的能力说明即可作为配置与排障的起点;深入源码时,建议从 RedshiftDriver.ts 的informationSchemaQuery、getExportBucket、unload、tableColumnTypes这几个方法入手,它们集中体现了驱动对 Redshift 平台特性的全部适配逻辑。
- 后端
- 数据分析
- 数据可视化
- 数据库
【免费下载链接】cube
📊 Cube Core is open-source semantic layer for AI, BI and embedded analytics
相关推荐
tsParticles Absorbers 插件全解析:从 CHANGELOG 演进史到源码实现与配置实战
tsParticles Absorbers 插件全解析:从 CHANGELOG 演进史到源码实现与配置实战 本篇技术指南以仓库中 plugins/absorbe
前端direnv 2.37.1 版本演进与核心机制全解:从 CHANGELOG 到源码的实战指南
direnv 2.37.1 版本演进与核心机制全解:从 CHANGELOG 到源码的实战指南 direnv 是一款"为 shell 而生的扩展",它根据当前所在
开发工具CLImailcow 内置的 GuzzleHttp\Psr7(PSR-7 消息实现)版本演进全解析:从 CHANGELOG 到源码
mailcow 内置的 GuzzleHttp\Psr7(PSR 7 消息实现)版本演进全解析:从 CHANGELOG 到源码 导读 本文以 mailcow do
后端企业应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考