把 Nginx 日志压到只剩 1/170:ClickHouse列式存储是怎么做到的?

图片

本文字数:11879;估计阅读时间:30 分钟

作者:Lionel Palacin & Dale McDiarmid

本文在公众号【ClickHouseInc】首发

图片

TL;DR

列式存储为高效存储日志提供了新路径,既能大幅压缩数据体积,又能保持查询的高效与灵活。通过将原始日志结构化为列数据,选择合适的数据类型,并将相似的值聚集存储,我们可以实现超过 170 倍的压缩效果。

日志在大规模存储场景下是一项难题。

它们往往是非结构化的文本格式,天然不利于压缩。但其中蕴含着系统和应用行为的重要历史信息,这些内容对排查故障非常关键,不容忽视。

在可观测性系统中,日志与追踪和指标一起构成三大支柱。不同于日志,追踪和指标天生具备结构性和重复性,因此天然适合以列式格式压缩。例如时间戳(Timestamp)、服务名(ServiceName)和延迟(Latency)等字段,在列存中表现优异,压缩效率也很高。

那如果我们也能让日志具备类似的结构会怎样?通过识别日志消息中的可变部分,提取为独立列,采用最优数据类型,并在磁盘上将相似值相邻存储,日志也可以实现高效压缩。

这篇文章是我们首次探索这种思路,将原始日志转化为结构化数据,目标是实现 170 倍压缩。在接下来的博客中,我们还会进一步探讨日志聚类技术,如何将这一方法扩展至各种类型的日志,并自动优化其压缩比。

为什么日志压缩至关重要  

压缩的意义不仅在于节省存储空间,它还直接影响系统的性能和资源利用效率。

更少的 I/O,查询更快

数据体积更小,读取速度自然更快。在列式数据库中,查询往往需要扫描大量数据,因此压缩后的数据块能显著降低磁盘 I/O 开销。这不仅缓解了磁盘带宽和网络资源的压力,也大大提升了查询的执行速度。

更低的存储成本

压缩能有效减少所需的存储空间,进而降低存储费用。即便使用如 Amazon S3 这样的对象存储,虽然单价较低,但压缩依然有价值——因为压缩数据可以缓存在本地的 NVMe 设备中,从而实现更快的访问。

更高的缓存命中率

压缩数据更容易装入内存和各级缓存,缓存命中率随之提升,减少了对磁盘读取的依赖,进一步提升系统整体性能。

用 Nginx 访问日志做压缩实验  

Nginx 访问日志记录了服务器处理的每一条请求,是一个标准且广为人知的数据集,便于读者理解并自行复现实验过程。

一条典型的日志通常包含客户端 IP、时间戳、HTTP 方法、状态码、用户代理和响应时间等信息。下面是一个 nginx 日志示例。

185.161.113.50 - - [2019-02-04 23:40:49] "GET /filter/p62,b113?page=0 HTTP/1.1" 200 33948 "https://www.zanbil.ir/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"

我们选择 nginx 日志作为实验对象,原因如下:

  1. 结构固定:Nginx 的日志格式定义清晰,结构一致。虽然具体字段值(如时间戳、IP 地址、URL、响应时间)会变化,但整体格式基本不变。

  2. 数据类型丰富:一条日志中包含 IP 地址、数值、字符串和日期,涵盖多种数据类型,非常适合用于展示如何针对不同类型的数据选择最优的压缩策略。

  3. 数据量大:生产环境中的访问日志增长迅速,短时间内就能累积数 GB 到数 TB 的数据量。这种规模下,压缩对存储成本和处理性能的影响尤为显著。

虽然 nginx 日志通常以纯文本方式保存,但其格式高度可预测。这虽然不一定代表所有应用日志的典型特征,我们对此也有所认识。但我们选择这个数据集,是为了首先建立压缩效率的“乐观上限”作为参考。在后续的文章中,我们还将进一步探索如何在结构不明显的日志中实现高效压缩。

建立压缩基线

要做任何压缩效果的基准测试,首先需要明确一个基线。在本实验中,我们的基线是:日志数据集在未压缩情况下,占用本地磁盘的空间是多少。

我们使用的测试数据集是一份包含 6600 万条 nginx 访问日志的文件。该文件已在后续命令中公开,便于大家复现实验。未压缩状态下,该日志文件约占 20GB 磁盘空间。

$ wc -l nginx-66.log
66747290 nginx-66.log

$ du -h nginx-66.log
20G	nginx-66.log

由于 ClickHouse 在写入磁盘时会自动压缩数据,并支持多种压缩算法,因此我们也测试了几种通用压缩方式作为对比参考。

我们将原始日志文件分别用 GZIP、ZSTD(3) 和 LZ4 进行了压缩,比较它们的磁盘存储效果。可以看到,压缩效果相当显著,ZSTD(3) 已经可以实现约 38 倍的压缩比。

压缩方式

磁盘空间占用

压缩比

None

20 GB

1

LZ4

1 GB

20x

GZIP

641 MB

31x

ZSTD(3)

522 MB

38x

压缩比的计算方式为:压缩后大小 ÷ 原始未压缩大小。

现在我们已经得到了基线数据,接下来就可以将日志导入 ClickHouse,并开始应用结构化和优化策略。

日志写入 ClickHouse

首先需要创建一张表来存储原始日志,我们定义一个简单的表 nginx_raw,结构仅包含一个 String 类型字段,数据无特定排序。

CREATE TABLE nginx_raw
(
    `Body` String
) ORDER BY ()

创建好表之后,就可以导入日志文件。以下示例展示了如何直接从 S3 插入数据。数据导入完成后,我们还可以校验是否全部导入成功。

INSERT INTO nginx_raw SELECT line As Body FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/http_logs/nginx-66.log.gz', 'LineAsString')

SELECT count() FROM nginx_raw

┌──count()─┐
│ 66747290 │ -- 66.75 million
└──────────┘

你也可以使用相同的命令将日志加载到自己的 ClickHouse 实例中。加载时间会根据本地 ClickHouse 配置和网络带宽有所不同(该文件大小约为 640MB)。

我们可以通过查询 system.parts (https://clickhouse.com/docs/operations/system-tables/parts)系统表来查看表在磁盘上的实际占用空间。该系统表记录了每个表分片的详细信息,包括压缩前后的磁盘大小。

SELECT
    `table`,
    formatReadableSize(SUM(data_uncompressed_bytes)) AS uncompressed_size,
    formatReadableSize(SUM(data_compressed_bytes)) AS compressed_size
FROM system.parts
WHERE (database = 'logs_blog') AND (`table` = 'nginx_raw') AND active
GROUP BY `table`
ORDER BY `table` ASC

   ┌─table─────┬─uncompressed_size─┬─compressed_size─┐
   │ nginx_raw │ 20.19 GiB         │ 575.62 MiB      │
   └───────────┴───────────────────┴─────────────────┘

从结果来看,并没有意外,未压缩数据的大小与原始磁盘文件一致。由于 ClickHouse 默认采用 ZSTD(1) 压缩算法,因此最终压缩后的大小也与预期相符。

将 Nginx 日志转换成结构化日志(压缩比提升至 56 倍)

要实现 170 倍压缩,第一步是将原始的纯文本 Nginx 日志转换为结构化格式。我们将日志中的关键信息(如 IP 地址、请求方法、URL、状态码、用户代理等)提取出来,分别存储在独立的字段中。

与其将整条日志记录作为一个长字符串存储,我们可以将其解析为多个字段,如下所示:

列名

数据类型

示例值

remote_addr

IPv4

185.161.113.50

remote_user

String

user

time_local

DateTime

2025-10-13 10:00

request_type

String

GET

request_path

String

/index.html

status

String

HTTP/1.1

size

UInt16

200

referrer

String

-

user_agent

String

Mozilla/5.0 (...)

Nginx 的日志格式是预定义的,因此可以方便地通过正则表达式函数对其进行字段解析。

我们先根据定义好的 nginx 日志 schema 创建一张新表。

CREATE TABLE nginx_column_tuple
(
    `remote_addr` String,
    `remote_user` String,
    `time_local` DateTime,
    `request_type` String,
    `request_path` String,
    `request_protocol` String,
    `status` UInt64,
    `size` UInt64,
    `referer` String,
    `user_agent` String
)
ORDER BY ()

然后从 nginx_raw 表中读取原始数据,通过正则表达式提取出每个字段的值,并将其写入这张新表中。

INSERT INTO nginx_column_tuple
SELECT
    m[1],
    m[2],
    parseDateTimeBestEffortOrNull(m[3]),
    m[4],
    m[5],
    m[6],
    toUInt64OrZero(m[7]),
    toUInt64OrZero(m[8]),
    if(length(trim(m[9])) = 0, '-', m[9]),
    m[10]
FROM (
    SELECT arrayElement(extractAllGroups(
        toValidUTF8(Body),'^(\S+) - (\S+) \[([^\]]+)\] "([A-Z]+)?\s*(.*?)\s*(HTTP\S+)?" (\d{3}) (\d+) "([^"]*)" "([^"]*)"'
    ), 1) AS m
    FROM nginx_raw
);

接下来,我们再来看一下这张结构化表在磁盘上的占用空间。

SELECT
    `table`,
    formatReadableSize(sum(data_compressed_bytes)) AS compressed_size,
    formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed_size
FROM system.columns
WHERE `table` = 'nginx_column_tuple'
GROUP BY `table`
FORMAT VERTICAL

Row 1:
──────
table:             nginx_column_tuple
compressed_size:   359.52 MiB
uncompressed_size: 18.48 GiB


需要注意的是,这次实验中的未压缩数据大小相比之前有所减少。这一变化主要得益于采用列式存储格式以及通过正则表达式过滤掉了日志中的冗余字符。

压缩后仅为 359.52MB,压缩比达到了 56 倍。仅仅是将日志结构化,把关键信息拆分成列存,就已经将压缩比从原来的 35 倍提升到了 56 倍。虽然日志不再以原始文本形式存在,但所有关键信息都被完整保留。如果需要,还可以随时还原回原始格式,这一点我们将在后续博客中展示。

优化数据类型(压缩率提升至 92 倍)

在列式数据库中,合理选择字段的数据类型至关重要。数据类型决定了数据库需要为该字段预留多少磁盘空间来容纳其可能的最大值。即使实际存储的内容很小,所占空间也取决于数据类型的定义。虽然较小的值更容易被压缩(因为它们包含大量可压缩的零序列),但在读取时解压仍然会占用额外内存。

我们在之前的实验中已经根据 nginx 日志中的字段特征,选择了匹配的 ClickHouse 数据类型。现在,我们希望在此基础上进一步优化。

一个关键优化手段是使用 ClickHouse 提供的 LowCardinality 类型。它通过字典编码压缩方式提升磁盘存储效率。不过这种方式更适用于字段值种类(基数)不太多的场景。实践经验表明,如果某列的不同值少于 10 万,使用 LowCardinality 类型能有效提升压缩效率。

我们先查看每个字段的基数。

SELECT * APPLY uniq
FROM nginx_column_tuple
FORMAT VERTICAL

Row 1:
──────
uniq(remote_addr):      258115
uniq(remote_user):      2
uniq(time_local):       2579628 -- 2.58 million
uniq(request_type):     5
uniq(request_path):     881124
uniq(request_protocol): 3
uniq(status):           15
uniq(size):             69712
uniq(referer):          103048
uniq(user_agent):       28344

结果显示,remote_user、request_type、request_protocol 和 user_agent 这几个 String 类型字段都非常适合使用 LowCardinality 类型。

除了优化数据类型,我们还可以结合 ClickHouse 支持的压缩算法(compression codec),进一步提升整体压缩效果。

接下来,我们使用 LowCardinality 类型结合不同压缩算法重新做一次实验。

CREATE TABLE nginx_column_tuple_optimized_types
(
    `remote_addr` IPv4,
    `remote_user` LowCardinality(String),
    `time_local` DateTime CODEC(Delta(4), ZSTD(1)),
    `request_type` LowCardinality(String),
    `request_path` String CODEC(ZSTD(6)),
    `request_protocol` LowCardinality(String),
    `status` UInt16,
    `size` UInt32,
    `referer` String CODEC(ZSTD(6)),
    `user_agent` LowCardinality(String)
)
ORDER BY ()

由于日志数据已经按列存储在 nginx_column_tuple 表中,我们可以直接从该表中读取数据进行重建。

INSERT INTO nginx_column_tuple_optimized_types SELECT * FROM nginx_column_tuple;

来看实验结果:

SELECT
    `table`,
    formatReadableSize(sum(data_compressed_bytes)) AS compressed_size,
    formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed_size
FROM system.columns
WHERE `table` = 'nginx_column_tuple_optimized_types'
GROUP BY `table`
FORMAT VERTICAL

Row 1:
──────
table:             nginx_column_tuple_optimized_types
compressed_size:   218.42 MiB
uncompressed_size: 9.69 GiB

最终压缩后的表仅占用 218MB,压缩比提升至 92 倍。这一成果相当可观,距离我们目标的 170 倍又近了一步。不过,我们还有一个重要优化尚未实施——磁盘上的数据排序方式。

磁盘排序优化(压缩率突破 178 倍!)

大多数压缩算法在相似数据相邻存储时效果最佳。ClickHouse 允许通过设置主键(即排序键)来控制数据在磁盘上的写入顺序。因此,如果我们的目标是实现极致压缩,就可以有意识地选择有利于压缩的数据排序方式。

当然,排序键的设计也需要考虑查询的访问模式。通常排序键中靠前的字段在过滤条件中出现越早,查询性能越好。但在本次实验中,我们优先考虑压缩效果。在实际生产中,需要在查询性能与压缩效率之间做出平衡,当然更高的压缩率往往也意味着更快的查询。

要想进一步提升压缩比,我们需要找出一个排序键,使所有字段都能在该排序方式下获得更好的压缩效果。这里要综合考虑两个因素:字段所占空间大小和字段的基数(唯一值数量)。某些占用空间大的高基数字段,并不会从排序中获益太多,反而会影响其后的字段压缩表现。而如果能选用低基数、占比大的字段来排序,更容易形成连续的数据序列,提升压缩效率。

图片

为此,我们首先分析表中各字段的空间占用情况,可以通过查询 system.columns(https://clickhouse.com/docs/operations/system-tables/columns) 表获得详细信息。

INSERT INTO nginx_column_tuple_optimized_types SELECT * FROM nginx_column_tuple;


接下来,我们查看当前表的磁盘占用情况。

SELECT
    name,
    formatReadableSize(sum(data_compressed_bytes)) AS compressed_size,
    formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed_size
FROM system.columns
WHERE `table` = 'nginx_column_tuple_optimized_types'
GROUP BY name
ORDER BY sum(data_uncompressed_bytes) DESC

    ┌─name─────────────┬─compressed_size─┬─uncompressed_size─┐
 1. │ referer          │ 13.69 MiB       │ 4.96 GiB          │
 2. │ request_path     │ 127.19 MiB      │ 3.55 GiB          │
 3. │ size             │ 39.37 MiB       │ 254.62 MiB        │
 4. │ time_local       │ 22.58 MiB       │ 254.62 MiB        │
 5. │ remote_addr      │ 10.76 MiB       │ 254.62 MiB        │
 6. │ user_agent       │ 589.91 KiB      │ 129.05 MiB        │
 7. │ status           │ 3.42 MiB        │ 127.31 MiB        │
 8. │ request_type     │ 722.43 KiB      │ 63.78 MiB         │
 9. │ request_protocol │ 62.79 KiB       │ 63.78 MiB         │
10. │ remote_user      │ 56.81 KiB       │ 63.78 MiB         │
    └──────────────────┴─────────────────┴───────────────────┘


结合空间占用和字段基数的信息,我们可以进一步评估哪组排序键能带来最优压缩效果。

Columns

Uncompressed size

Cardinality

referer

4.96 GiB

103048

request_path

3.55 GiB

881124

size

254.62 MiB

69712

time_local

254.62 MiB

2579628

remote_addr

254.62 MiB

258115

user_agent

129.05 MiB

28344

status

127.31 MiB

15

request_type

63.78 MiB

5

request_protocol

63.78 MiB

3

remote_user

63.78 MiB

2

结合这些数据以及字段基数,我们识别出几个排序键候选字段:referrer、remote_addr 和 user_agent。request_path 字段虽然占用空间大,但由于其基数过高,排序带来的压缩收益可能有限。

另一个重要因素是值的分布情况。即便字段基数较高,只要其中有少数值占据了大部分记录,它依然可以成为良好的排序字段。

我们统计了 referrer、remote_addr、user_agent 和 request_path 四个字段中最常见的前 20 个值,并计算它们的占比。

结果显示,referrer 和 user_agent 的分布明显偏斜。并且在前 12 个值之后,分布趋于平稳,没有必要继续分析长尾数据。基于这些分析,我们最终选择的排序键组合为:referrer、remote_user、user_agent、request_path。

排序策略如下:以 referrer 为首,虽然它基数高,但其高度偏斜的分布能提升压缩效果;接着是 remote_addr,这是一列低基数字段,有助于保持后续字段的数据聚集;随后加入 user_agent,其行为和 referrer 类似;最后是 request_path,为这一大字段带来额外的压缩空间。

我们基于此排序逻辑创建新表,并将数据重新导入。

-- Create table
CREATE TABLE nginx_column_tuple_optimized_types_sort
(
    `remote_addr` IPv4,
    `remote_user` LowCardinality(String),
    `time_local` DateTime CODEC(Delta(4), ZSTD(1)),
    `request_type` LowCardinality(String),
    `request_path` String CODEC(ZSTD(6)),
    `request_protocol` LowCardinality(String),
    `status` UInt16,
    `size` UInt32,
    `referer` String CODEC(ZSTD(6)),
    `user_agent` LowCardinality(String)
)
ORDER BY (referer, user_agent, remote_user, request_path);

-- Ingest data to new table
INSERT INTO nginx_column_tuple_optimized_types_sort SELECT * FROM nginx_column_tuple;


最后来看一下这张表的总体磁盘使用量。

SELECT
    `table`,
    formatReadableSize(sum(data_compressed_bytes)) AS compressed_size,
    formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed_size
FROM system.columns
WHERE `table` = 'nginx_column_tuple_optimized_types_sort'
GROUP BY `table`
FORMAT VERTICAL

Row 1:
──────
table:             nginx_column_tuple_optimized_types_sort
compressed_size:   109.12 MiB
uncompressed_size: 9.70 GiB

最终压缩结果令人惊艳:日志文件从原始的 20GB 压缩到了仅 109MB,压缩比高达 178 倍!

回到现实(虽然有点失落)

虽然我们实现了惊人的压缩效果,但现实是,大多数情况下,nginx 日志查询并不会按 referer 或 user_agent 字段进行筛选。虽然这些字段在分析时可能会用到,但更多的查询场景是基于时间的,比如“查看最近一小时的访问日志”。我们来看看这种更贴近实际使用的场景下,压缩效果如何。

我们新建一张表,把 time_local 字段作为排序键的第一位。为了避免时间戳过高的基数影响压缩效果,我们将时间值进行粗粒度处理,比如按“天”来归整时间戳。

-- Create table
CREATE TABLE logs_blog.nginx_column_tuple_optimized_types_time_sort
(
    `remote_addr` IPv4,
    `remote_user` LowCardinality(String),
    `time_local` DateTime CODEC(Delta(4), ZSTD(1)),
    `request_type` LowCardinality(String),
    `request_path` String CODEC(ZSTD(6)),
    `request_protocol` LowCardinality(String),
    `status` UInt16,
    `size` UInt32,
    `referer` String CODEC(ZSTD(6)),
    `user_agent` LowCardinality(String)
)
ORDER BY (toStartOfDay(time_local), referer, user_agent, remote_user, request_path);

-- Ingest data
INSERT INTO logs_blog.nginx_column_tuple_optimized_types_time_sort SELECT * FROM logs_blog.nginx_column_tuple_optimized_types_sort;

-- Check size
SELECT
    `table`,
    formatReadableSize(sum(data_compressed_bytes)) AS compressed_size,
    formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed_size
FROM system.columns
WHERE `table` = 'nginx_column_tuple_optimized_types_time_sort'
GROUP BY `table`
FORMAT VERTICAL

Row 1:
──────
table:             nginx_column_tuple_optimized_types_time_sort
compressed_size:   380.82 MiB
uncompressed_size: 9.76 GiB

最终的压缩效果就没那么惊艳了,这种设置下我们只达到了约 50 倍的压缩率。这也进一步说明了排序方式对压缩效率的影响有多么显著。

总结回顾

通过这一系列优化实验,我们最终将原始日志压缩到了原来的 1/178。以下是各个实验场景和结果的汇总表:

名称

存储方式

压缩方式

大小(字节)

大小(可读)

 压缩比

nginx-66.log

local

None

21237294480

20G

1.00

nginx-66.log.gz

local

GZIP

672053616

641M

31.60

nginx_raw

Clickhouse

Uncompressed

21673487121

20.19 GiB

0.98

nginx_raw

Clickhouse

Compressed

603582977

575.62 MiB

35.19

nginx_column_tuple

Clickhouse

Compressed

1387994151

1.29 GiB

15.30

optimized_types

Clickhouse

Compressed

229027241

218.42 MiB

92.73

optimized_types_sort

Clickhouse

Compressed

118984801

109.12 MiB

178.49

optimized_types_sort_time

Clickhouse

Compressed

402837184

380.82 MiB

52.71

写在最后

实现高压缩比的日志存储并不轻松,但借助 ClickHouse 这样的列式数据库,我们可以将这一目标变为现实。只要将原始日志转换为结构化格式,采用合适的数据类型,并通过合理的字段排序将相似数据聚集在一起,就能获得极具优势的压缩效果。虽然这种存储布局不一定适用于所有查询场景,但当我们的目标是用最小的空间保留最大量的日志信息时,这无疑是一种高效、可行的方案。

本文展示了列式存储在日志压缩方面的强大能力,不仅节省存储空间,还提升了 I/O 效率,加快了查询速度。以 nginx 访问日志为例,我们最终实现了超过 170 倍的压缩率,证明这一方法具备出色的实践价值。

征稿启示

面向社区长期正文,文章内容包括但不限于关于 ClickHouse 的技术研究、项目实践和创新做法等。建议行文风格干货输出&图文并茂。质量合格的文章将会发布在本公众号,优秀者也有机会推荐到 ClickHouse 官网。请将文章稿件的 WORD 版本发邮件至:Tracy.Wang@clickhouse.com

要连接到 ClickHouse 数据库并配置 JDBC 连接字符串以及 socket timeout,需要考虑以下几个关键点: 1. **JDBC 连接字符串的基本格式**: ClickHouse JDBC 驱动的连接字符串格式如下: ``` jdbc:clickhouse://<host>:<port>/<database> ``` 例如,如果 ClickHouse 服务运行在 `124.70.101.18` 上,默认端口为 `8123`,并且希望连接到 `default` 数据库,则连接字符串为: ``` jdbc:clickhouse://124.70.101.18:8123/default ``` 2. **配置 Socket Timeout**: Socket timeout 是指客户端等待服务器响应的最大时间。在 ClickHouse JDBC 驱动中,可以通过在连接字符串中添加参数来配置 socket timeout。具体参数如下: ``` jdbc:clickhouse://<host>:<port>/<database>?socketTimeout=30000 ``` 上述配置中,`socketTimeout=30000` 表示 socket timeout 设置为 30,000 毫秒(即 30 秒)。该配置确保在与 ClickHouse 服务器通信时,如果在指定时间内没有响应,连接将超时并抛出异常[^1]。 3. **通过连接池管理连接**: 如果使用连接池(如 C3P0)来管理 ClickHouse 的 JDBC 连接,还需要考虑连接池的配置。特别是 `idleConnectionTestPeriod` 参数,该参数用于控制连接池中空闲连接的测试周期。为了避免数据库的 `wait_timeout`(默认为 8 小时),建议将 `idleConnectionTestPeriod` 设置为一个较小的值,例如 5 小时(即 18000 秒)[^3]。这样可以确保连接池中的空闲连接不会因为数据库的超时设置而失效。 4. **Nginx 作为反向代理的配置**: 如果 ClickHouse 服务通过 Nginx 作为反向代理进行负载均衡,还需要确保 Nginx 的配置正确。Nginx 的 `keepalive_timeout` 参数应设置为适当的值,以确保连接在空闲时不会过早关闭。例如,`keepalive_timeout 65;` 表示保持连接的超时时间为 65 秒。此外,Nginx 的 `upstream` 配置应包含所有 ClickHouse 服务器的地址和端口,以实现负载均衡[^2]。 ### 示例代码 以下是一个完整的 JDBC 连接 ClickHouse 的示例代码,包含 socket timeout 配置: ```java import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class ClickHouseJDBCExample { public static void main(String[] args) { String url = "jdbc:clickhouse://124.70.101.18:8123/default?socketTimeout=30000"; String user = "default"; String password = ""; try { Connection connection = DriverManager.getConnection(url, user, password); System.out.println("Connected to ClickHouse successfully."); // Perform database operations here connection.close(); } catch (SQLException e) { System.err.println("Failed to connect to ClickHouse."); e.printStackTrace(); } } } ``` ### 相关问题 1. 如何在 ClickHouse JDBC 中配置连接超时(connect timeout)? 2. ClickHouse JDBC 驱动是否支持 SSL 加密连接?如何配置? 3. 在使用 ClickHouse JDBC 时,如何通过 Nginx 实现负载均衡? 4. 如何在 C3P0 连接池中配置 ClickHouse JDBC 的连接测试周期? 5. ClickHouse JDBC 驱动是否支持批量插入操作?如何优化批量插入性能?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值