导读:本期聚焦于小菜鸟创作的《自建CDN的日志分析如何用ClickHouse列式存储加速SQL查询?》,敬请观看详情。CDN日志的典型特征是字段多、写入量大、查询往往只涉及少数几列。传统行式数据库在分析这类数据时,即使只统计某个域名的流量,也要把整行所有字段从磁盘读出来,IO开销巨大。ClickHouse将同一列的数据连续存储,扫描查询只读取目标列,配合LZ4或ZSTD压缩、向量化执行引擎以及稀疏索引,能把原本需要几分钟的聚合查询压缩到秒级。文章围绕自建CDN场景,解析列式存储为何天然适合日志分析,给出MergeTree建表、分区键与排序键的设计思路,并展示命中率统计、Top URL、流量趋势等典型SQL的写法与调优方法。

自建CDN系统需要持续记录每一次边缘节点的请求与响应,典型字段包括访问时间、客户端IP、请求域名、完整URL、响应状态码、传输字节数、是否命中缓存、回源耗时等。当节点数量增多、业务流量上升后,每天积累的日志很容易达到数十亿行,单日数据量可达TB级别。分析团队经常需要回答这样的问题:哪些域名消耗了最多带宽?某个文件的缓存命中率是多少?回源延迟集中在哪些地区?这些查询如果跑在按行存储的数据库上,往往会因为读取大量无关字段而变得非常慢。ClickHouse凭借列式存储、向量化计算和稀疏索引,能够在秒级完成这类聚合分析。

自建CDN的日志分析如何用ClickHouse列式存储加速SQL查询?

一、列式存储为什么适合CDN日志分析

列式存储与行式存储的物理布局差异,直接决定了日志分析场景下的IO效率。行式存储把一行记录的所有字段连续存放在一起,读取一行就需要把所有列加载进内存;列式存储则把每一列独立组织成数据文件,同一列的数据类型一致、取值范围相近,压缩比通常高出数倍。CDN日志查询绝大多数是聚合统计,例如统计域名流量只需要domainbody_bytes_sent,判定缓存命中率只需domaincache_status。列式存储允许ClickHouse只扫描这些目标列,其他无关列完全不参与磁盘读取,IO开销大幅下降。

除了按列读取,压缩带来的好处也不能忽视。CDN日志中的状态码、缓存状态、域名等字段重复度很高,列式压缩后体积可能只有原始文本的十分之一。更紧凑的数据块可以在相同内存中容纳更多记录,CPU缓存命中率随之提高。ClickHouse执行聚合时使用向量化引擎,一次处理一批列数据,而不是一行一行解释执行,进一步放大了列式存储的性能优势。再配合MergeTree表引擎的稀疏索引,查询可以在分区和数据块级别跳过大量无关数据,最终将分钟级的查询压缩到秒级。

二、设计ClickHouse表结构的关键点

在ClickHouse中处理CDN日志,通常使用MergeTree系列表引擎。建表时需要重点考虑分区键、排序键和字段类型。下面是一个适合CDN访问日志的基础表结构:

CREATE TABLE cdn_logs
(
    log_time DateTime,
    client_ip String,
    domain String,
    url String,
    status_code UInt16,
    body_bytes_sent UInt64,
    cache_status LowCardinality(String),
    upstream_response_time Float32,
    user_agent String
)
ENGINE = MergeTree()
PARTITION BY toYYYYMMDD(log_time)
ORDER BY (domain, log_time)
TTL log_time + INTERVAL 30 DAY
SETTINGS index_granularity = 8192;

分区键选择toYYYYMMDD(log_time),数据按天划分分区。这样做的直接好处是,清理过期数据时只需删除整个分区,而不需要逐行执行删除操作,维护成本低且不会产生大量碎片。排序键设置为(domain, log_time),原因是CDN日志查询经常先按域名过滤,再限定时间范围。稀疏索引会依据排序键快速定位到满足条件的连续数据块,避免扫描整个分区。

字段类型方面,cache_status使用LowCardinality(String)可以显著降低内存占用,因为缓存状态通常只有HIT、MISS、EXPIRED等少数几种取值。client_ipuser_agent这类高基数字段保留普通字符串即可,不必建立二级索引。TTL设置log_time + INTERVAL 30 DAY可以让ClickHouse后台自动合并时删除过期分区,控制总存储量。如果查询模式还频繁涉及按URL前缀过滤,可以考虑将URL拆分为路径和查询参数两列,或者在建表后使用物化列提取路径前缀,进一步提升过滤效率。

三、典型SQL查询与性能调优实践

CDN日志分析中最常见的需求之一是计算缓存命中率。用传统SQL可能需要两条查询或子查询分别统计命中数和总数,而ClickHouse的条件聚合函数可以在一次扫描中完成:

SELECT
    domain,
    countIf(cache_status = 'HIT') AS hit_count,
    count() AS total_count,
    round(hit_count / total_count * 100, 2) AS hit_ratio
FROM cdn_logs
WHERE log_time >= now() - INTERVAL 7 DAY
GROUP BY domain
ORDER BY total_count DESC
LIMIT 20;

这里countIf是ClickHouse内置的聚合函数,它在单次顺序扫描中同时完成条件计数和全量计数,避免了多次扫描明细数据。查询执行时,分区裁剪会让ClickHouse只读取最近7天的数据分区,排序键(domain, log_time)则帮助快速定位每个域名对应的数据块。由于只涉及domaincache_statuslog_time三列,整体扫描量远低于行式数据库读取整行的开销。

另一个高频需求是统计某个域名下流量最大的URL。下面这条SQL可以快速输出Top URL的字节数和请求次数:

SELECT
    url,
    sum(body_bytes_sent) AS total_bytes,
    count() AS request_count
FROM cdn_logs
WHERE log_time >= now() - INTERVAL 1 DAY
  AND domain = 'img.ippipp.com'
GROUP BY url
ORDER BY total_bytes DESC
LIMIT 50;

此查询只会读取urlbody_bytes_sentlog_timedomain四个列,其他列完全不访问。如果某个域名下的URL数量非常多,GROUP BY url可能会消耗较多内存,可以在分组前使用substring截取路径前若干字符,降低分组基数。ClickHouse还支持SAMPLE子句进行抽样统计,例如在表结构中设置采样键后,通过SAMPLE 0.1可以快速估算流量分布,适合做趋势分析而不必扫描全量明细。

进一步调优时,可以根据实际查询模式组合多种手段:使用物化视图或投影将分钟级聚合结果预先计算,避免重复扫描明细数据;对于状态码这类低基数字段使用LowCardinality;避免在WHERE条件中对列使用函数,尽量让过滤条件命中分区键和排序键;对超长URL字符串使用截断或哈希分桶降低内存压力。这些措施叠加后,自建CDN日志分析的查询延迟可以从分钟级下降到秒级,同时保持较低的硬件成本。

ClickHouse的列式存储从磁盘读取层面降低了CDN日志分析的开销,配合MergeTree的稀疏索引和分区裁剪,能够让自建CDN场景下的日志分析从小时级压缩到秒级。实际落地时,重点在于表结构设计是否匹配真实的日志查询模式,以及SQL是否充分利用了列式扫描和条件聚合的优势。合理规划分区键、排序键和TTL,再结合物化视图等进阶功能,可以构建一套高效稳定的日志分析平台。

ClickHouseCDN日志分析列式存储修改时间:2026-08-30 03:51:51

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。