<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      萬(wàn)字長(zhǎng)文:企業(yè)可觀察性平臺(tái)的建設(shè)方案實(shí)踐

      背景

      家里放置了一個(gè) 32G+1T 的 R7-8745H 主機(jī),部署一些數(shù)據(jù)庫(kù)等服務(wù)以便日常開(kāi)發(fā),后續(xù)需求越來(lái)越多,需要用到可觀察性組件,所以研究一些在中小公司中實(shí)現(xiàn)性價(jià)比高、簡(jiǎn)單易用、吞吐量大的部署方案。


      本問(wèn)主要部署環(huán)境是 Docker,不涉及 Kubernetes 部署,但是涉及的組件可以根據(jù)實(shí)際需求放在 Kubernetes 中進(jìn)行分布式擴(kuò)展,以及收集集群信息。

      如需了解集群部署原理等相關(guān)知識(shí),可參考筆者以前的文章:

      Kubernetes 集群日志 和 EFK 架構(gòu)日志方案: http://www.rzrgm.cn/whuanle/p/15893923.html

      Kubernetes 集群和應(yīng)用監(jiān)控方案的設(shè)計(jì)與實(shí)踐 :http://www.rzrgm.cn/whuanle/p/15890343.html

      方案說(shuō)明

      可觀測(cè)性的實(shí)現(xiàn)方案有很多,例如 Grafana 全家桶、Elastic 商業(yè)全家桶,商業(yè)收費(fèi)或開(kāi)源也有一些一體化平臺(tái)例如 GreptimeDB,為了在部署過(guò)程研究各種中間件服務(wù)的特點(diǎn)和部署流程,我們不采用這種一體化平臺(tái),使用各種開(kāi)源組件實(shí)現(xiàn)部署。

      主要目標(biāo)是實(shí)現(xiàn)小企業(yè)低成本建設(shè),我們考慮在最小內(nèi)存實(shí)現(xiàn)滿足 10 天以上的日志、鏈路追蹤、監(jiān)控等數(shù)據(jù)存儲(chǔ)和查詢。


      主要思路是分開(kāi) 日志(Logs)、鏈路追蹤(Traces)、指標(biāo)(Metrics)三方面研究。


      讓我們了解一下日志記錄的三個(gè)關(guān)鍵組件。

      Logging Agent: 日志代理,在服務(wù)器節(jié)點(diǎn)上運(yùn)行,采集系統(tǒng)日志、服務(wù)日志、Docker 容器日志、Kubernetes 服務(wù)日志等,它將日志不斷地集中到日志后端。

      Logging Backend: 一個(gè)集中的系統(tǒng),能夠存儲(chǔ)、搜索和分析日志數(shù)據(jù)。

      Log Visualization: 以儀表板的形式可視化日志數(shù)據(jù)的工具。


      首先是 Logging Agent,社區(qū)最常用的是 Logstash 組件,用于采集、過(guò)濾、二次處理日志,然后推送到存儲(chǔ)后端。

      要先評(píng)估每天產(chǎn)生的日志數(shù)量,量小且沒(méi)有太多分析需求時(shí),使用 Filebeat 收集日志、打標(biāo)簽、推送到 ElasticSearch、Clickhouse 等即可。

      如果要應(yīng)對(duì)集群、每天產(chǎn)生的日志數(shù)量大、有峰值瓶頸,可以在每個(gè)節(jié)點(diǎn)部署 Filebeat 收集日志,推送到 Kafka 集群,然后使用 Logstash 逐步消費(fèi) Kafka 日志推送到 ElasticSearch。這種方式好處是可以進(jìn)行流量削峰,可以很容易水平伸縮應(yīng)對(duì)高吞吐量,滿足有額外日志處理的需求,方便進(jìn)行二次處理。


      Logging Backend 是存儲(chǔ)日志的后端,ElasticSearch、Clickhouse 都是常用的日志存儲(chǔ)數(shù)據(jù)庫(kù),兩者都支持分布式部署,Clickhouse 的成本更低一些,不過(guò)使用曲線復(fù)雜一些,所以后續(xù)主要使用 ElasticSearch 做存儲(chǔ)后端。


      無(wú)標(biāo)題-2025-09-26-1458

      鏈路追蹤和指標(biāo),可以使用 OpenTelemetry Collector 做統(tǒng)一接入層,然后使用 Collector 轉(zhuǎn)發(fā)到不同的方案中。好處是應(yīng)用只需要有一個(gè)統(tǒng)一的推送地址,應(yīng)用只需要使用 OpenTelemetry SDK 統(tǒng)一接入就行,而運(yùn)維可以使用 Collector 綁定不同的后端存儲(chǔ)服務(wù)。

      OpenTelemetry Collector 本身不存儲(chǔ)數(shù)據(jù),它是實(shí)現(xiàn)了 OpenTelemetry 協(xié)議的統(tǒng)一接入層,然后轉(zhuǎn)發(fā)到對(duì)應(yīng)的后端存儲(chǔ)服務(wù),需要搭配對(duì)應(yīng)的 Logs、Traces、Metrics 使用。

      比如 Traces 可以使用 Jaeger 或 Skywalking + ElasticSearch,Metrics 可以使用 Prometheus + Grafana,而應(yīng)用服務(wù)并不需要關(guān)注具體的實(shí)現(xiàn),統(tǒng)一將數(shù)據(jù)推送到 OpenTelemetry Collector 服務(wù)即可,具體怎么處理,由運(yùn)維配置 Collector 轉(zhuǎn)發(fā)到具體的存儲(chǔ)后端。

      當(dāng)然,OpenTelemetry Collector 也支持應(yīng)用推送日志,不過(guò)一般是采集器在宿主機(jī)采集。


      graph TB subgraph tdf[遙測(cè)數(shù)據(jù)流] subgraph subgraph_padding [ ] style subgraph_padding fill:none,stroke:none; %% 為了避免標(biāo)題重疊進(jìn)行填充 subgraph od[OpenTelemetry 演示] ms(微服務(wù)) end ms -.->|"OTLP<br/>gRPC"| oc-grpc ms -.->|"OTLP<br/>HTTP POST"| oc-http subgraph oc[OTel Collector(收集器)] style oc fill:#97aef3,color:black; oc-grpc[/"OTLP 接收器<br/>監(jiān)聽(tīng)地址<br/>grpc://localhost:4317"/] oc-http[/"OTLP 接收器<br/>監(jiān)聽(tīng)地址<br/>localhost:4318<br/>"/] oc-proc(處理器) oc-prom[/"OTLP HTTP 導(dǎo)出器"/] oc-otlp[/"OTLP 導(dǎo)出器"/] oc-grpc --> oc-proc oc-http --> oc-proc oc-proc --> oc-prom oc-proc --> oc-otlp end oc-prom -->|"localhost:9090/api/v1/otlp"| pr-sc oc-otlp -->|gRPC| ja-col subgraph pr[Prometheus(指標(biāo)系統(tǒng))] style pr fill:#e75128,color:black; pr-sc[/"Prometheus OTLP<br/>寫(xiě)入接收器"/] pr-tsdb[(Prometheus 時(shí)序數(shù)據(jù)庫(kù))] pr-http[/"Prometheus HTTP<br/>監(jiān)聽(tīng)地址<br/>localhost:9090"/] pr-sc --> pr-tsdb pr-tsdb --> pr-http end pr-b{{"瀏覽器<br/>Prometheus UI"}} pr-http ---->|"localhost:9090/graph"| pr-b subgraph ja[Jaeger(追蹤系統(tǒng))] style ja fill:#60d0e4,color:black; ja-col[/"Jaeger Collector<br/>監(jiān)聽(tīng)地址<br/>grpc://jaeger:4317"/] ja-db[(Jaeger 數(shù)據(jù)庫(kù))] ja-http[/"Jaeger HTTP<br/>監(jiān)聽(tīng)地址<br/>localhost:16686"/] ja-col --> ja-db ja-db --> ja-http end subgraph gr[Grafana(可視化)] style gr fill:#f8b91e,color:black; gr-srv["Grafana 服務(wù)器"] gr-http[/"Grafana HTTP<br/>監(jiān)聽(tīng)地址<br/>localhost:3000"/] gr-srv --> gr-http end pr-http --> |"localhost:9090/api"| gr-srv ja-http --> |"localhost:16686/api"| gr-srv ja-b{{"瀏覽器<br/>Jaeger UI"}} ja-http ---->|"localhost:16686/search"| ja-b gr-b{{"瀏覽器<br/>Grafana UI"}} gr-http -->|"localhost:3000/dashboard"| gr-b end end

      當(dāng)然,很多可觀察性組件本身就已經(jīng)兼容了 OpenTelemetry 協(xié)議,不需要 OpenTelemetry Collector 也可以直接接收數(shù)據(jù),這點(diǎn)后面再講解。


      采用的大概方案就是這樣,接下來(lái)將講解具體實(shí)現(xiàn)細(xì)節(jié)。

      日志方案

      存儲(chǔ)后端 ElasticSearch + Kibana

      日志存儲(chǔ)和索引最常用的就是 ElasticSearch + Kibana 了,雖然說(shuō) ElasticSearch 占用資源大一些,但是相對(duì)來(lái)說(shuō)維護(hù)還是比較簡(jiǎn)單的,資料也多,需要擴(kuò)展成集群也相對(duì)容易一些,配置日志清理規(guī)則等,都容易處理,所以日志存儲(chǔ)服務(wù)首選還是 ElasticSearch。


      本章將 ElasticSearch 部署為單節(jié)點(diǎn)模式,本文的 ElasticSearch、Kibana 不創(chuàng)建網(wǎng)絡(luò)也不創(chuàng)建存儲(chǔ)卷,直接以節(jié)點(diǎn)的形式暴露端口,并且映射本地目錄持久化存儲(chǔ)。


      創(chuàng)建 /data/elasticsearch/data/data/elasticsearch/config 用于存儲(chǔ) ElasticSearch 的配置文件和數(shù)據(jù),目錄權(quán)限設(shè)置 755。


      先啟動(dòng)一個(gè) ElasticSearch:

      docker run -itd --name elasticsearch -m 2GB  \
      --restart=always   \
      --publish 9200:9200   \
      --env discovery.type=single-node   \
      --env xpack.security.authc.api_key.enabled=true   \
      -v /data/elasticsearch/data:/usr/share/elasticsearch/data   \
      docker.elastic.co/elasticsearch/elasticsearch:9.1.3
      ```(http://nps.local.whuanle.cn:36006/images
      
      > 部署 ElasticSearch  最好設(shè)置限制內(nèi)存,否則吃掉非常多的主機(jī)資源。
      
      <br />
      
      如果需要將 ElasticSearch 的配置文件也放出來(lái),可以先復(fù)制到 config 目錄:
      
      
      ```bash
      docker cp elasticsearch:/usr/share/elasticsearch/config ./
      

      然后刪除容器重新創(chuàng)建:

      docker rm -f elasticsearch
      docker run -itd --name elasticsearch -m 2GB  \
      --restart=always   \
      --publish 9200:9200   \
      --env discovery.type=single-node   \
      --env xpack.security.authc.api_key.enabled=true   \
      -v /data/elasticsearch/config:/usr/share/elasticsearch/config   \
      -v /data/elasticsearch/data:/usr/share/elasticsearch/data   \
      docker.elastic.co/elasticsearch/elasticsearch:9.1.3
      

      接著進(jìn)入容器,初始化 elastic、kibana_system、logstash_system 三個(gè)賬號(hào)的密碼。

      docker exec -it elasticsearch bash
      

      進(jìn)入容器后打開(kāi) bin 目錄。

      b2986ce9-8937-4737-ad0a-907a3c13ad87


      分別執(zhí)行 ./elasticsearch-reset-password -u elastic./elasticsearch-reset-password -u kibana_system./elasticsearch-reset-password -u logstash_system ,復(fù)制輸出的密碼。


      或者執(zhí)行 ./elasticsearch-setup-passwords interactive,按照提示選擇要重置密碼的賬號(hào)。

      1d33d912-657f-4c22-993c-61164d3a62f0

      建議使用隨機(jī)密碼,如果密碼太簡(jiǎn)單,Kibana 連接時(shí)會(huì)提示 Error: [config validation of [elasticsearch].password]: expected value of type [string] but got [number]


      測(cè)試 ElasticSearch 是否部署成功:

      curl -u elastic http://localhost:9200/
      

      image-20250918110900548


      或者在瀏覽器打開(kāi)地址后輸入 elastic 的賬號(hào)密碼,能夠進(jìn)入說(shuō)明部署正常。

      image-20250918110754657

      image-20250918110811190


      接下來(lái)開(kāi)始部署 Kibana,因?yàn)?Kibana 是無(wú)狀態(tài)的,因此只需要注冊(cè)相關(guān)環(huán)境變量,不需要映射目錄。

      docker run --name kibana --restart=always   \
      -itd   --publish 5601:5601   \
      --env ELASTICSEARCH_HOSTS="http://192.168.50.199:9200"  \
      --env ELASTICSEARCH_USERNAME=kibana_system   \
      --env ELASTICSEARCH_PASSWORD='密碼'   \
      docker.elastic.co/kibana/kibana:9.1.3
      
      • ELASTICSEARCH_HOSTS 是 ElasticSearch 容器所在的節(jié)點(diǎn) IP 和端口。
      • ELASTICSEARCH_USERNAMEELASTICSEARCH_PASSWORD 是賬號(hào)密碼,賬號(hào)固定使用 kibana_system

      至此,ElasticSearch、Kibana 部署完成。

      image-20250918113218947

      日志收集方案

      開(kāi)源社區(qū)中有很多方案,社區(qū)中常用的有 logstash 、Flunetd/Fluentbit、Filebeat 等工具,例如大名鼎鼎的 ELK 中的 L 是 logstash ,LogsStash 功能強(qiáng)勁但是占用資源大,在集群里面收集日志或節(jié)點(diǎn)里面收集日志可能會(huì)消耗過(guò)多的資源。

      所以筆者主要使用 Filebeat 收集日志,讀者可以根據(jù)需求確認(rèn)使用哪種具體的收集方式。

      Filebeat 是 Elastic 家的產(chǎn)品之一,其文檔介紹:https://elastic.ac.cn/docs/reference/beats/filebeat/how-filebeat-works


      例如只需要收集日志轉(zhuǎn)發(fā),F(xiàn)ilebeat 足夠輕量,支持 Docker 部署,也支持 Kubernetes 部署,無(wú)需安裝插件即可支持輸出到 Kafka、ElasticSearch。

      不需要按照額外插件即可支持多種接口,這是非常重要的,一開(kāi)始筆者嘗試過(guò) Fluentd,奈何部署需要另外安裝插件,Docker 啟動(dòng)需要另外制作帶插件的包,部署過(guò)于麻煩,所以筆者放棄了 Fluentd。


      筆者采用的方案是 filebeat + kafka + logstash 。如果你的服務(wù)器數(shù)量少,每天產(chǎn)生的日志量不大,直接使用 Filebeat 推送到 ElasticSearch 即可

      如果集群日志量比較大,則每個(gè)節(jié)點(diǎn)使用使用 Filebeat 推送到 Kafka,然后 Logstash 從 Kafka 消費(fèi)處理后推送到 ElasticSearch。


      因?yàn)槎虝r(shí)間集群日志的量可能比較大,ElasticSearch 萬(wàn)一頂不住那么大的直接炸了就不好了,使用 Kafka 可以以集群的方式部署,對(duì)流量進(jìn)行削峰。


      Logstash 可以單節(jié)點(diǎn)部署,因?yàn)?Logstash 的吞吐量很大,即使多個(gè) Filebeat 同時(shí)推送到 Kafka,Logstash 也可以應(yīng)對(duì),并且 Kafka 有持久化能力,即使單節(jié)點(diǎn) Logstash 消費(fèi)慢一些,后續(xù)也可以通過(guò)部署多個(gè) Logstash 解決問(wèn)題。

      多個(gè) Logstash 并不需要分布式通訊協(xié)調(diào),因?yàn)樗麄兪褂孟嗤?Consumer 訂閱 Kafka 主題即可,Kafka 會(huì)均衡將消息分配給每個(gè)實(shí)例,所以擴(kuò)展起來(lái)也很簡(jiǎn)單。


      Filebeat 的配置挺簡(jiǎn)單的,如果直接使用 Filebeat 推送到 ElasticSearch,只需要這樣配置即可:

      這里只做演示,不實(shí)際使用。

      filebeat.config:
        modules:
          path: ${path.config}/modules.d/*.yml
          reload.enabled: false
      
      filebeat.autodiscover:
        providers:
          - type: docker
            hints.enabled: true
      
      processors:
      - add_cloud_metadata: ~
      
      output.elasticsearch:
        hosts: '${ELASTICSEARCH_HOSTS:elasticsearch:9200}'
        username: '${ELASTICSEARCH_USERNAME:}'
        password: '${ELASTICSEARCH_PASSWORD:}'
      

      配置內(nèi)容參考:raw.githubusercontent.com/elastic/beats/9.0/deploy/docker/filebeat.docker.yml

      部署 Kafka

      筆者內(nèi)網(wǎng)的日志量不大,所以只需要部署單機(jī)即可。

      創(chuàng)建目錄:

      mkdir -p /data/kafka/broker/logs
      mkdir -p /data/kafka/broker/data
      chmod -R 777 /data/kafka
      

      /data/kafka 目錄下創(chuàng)建 docker-compose.yml 文件:

      services:
        kafka:
          image: apache/kafka-native
          ports:
            - "9092:9092"
            - "9093:9093"
          volumes:
            - /data/kafka/broker/logs:/opt/kafka/logs  # 持久化日志和數(shù)據(jù)
            - /data/kafka/broker/data:/opt/kafka/data
          environment:
            # Configure listeners for both docker and host communication
            KAFKA_LISTENERS: CONTROLLER://:9091,HOST://0.0.0.0:9092,DOCKER://0.0.0.0:9093
            KAFKA_ADVERTISED_LISTENERS: HOST://192.168.50.199:9092,DOCKER://kafka:9093
            KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,DOCKER:PLAINTEXT,HOST:PLAINTEXT
      
            # Settings required for KRaft mode
            KAFKA_NODE_ID: 1
            KAFKA_PROCESS_ROLES: broker,controller
            KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
            KAFKA_CONTROLLER_QUORUM_VOTERS: 1@localhost:9091
      
            # Listener to use for broker-to-broker communication
            KAFKA_INTER_BROKER_LISTENER_NAME: DOCKER
      
            # Required for a single node cluster
            KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      
        kafka-ui:
          image: kafbat/kafka-ui:main
          ports:
            - 8080:8080
          environment:
            DYNAMIC_CONFIG_ENABLED: "true"
            KAFKA_CLUSTERS_0_NAME: local
            KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9093
          depends_on:
            - kafka
      

      生產(chǎn)環(huán)境建議按需部署 Kafka 集群,請(qǐng)勿使用單機(jī) Kafka。

      如果不需要 ui,可以刪除 kafka-ui 服務(wù)。


      打開(kāi) kafka-ui 端口,然后填寫(xiě) Kafka 地址。

      注,筆者實(shí)際使用的是 38080 端口,管理 Kafka 要使用 9093 端口而不是 9092 端口。


      image-20250919100754293

      部署 Filebeat

      Filebeat 支持采集多行消息、AWS S3 、Azure Blob Storage、容器、 Kafka 等各種日志源支持采集和集中處理日志,詳細(xì)介紹參考:https://www.elastic.co/cn/beats/filebeat

      Filebeat 支持裸機(jī)、Docker 部署和集群部署,考慮到維護(hù)方法,這里使用 Docker 部署收集宿主機(jī)的日志,這里講解 Kubernetes 的部署。

      docker pull docker.elastic.co/beats/filebeat:9.1.3
      

      創(chuàng)建 /data/filebeat/filebeat.docker.yml 文件和 /data/filebeat/data 目錄。

      filebeat.docker.yml 文件內(nèi)容如下:

      #######################
      # Filebeat 主配置
      #######################
      filebeat.inputs:
        # Docker日志輸入(添加多行處理)
        - type: filestream
          id: docker-logs
          paths:
            - /var/lib/docker/containers/*/*.log
          parsers:
            - container:   # 使用 container 解析器處理 Docker JSON 日志
                format: docker
                stream: all
          # 新增多行配置(關(guān)鍵修改)
          multiline:
            type: pattern
            pattern: '^[[:space:]]'  # 匹配以空格/制表符開(kāi)頭的行
            negate: false
            match: after
            timeout: 5s
          fields:
            log_source: docker
            log_topic: docker-logs
      
        # Nginx日志輸入(保持不變)
        - type: filestream
          id: nginx-logs
          paths:
            - /var/log/nginx/*.log
          multiline:
            pattern: '^\[[0-9]{4}-[0-9]{2}-[0-9]{2}'
            negate: true
            match: after
          fields:
            log_topic: nginx-logs
              
      processors:
        - add_host_metadata:
            when.not.contains.tags: forwarded
        - add_cloud_metadata: ~
        - add_docker_metadata: ~
        - drop_fields:
            fields: ["log.offset", "input.type", "host.uptime"]
        - drop_event.when:
            or:
              - contains.container.name: "logstash"
              - contains.container.name: "filebeat"
              
      #######################
      # 輸出配置
      #######################
      output.kafka:
        # initial brokers for reading cluster metadata
        hosts: ["192.168.50.199:9092"]
      
        # message topic selection + partitioning
        topic: '%{[fields.log_topic]}'
        partition.round_robin:
          reachable_only: false
      
        required_acks: 1
        compression: gzip
        max_message_bytes: 1000000
      

      部署時(shí)如發(fā)現(xiàn)運(yùn)行異常,可以開(kāi)啟輸出調(diào)試信息功能。

      logging.level: debug  # 開(kāi)啟調(diào)試日志
      

      這里使用 Filebeat 收集兩類日志,一個(gè)是 Docker 容器的日志,要使用 drop_event.when 排除 logstashfilebeat 容器的日志;另一個(gè)是收集 nginx 的日志,如果不需要收集 nginx 日志,可以去掉 nginx-logs,這里只做演示使用。

      讀者可以調(diào)整配置收集 /var/log/var/lib/docker/containers/ 等目錄下的日志。


      日志收集沒(méi)有這么簡(jiǎn)單,因?yàn)椴煌绦蜉敵龅娜罩居懈鞣N各樣的,而默認(rèn) Docker 是按照每行輸出一個(gè) json 記錄,會(huì)導(dǎo)致完整的日志被拆散,需要想辦法重新組合,這一點(diǎn)在部署 Logstash 消費(fèi)日志時(shí)再說(shuō)。


      配置里面根據(jù) docker 和 nginx 分開(kāi)推送到 kafka,產(chǎn)生兩個(gè) topic, topic: '%{[fields.log_topic]}' 是 區(qū)配所有 topic,跟每個(gè) inputs 的字段變量有關(guān),可以自行修改。


      如果使用不是 Docker 或者使用 containerd 等啟動(dòng),容器日志的目錄可能是 /var/log/containers/*.log,讀者自行調(diào)整。


      啟動(dòng) filebeat,將宿主機(jī)的日志文件映射到 filebeat 容器中:

      docker run -d \
        --name=filebeat \
        --user=root \
        --volume="/data/filebeat/filebeat.docker.yml:/usr/share/filebeat/filebeat.yml:ro" \
        --volume="/var/run/docker.sock:/var/run/docker.sock:ro" \
        --volume="/data/filebeat/data:/usr/share/filebeat/data:rw" \
        --volume="/var/lib/docker/containers:/var/lib/docker/containers" \
        --mount type=bind,source=/var/log,target=/var/log \
        docker.elastic.co/beats/filebeat:9.1.3 filebeat -e --strict.perms=false 
      

      --strict.perms=false:避免因文件權(quán)限問(wèn)題導(dǎo)致啟動(dòng)失敗。

      打開(kāi) kafbat UI,查看是否有 topic 。

      image-20250919112904491

      日志收集處理方式

      消費(fèi)的日志非常依賴收集時(shí)的日志格式和各類元數(shù)據(jù),好的收集方式可以大大簡(jiǎn)化消費(fèi)日志的復(fù)雜配置,所以這里先講解收集階段如何正確處理日志文件。

      基本需求: 增加或去除無(wú)用字段, 處理不同格式的日志:json、單行、多行、異常堆棧,對(duì)日志處理時(shí),還要給其附加所在的環(huán)境、節(jié)點(diǎn)名稱、容器/服務(wù)名稱等信息。。


      第一類,Json 日志格式日志,這是微服務(wù)下推薦使用的的日志格式,后端服務(wù)使用日志框架生成 json 格式的日志輸出,每行一個(gè) json,多行文本被壓縮到字段里面,json 日志可以附帶上下文信息和元數(shù)據(jù),日志收集和分析都很方便。

      image-20241013131644962

      C# 程序參考筆者的教程:https://maomi.whuanle.cn/3.2.serilog.html#serilog-日志格式模板


      推送到 ElasticSearch 時(shí),可以利用 Json 字段生成 ElasticSearch 的字段,這樣搜索、篩選都是很方便,例如日志框架固定 "@tr" 服務(wù)輸出鏈路追蹤 id,那么可以通過(guò)其 id 查找一次請(qǐng)求中關(guān)聯(lián)的所有日志。

      {"log.level":"warn","@timestamp":"2025-09-19T03:39:29.165Z","log.logger":"input.scanner","log.origin":{"function":"github.com/elastic/beats/v7/filebeat/input/filestream.(*fileScanner).GetFiles","file.name":"filestream/fswatch.go","file.line":421},"message":"1 file is too small to be ingested, files need to be at least 1024 in size for ingestion to start. To change this behaviour set 'prospector.scanner.fingerprint.length' and 'prospector.scanner.fingerprint.offset'. Enable debug logging to see all file names.","service.name":"filebeat","filestream_id":"docker-logs","ecs.version":"1.6.0"}
      

      單行日志沒(méi)有特定格式,所有內(nèi)容壓縮在一行,這樣難以攜帶上下文信息、閱讀困難。

      image-20250919115953782


      單行日志處理其實(shí)挺簡(jiǎn)單,但是如果程序拋出堆棧或需要多行格式輸出屬性時(shí),會(huì)導(dǎo)致一個(gè)日志被分開(kāi)成多個(gè)行,導(dǎo)致日志質(zhì)量低下、信息被打散。

      image-20250919140855452


      Docker 是將每行日志生成一個(gè) json 輸出的,例如:

      [2025-09-19 03:22:55,782] INFO KafkaConfig values: 
      	add.partitions.to.txn.retry.backoff.max.ms = 100
      	add.partitions.to.txn.retry.backoff.ms = 20
      


      Docker 對(duì)日志的處理方式非常簡(jiǎn)單,它完全不關(guān)心日志內(nèi)容的格式或結(jié)構(gòu),包括多行日志,Docker 只會(huì)捕獲容器的標(biāo)準(zhǔn)輸出(stdout)和標(biāo)準(zhǔn)錯(cuò)誤(stderr)流,將這個(gè)流中的每一行以換行符 \n為分隔,然后以 json 格式輸出到容器日志文件。


      最后生成三行日志:

      {"log":"[2025-09-19 03:22:55,782] INFO KafkaConfig values: \n","stream":"stdout","time":"2025-09-19T03:22:55.782123456Z"}
      {"log":"\tadd.partitions.to.txn.retry.backoff.max.ms = 100\n","stream":"stdout","time":"2025-09-19T03:22:55.782234567Z"}
      {"log":"\tadd.partitions.to.txn.retry.backoff.ms = 20\n","stream":"stdout","time":"2025-09-19T03:22:55.782345678Z"}
      

      所以日志收集消費(fèi)都要考慮各種各樣的日志格式問(wèn)題。

      為了保證日志收集和消費(fèi)的高效,F(xiàn)ilebeat 收集日志只在乎單行還是多行,只負(fù)責(zé)將日志提前出完整的一部分。

      所以在 filebeat.docker.yml 文件有這一部分配置:

      multiline:
        type: pattern
        pattern: '^[[:space:]]'  # 識(shí)別縮進(jìn)行(如堆棧跟蹤)
        negate: false            # 直接匹配pattern
        match: after             # 合并到前一行之后
        timeout: 5s              # 多行組等待時(shí)間
      

      而對(duì)應(yīng)其他更加特殊的格式,需要讀者自行查找解析方法。

      雖然 Filebeat 也支持 Json 解析和各種各樣的驗(yàn)證規(guī)則,但是為了性能和速度起見(jiàn),只按單行多行處理就推送到 Kafka。

      過(guò)程:

      Docker Containers
            ↓ (stdout/stderr)
      /var/lib/docker/containers/*.log
            ↓
      Filebeat (多行合并 + Docker元數(shù)據(jù))
            ↓ (Kafka Producer)
      Kafka Topic: raw-docker-logs
            ↓ (Kafka Consumer)
      Logstash (JSON檢測(cè) + 字段處理)
            ↓
      Elasticsearch Index: docker-{容器名稱}-*
      

      日志消費(fèi)

      目的是從 Kafka 消費(fèi)日志,清洗日志后推送到 ElasticSearch。

      由于筆者的需求不多,因此只需要消費(fèi)日志后打標(biāo)簽推送到 ElasticSearch。


      /data/logstash 目錄創(chuàng)建 logstash.conf 文件,內(nèi)容如下:

      # logstash.conf
      input {
        kafka {
          bootstrap_servers => "192.168.50.199:9092"
          topics => ["docker-logs"]
          codec => "json"  # 解析Filebeat輸出的JSON格式
        }
      }
      
      filter {
        # 提取Docker容器元數(shù)據(jù)
        ruby {
          code => '
            if container_id = event.get("[container][id]")
              event.set("container_name", event.get("[container][name]") || container_id[0..11])
            end
          '
        }
      
        # 智能JSON檢測(cè)(關(guān)鍵)
        if [message] =~ /^{.*}$/ {
          json {
            source => "message"
            target => "json_content"
            remove_field => ["message"]
          }
        }
      
        # 公共字段清理
        mutate {
          remove_field => [
            "agent", "ecs", "input", "log", "host"
          ]
        }
      }
      
      output {
        elasticsearch {
          hosts => ["http://192.168.50.199:9200"]
          index => "docker-%{[container][name]}-%{+YYYY.MM.dd}"
          user => "ES賬號(hào)"
          password => "ES密碼"
          ssl_enabled  => false
        }
      
        # 調(diào)試用(可選)
        stdout {
          codec => rubydebug
        }
      }
      

      注意,這里推送到 ElasticSearch 的日志索引都帶有 docker- 前綴,可以自行改掉。

      如果需要啟用 ElasticSearch SSL:

      ssl_enabled => true
      ssl_certificate_verification => true
      cacert => "/path/to/ca.crt"
      

      啟動(dòng) logstash 服務(wù)。

      docker pull docker.elastic.co/logstash/logstash:9.1.4
      # 國(guó)內(nèi)網(wǎng)絡(luò) docker pull logstash:9.1.4
      
      docker run --name logstash -itd  --restart=always \
      -v /data/logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf \
      docker.elastic.co/logstash/logstash:9.1.4
      
      # 國(guó)內(nèi)網(wǎng)絡(luò)使用以下命令
      docker run --name logstash -itd  --restart=always \
      -v /data/logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf \
      logstash:9.1.4
      

      查看 logstash 的日志,正在消費(fèi) Kafka:

      image-20250919150414575


      logstash 消費(fèi)能力非常強(qiáng),啟動(dòng)后短時(shí)間就消費(fèi)了僅 3000w 條日志。

      image-20250919164439401


      查看 ElasticSearch 輸出了對(duì)應(yīng)的容器索引日志。

      這里帶上了 docker- 前綴,如不需要,可以修改 logstash.confindex => "docker-%{[container][name]}-%{+YYYY.MM.dd}"

      image-20250919173857544


      如果要在界面按照服務(wù)名稱搜索和查看日志,需要進(jìn)入 Discover,添加新的視圖。

      37f97a9b-f47a-4383-9be2-68a69aa88657

      例如,要查看查看 astrbot 容器的日志,因?yàn)槿罩臼前刺焐傻模孕枰榭?docker-astrbot-* 的所有相關(guān)日志,之后即可查看 astrbot 的所有日期的日志。

      image-20250926173630914

      image-20250928102143947

      監(jiān)控方案

      Metrics 毫無(wú)疑問(wèn)固定搭配 Prometheus + Grafana,本文涉及到的組件有 Prometheus、Grafana、pushgateway、node exporter、mysql exporter 等。

      Prometheus 只需要固定采集 pushgateway 即可,各類數(shù)據(jù)源可以自己推送到 pushgateway,省去大量配置 Prometheus 的麻煩。

      下面直接開(kāi)始講解部署過(guò)程。


      拉取鏡像:

      docker pull prom/pushgateway
      docker pull  prom/prometheus
      

      創(chuàng)建兩個(gè)目錄:

      /data/prometheus/config
      /data/prometheus/data
      

      先部署 pushgateway。

      docker run -d -restart=always --name pushgateway -p 9091:9091 prom/pushgateway
      

      /data/prometheus/config 目錄新建 prometheus.yml 文件。

      global:
        scrape_interval: 15s
        evaluation_interval: 15s
        scrape_timeout: 10s
      
      scrape_configs:
        # 監(jiān)控Prometheus自身
        - job_name: 'prometheus'
          static_configs:
            - targets: ['localhost:9090']
      
        # Pushgateway監(jiān)控 (核心配置)
        - job_name: 'pushgateway'
          honor_labels: true  # 關(guān)鍵配置:保留推送的原始標(biāo)簽
          static_configs:
            - targets: ['192.168.50.199:9091']  # 替換為 pushgateway 實(shí)際IP和端口
              labels:
                env: 'prod'
                component: 'batch_jobs'  # 按實(shí)際用途標(biāo)記
      

      部署 Promethes:

      docker run    -itd --restart=always  -p 9090:9090         \
      -v /data/prometheus/config/prometheus.yml:/prometheus/prometheus.yml     \
      -v /data/prometheus/data:/prometheus     \
      prom/prometheus
      

      部署完成后,打開(kāi) Prometheus 地址,查看是否開(kāi)源正常訪問(wèn)數(shù)據(jù)源。

      image-20250921095005675


      部署 node_exporter

      目的是監(jiān)控機(jī)器的 CPU、內(nèi)容、網(wǎng)絡(luò)等。


      在 Github 上下載最新版本 node_exporter: https://github.com/prometheus/node_exporter/releases/tag/v1.9.1

      tar -zvxf node_exporter-1.9.1.linux-amd64.tar.gz
      mv node_exporter-1.9.1.linux-amd64/node_exporter /usr/local/bin/
      

      制作系統(tǒng)啟動(dòng)項(xiàng):

      cd /etc/systemd/system
      nano node_exporter.service
      


      node_exporter.service 內(nèi)容如下:

      [Unit]
      Description=Node Exporter
      Documentation=https://prometheus.io/docs/guides/node-exporter/
      Wants=network-online.target
      After=network-online.target
      
      [Service]
      User=nobody
      Group=nogroup
      Type=simple
      # 啟動(dòng)Node Exporter,默認(rèn)監(jiān)聽(tīng)9100端口
      ExecStart=/usr/local/bin/node_exporter \
        --collector.systemd \
        --collector.processes \
        --collector.filesystem.ignored-mount-points="^/(sys|proc|dev|host|etc)($$|/)"
      
      [Install]
      WantedBy=multi-user.target
      

      配置開(kāi)機(jī)自啟動(dòng):

      sudo systemctl daemon-reload
      sudo systemctl start node_exporter 
      sudo systemctl enable node_exporter
      sudo systemctl status node_exporter
      

      修改 prometheus.yml 文件,加上:

        - job_name: mininode
          static_configs:
          - targets: ['192.168.50.199:9100']
      

      重啟 Prometheus 容器。

      部署 Grafana

      創(chuàng)建 /data/grafana/storage 目錄。

      mkdir /data/grafana/storage
      docker run -d -p 3000:3000 --name=grafana \
        --volume /data/grafana/storage:/var/lib/grafana \
        grafana/grafana:12.1.1
      

      瀏覽器打開(kāi) 3000 端口,默認(rèn)賬號(hào)密碼都是 admin,第一次進(jìn)入會(huì)提示修改密碼。


      需要在 Grafana 上配置數(shù)據(jù)源連接到 Prometheus。

      image-20250921101255411


      點(diǎn)擊右上角的 Add new data source,選擇 Prometheus。

      image-20250921101330375


      由于內(nèi)網(wǎng)部署沒(méi)有設(shè)置密碼,因此只需要填寫(xiě) Connection 地址即可。

      image-20250921101401064

      可視化配置

      前面已經(jīng)部署了 nodeexporter,用于監(jiān)控服務(wù)器資源,一般我們關(guān)注:

      CPU 使用率
      負(fù)載平均值
      內(nèi)存使用率
      磁盤 I/O
      磁盤使用率
      網(wǎng)絡(luò)接收量
      網(wǎng)絡(luò)傳輸量
      

      接入 Prometheus 數(shù)據(jù)源后,不同的數(shù)據(jù)源需要選擇合適的面板顯示數(shù)據(jù),例如這個(gè) node_exporter 模板:

      https://grafana.com/grafana/dashboards/1860-node-exporter-full/

      在模板介紹頁(yè)面,復(fù)制 ID 或下載 JSON:

      image-20250921110107076

      回到 Grafana 導(dǎo)入面板。

      cbd210b7-a9d2-42a1-accf-90ffc332076b

      image-20250921110456995


      導(dǎo)入成功后,可以看到節(jié)點(diǎn)的各項(xiàng)數(shù)據(jù)。

      image-20250921110516381

      mysql exporter

      用于觀測(cè) Mysql 數(shù)據(jù)庫(kù)的各種性能指標(biāo)。


      在 mysql 創(chuàng)建 exporter 用戶:

      CREATE USER 'exporter'@'%' IDENTIFIED BY '你的密碼' WITH MAX_USER_CONNECTIONS 3;
      
      # 授權(quán)
      GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'%';
      FLUSH PRIVILEGES;
      

      如果經(jīng)過(guò)授權(quán)后 mysql-exporter 不能正常工作,參考:

      -- 對(duì)于 MySQL 8.0.22 及以上版本
      GRANT PROCESS, REPLICATION CLIENT, REPLICATION SLAVE MONITOR, SELECT ON *.* TO 'exporter'@'%';
      
      -- 對(duì)于 MySQL 8.0.22 以下版本
      GRANT PROCESS, REPLICATION CLIENT, REPLICATION SLAVE ADMIN, SELECT ON *.* TO 'exporter'@'%';
      
      FLUSH PRIVILEGES;
      

      如果是 MariaDB :

      # MariaDB 10.5 及以上版本
      -- 授予 SLAVE MONITOR 權(quán)限(僅用于監(jiān)控從庫(kù)狀態(tài),權(quán)限更精細(xì))
      GRANT SLAVE MONITOR ON *.* TO 'exporter'@'%';
      
      # MariaDB 10.4 及以下版本
      GRANT SUPER ON *.* TO 'exporter'@'%';
      
      FLUSH PRIVILEGES;
      

      /data/exporter/mysql 創(chuàng)建 my.cnf 文件。

      [client]
      host=192.168.50.199
      port=3306
      user=exporter
      password=你的密碼
      

      啟動(dòng) docker:

      docker pull prom/mysqld-exporter
      
      docker run -itd --restart=always -p 9104:9104 \
      --name mysqld-exporter \
      --volume=/data/exporter/mysql/my.cnf:/etc/mysql/my.cnf:ro prom/mysqld-exporter \
      --config.my-cnf=/etc/mysql/my.cnf
      

      然后修改 prometheus.yml,增加內(nèi)容:

        - job_name: mysql
          static_configs:
          - targets: ['192.168.50.199:9104']
      

      最后我們使用官方的面板 https://grafana.com/grafana/dashboards/14057-mysql/

      image-20250921114907602

      mysql exporter 主要記錄了:

      Uptime
      Current QPS
      InnoDB Buffer Pool
      MySQL Connections
      MySQL Client Thread Activity
      MySQL Questions
      MySQL Thread Cache
      MySQL Temporary Objects
      MySQL Select Types
      MySQL Sorts
      MySQL Slow Queries
      MySQL Aborted Connections
      MySQL Table Locks
      MySQL Network Traffic
      MySQL Internal Memory Overview
      Top Command Counters
      MySQL Handlers
      MySQL Transaction Handlers
      Process States
      Top Process States Hourly
      MySQL Query Cache Memory
      MySQL Query Cache Activity
      MySQL File Openings
      MySQL Open Files
      MySQL Table Open Cache Status
      MySQL Open Tables
      MySQL Table Definition Cache
      

      其他

      官方有很多優(yōu)秀的監(jiān)控庫(kù):https://prometheus.io/docs/instrumenting/exporters/

      鏈路追蹤方案

      社區(qū)上鏈路追蹤使用廣泛的有 JaeGer、SkyWalking、Zipkin 等,它們各有優(yōu)缺點(diǎn),這里就不一一介紹了。

      鏈路追蹤主要是存儲(chǔ)器和 UI 兩部分,例如 Jaeger 支持內(nèi)存、Cassandra、ElasticSearch 等方式存儲(chǔ)接收到的數(shù)據(jù),然后通過(guò)操作界面查找、分析鏈路。


      隨著云原生的發(fā)展,很多組件其實(shí)都對(duì) Metrics、Logging、Tracing 有不同程度的支持,例如 ElasticSearch + Kibana 可以直接支持三者,無(wú)需另外部署 Prometheus、Grafana。

      而 Grafana 家有 Prometheus + Grafana 監(jiān)控、Grafana Loki 日志、Grafana Tempo 鏈路追蹤,而且也有很多商業(yè)一體化的平臺(tái)。


      所以要根據(jù)自身情況選用合適的方案。


      為了方便起見(jiàn),這里選用 Jaeger + ElasticSearch 的方式實(shí)現(xiàn)鏈路追蹤。


      Jaeger 原生支持接收 OpenTelemetry 協(xié)議格式的數(shù)據(jù),無(wú)需額外部署 OpenTelemetry Collector,所以這里不需要 OpenTelemetry 相關(guān)組件的部署。


      創(chuàng)建 /data/jaeger/jaeger.yml 文件:

      service:
        extensions: [jaeger_storage, jaeger_query]
        pipelines:
          traces:
            receivers: [otlp]
            processors: [batch]
            exporters: [jaeger_storage_exporter]
      
      extensions:
        jaeger_query:
          storage:
            traces: elasticsearch_trace_storage
            metrics: elasticsearch_trace_storage
        jaeger_storage:
          backends:
            elasticsearch_trace_storage: &elasticsearch_config
              elasticsearch:
                server_urls:
                  - http://192.168.50.199:9200
                username: elastic
                password: "your-password"
                # 索引配置
                index_prefix: jaeger
                # 索引生命周期管理
                use_ilm: true
                ilm:
                  policy_name: jaeger-ilm-policy
                  rollover_alias: jaeger-span
                  pattern: "{now/d}-000001"
                  max_age: 7d  # 數(shù)據(jù)保留7天
                # 批量寫(xiě)入配置
                bulk_size: 1000
                flush_interval: 5s
          metric_backends:
            elasticsearch_trace_storage: *elasticsearch_config
      
      receivers:
        otlp:
          protocols:
            grpc:
              endpoint: "0.0.0.0:4317"
            http:
              endpoint: "0.0.0.0:4318"
      
      processors:
        batch:
          timeout: 10s
          send_batch_size: 1024
      
      exporters:
        jaeger_storage_exporter:
          trace_storage: elasticsearch_trace_storage
      

      啟動(dòng) Jaeger:

      docker run -d \
        --name jaeger \
        -p 4317:4317 \
        -p 4318:4318 \
        -p 5775:5775/udp \
        -p 6831:6831/udp \
        -p 6832:6832/udp \
        -p 5778:5778 \
        -p 16686:16686 \
        -p 14268:14268 \
        -p 14250:14250 \
      -v /data/jaeger/jaeger.yml:/etc/jaeger/jaeger.yml \
        jaegertracing/all-in-one:latest \
        --config-file=/etc/jaeger/jaeger.yml
      


      以下是 Jaeger 各組件常用端口及其作用的詳細(xì)說(shuō)明:

      端口號(hào) 協(xié)議 組件 / 用途 具體作用說(shuō)明
      5775 UDP Agent (Zipkin) 接收 Zipkin 兼容的 thrift 協(xié)議數(shù)據(jù)(較少使用)
      6831 UDP Agent (Jaeger Thrift) 接收 Jaeger 原生客戶端通過(guò) compact 編碼格式發(fā)送的追蹤數(shù)據(jù)
      6832 UDP Agent (Jaeger Thrift) 接收 Jaeger 原生客戶端通過(guò) binary 編碼格式發(fā)送的追蹤數(shù)據(jù)
      5778 TCP Agent/Health Check 提供 Agent 的配置接口和健康檢查端點(diǎn)(可獲取采樣策略等)
      16686 TCP Query Service (UI) Jaeger Web UI 訪問(wèn)端口,通過(guò)瀏覽器訪問(wèn)查看追蹤數(shù)據(jù)
      14268 TCP Collector (Jaeger Thrift) 接收 Jaeger 原生客戶端直接發(fā)送的追蹤數(shù)據(jù)(不經(jīng)過(guò) Agent 時(shí)使用)
      14250 TCP Collector (gRPC) 接收通過(guò) gRPC 協(xié)議發(fā)送的 Jaeger 格式數(shù)據(jù)
      4317 TCP Collector (OTLP gRPC) 接收 OpenTelemetry 客戶端通過(guò) gRPC 協(xié)議發(fā)送的追蹤數(shù)據(jù)(OTLP 標(biāo)準(zhǔn)端口)
      4318 TCP Collector (OTLP HTTP) 接收 OpenTelemetry 客戶端通過(guò) HTTP 協(xié)議發(fā)送的追蹤數(shù)據(jù)(OTLP 標(biāo)準(zhǔn)端口)
      9411 TCP Collector (Zipkin) 兼容 Zipkin 協(xié)議的接收端口,用于接收 Zipkin 客戶端發(fā)送的數(shù)據(jù)(可選啟用)

      訪問(wèn) 16686 端口即可訪問(wèn) UI。

      image-20250921162554273


      如果有需要,你可以啟動(dòng)一個(gè)任務(wù),將超過(guò)一段時(shí)間的鏈路追蹤數(shù)據(jù)移到其它索引中。

      docker run -it --rm --net=host \
        -e CONDITIONS='{"max_age": "2d"}' \
        -e ES_USERNAME=elastic \
        -e ES_PASSWORD=你的密碼 \
        jaegertracing/jaeger-es-rollover:latest \
        rollover  http://localhost:9200
      

      如果有需要,你可以啟動(dòng)一個(gè)任務(wù),將時(shí)間太長(zhǎng)的數(shù)據(jù)刪除。

      docker run -it --rm --net=host \
        -e UNIT=days -e UNIT_COUNT=7 \
        -e ES_USERNAME=elastic \
        -e ES_PASSWORD=你的密碼 \
        jaegertracing/jaeger-es-rollover:latest \
        lookback http://localhost:9200
      

      接入 OpenTelemetry

      隨著 OpenTelemetry 的發(fā)展,對(duì) Metrics、Logging、 做了完整的支持,通過(guò) Opentelemetry Collector 統(tǒng)一收集再將其轉(zhuǎn)發(fā)到不同的后端,Collector 本身是不存儲(chǔ)數(shù)據(jù)的,它是一個(gè)收集器。

      不過(guò)實(shí)踐中主要還是作為鏈路追蹤和監(jiān)控的收集器來(lái)使用,很少當(dāng)作 Logging 收集器。


      Opentelemetry 暴露的端口如下:

        ports:
          - 1888:1888 # pprof extension
          - 8888:8888 # Prometheus metrics exposed by the Collector
          - 8889:8889 # Prometheus exporter metrics
          - 13133:13133 # health_check extension
          - 4317:4317 # OTLP gRPC receiver
          - 4318:4318 # OTLP http receiver
          - 55679:55679 # zpages extension
      

      Opentelemetry Collector 在端口還暴露了對(duì)應(yīng)的地址,用來(lái)收集不同的內(nèi)容,例如 /v1/traces 收集鏈路追蹤 /v1/metrics 收集監(jiān)控。


      參考 C# 代碼:

      builder.Services.AddOpenTelemetry()
      	  .ConfigureResource(resource => resource.AddService(serviceName))
      	  .WithTracing(tracing =>
      	  {
      		  .AddAspNetCoreInstrumentation()
      		  .AddOtlpExporter(options =>
      		  {
      			  options.Endpoint = new Uri("http://192.168.50.199:4318" + "/v1/traces");
      			  options.Protocol = OtlpExportProtocol.HttpProtobuf;
      		  });
      	  })
      	  .WithMetrics(metrices =>
      	  {
      		  metrices.AddAspNetCoreInstrumentation()
      		  .AddOtlpExporter(options =>
      		  {
      			  options.Endpoint = new Uri("http://192.168.50.199:4318" + "/v1/metrics");
      			  options.Protocol = OtlpExportProtocol.HttpProtobuf;
      		  });
      	  });
      

      這里我們使用 OpenTelemetry Collector 做統(tǒng)一接入層,接入鏈路追蹤和監(jiān)控,主要目標(biāo)是面向后端服務(wù),也就是后端服務(wù)統(tǒng)一接入 OpenTelemetry Collector 推送內(nèi)容。OpenTelemetry Collector 再將鏈路追蹤和監(jiān)控?cái)?shù)據(jù)推送到 Jaeger 和 Prometheus。


      拉取 OpenTelemetry Collector 鏡像。

      docker pull otel/opentelemetry-collector-contrib:0.135.0
      

      Prometheus 默認(rèn)不開(kāi)啟寫(xiě)如果功能,需要加上 --web.enable-remote-write-receiver 環(huán)境變量開(kāi)啟寫(xiě)入,還支持使用 --web.enable-otlp-receiver 開(kāi)啟 /api/v1/otlp/v1/metrics OTLP 接收 監(jiān)控?cái)?shù)據(jù)。

      不過(guò)官網(wǎng)提示這兩種方式都不是高效的,但是阿里云官方相關(guān)的產(chǎn)品用的是 --web.enable-remote-write-receiver

      參考:https://help.aliyun.com/zh/prometheus/use-cases/write-metrics-to-managed-service-for-prometheus-based-on-opentelemetry-collector


      有兩種方法接收 Opentelemetry Collector 的 metrics,一種是刪除 Prometheus 容器,使用新的命令啟動(dòng):

      docker run    -itd --restart=always  -p 9090:9090         \
      -v /data/prometheus/config/prometheus.yml:/etc/prometheus/prometheus.yml     \
      -v /data/prometheus/data:/prometheus     \
      prom/prometheus --web.enable-remote-write-receiver
      

      另一種是推送到 pushgateway,然后 prometheus 采集 pushgateway 即可,下面采用這種方法。


      新建 /data/opentelemetry/config.yaml 配置文件:

      receivers:
        # 僅保留 OTLP 接收器(接收應(yīng)用推送的 OTLP 格式數(shù)據(jù))
        otlp:
          protocols:
            grpc:
              endpoint: "0.0.0.0:4317"  # 接收 OTLP gRPC 協(xié)議數(shù)據(jù)
            http:
              endpoint: "0.0.0.0:4318"  # 接收 OTLP HTTP 協(xié)議數(shù)據(jù)
      
      processors:
        # 批量處理(減少網(wǎng)絡(luò)請(qǐng)求次數(shù),提高效率)
        batch:
          timeout: 10s
          send_batch_size: 1024
        
        # 資源屬性增強(qiáng)(添加環(huán)境、集群等標(biāo)簽)
        resource:
          attributes:
            - key: "env"
              value: "production"
              action: upsert
            - key: "cluster"
              value: "k8s-cluster-01"
              action: upsert
      
      exporters:
        # 導(dǎo)出追蹤數(shù)據(jù)到 Jaeger(通過(guò) OTLP HTTP 協(xié)議)
        otlphttp/jaeger:
          endpoint: "http://192.168.50.199:4318"
          tls:
            insecure: true
        
        # 導(dǎo)出指標(biāo)數(shù)據(jù)到 Prometheus(通過(guò) remote_write 協(xié)議)
        prometheusremotewrite:
          endpoint: "http://192.168.50.199:9090/api/v1/write"
          tls:
            insecure: true
          headers:
            X-Prometheus-Remote-Write-Version: "0.1.0"
      
        # 可選:在本地暴露 Prometheus 格式指標(biāo)(供調(diào)試或臨時(shí)抓取)
        prometheus:
          endpoint: "0.0.0.0:8889"
          const_labels:
            source: "otel-collector"
      
      service:
        telemetry:
          logs:
            level: debug  # 調(diào)試日志級(jí)別,生產(chǎn)環(huán)境可改為 info
        pipelines:
          # 追蹤數(shù)據(jù)處理管道
          traces:
            receivers: [otlp]  # 僅接收 OTLP 追蹤數(shù)據(jù)
            processors: [batch, resource]  # 批量處理 + 資源增強(qiáng)
            exporters: [otlphttp/jaeger]  # 導(dǎo)出到 Jaeger
          
          # 指標(biāo)數(shù)據(jù)處理管道
          metrics:
            receivers: [otlp]  # 僅接收 OTLP 指標(biāo)數(shù)據(jù)
            processors: [batch, resource]  # 批量處理 + 資源增強(qiáng)
            exporters: [prometheusremotewrite, prometheus]  # 導(dǎo)出到 Prometheus 及本地端點(diǎn)
      
      

      如果,你想使用 Collocter 幫你抓取,而不是使用 Prometheus 抓取,可以添加 prometheus 配置,參考:

      receivers:
        # 僅保留 OTLP 接收器(接收應(yīng)用推送的 OTLP 格式數(shù)據(jù))
        otlp:
          protocols:
            grpc:
              endpoint: "0.0.0.0:4317"  # 接收 OTLP gRPC 協(xié)議數(shù)據(jù)
            http:
              endpoint: "0.0.0.0:4318"  # 接收 OTLP HTTP 協(xié)議數(shù)據(jù)
      
        prometheus:
          config:
            scrape_configs:
              - job_name: "otel-collector-self"
                scrape_interval: 10s
                static_configs:
                  - targets: ["localhost:8888"]
              - job_name: "your-app"
                scrape_interval: 15s
                static_configs:
                  - targets: ["app-service:8080"]
        
        # 修正:prometheusremotewrite接收器只需要配置端口,不需要路徑
        prometheusremotewrite:
          endpoint: "0.0.0.0:9090"  # 移除了/api/v1/write路徑
      ... 省略 ...  
      

      http://192.168.50.199:9091/api/v1/write 是 pushgateway 的地址。


      啟動(dòng) opentelemetry-collector-contrib:

      docker run -itd \
      --name=otelcol \
      --restart=always \
      -p 1888:1888 \
      -p 8888:8888 \
      -p 8889:8889 \
      -p 13133:13133 \
      -p 4317:4317 \
      -p 4318:4318 \
      -p 55679:55679 \
      -v /data/opentelemetry/config.yaml:/etc/otelcol-contrib/config.yaml \
      otel/opentelemetry-collector-contrib:0.135.0
      

      由于 Opentelemetry Collector 跟 Jaeger 有端口沖突,因此讀者需要修改映射的 4317 、4318 端口。

      image-20250922151324497

      Grafana 全家桶

      本節(jié)探索 Grafana Prometheus、Grafana Loki、Grafana Tempo 全家桶方案。

      Metrics 方案

      在上一節(jié),監(jiān)控?cái)?shù)據(jù)通過(guò) Opentelemetry Collector 推送到 Prometheus,這是比較推薦的做法。

      當(dāng)然 Prometheus 也可以直接提供兼容 Collector 接口的功能,要兼容 OpenTelemetry 的 /v1/metrics 接口,需要在 Prometheus 上使用 --web.enable-otlp-receiver 開(kāi)啟 /api/v1/otlp/v1/metrics OTLP 接收 監(jiān)控?cái)?shù)據(jù)。


      docker run    -itd --restart=always  -p 9090:9090         \
      -v /data/prometheus/config/prometheus.yml:/prometheus/prometheus.yml     \
      -v /data/prometheus/data:/prometheus     \
      prom/prometheus \
      --web.enable-remote-write-receiver \
      --web.enable-otlp-receiver
      

      C# 代碼參考:https://opentelemetry.io/docs/languages/dotnet/metrics/getting-started-prometheus-grafana/

      image-20250922155015140

      image-20250922155050486


      不過(guò)還是建議先走 Opentelemetry Collector,由 Collector 走轉(zhuǎn)發(fā)。

      應(yīng)用程序只需要統(tǒng)一接口 Collector,具體的后端由運(yùn)維靈活處理,后期萬(wàn)一某個(gè)方案不滿足增長(zhǎng)需求,只需要替換 Collector 配置即可,后端服務(wù)無(wú)需修改代碼和配置。

      Logging 方案

      Loki 支持在 Kubernetes 上水平伸縮,不過(guò)由于筆者是家庭服務(wù)器,因此單機(jī) docker 部署即可滿足需求,單機(jī)架構(gòu)適合每天 20GB 左右的少量日志讀寫(xiě)。

      Loki 日志的資源使用量主要取決于攝入的日志量,根據(jù)官方文檔的說(shuō)法,每秒攝入 1 MiB 日志,預(yù)計(jì)會(huì)使用大約

      • 1 CPU 核心
      • 120 MiB 內(nèi)存

      Grafana 有 Alloy 可以支持對(duì)宿主機(jī)、容器、Kubernetes 集群采集日志,不過(guò)由于習(xí)慣上,我們繼續(xù)使用原本的 Filebeat、Kafka 日志采集方案。

      筆者提示,Loki 方案不太成熟,吞吐量沒(méi)有 ElasticSearch 大,Grafana Alloy 推送的量一大 Loki 就返回 429。


      創(chuàng)建 /data/loki/config 、``/data/loki/data目錄,在 /data/loki/config` 目錄下執(zhí)行命令下載配置文件。

      wget https://raw.githubusercontent.com/grafana/loki/v3.4.1/cmd/loki/loki-local-config.yaml -O loki-config.yaml
      

      配置文件規(guī)定了使用 TSDB:

      schema_config:
        configs:
          - from: 2020-10-24
            store: tsdb
            object_store: filesystem
      
      

      修改 config.yaml 文件,配置 TSDB 存儲(chǔ)目錄映射到宿主機(jī),以便實(shí)現(xiàn)持久化:

      auth_enabled: false
      
      server:
        http_listen_port: 3100
        grpc_listen_port: 9096
        log_level: debug
        grpc_server_max_concurrent_streams: 1000
        
      common:
        instance_addr: 192.168.50.199
        path_prefix: /var/lib/loki  # 更改為非臨時(shí)目錄
        storage:
          filesystem:
            chunks_directory: /var/lib/loki/chunks
            rules_directory: /var/lib/loki/rules
        replication_factor: 1
        # 單機(jī)部署,集群部署需要使用 consul
        ring:
          kvstore:
            store: inmemory
            
      query_range:
        results_cache:
          cache:
            embedded_cache:
              enabled: true
              max_size_mb: 100
      
      limits_config:
        metric_aggregation_enabled: true
      
      schema_config:
        configs:
          - from: 2020-10-24
            store: tsdb
            object_store: filesystem
            schema: v13
            index:
              prefix: index_
              period: 24h
      
      pattern_ingester:
        enabled: true
        metric_aggregation:
          loki_address: 192.168.50.199:3100
      
      ruler:
        alertmanager_url: http://192.168.50.199:9093
      
      frontend:
        encoding: protobuf
      

      啟動(dòng) Loki 服務(wù):

      docker run --name loki -itd --restart=always \
      -v /data/loki/config:/mnt/config \
      -v /data/loki/data:/var/lib/loki \
      -p 3100:3100 \
      -p 9096:9096 \
      grafana/loki:3.4.1 \
      -config.file=/mnt/config/loki-config.yaml
      

      部署 loki 后,還需要做兩個(gè)事情,一個(gè)是使用 Prometheus 監(jiān)控 Loki 的 http://:3100/metrics 地址,一個(gè)是使用 Alloy 消費(fèi) Kafka 日志推送到 Loki。


      修改 prometheus.yml 文件,添加配置并重啟 Prometheus 容器。

        - job_name: loki
          static_configs:
          - targets: ['192.168.50.199:3100']
      

      image-20250922163142088


      要將 logstash 的數(shù)據(jù)推送到 Loki,需要安裝插件, Loki 官方不推薦這樣用,官方推送使用 Grafana Alloy ,或者接入 OpenTelepmetry。


      由于 Logstash 推送到 Loki 的配置比較麻煩,因此這里就不使用 了。

      讀者可參考:https://grafana.org.cn/docs/loki/latest/send-data/logstash/


      Grafana Alloy 是官方主推的日志采集方案組件,功能類似 Filebeat、Logstash。

      Alloy flow diagram

      圖片來(lái)自 Grafana 官網(wǎng)文檔。

      Alloy 流水線由執(zhí)行特定功能的組件構(gòu)建而成,對(duì)于日志,這些組件可以分為三類:

      • 采集器: 這些組件從各種源采集/接收日志。這包括從文件抓取日志、通過(guò) HTTP、gRPC 接收日志或從消息隊(duì)列采集日志。
      • 轉(zhuǎn)換器: 這些組件用于在日志發(fā)送到寫(xiě)入器之前對(duì)其進(jìn)行處理。例如,可以添加額外元數(shù)據(jù)、過(guò)濾日志或在發(fā)送前批量處理日志。
      • 寫(xiě)入器: 這些組件將日志發(fā)送到目標(biāo)目的地。重點(diǎn)介紹如何將日志發(fā)送到 Loki,但 Alloy 支持將日志發(fā)送到各種目的地。

      Alloy 可以采集 Filebeat 推送到 Kafak 的日志,然后處理再推送到 Loki,或者 Alloy 直接采集 Docker 和 主機(jī)的日志,但是既然已經(jīng)有 Filebeat 了,我們就不折騰采集這一步了,而是使用 Alloy 替換 Logstash 這一步。


      Grafana Loki

      部署 Loki 之后,需要在 Grafana 里面顯示 Loki,添加數(shù)據(jù)源。

      image-20250922164826233


      然后使用 13186 模板顯示 Loki 日志: https://grafana.com/grafana/dashboards/13186-loki-dashboard/

      image-20250922165242253


      Filebeat + Kafka + Alloy

      創(chuàng)建 /data/alloy/data 目錄,在 /data/alloy/config 目錄下創(chuàng)建 config.alloy 文件:

      loki.source.kafka "local" {
        brokers                = ["192.168.50.199:9092"]
        topics                 = ["docker-logs"]
        labels                 = {component = "loki.source.kafka"}
        forward_to             = [loki.process.add_labels.receiver]
        use_incoming_timestamp = true
        relabel_rules          = loki.relabel.kafka.rules
      }
      
      loki.process "add_labels" {
        // 解析 JSON 消息內(nèi)容,提取 container.name、host.name 等字段
        stage.json {
          expressions = {
            container_name = "container.name",
            host_name      = "host.name",
            image_name     = "container.image.name",
          }
        }
        // 將提取的字段作為標(biāo)簽
        stage.labels {
          values = {
            container = "container_name",
            host      = "host_name",
            image     = "image_name",
          }
        }
        forward_to = [loki.write.local.receiver]
      }
      
      loki.relabel "kafka" {
        forward_to = [loki.write.local.receiver]
        rule {
          source_labels = ["__meta_kafka_topic"]
          target_label  = "topic"
        }
      }
      
      loki.write "local" {
        endpoint {
          url = "http://192.168.50.199:3100/loki/api/v1/push"
        }
      }
      

      啟動(dòng) alloy:

      docker run -itd --restart=always \
        -v /data/alloy/config/config.alloy:/etc/alloy/config.alloy \
        -v /data/alloy/data:/var/lib/alloy/data \
        -p 12345:12345 \
        grafana/alloy:latest \
          run --server.http.listen-addr=0.0.0.0:12345 --storage.path=/var/lib/alloy/data \
          /etc/alloy/config.alloy
      


      重啟 Loki,會(huì)發(fā)現(xiàn) Kafka 多了一個(gè)消費(fèi)者:

      image-20250922173753457


      在 Grafana 下的 Drilldown/Logs 可以看到被收集的日志。

      image-20250925144909987


      Alloy 的資料太少了,要定制化比較困難,例如從 Kafka 的 docker-logs 主題消費(fèi)后,需要給消息打標(biāo)簽,以便可以篩選對(duì)應(yīng)的容器日志,筆者陸陸續(xù)續(xù)搞了兩天,使用了元寶、豆包和 Grafana 自己的 Grot AI 都不行,最后根據(jù)文檔重新?lián)Q了個(gè)辦法才行。生產(chǎn)級(jí)別的使用需求會(huì)比較復(fù)雜,使用 Alloy 折騰配置需要消耗非常多的時(shí)間,而且 Loki 的吞吐量似乎沒(méi)有 ElasticSearch 高,資料也少,還是建議采用 ElasticSearch 存儲(chǔ)方案。


      Loki 吞吐量似乎不高,Alloy 消費(fèi)推送帶 Loki ,量大了會(huì)被拒絕。

      image-20250925144551120


      所以筆者并不建議使用 Loki 做日志存儲(chǔ)后端,省得折騰。

      Tracing 方案

      Tempo 挺值得用,可以輕松應(yīng)對(duì)中小公司的數(shù)據(jù)量,搭配 Grafana 的 UI,用起來(lái)挺方便。

      How does Tempo work?

      Tempo 主要使用 OSS 存儲(chǔ)數(shù)據(jù),利用 memcached 的加快 trace id 篩選和查詢的速度,但是感覺(jué)數(shù)據(jù)量非常大之后,OSS 查詢比較吃力,查詢會(huì)緩慢,可能需要維護(hù)者調(diào)整各類壓縮配置等。

      Tempo 的配置項(xiàng)非常多,對(duì)壓縮、存儲(chǔ)、搜索等涉及的配置非常多,維護(hù)者要注意不同事情的數(shù)據(jù)和數(shù)據(jù)量如何合理配置。


      拉取 Tempo 倉(cāng)庫(kù):

      git clone https://github.com/grafana/tempo.git
      

      這里只使用到官方的 tempo.yaml 文件,如拉取倉(cāng)庫(kù)可能,只需要下載 https://github.com/grafana/tempo/blob/main/example/docker-compose/local/tempo.yaml


      創(chuàng)建 /data/tempo/data 目錄,在 /data/tempo/ 下創(chuàng)建 docker-compose.yaml 文件。

      services:
        init:
          image: &tempoImage grafana/tempo:latest
          user: root
          entrypoint:
            - "chown"
            - "10001:10001"
            - "/var/tempo"
          volumes:
            - /data/tempo/data:/var/tempo
      
        memcached:
          image: memcached:1.6.38
          container_name: memcached
          ports:
            - "11211:11211"
          environment:
            - MEMCACHED_MAX_MEMORY=64m  # Set the maximum memory usage
            - MEMCACHED_THREADS=4       # Number of threads to use
      
        tempo:
          image: *tempoImage
          command: [ "-config.file=/etc/tempo.yaml" ]
          volumes:
            - /data/tempo/tempo.yaml:/etc/tempo.yaml
            - /data/tempo/data:/var/tempo
          ports:
            - "14268:14268"  # jaeger ingest
            - "3200:3200"   # tempo
            - "9095:9095" # tempo grpc
            - "4317:4317"  # otlp grpc
            - "4318:4318"  # otlp http
            - "9411:9411"   # zipkin
          depends_on:
            - init
            - memcached
      
        k6-tracing:
          image: ghcr.io/grafana/xk6-client-tracing:v0.0.7
          environment:
            - ENDPOINT=tempo:4317
          restart: always
          depends_on:
            - tempo
      
      

      k6-tracing 是模擬產(chǎn)生鏈路追蹤信息的程序,可以去掉。

      Memcached 緩存主要用于通過(guò)存儲(chǔ)所有后端塊的布隆過(guò)濾器(在每次查詢時(shí)訪問(wèn))來(lái)提升查詢性能。

      由于 tempo 服務(wù)啟動(dòng)的端口跟 jaeger、Opentelemetry Collector 沖突,所以需要先把這兩個(gè)停掉。


      修改 tempo.yaml 文件,復(fù)制到 /data/tempo/tempo.yaml,替換 Prometheus 地址:

      如果從 git 倉(cāng)庫(kù)找,位置在 example/docker-compose/local/tempo.yaml

        storage:
          path: /var/tempo/generator/wal
          remote_write:
            - url: http://192.168.50.199:9090/api/v1/write
              send_exemplars: true
      

      執(zhí)行 docker-compose up -d 部署,然后在 Grafana 添加 Tempo 數(shù)據(jù)源,在 Drilldown/Traces 可以看到一些數(shù)據(jù),但是主要使用 Explore 菜單檢索和分析鏈路。

      image-20250925155402587


      在各種鏈路追蹤 UI 里面,感覺(jué) Tempo 的 UI 非常舒服。

      image-20250925161629510

      image-20250925162229703


      默認(rèn) Tempo 使用的是本地 TSDB 存儲(chǔ),不支持分布式存儲(chǔ),所以對(duì)于業(yè)務(wù)量大的公司,使用 OSS 存儲(chǔ)。

      不過(guò) TSDB 確實(shí)性能強(qiáng)。


      另外考慮到,公司業(yè)務(wù)比較大時(shí),鏈路追蹤數(shù)據(jù)量增長(zhǎng)速度快,需要將太長(zhǎng)時(shí)間之前鏈路數(shù)據(jù)移動(dòng)到其它地方。


      修改 tempo.yaml 文件,找到以下內(nèi)容:

      storage:
        trace:
          backend: local                     # backend configuration to use
          wal:
            path: /var/tempo/wal             # where to store the wal locally
          local:
            path: /var/tempo/blocks
      

      修改為:

      storage:
        trace:
          backend: s3
          s3:
            endpoint: 192.168.50.199:9000         # 例如 s3.us-east-1.amazonaws.com 或 MinIO 的地址
            bucket: tempo           # S3 存儲(chǔ)桶名稱
            access_key: <ACCESS_KEY>        # S3 Access Key
            secret_key: <SECRET_KEY>        # S3 Secret Key
            region: <REGION>                # 區(qū)域(可選,部分 S3 兼容存儲(chǔ)需要)
            insecure: true                  # 如果使用 http 協(xié)議,需設(shè)置為 true
            forcepathstyle: true            # 對(duì)于 MinIO 等 S3 兼容存儲(chǔ)建議開(kāi)啟
      

      筆者使用的是 MinIO,相對(duì)比較簡(jiǎn)單,另外阿里云、騰訊云等云服務(wù)商的對(duì)象存儲(chǔ)都支持 S3 協(xié)議。

      image-20250925170559266


      不過(guò) Tempo 本身沒(méi)有自動(dòng)數(shù)據(jù)過(guò)期或清理機(jī)制,所以需要依賴 OSS 本身的對(duì)象過(guò)期機(jī)制,例如 MinIO 可以使用 mc 工具每天處理過(guò)期的對(duì)象,移動(dòng)到低頻存儲(chǔ)或刪除。

      參考:https://min-io.cn/docs/minio/linux/administration/object-management/create-lifecycle-management-expiration-rule.html


      至于 SkyWalking + ElasticSearch 之類的方案,這里就不再講解,讀者可以自行嘗試。

      低成本的 ClickStack 可觀察性平臺(tái)

      本節(jié)介紹基于 Clickhouse 家的產(chǎn)品 ClickStack 建設(shè)低成本的課觀測(cè)性平臺(tái)。

      ClickStack 是一個(gè)基于 ClickHouse 和 OpenTelemetry (OTel) 的生產(chǎn)級(jí)可觀測(cè)性平臺(tái),統(tǒng)一了日志、跟蹤、指標(biāo)和會(huì)話,提供單一高性能解決方案。旨在監(jiān)控和調(diào)試復(fù)雜系統(tǒng),ClickStack 使開(kāi)發(fā)者和 SRE 能夠端到端地追蹤問(wèn)題,無(wú)需在工具之間切換或手動(dòng)使用時(shí)間戳或關(guān)聯(lián) ID 拼湊數(shù)據(jù)。

      介紹來(lái)自官網(wǎng):https://clickhouse.com/docs/zh/use-cases/observability/clickstack/overview


      Landing page

      圖片來(lái)自 ClickStack 官網(wǎng)文檔。


      ClickStack 由三個(gè)核心組件組成:

      1. HyperDX UI – 專為探索和可視化可觀察性數(shù)據(jù)而設(shè)計(jì)的前端
      2. OpenTelemetry collector – 一個(gè)定制構(gòu)建的、預(yù)配置的收集器,具有針對(duì)日志、跟蹤和指標(biāo)的立場(chǎng)導(dǎo)向架構(gòu)
      3. ClickHouse – 堆棧核心的高性能分析數(shù)據(jù)庫(kù)

      這些組件可以獨(dú)立或一起部署,官方都提供了鏡像,部署起來(lái)比較簡(jiǎn)單。


      為了方便起見(jiàn),筆者這里使用 All-in-One 的方式部署,單個(gè) Docker 容器部署所有組件,但是生產(chǎn)需要容錯(cuò)、分布式部署時(shí)建議根據(jù)官方的文檔部署。如果規(guī)模小、要求不高,All-in-One 是個(gè)不錯(cuò)的選擇,一個(gè)容器支撐三大組件,不需要那么多中間件服務(wù)。

      官方文檔地址:https://clickhouse.com/docs/zh/use-cases/observability/clickstack/deployment

      名稱 描述 適用對(duì)象 限制
      All-in-One 單個(gè) Docker 容器,捆綁了所有 ClickStack 組件。 演示、局部全棧測(cè)試 不推薦用于生產(chǎn)
      Helm 官方的 Helm 圖表,用于基于 Kubernetes 的部署。支持 ClickHouse Cloud 和生產(chǎn)擴(kuò)展。 Kubernetes 上的生產(chǎn)部署 需要 Kubernetes 知識(shí),需通過(guò) Helm 進(jìn)行自定義
      Docker Compose 通過(guò) Docker Compose 單獨(dú)部署每個(gè) ClickStack 組件。 本地測(cè)試、概念驗(yàn)證、在單個(gè)服務(wù)器上的生產(chǎn)、自管理 ClickHouse 無(wú)容錯(cuò)能力,需要管理多個(gè)容器
      HyperDX Only 獨(dú)立使用 HyperDX,并使用您自己的 ClickHouse 和架構(gòu)。 現(xiàn)有 ClickHouse 用戶、自定義事件管道 不包括 ClickHouse,用戶必須管理數(shù)據(jù)攝取和架構(gòu)
      Local Mode Only 完全在瀏覽器中運(yùn)行,使用本地存儲(chǔ)。沒(méi)有后端或持久性。 演示、調(diào)試、與 HyperDX 的開(kāi)發(fā) 無(wú)身份驗(yàn)證,無(wú)持久性,無(wú)警報(bào),僅限單用戶

      部署 ClickStack

      新建目錄:

      mkdir /data/clickstack
      mkdir /data/clickstack/db
      mkdir /data/clickstack/ch_data
      mkdir /data/clickstack/ch_logs
      
      chmod -R 777 /data/clickstack/*
      

      部署服務(wù):

      docker run -itd --restart=always \
        -p 8080:8080 \
        -p 4317:4317 \
        -p 4318:4318 \
        -e FRONTEND_URL="http://192.168.50.199:8080" \
        -v "/data/clickstack/db:/data/db" \
        -v "/data/clickstack/ch_data:/var/lib/clickhouse" \
        -v "/data/clickstack/ch_logs:/var/log/clickhouse-server" \
        docker.hyperdx.io/hyperdx/hyperdx-all-in-one
      

      國(guó)內(nèi)用戶有配置鏡像加速器,可去掉鏡像的 docker.hyperdx.io/ 前綴。


      部署選項(xiàng) | ClickHouse Docs

      打開(kāi) 8080 端口,訪問(wèn) HyperDX UI。

      cc4bcc7f-9a57-4c1f-b8ee-c4ffadde93f6

      9b71d24c-7830-4051-bedf-eb9553251e5e


      打開(kāi) Team Settings 配置,復(fù)制 API Key,對(duì)接 OpenTelemetry 協(xié)議推送數(shù)據(jù)時(shí)需要使用。

      2c85a24e-5aa1-408e-a98c-264d17e103b6


      為了觀察 ClickStack 的使用,你可以寫(xiě)程序推送數(shù)據(jù),也可以使用官方的模擬數(shù)據(jù)。

      官方模擬數(shù)據(jù)教程:https://clickhouse.com/docs/zh/use-cases/observability/clickstack/getting-started/sample-data#load-sample-data


      f342e5d8-195e-4133-b23d-3eb963c992b6


      ClickStack 默認(rèn)已經(jīng)配置好了各種數(shù)據(jù)源。

      image-20250928164136325


      如果需要查看只需要數(shù)據(jù)源,需要在左側(cè)菜單 Search 操作。

      1c8eb913-11f8-41e8-9d39-6fb4cb478448

      搜索 Traces

      以 Traces 為例,默認(rèn) ClickStack 按照 span 來(lái)顯示,你可以點(diǎn)擊到具體的 span 后,搜索對(duì)應(yīng)的 TraceId 或者使用 TraceId = 'ea32fc1170b28d49f40b897b4624b6f4' 這樣的條件查找。

      image-20250928162956200

      image-20250928163128290


      動(dòng)圖演示:

      clickstack_find_traceid

      搜索 Logs

      ClickStack 的日志有個(gè)好用的功能,就是可以自動(dòng)聚合上下文,例如如圖,這條日志有對(duì)應(yīng)的 TraceId ,Surrounding Context 就是相同的 TraceId 中按時(shí)間順序發(fā)生的日志列表。

      image-20250928163722171

      查看 Metrics

      ClickStack 的圖表沒(méi)有 Grafana 看起來(lái)舒服,界面比較原始。

      image-20250928164810164


      比如筆者的 demo 程序有個(gè) orders.created 訂單創(chuàng)建計(jì)數(shù)器,每下一個(gè)訂單,計(jì)算器 +1

      4fdee1d1-d204-44d0-b8b9-24eed311dccc


      你可以新增面板,在里面添加需要顯示的圖表。

      不過(guò)功能沒(méi)有 Grafana 強(qiáng)大,并且沒(méi)有社區(qū)模板,需要自行一點(diǎn)點(diǎn)配置。

      e9b77fee-0b16-4660-b869-77b78fe5a2c8

      其它

      ClickStack 有個(gè)非常好用的功能叫回話回放,可以記錄用戶在頁(yè)面進(jìn)行的操作。

      9aa4feb6-b58f-442d-8ed3-c2192b8f5c4d

      1de0452f-0e04-4c00-b4e7-fd116660bf6a

      posted @ 2025-09-29 08:53  癡者工良  閱讀(214)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 午夜成年男人免费网站| 久久亚洲国产精品久久| 色悠久久网国产精品99| 九九热精品视频免费在线| 无码人妻精品一区二区三区夜夜嗨| 少妇办公室好紧好爽再浪一点| 人人综合亚洲无线码另类| 无码一区中文字幕| 国产成人无码免费视频在线| 亚洲综合伊人久久大杳蕉| 人妻饥渴偷公乱中文字幕| 在线a亚洲v天堂网2018| 国产va免费精品观看| 中文熟妇人妻av在线| 美女裸体十八禁免费网站| 农村妇女野外一区二区视频| 国产欧美日韩亚洲一区二区三区| 日韩有码中文字幕国产| 极品少妇无套内射视频| bt天堂新版中文在线| 18岁日韩内射颜射午夜久久成人| 亚洲av激情一区二区三区| 精品无码中文视频在线观看| 国产精品播放一区二区三区| 男女爽爽无遮挡午夜视频| 午夜DY888国产精品影院| 日韩高清免费一码二码三码| 欧美国产精品啪啪| 韩国精品一区二区三区在线观看| 亚洲人成色77777| 欧美熟妇乱子伦XX视频| 中文字幕日韩国产精品| 国产精品99一区二区三区| 国产欧美另类精品久久久 | 成人午夜在线观看日韩| 成人麻豆日韩在无码视频 | 日韩一本不卡一区二区三区| 日本夜爽爽一区二区三区| 精品国产片一区二区三区| 阿合奇县| 国产成人一区二区不卡|