@clickhouse/client- 仅限 Node.js@clickhouse/client-web- 浏览器 (Chrome/Firefox) 、Cloudflare Workers
AI 智能体技能JavaScript 客户端随附 AI 智能体技能,可帮助编码智能体使用该客户端。使用以下命令安装:
环境要求 (node.js)
环境要求 (web)
安装
与 ClickHouse 的兼容性
客户端也很可能可用于较早版本;不过,这类支持仅属尽力而为,不作保证。如果你的 ClickHouse 版本早于 23.3,请参阅 ClickHouse 安全策略 并考虑升级。
示例
客户端 API
创建客户端实例
createClient 工厂函数创建任意数量的客户端实例:
配置
Node.js 专用配置参数
URL 配置
http[s]://[username:password@]hostname:port[/database][?param1=value1¶m2=value2]。在绝大多数情况下,某个参数的名称都对应于它在 config 选项 interface 中的路径,只有少数例外。支持以下参数:
- (1) 对于布尔值,有效值为
true/1和false/0。 - (2) 任何带有
clickhouse_setting_或ch_前缀的参数,都会移除该前缀,并将其余部分添加到客户端的clickhouse_settings中。例如,?ch_async_insert=1&ch_wait_for_async_insert=1与以下配置相同:
clickhouse_settings 的布尔值应在 URL 中以 1/0 形式传递。
- (3) 与 (2) 类似,但适用于
http_header配置。例如,?http_header_x-clickhouse-auth=foobar等同于:
建立连接
获取连接信息
你的 ClickHouse Cloud 服务的连接信息可在 ClickHouse Cloud 控制台中查看。
选择一个服务,然后点击 Connect:
选择 HTTPS。连接信息会显示在示例
curl 命令中。
如果你使用的是自管理 ClickHouse,则连接信息由你的 ClickHouse 管理员配置。
连接概览
url (包括
协议和端口) 以及 password 值通过环境变量指定,并使用 default 用户。
**示例:**使用环境变量进行配置,创建 Node.js 客户端实例。
连接池 (仅限 Node.js)
10,但你可以通过 max_open_connections 配置选项 进行更改。
除非用户设置 max_open_connections: 1,否则无法保证连接池中的同一个连接会用于后续查询。这种需求很少见,但在用户使用临时表时可能是必需的。
另请参见:Keep-Alive 配置。
查询 ID
command、exec、insert、select) 都会在结果中返回 query_id。这个唯一标识符由客户端为每个查询分配,可用于从 system.query_log 中获取数据,
前提是已在服务器配置中启用该日志;也可用于取消长时间运行的查询 (参见该示例) 。如有需要,用户可以在 command/query/exec/insert 方法的参数中覆盖 query_id。
所有客户端方法的基础参数
查询方法
SELECT,也可用于发送 CREATE TABLE 之类的 DDLs,因此应使用 await 等待其完成。返回的结果集通常应由应用程序进行处理。
结果集与行抽象
ResultSet 提供了多种便捷方法,方便你在应用程序中处理数据。
Node.js 中的 ResultSet 实现底层使用 Stream.Readable,而 Web 版本使用 Web API ReadableStream。
你可以调用 ResultSet 的 text 或 json 方法来读取 ResultSet,并将查询返回的全部行一次性加载到内存中。
你应尽快开始读取 ResultSet,因为它会一直保持响应流处于打开状态,从而占用底层连接。客户端不会缓冲传入的数据,以避免应用程序出现过高的内存使用。
或者,如果数据量太大,无法一次性放入内存,你可以调用 stream 方法,以流式方式处理数据。这样,响应中的每个 chunk 都会被转换为一个相对较小的行数组 (数组大小取决于客户端从 server 接收到的具体 chunk 大小——该大小可能会变化——以及单行的大小) ,然后逐个 chunk 进行处理。
请参阅支持的数据格式列表,以确定哪种格式最适合你的流式处理场景。例如,如果你想流式处理 JSON 对象,可以选择 JSONEachRow,这样每一行都会被解析为一个 JS 对象;或者也可以选择更紧凑的 JSONCompactColumns 格式,这样每一行都会成为一个紧凑的值数组。另请参阅:文件流式传输。
JSONEachRow 格式,读取整个 stream,并将其内容解析为 JS 对象。
源代码。
on('data') 方法,以 JSONEachRow 格式流式处理查询结果。这种方式可与 for await const 语法互换使用。源代码。
on('data') 方式,以 CSV 格式流式处理查询结果。这种方式可与 for await const 语法互换使用。
源代码
for await const 语法,以 JS 对象形式消费 JSONEachRow 格式的流式查询结果。这种方式可与经典的 on('data') 用法互换。
源代码.
for await const 语法比 on('data') 方式需要的代码更少,但可能会对性能产生负面影响。
详情请参见 Node.js 仓库中的这个 issue。ReadableStream。
insert 方法
{ query_id: '...', executed: false }。在这种情况下,如果未在方法参数中提供 query_id,则结果中的它将是空字符串,因为返回由客户端生成的随机 UUID 可能会造成混淆,毕竟带有该 query_id 的查询并不存在于 system.query_log 表中。
如果 insert 语句已发送到服务器,则 executed 标志将为 true。
Insert 方法与 Node.js 中的流式处理
Stream.Readable 配合使用,也可以使用普通的 Array<T>,具体取决于为 insert 方法指定的数据格式。另请参阅本节中关于文件流式传输的内容。
通常应使用 await 等待 Insert 方法完成;不过,也可以先指定一个输入流,等到流结束后再等待 insert 操作 (这也会使 insert promise 完成) 。这在事件监听器等类似场景中可能很有用,但客户端侧的错误处理并不简单,而且会有很多边界情况。作为替代方案,建议使用异步插入,如此示例所示。
Web 版本限制
@clickhouse/client-web 中的插入操作仅支持 Array<T> 和 JSON* 格式。
由于浏览器兼容性不佳,Web 版本目前尚不支持通过流进行插入。
因此,Web 版本的 InsertParams 接口与 Node.js 版本略有不同,
因为 values 仅限为 ReadonlyArray<T> 类型:
Command 方法
FORMAT 子句不适用的情况,或者你根本不关心响应内容的情况。例如,这类语句可以是 CREATE TABLE 或 ALTER TABLE。
应等待其完成。
响应流会立即销毁,这意味着底层套接字会被释放。
Exec 方法
query/insert 处理的自定义查询,
并且需要获取返回结果,可以使用 exec 作为 command 的替代方案。
exec 会返回一个可读流,必须由应用程序端消费或销毁。
Ping
ping 方法在服务器可达时会返回 true。
如果服务器不可达,结果中也会包含底层错误信息。
/ping 端点,而 Web 版本则使用简单的 SELECT 1 查询来达到类似效果,因为 /ping 端点不支持 CORS。
示例: (Node.js/Web) 向 ClickHouse 服务器实例发送一个简单的 ping。注意:对于 Web 版本,捕获到的错误会有所不同。
源代码。
ping 方法时也一并校验凭据,或指定额外参数 (如 query_id) ,可以按如下方式使用:
ping 方法支持大多数标准 query 方法的参数——请参阅 PingParamsWithSelectQuery 类型定义。
关闭 (仅限 Node.js)
文件流式传输 (仅限 Node.js)
query 调用中使用的格式 (JSONEachRow、CSV 等) 以及输出文件名。
支持的数据格式
format 指定为 JSON 家族中的某种格式 (JSONEachRow、JSONCompactEachRow 等) ,客户端会在传输过程中对数据进行序列化和反序列化。
以“原始”文本格式 (CSV、TabSeparated 和 CustomSeparated 家族) 提供的数据会直接发送,不会进行额外转换。
对于 Parquet,
select 的主要用途很可能是将结果流写入文件。请参见客户端代码仓库中的该示例。
JSONEachRowWithProgress 是一种仅用于输出的格式,支持在流中报告进度。更多详情请参见此示例。
ClickHouse 输入和输出格式的完整列表可在
此处查看。
支持的 ClickHouse 数据类型
对应的 JS 类型适用于所有
JSON* 格式,但不包括将所有内容都表示为字符串的格式 (例如 JSONStringEachRow)
完整的受支持 ClickHouse 格式列表可在
此处查看。
另请参阅:
Date/Date32 类型注意事项
Date/Date32 类型的列只能以字符串形式插入。
**示例:**插入一个 Date 类型的值。
源代码
DateTime 或 DateTime64 列,也可以同时使用字符串和 JS Date 对象。将 date_time_input_format 设为 best_effort 时,JS Date 对象可以原样传递给 insert。更多详情请参见这个示例。
Decimal* 类型的注意事项
JSON* 家族格式插入 Decimal 类型的值。假设定义了如下表:
JSON* 格式查询数据时,ClickHouse 默认会将 Decimal 作为数值返回,这可能会导致精度丢失。为避免这种情况,你可以在查询中将 Decimal 转换为字符串:
整数类型:Int64、Int128、Int256、UInt64、UInt128、UInt256
JSON* 家族输出格式中,它会以字符串形式返回,
因为这些类型的最大值超过了 Number.MAX_SAFE_INTEGER。
不过,这种行为可以通过
output_format_json_quote_64bit_integers 设置
进行修改。
**示例:**调整 64 位数值的 JSON 输出格式。
ClickHouse 设置
进阶主题
带参数的查询
name— 占位符标识符。data_type- 应用参数值的数据类型。
压缩
GZIP。
response: true指示 ClickHouse 服务器 返回压缩后的响应体。默认值:response: falserequest: true为客户端请求体启用压缩。默认值:request: false
日志 (仅限 Node.js)
console.debug/info 方法将日志记录输出到 stdout,并通过 console.warn/error 方法输出到 stderr。
你可以通过提供 LoggerClass 自定义日志逻辑,并通过 level 参数选择所需的日志级别 (默认为 WARN) :
TRACE- 有关 Keep-Alive 套接字生命周期的底层信息DEBUG- 响应信息 (不含授权请求头和主机信息)INFO- 基本上未使用;会在客户端初始化时输出当前日志级别WARN- 非致命错误;失败的ping请求会记录为警告,因为底层错误已包含在返回结果中ERROR-query/insert/exec/command方法中的致命错误,例如请求失败
TLS 证书 (仅限 Node.js)
certs 文件夹中,
且 CA 文件名为 CA.pem:
Keep-alive 配置 (仅限 Node.js)
Connection: keep-alive 请求头。默认情况下,空闲套接字会在连接池中保留 2500 毫秒 (请参阅有关调整此选项的说明) 。
keep_alive.idle_socket_ttl 的值应明显低于服务器/LB 配置。主要原因是,HTTP/1.1 允许服务器在不通知客户端的情况下关闭套接字,因此如果服务器或负载均衡器在客户端之前关闭了连接,客户端就可能尝试复用已关闭的套接字,从而导致 socket hang up 错误。
如果你要修改 `keep_alive.idle_socket_ttl“,请记住它必须始终与你的服务器/LB Keep-Alive 配置保持一致,并且必须始终低于后者,以确保服务器不会先关闭仍处于打开状态的连接。
调整 idle_socket_ttl
keep_alive.idle_socket_ttl 设为 2500 毫秒,因为这通常可视为最稳妥的默认值;在服务端,如果不修改 config.xml,keep_alive_timeout 在 23.11 之前的 ClickHouse 版本中最低可能只有 3 秒。
你可以运行以下命令,在服务器响应请求头中找到正确的 Keep-Alive 超时值:
Connection 和 Keep-Alive 请求头的值。例如:
keep_alive_timeout 为 10 秒,你可以尝试将 keep_alive.idle_socket_ttl 增加到 9000 甚至 9500 毫秒,让空闲套接字保持打开状态的时间比默认情况下稍长一些。请留意可能出现的 “Socket hang-up” 错误,这表明服务器会在客户端之前关闭连接;继续调低该值,直到错误消失。
故障排查
socket hang up 错误,可尝试以下方法解决:
-
启用至少为
WARN的日志级别 (默认值) 。这样可以检查应用代码中是否存在未消费或悬空的 stream:传输层会以 WARN 级别记录此类情况,因为这可能会导致套接字被服务器关闭。你可以按如下方式在客户端配置中启用日志: -
确保所需配置已应用到正确的客户端实例。如果应用中有多个客户端实例,请再次确认你实际用于查询的那个实例设置了正确的
keep_alive.idle_socket_ttl值。 -
将客户端配置中的
keep_alive.idle_socket_ttl设置减少 500 毫秒。在某些情况下,例如客户端与服务器之间的网络延迟较高时,这样做可能会有帮助,从而避免出现这样的情况:某个发出的请求拿到了一个服务器即将关闭的套接字。 -
如果该错误发生在长时间运行且没有数据进出的查询期间 (例如长时间运行的
INSERT FROM SELECT) ,这可能是负载均衡器或其他网络组件关闭了长连接或长时间运行的请求所致。你可以尝试组合使用这些 ClickHouse settings,在长时间运行的查询中强制产生一些传入数据:不过请注意,在较新的 Node.js 版本中,接收的请求头总大小限制为 16KB;在接收到一定数量的进度请求头后 (在我们的测试中大约是 70-80 个) ,会抛出异常。 也可以采用一种完全不同的方法,彻底避免在线路上的等待时间;这可以利用 HTTP interface 的一个“特性”:连接丢失时,变更不会被取消。更多细节请参见此示例 (第 2 部分) 。 -
也可以完全禁用 Keep-Alive 功能。在这种情况下,客户端还会为每个请求添加
Connection: close请求头,底层 HTTP agent 也不会复用连接。keep_alive.idle_socket_ttl设置将被忽略,因为不会有空闲套接字。这样会带来额外开销,因为每个请求都需要建立一个新连接。 -
可通过一个简单的命令行测试,使用相同的 ClickHouse 实例和相同的网络路径 (即来自同一台机器或同一网段,例如 Kubernetes pod (容器组) ) ,排除包括 Node.js 本身在内的其余网络栈潜在问题,例如使用
curl:你可能需要循环运行几分钟。如果你在curl中也看到类似错误,那么问题很可能与客户端配置无关,而是出在网络栈或服务器配置上。 -
如果要使用原生 Node.js 功能测试连接,你可以尝试使用内置的
fetchAPI 向 ClickHouse 服务器发起一个简单的 HTTP request:
-
在某些情况下,应用代码或框架适配器可能会在实际执行查询前先发出一次
ping(),这可能导致这样一种情况:ping()请求成功,但后续查询请求却因空闲连接的同一底层问题而报 “socket hang up” 错误并失败。如果你在日志中看到这种情况,请检查你的框架或应用代码中是否提供了禁用预先ping()的选项。这也有助于降低被中间网络组件限流的概率。 - 确保应用程序本身获得了足够的 CPU 时间,并且网络未被托管提供商限流。GC 暂停指标、事件循环延迟指标等各类监控手段,也有助于排查潜在的资源饥饿问题。
- 尝试在启用 no-floating-promises ESLint 规则的情况下检查你的应用代码,这有助于识别未处理的 Promise,它们可能导致悬空的流和套接字。
只读用户
enable_http_compression 设置。以下配置会导致报错:
带路径名的代理
clickhouse_server 指定为 pathname 配置选项 (可带前导斜杠,也可不带) ;否则,如果直接在 url 中提供,它会被视为 database 选项。支持多段路径,例如 /my_proxy/db。
带身份验证的反向代理
http_headers 设置提供所需的请求头:
自定义 HTTP/HTTPS agent (实验性,仅限 Node.js)
max_open_connections、keep_alive.enabled、tls) 来配置底层 HTTP 或 HTTPS agent,由它负责处理与 ClickHouse 服务器 的连接。另外,如果使用了 TLS 证书,底层 agent 也会配置所需证书,并强制使用正确的 TLS 认证请求头。
从 1.2.0 开始,可以为客户端提供自定义 HTTP 或 HTTPS agent,以替换默认的底层 agent。这在网络配置较复杂时会很有用。如果提供了自定义 agent,则需注意以下几点:
max_open_connections和tls选项将_不会生效_,客户端会忽略它们,因为它们属于底层 agent 配置的一部分。keep_alive.enabled仅控制Connection请求头的默认值 (true->Connection: keep-alive,false->Connection: close) 。- 空闲 keep-alive 套接字的管理仍会继续生效 (因为它不依赖于 agent,而是依赖于具体的套接字本身) ,但现在也可以通过将
keep_alive.idle_socket_ttl设置为0来完全禁用它。
自定义代理使用示例
set_basic_auth_header 设置 (于 1.2.0 版本中引入) 禁用默认的 Authorization 请求头,因为它会与 TLS 请求头冲突。所有 TLS 请求头都应手动提供。
已知限制 (Node.js/web)
- 结果集中没有数据映射器,因此只能使用语言的基本类型。后续计划在支持 RowBinary format 后,为部分数据类型提供映射器。
- 某些 Decimal* 和 Date* / DateTime* 数据类型有一些注意事项。
- 使用 JSON* 家族格式时,大于 Int32 的数值会以字符串表示,因为 Int64+ 类型的最大值超过了
Number.MAX_SAFE_INTEGER。更多详情请参见 Integral types 部分。
已知限制 (web)
select查询支持流式传输,但insert已被禁用 (类型层面也一样) 。- 请求压缩已禁用,相关配置会被忽略。响应压缩可用。
- 尚不支持日志。
性能优化提示
- 为减少应用程序的内存占用,在适用情况下,可考虑对大型插入 (例如从文件插入) 和查询使用流。对于事件监听器及类似用例,异步插入 也是一个不错的选择,它可以最大限度减少,甚至完全避免在客户端进行批处理。异步插入示例可在客户端代码仓库中找到,文件名前缀为
async_insert_。 - 客户端默认不启用请求或响应压缩。不过,在查询或插入大型数据集时,可以考虑通过
ClickHouseClientConfigOptions.compression启用它 (仅启用request或response,或同时启用两者) 。 - 压缩会带来明显的性能开销。分别为
request或response启用压缩,会降低查询或插入的速度,但也会减少应用程序传输的网络流量。
联系我们
#clickhouse-js 频道) 中联系我们,或通过 GitHub issues 与我们取得联系。