能看网站的视频app无锡百度快速优化排名
- 作者: 五速梦信息网
- 时间: 2026年03月21日 10:17
当前位置: 首页 > news >正文
能看网站的视频app,无锡百度快速优化排名,WordPress对象储存,看板娘wordpress怎么带声音ELK一直是日志领域的主流产品#xff0c;但是ElasticSearch的成本很高#xff0c;查询效果随着数据量的增加越来越慢。业界已经有很多公司#xff0c;比如滴滴、B站、Uber、Cloudflare都已经使用ClickHose作为ElasticSearch的替代品#xff0c;都取得了不错的效果#xff… ELK一直是日志领域的主流产品但是ElasticSearch的成本很高查询效果随着数据量的增加越来越慢。业界已经有很多公司比如滴滴、B站、Uber、Cloudflare都已经使用ClickHose作为ElasticSearch的替代品都取得了不错的效果实现了降本增效费用节约大多在50%以上。但是目前使用ClickHose作为日志方案存在以下问题。 主流的VectorClickHose并未实现开箱即用有许多的管理配置工作绝大多数方案不支持近似全文检索的功能该功能很重要使用双数组或者Map的表结构查询效率不高ClickVisual是最接近的开箱即用的日志方案也存在以下问题 ○强依赖Kafka对于某些中小用户而言方案不够灵活不友好 ○未引入Vector原生的ClickHose Kafka引擎在大流量情况下可能导致ClickHose内存爆掉感谢社区大佬 十四反馈 主流的VectorClickHouse方案并未实现开箱即用
目前业界很多公司都是基于VectorClickHouse的方案来实现日志的采集和存储该方案需要管理维护的工作量相对而言比较高适用于动手能力强的公司。
维护工作为每种日志手动维护一张表
每个公司的部门团队可能日志规范都不完全一致如果需要对日志内容进行快速搜索定位故障就需要提前想好ClickHouse的表结构然后调整Vector的配置文件最终实现Vector根据不同日志格式parse成不同的日志表字段写入不同的日志表。
比如每种日志都得建立以下类似的表结构才能完成日志按照ip、url等字段的索引实现快速搜索。但是另外一个部门的日志也许就不需要IP和url字段那么该部门得重新设计表结构。
CREATE TABLE log
(ip String,time Datetime,url String,status UInt8,size UInt32,agent String
)
ENGINE MergeTree
ORDER BY date(time)使用双数组或者Map的表结构查询效率不高
为了能够规避这些维护工作所以很多公司对固定日志表结构进行了调整常见的有两种方案一种是双数组方案另外一种就是Map方案。
Uber和Signoz的日志实现方案都是基于双数组
其日志表结构类似于下面这种
CREATE TABLE table_name
(//Common metadata fields._namespace String,_timestamp Int64,hostname String,zone String,…//Raw log event._source String,//Type-specific field names and field values.string.names Array(String),string.values Array(String),number.names Array(String), number.values Array(Float64),bool.names Array(String),bool.values Array(UInt8),//Materialized fieldsbar.String, Stringfoo.Number Float64,…
)
…滴滴、B站等日志实现是基于Map结构
引入Map结构能够动态实现日志关键字段搜索
CREATE TABLE ck_bamai_stream.cn_bmauto_local
(logTime Int64 DEFAULT 0, –Log打印的时间logTimeHour DateTime MATERIALIZED toStartOfHour(toDateTime(logTime / 1000)),–将LogodinLeaf String DEFAULT ,uri LowCardinality(String) DEFAULT ,traceid string DEFAULT ,cspanid String DEFAULT ,dltag String DEFAULT ,spanid String DEFAULT ,message String DEFAULT ,otherColumn MapString,String_sys_insert_time DateTime MATERIALIZED now()
)
ENGINE MergeTree
PARTITION BY toYYYYMMDD(logTimeHour)
ORDER BY(logTimeHour,odinLeaf,uri,traceid)
TTL _sys_insert_time toIntervalDay(7),_sys_insert_time toIntervalDay(3)To VOLUME hdfs
SETTINGS index_granularity 8192,min_bytes_for_wide_part31457280Create Table log_app_name ON CLUSTER …
{_timestamp Datetime64(3),log,level String CODC(ZSTD(1)),log.msg String CODC(ZSTD(1)),log.trace_id String CODC(ZSTD(1)),…string_map MapV2(String, Nullable(String))CODEC(ZSTD(1))number_map MapV2(String, Nullable(Float64))CODEC(ZSTD(1))bool_map MapV2(String, Nullable(UInt8))
}
ENGIN ReplicatedMergeTree(…)
PARTITION BY toYYYYMMDD(_timestamp)
ORDER BY timestamp
TTL toDateTime(timestamp) toIntervalDay(…),toDateTime(timestamp) toIntervalDay(…) TO VOLUME cold_volumeMap的动态字段搜索效率低 https://clickhouse.ac.cn/docs/knowledgebase/improve-map-performance 根据社区反馈map底层实现为线性数组map查询效率通常低于列查询3~10倍特别是日志量规模越大map查询效率越低。
同时支持Map类型的最低clickhosue版本为21.11 列式存储优势 ClickHouse 的核心优势在于它是列式存储数据库这意味着当执行查询时只需要读取查询中涉及的列而不必加载不相关的列。列式存储还能够通过数据类型特定的压缩技术显著减少 IO 操作从而加快查询速度 基于 Map 的查询 Map 是一种键值对数据结构在查询时需要额外的开销来解析嵌套结构并且无法像列式存储那样直接跳过不相关的数据。虽然 ClickHouse 对 Map 数据类型有一些优化但它在处理复杂结构时往往会比简单的列查询慢
双数组的搜索效率也不高
虽然 ClickHouse 对Array有一定的优化但双数组结构仍然比单纯的列查询开销大。
影响性能的因素
多级解析开销查询双数组时需要进行多层嵌套解析。例如访问数组中的子数组意味着需要遍历父数组然后进一步解析子数组的结构这比单纯读取一个列复杂得多随机存取双数组的访问模式往往比简单的列查询更加随机化。访问数组中的元素可能导致更多的跳转影响缓存命中率从而降低性能内存使用和数据存储嵌套数组会使得 ClickHouse 的数据存储和内存管理更加复杂因为数组中的数据长度不固定导致压缩效果比单纯列差数据块的大小也更加难以优化
性能上的差距取决于具体的查询模式和数据结构
在简单查询场景例如读取一个基本的列数据单纯的列查询会比双数组快得多特别是在处理大规模数据时。性能差距可能达到 数倍甚至十倍 以上尤其是当查询不涉及嵌套结构时。在复杂查询场景例如查询涉及嵌套数组、需要频繁地进行数组拆解和操作双数组的查询性能通常明显低于单纯的列查询。查询双数组的额外解析和处理开销会使查询时间增加。根据不同的嵌套深度和数据量性能可能下降 数倍。 ClickHouse的官方文档中日志方案也由于引入了Map效率不高
ClickHouse官方blog https://ClickHouse.com/blog/storing-log-data-in-ClickHouse-fluent-bit-vector-open-telemetry 提到有以下几种表结构
OTEL的日志字段表
CREATE TABLE otel.otel_logs
(Timestamp DateTime64(9) CODEC(Delta(8), ZSTD(1)),TraceId String CODEC(ZSTD(1)),SpanId String CODEC(ZSTD(1)),TraceFlags UInt32 CODEC(ZSTD(1)),SeverityText LowCardinality(String) CODEC(ZSTD(1)),SeverityNumber Int32 CODEC(ZSTD(1)),ServiceName LowCardinality(String) CODEC(ZSTD(1)),Body String CODEC(ZSTD(1)),ResourceAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),LogAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),//数据索引INDEX idx_trace_id TraceId TYPE bloom_filter(0.001) GRANULARITY 1,INDEX idx_res_attr_key mapKeys(ResourceAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,INDEX idx_res_attr_value mapValues(ResourceAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,INDEX idx_log_attr_key mapKeys(LogAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,INDEX idx_log_attr_value mapValues(LogAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,INDEX idx_body Body TYPE tokenbf_v1(32768, 3, 0) GRANULARITY 1
)
ENGINE MergeTree
PARTITION BY toDate(Timestamp)
ORDER BY (ServiceName, SeverityText, toUnixTimestamp(Timestamp), TraceId)
SETTINGS index_granularity 8192, ttl_only_drop_parts 1Vector 字段表
CREATE TABLE vector.vector_logs
(file String,timestamp DateTime64(3),kubernetes_container_id LowCardinality(String),kubernetes_container_image LowCardinality(String),kubernetes_container_name LowCardinality(String),kubernetes_namespace_labels Map(LowCardinality(String), String),kubernetes_pod_annotations Map(LowCardinality(String), String),kubernetes_pod_ip IPv4,kubernetes_pod_ips Array(IPv4),kubernetes_pod_labels Map(LowCardinality(String), String),kubernetes_pod_name LowCardinality(String),kubernetes_pod_namespace LowCardinality(String),kubernetes_pod_node_name LowCardinality(String),kubernetes_pod_owner LowCardinality(String),kubernetes_pod_uid LowCardinality(String),message String,source_type LowCardinality(String),stream Enum(stdout, stderr)
)
ENGINE MergeTree
ORDER BY (kubernetes_container_name, timestamp)fluent字段表
CREATE TABLE fluent.fluent_logs
(timestamp DateTime64(9),log String,kubernetes Map(LowCardinality(String), String),host LowCardinality(String),pod_name LowCardinality(String),stream LowCardinality(String),labels Map(LowCardinality(String), String),annotations Map(LowCardinality(String), String)
)
ENGINE MergeTree
ORDER BY (host, pod_name, timestamp)
日志需要近似全文检索
基于ElasticSearch的日志方案由于可以基于ElasticSearch实现的日志内容分词所以很容易实现全文检索但是基于ClickHouse就很难实现该功能。
那是不是基于ClickHouse的方案就完全没有办法呢
ClickHouse的索引介绍
tokenbf_v1 按非字母数字字符non-alphanumeric拆分。相当于按符号分词而通常日志中会有大量符号
在大牛的文章中
https://juejin.cn/post/7130514546069864456
详细介绍了全文检索的实现有兴趣的可以仔细看下大牛的文章。
最理想的日志方案应该满足什么条件
我们认为理想的基于ClickHouse的日志方案应该满足以下几条
使用列来进行检索而不是map或者双array保证高效的查询效率用户不需要为了不同部门的日志内容进行维护单独的表结构支持对原始日志内容进行近似的全文检索
我们调研了国内外几乎所有基于ClickHouse的日志方案最后发现国内开源项目ClickVisual项目的思路最相近ClickVisual几乎可以做到开箱即用。 ClickVisual的方案不足
ClickVisual工作原理
针对每种日志格式定义不同的parse规则ClickVisual为每种规则生成一张新的日志表。该日志表存的就是解析之后的日志之后的日志查询都是针对该日志表。因为解析之后的日志已经按照ClickHouse列存储了所以关键字段查询是非常快的基于Kafka表引擎读取Kafka原始日志落库至临时表中魔术开始的地方 基于ClickHouse的物化视图将原始日志中的新增日志_raw_log_内容按照日志解析规则parse成日志列格式并将解析好的日志存入该规则对应的日志表中
临时表
CREATE TABLE default.test_stream
(status String,timestamp Float64,message String CODEC(ZSTD(1))
)
ENGINE Kafka
SETTINGS kafka_broker_list 127.0.0.1:9092,
kafka_topic_list test,
kafka_group_name default_test,
kafka_format JSONEachRow,
kafka_num_consumers 1,
kafka_skip_broken_messages 0物化视图
CREATE MATERIALIZED VIEW default.test_view TO default.test
(status String,_timesecond DateTime,_timenanosecond DateTime64(9),_rawlog String,// 日志表的列level Nullable(String)//根据需要调整列…
) AS
SELECTstatus,toDateTime(toInt64(timestamp)) AS _timesecond,fromUnixTimestamp64Nano(toInt64(timestamp * 1000000000)) AS _timenanosecond,message AS _rawlog,// 物化视图处理成列toNullable(toString(replaceAll(JSONExtractRaw(message, level), , ))) AS level// 根据需要添加更多解析规则…
FROM default.test_stream
WHERE 1 1按照日志解析规则将_raw_log_parse成新的真实日志表
CREATE TABLE default.test
(status String,_timesecond DateTime,_timenanosecond DateTime64(9),_rawlog String CODEC(ZSTD(1)),// 该列通过物化视图解析得到level Nullable(String),// 根据需要添加更多列…INDEX idx_raw_log _rawlog TYPE tokenbf_v1(30720, 2, 0) GRANULARITY 1
)
ENGINE MergeTree
PARTITION BY toYYYYMMDD(_timesecond)
ORDER BY _timesecond
TTL toDateTime(_timesecond) toIntervalDay(1)
SETTINGS index_granularity 8192
每当需要分析新的索引字段clickvisual会执行Add Colum为日志表添加新的列同时更新物化视图添加新的解析处理规则。
ClickVisual的不足
根据上述的原理
不支持高效的近似全文检索工作原理可以看出由于ClickVisual并未对_raw_log_进行跳数索引所以也就导致ClickVisual不能高效的支持近似的对原始日志全文检索由于ClickVisual完全依赖Kafka表引擎来实现日志的摄入虽然ClickVisual也支持引入ClickHouse的已有日志表结构进行查询但是很可能并不是直接针对列查询而是针对map数据查询只有通过Kafka引擎来摄入的日志才能生成新日志表结构最终查询才是针对列式查询才能有较高的查询效率Kafka表引擎读写日志速度无法控制如果日志量非常多导致ClickHouse物化视图工作过程中内存爆掉 APO 日志设计方案
ClickVisual已经非常接近理想日志方案了只是我们需要对ClickVisual的逻辑进行调整。
不使用ClickHouse的Kafka表引擎来完成日志的摄取工作而是改成Vector的方式完成日志的摄取工作。这样就不再依赖Kafka对于中小用户日志规模没有那么大的用户可以直接使用而不需要维护Kafka。虽然去掉了Kakfa同时增加了Vector但是Vector的运维工作相比kafka而言Vector几乎不需要运维引入了Vector之后可以通过配置Vector来调整参数确保在大量日志洪锋的时候也不至于将ClickHouse内存打爆用户如果真的需要引入Kafka也有已经维护好的Kafka完全可以使用Vector先将原始日志写入Kafka然后使用Vector从Kafka读取出来继续实现后续的日志处理APO引入了ClickHouse null表引擎来实现原始日志(从Vector写入的) 转换成按照日志解析格式解析之后的真实日志表。所有的查询都是针对真实日志表的列查询所以性能比较高在真实日志表中额外存储了_rawlog,配合跳数索引完成 近似日志全文检索。
欢迎使用APO全量日志功能 APO v0.6.0更新日志
新增功能
支持全量日志的采集、处理与展示功能
缺陷修复
修复服务端点存在特殊字符时无法获取到依赖延时曲线的问题修复无故障场景下频繁采集故障现场数据的问题修复部分场景下数据库调用无指标的问题修复传统服务器场景下网络质量状态无法关联到告警的问题修复传统服务器场景下OneAgent配置注入失败的问题
其他
允许在创建 ClickHouse 表时选择是否创建副本向下兼容 ClickHouse 版本当前支持最低版本为 22.8.x APO介绍 国内开源首个 OpenTelemetry 结合 eBPF 的向导式可观测性产品 apo.kindlingx.com https://github.com/CloudDetail/apo
- 上一篇: 能看网站的浏览器影视文化传媒公司网站建设
- 下一篇: 能免费做网站建网站需要多少钱和什么条件
相关文章
-
能看网站的浏览器影视文化传媒公司网站建设
能看网站的浏览器影视文化传媒公司网站建设
- 技术栈
- 2026年03月21日
-
能接做网站的活的网站太原代理记账
能接做网站的活的网站太原代理记账
- 技术栈
- 2026年03月21日
-
能够做物理题的网站东莞企业建站公司
能够做物理题的网站东莞企业建站公司
- 技术栈
- 2026年03月21日
-
能免费做网站建网站需要多少钱和什么条件
能免费做网站建网站需要多少钱和什么条件
- 技术栈
- 2026年03月21日
-
能搜任何网站的浏览器西安网址开发 网站制作
能搜任何网站的浏览器西安网址开发 网站制作
- 技术栈
- 2026年03月21日
-
能搜任何网站的浏览器怎样创造一个网站
能搜任何网站的浏览器怎样创造一个网站
- 技术栈
- 2026年03月21日
