圈内最近有个段子挺火:“ELK就像程序员衣柜里的旧格子衫,当年穿出去倍儿有面,现在看着就透着股‘油腻’。”这话虽糙,但理不糙。你看携程、快手这些大厂,早就悄悄把日志系统从ELK换成了ClickHouse+Kafka+FileBeat的组合——咱们叫它“KFC套餐”。今天就来扒一扒,这新组合到底凭啥能让ELK“退休”。
先说说ELK的那些“硬伤”
ELK(Elasticsearch+Logstash+Kibana)当年确实牛,尤其Elasticsearch的全文检索和实时分析能力,一度是日志处理的“标杆”。但数据量一炸锅,这老伙计就扛不住了,问题一堆:
性能顶不住
Elasticsearch的写入速度跟ClickHouse比,差了能有5倍。查询延迟更离谱,动不动就秒级。之前有个电商平台,日志量冲到500万QPS,ES集群直接“假死”,运维团队通宵熬夜救场,那场面现在想起来都头大。
存储太烧钱
ES的存储成本简直是“吞金兽”。同样存1TB日志,ES得3台高配服务器扛着,ClickHouse用1台普通服务器就够。有游戏公司算过账,换了之后每年服务器成本省了200多万,这可不是小数目。
运维能逼疯人
Logstash这东西,配置复杂不说,还特耗资源。某金融公司就栽过跟头,Logstash内存泄漏把整个日志管道搞瘫了,直接引来监管层检查,那滋味谁尝谁知道。
技术这东西,迭代快得很。就像智能手机干掉诺基亚,ELK跟不上大数据时代的节奏,被替代是早晚的事。
日志处理新王牌:KFC组合登场
既然ELK扛不动了,谁来接棒?答案就是Kafka+FileBeat+ClickHouse的“KFC组合”。这仨工具凑一起,各司其职还配合得特默契,跟搭班子干活似的,效率拉满。
FileBeat:轻量能打的“采集小能手”
FileBeat看着不起眼,实则是个狠角色。用Go语言写的,轻量得很,启动速度比Logstash快3倍,内存占用才后者的1/10。最爽的是支持“零停机”热更新配置,运维改个正则表达式不用重启服务,省老事了。
下面是个常用的配置示例,咱们看看它能干啥:
filebeat.inputs:
- type: log # 采集类型为日志文件
paths:
- /var/log/nginx/access.log # 监控nginx的访问日志路径
exclude_files: [".gz$"] # 排除.gz结尾的压缩文件,避免重复处理
multiline.pattern: '^\[' # 多行日志匹配规则,这里匹配以[开头的行
multiline.match: after # 符合规则的行跟在前面的日志后,合并成一条
multiline.max_lines: 100 # 最多合并100行,防止内存爆掉
output.kafka: # 输出到Kafka
hosts: ["kafka1:9092","kafka2:9092"] # Kafka集群地址
topic: "nginx-logs" # 发送到名为nginx-logs的主题
compression: gzip # 数据压缩传输,省带宽
required_acks: 1 # 至少1个副本确认接收,保证可靠性
这段配置的核心作用:监控nginx日志,自动合并多行日志(比如Java报错时的堆栈信息),压缩后发给Kafka,稳定又高效。
Kafka:日志传输的“高速通道”
Kafka在消息队列里算是老江湖了,处理日志跟走高速似的,一点不堵车。吞吐量能到每秒百万级,延迟也就毫秒级。之前见过某出行平台用它处理实时订单,高峰期每秒200万条消息,稳稳当当的。
核心优势
- 数据能存挺久,默认保留7天,想存更久也能扩展;
- 用了“零拷贝”技术,数据直接从磁盘怼到网络,不用CPU来回倒腾,省资源;
- 多副本机制,就算某个节点挂了,数据也丢不了,靠谱。
实操建议
- 按业务分主题(Topic),比如nginx日志放“nginx-logs”,应用日志放“app-logs”,好管理;
- 每个主题设3个副本,性能和可靠性都兼顾到;
- 用Confluent Schema Registry管数据格式,免得生产者和消费者格式对不上,出乱子。
ClickHouse:数据分析的“性能猛兽”
ClickHouse专治大数据分析的“慢”。专为这场景设计的列式数据库,写入速度能到每秒60万条,查询比ES快5-30倍。有个电商平台用它分析用户行为日志,之前查10分钟的活儿,现在150毫秒就搞定,差距太明显了。
核心技术
- 列式存储:数据按列存,查的时候只取需要的列,不用整行都读,速度自然快;
- 向量化计算:一批数据一起处理,CPU利用率能提3倍;
- 自带压缩:默认用LZ4算法,1TB数据能压成100GB,省存储。
性能对比(1TB日志数据)
指标 | Elasticsearch | ClickHouse |
---|---|---|
写入吞吐量 | 12万条/秒 | 60万条/秒 |
查询延迟 | 800ms | 150ms |
存储成本 | $1200/月 | $400/月 |
手把手搭KFC日志平台:从0到1实战
光说不练假把式,咱们一步步把KFC平台搭起来。整个过程分三步:准备基础设施、建数据管道、做分析可视化。
1. 基础设施准备
硬件咋选?
- FileBeat节点:2核4G内存够了,一台能采100多台服务器的日志;
- Kafka集群:3台4核16G服务器,每个节点存1TB数据没问题;
- ClickHouse集群:3台8核32G服务器,每个节点存5TB数据妥妥的。
网络咋配?
- FileBeat和Kafka之间用私有网络,带宽至少10Gbps,不然传数据卡;
- ClickHouse集群内部用RDMA技术,数据传输更快。
环境部署
先装Docker和Docker Compose,然后启动Kafka集群:
docker-compose up -d kafka # -d表示后台运行,启动Kafka集群
部署ClickHouse集群:
docker run -d --name clickhouse-server \ # 容器名设为clickhouse-server
-p 8123:8123 -p 9000:9000 \ # 映射端口,8123是HTTP接口,9000是TCP接口
-v /data/clickhouse:/var/lib/clickhouse \ # 挂载数据目录到本地,防止容器挂了数据丢了
clickhouse/clickhouse-server # 用官方镜像
2. 数据管道咋建?
步骤1:用FileBeat采集日志
在要监控的服务器上装FileBeat,配置如下(根据自己的应用名改):
filebeat.inputs:
- type: log
paths:
- /var/log/*.log # 监控所有log结尾的日志文件
exclude_files: [".gz$"] # 排除压缩文件
fields: # 自定义字段,标记应用名和环境
app_name: "my-app" # 这里改成你的应用名
environment: "prod" # 环境,比如生产环境prod
output.kafka:
hosts: ["kafka1:9092","kafka2:9092"] # Kafka地址
topic: "%{[fields.app_name]}-logs" # 主题名用应用名+logs,自动区分
partition.round_robin:
reachable_only: true # 只往能连得上的分区发,避免报错
步骤2:Kafka缓冲数据
创建一个专门存nginx日志的主题:
kafka-topics.sh --create \
--bootstrap-server kafka1:9092 \ # 连Kafka集群
--replication-factor 3 \ # 3个副本,保证数据不丢
--partitions 16 \ # 16个分区,提高并行处理能力
--topic nginx-logs # 主题名
步骤3:ClickHouse消费数据
先在ClickHouse里建个Kafka引擎表,用来接Kafka的数据:
CREATE TABLE default.nginx_logs (
timestamp DateTime, # 日志时间
remote_addr String, # 客户端IP
status Int32, # 响应状态码
body_bytes_sent Int64, # 发送的字节数
request_time Float32 # 请求耗时
) ENGINE = Kafka SETTINGS
kafka_broker_list = 'kafka1:9092,kafka2:9092', # Kafka地址
kafka_topic_list = 'nginx-logs', # 订阅的主题
kafka_group_name = 'clickhouse-consumer', # 消费者组名
kafka_format = 'JSONEachRow'; # 数据格式是JSON,每行一条
再建个物化视图,实时把数据同步到MergeTree表(ClickHouse的主力存储引擎):
CREATE MATERIALIZED VIEW default.nginx_logs_mv
ENGINE = MergeTree() # 用MergeTree引擎,适合大规模数据存储和查询
ORDER BY (timestamp, remote_addr) # 按时间和IP排序,查得快
POPULATE # 初始化时把历史数据也同步过来
AS SELECT
timestamp,
remote_addr,
status,
body_bytes_sent,
request_time
FROM default.nginx_logs; # 从Kafka表取数据
3. 数据分析与可视化
实时查询例子
查最近1小时的错误日志(500及以上状态码),看看哪些IP报错多:
SELECT
remote_addr, # 客户端IP
COUNT(*) AS error_count # 错误次数
FROM default.nginx_logs_mv
WHERE status >= 500 # 过滤500及以上的错误
AND timestamp >= now() - INTERVAL 1 HOUR # 最近1小时
GROUP BY remote_addr
ORDER BY error_count DESC # 按错误次数倒序
LIMIT 10; # 取前10
分析请求延迟分布,看看95%和99%的请求耗时多少:
SELECT
quantile(0.95)(request_time) AS p95_latency, # 95%的请求耗时不超过这个值
quantile(0.99)(request_time) AS p99_latency # 99%的请求耗时不超过这个值
FROM default.nginx_logs_mv;
可视化咋搞?
- Grafana:装个ODBC驱动连ClickHouse,拖拖拽拽就能做仪表盘,实时看数据;
- Metabase:支持用自然语言查,比如“查昨天的错误日志”,业务同学也能用;
- 自己写前端:调用ClickHouse的REST API拿数据,做定制化报表。
踩坑指南:这些问题要注意
1. FileBeat内存泄漏
症状:FileBeat进程内存越用越多,最后服务器内存炸了(OOM)。
原因:多行日志合并没配置好,或者正则表达式太复杂,导致内存释放不了。
解决办法:加个自动重载配置,再删掉没用的字段,减轻内存压力:
filebeat.config.modules:
path: ${path.config}/modules.d/*.yml # 模块配置路径
reload.enabled: true # 允许自动重载配置
reload.period: 10s # 每10秒检查一次配置,有变化就更
filebeat.processors:
- drop_fields: # 删掉没用的字段,省内存
fields: ["input", "agent", "ecs"]
ignore_missing: true # 字段不存在也不报错
2. Kafka消费延迟
症状:Kafka里堆了一堆没处理的消息,数据延迟严重。
原因:ClickHouse消费太慢,或者Kafka分区太少,并行不起来。
解决办法:
- 加ClickHouse的消费者数量:
ALTER TABLE default.nginx_logs
SETTINGS kafka_num_consumers = 4; # 改成4个消费者,并行处理
- 把Kafka分区数加到32个,提高吞吐量。
3. ClickHouse查询变慢
症状:查询突然变卡,CPU飙到100%。
原因:数据分布不均(有的分区数据太多),或者查询没用到分区键,全表扫了。
解决办法:
- 先看查询计划,找找慢的原因:
EXPLAIN SELECT * FROM default.nginx_logs_mv WHERE timestamp >= '2023-01-01'; # 分析查询路径
- 按时间分区,比如按月分,查的时候只扫对应月份的数据:
CREATE TABLE default.nginx_logs_mv (
timestamp DateTime,
... # 其他字段
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(timestamp) # 按年月分区
ORDER BY (timestamp, remote_addr);
最后说两句
ELK当年确实风光,但数据量一大就露怯了。KFC组合不一样,FileBeat轻量能采,Kafka稳当能传,ClickHouse能扛能算,仨放一起,处理日志又快又省。
要是你还在为ELK的性能头疼,真可以试试这个“KFC套餐”。实测过,原来查10分钟的日志,ClickHouse里100毫秒搞定,那感觉,跟夏天喝冰阔落一样——透心凉,贼爽!