当前位置: 首页 > wzjs >正文

佛山制作网站公司吗seo是什么意思 seo是什么职位

佛山制作网站公司吗,seo是什么意思 seo是什么职位,设计网站广告语,gif网站banner怎么做APM-基于Grafana生态以及OTLP协议的Java轻量级日志监控系统 读写分离模式部署 初始化文件夹和一些配置文件 初始化文件夹 # minio存储 mkdir -p /data/apm/minio # java日志存储 mkdir -p /opt/app创建nginx相关配置文件 nginx.conf vim /data/apm/nginx/nginx.confuser …

APM-基于Grafana生态以及OTLP协议的Java轻量级日志监控系统

读写分离模式部署

初始化文件夹和一些配置文件

初始化文件夹
# minio存储
mkdir -p /data/apm/minio
# java日志存储
mkdir -p /opt/app
创建nginx相关配置文件
nginx.conf
vim /data/apm/nginx/nginx.conf
user nginx;
worker_processes 5; # worker线程数events {worker_connections 1000; # 单个worker连接数
}http {# 使用Docker内置DNS解析服务名, DNS缓存有效期10秒resolver 127.0.0.11 valid=10s;# 开启访问日志, 生产中建议关闭access_log on;# 定义上游Loki writer服务器组upstream loki_writers {server write:3100;# 保持长连接池keepalive 32;}# 定义上游Loki reader服务器组upstream loki_readers {server read:3100;keepalive 32;}# 定义上游alloy服务器组upstream alloys {server alloy:12345;}# Grafana UIserver {listen 3000;location / {proxy_pass http://grafana:3000;# 代理设置请求头, 否则Grafana会提示一直登录# 并且要设置WebSocket, 否则无法运行实时跟踪# 见https://blog.csdn.net/weixin_41287260/article/details/134630447# https://www.cnblogs.com/hahaha111122222/p/16407564.htmlproxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";proxy_set_header Host $http_host;}}# Loki相关日志推送, 存储等配置server {# 监听容器内 3100 端口(通过 ports 映射到宿主机 3100)启用端口复用提升性能listen 3100 reuseport;# 定义写入类请求的通用配置块location ~ ^/(api/prom/push|loki/api/v1/push) {proxy_pass http://loki_writers$request_uri;proxy_http_version 1.1;proxy_set_header Connection "";}# 定义实时日志流式传输(tail)请求的通用配置块location ~ ^/(api/prom/tail|loki/api/v1/tail) {proxy_pass http://loki_readers$request_uri;proxy_read_timeout 3600s;# 这里必须要配置WebSocket, 否则无法运行实时跟踪proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";}# 定义所有 Prometheus 格式和 Loki 原生格式查询请求的通用配置块location ~ ^/(api/prom/.*|loki/api/.*) {proxy_pass http://loki_readers$request_uri;proxy_http_version 1.1;proxy_set_header Connection "";# 缓存查询结果10秒proxy_cache_valid 200 10s;}}# read 端点, 生产中应该禁外界访问(这里做演示, 所以开放), 容器内部通信即可server {listen 3101;location / {proxy_pass http://loki_readers/ready;}}# write 端点, 生产中禁外界访问(这里做演示, 所以开放), 容器内部通信即可server {listen 3102;location / {proxy_pass http://loki_writers/ready;}}# Minio UIserver {listen 9001;location / {proxy_pass http://minio:9001;# 添加websocket支持, 否则Minio会卡主, 页面一直loading# 见https://blog.csdn.net/qq_25231683/article/details/128734555proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";proxy_set_header Host $http_host;}}# Alloy UIserver {listen 12345;location / {proxy_pass http://alloys;}}    
}
创建alloy相关配置文件
alloy-local-config.yaml
vim /data/apm/alloy/alloy-local-config.yaml

基础架构的日志(例如MySQL, Redis等中间件): 这些组件以类似于 Prometheus 指标的方式标记您的日志。 这使得关联组件收集的基础设施指标变得容易 以及组件收集的日志。组件通常有以下特点

  • loki.*: 日志收集

  • prometheus.*: 指标收集

应用程序的日志(比如Java, Python产生的日志): 以 OpenTelemetry 原生方式收集应用程序日志, 从而更轻松地 将日志与来自应用程序的 OpenTelemetry 指标和跟踪相关联。 所有应用程序遥测都必须遵循 OpenTelemetry 语义约定, 从而简化此关联。组件通常有以下特点

  • otelcol.receiver.*
// ========================
// 实时调试
// ========================
livedebugging {enabled = true
}// ========================
// Docker容器日志发现和采集
// ========================
// Docker 容器发现配置
discovery.docker "flog_scrape" {// 连接 Docker daemon 的地址(Unix 套接字)host             = "unix:///var/run/docker.sock"  // 每5s抓取Docker信息日志refresh_interval = "5s"  
}// 主要用于服务发现阶段对发现的目标(如容器、节点等)的元数据标签进行预处理。当通过服务发现机制(如基于 Docker、Kubernetes 等)发现一系列目标时,这些目标会带有各种元数据标签,这里可以对这些原始标签进行修改、添加、删除等操作,使得标签更加符
discovery.relabel "flog_scrape" {// 初始空目标列表(自动从上游发现discovery.docker "flog_scrape"填充)targets = []  // 提取容器名称rule {// 原始元数据标签(来自 Docker 的属性)source_labels = ["__meta_docker_container_name"]  // 正则提取容器名称(去除路径前缀)regex         = "/(.*)"  // 生成新标签 container 存储处理结果target_label  = "container"}// 提取项目名rule {//source_labels = ["__meta_docker_container_label_com_docker_compose_project"]regex         = "(.*)"  target_label  = "project"     }       
}// Loki Docker 日志采集配置
loki.source.docker "flog_scrape" {// Docker 连接配置(需与发现模块一致)host             = "unix:///var/run/docker.sock"  // 要从中读取日志的容器列表, 关联发现模块获取的目标列表targets          = discovery.docker.flog_scrape.targets  // 日志转发目的地(指向写入模块)forward_to       = [loki.write.default.receiver]  // 应用标签重写规则relabel_rules    = discovery.relabel.flog_scrape.rules  // 目标同步频率(与发现模块同步)refresh_interval = "5s"  
}// ========================
// *.log文件匹配和采集
// ========================
// 本地*.log文件匹配
local.file_match "local_log" {path_targets = [{__path__ = "/opt/app/logs/*.log"},]
}// ========================
// 本地*.log文件采集
// ========================
loki.source.file "local_log" {// 关联发现模块获取的目标列表, 关联到本地机器日志匹配targets    = local.file_match.local_log.targets// 日志转发目的地(指向写入模块)forward_to = [loki.write.default.receiver]
}// ========================
// *.gz文件匹配和采集
// ========================
// 本地*.gz文件匹配
local.file_match "local_log_gz" {path_targets = [{__path__ = "/opt/app/logs/*.gz"},]
}// 本地*.log文件采集
loki.source.file "local_log_gz" {// 关联发现模块获取的目标列表, 关联到本地机器日志匹配targets    = local.file_match.local_log_gz.targets// 日志转发目的地(指向写入模块)forward_to = [loki.write.default.receiver]// 解压缩decompression {// 是否启用解压缩enabled       = true// 开始从新的压缩文件读取之前要等待的时间initial_delay = "10s"// 使用的压缩格式Gzipformat        = "gz"}
}// ========================
// Loki 日志写入配置
// ========================
loki.write "default" {// 将日志发送到的位置endpoint {// 要将日志发送到的完整 URL, Loki 接收端 API 地址url       = "http://gateway:3100/loki/api/v1/push"// 发送前要累积的最大日志批次大小batch_size = "1MiB"// 发送批次前要等待的最长时间batch_wait = "1s"// 多租户标识(生产环境建议动态获取)tenant_id = "tenant1"}// 附加全局标签(当前为空配置)external_labels = {}  
}// =====================Otel配置===================================
// 接收otel协议转发数据
otelcol.receiver.otlp "default" {http {}// gRPC方式接受OTEL数据grpc {endpoint = "0.0.0.0:4317"}// 输出output {//logs 通过 loki.source.file 采集, 不通过这个方式采集// otel需要在应用服务启动中并且agent代理生效后,才能正常抓取otel协议日志数据,因此会有部份缺失;通过Alloy直接抓取本地日志文件内容,能保证日志数据的全生命周期流程完整性// logs	= [otelcol.exporter.loki.default.input]// 指标输出metrics = [otelcol.exporter.prometheus.default.input]// traces链路数据输出traces  = [// 输出到tempo存储otelcol.exporter.otlp.tempo_default.input, // 输出到span日志otelcol.connector.spanlogs.default.input,// 输出到服务拓扑图otelcol.connector.servicegraph.default.input,]}
}// 案例中, 不适用otel转发日志, 日志还是存储在本地
// 从otel中输出日志loki
otelcol.exporter.loki "default" {forward_to = [loki.write.default.receiver]
}// 通过gRPC发送otlp链路数据到tempo服务
otelcol.exporter.otlp "tempo_default" {client {endpoint = "tempo:4317"tls { insecure = true        	insecure_skip_verify = true}}
}// 从otel中输出指标数据到prometheus
otelcol.exporter.prometheus "default" {forward_to = [prometheus.remote_write.default.receiver]
}// =====================Span日志记录配置===================================
otelcol.connector.spanlogs "default" {roots = truespan_attributes = ["http.method", "http.target"]output {logs = [otelcol.exporter.loki.default.input]}
}// =====================服务图配置===================================
otelcol.connector.servicegraph "default" {dimensions = ["http.method", "http.target"]output {metrics = [otelcol.exporter.prometheus.default.input]}
}// =====================Prometheus配置===================================
// 抓取远程服务(Java程序)指标
prometheus.scrape "remote_default" {// 这里填写docker0的地址, 此时才可以实现docker容器访问宿主机targets = [{"__address__" = "172.17.0.1:8080"}]// 使用http方式拉取scheme = "http"// 指标地址metrics_path = "/actuator/prometheus"// 拉取时间间隔scrape_interval = "30s"// 超时时间scrape_timeout = "10s"// 抓发到Prometheusforward_to = [prometheus.remote_write.default.receiver]
}// Alloy指标导出器
prometheus.exporter.self "alloy" { }// Linux主机指标导出器
prometheus.exporter.unix "node" {}// 抓取Alloy指标和Linux主机指标
prometheus.scrape "defalut" {targets    = array.concat(prometheus.exporter.self.alloy.targets, prometheus.exporter.unix.node.targets)forward_to = [prometheus.remote_write.default.receiver]job_name   = "scraper"
}// 指标发送Prometheus
prometheus.remote_write "default" {endpoint {url  = "http://gateway:9090/api/v1/write"}
}
endpoints.json

这个是alloy的endpoints文件, 定了endpoints, 和一些认证的信息

vim /etc/apm/alloy/endpoints.json

metrics: minir服务

logs: loki服务

traces: tempo服务

profiles: pyroscope服务

{"metrics": {"url": "http://mimir:9009/api/v1/push","basicAuth": {"username": "","password": ""}},"logs": {"url": "http://gateway:3100/loki/api/v1/push","basicAuth": {"username": "","password": ""}},"traces": {"url": "http://tempo:4317","basicAuthToken": "","tls": {"insecure": true,"insecureSkipVerify": true}},"profiles": {"url": "http://pyroscope:4040","basicAuth": {"username": "","password": ""}}
}
创建loki相关配置文件

Loki 是一个用于长期保留日志的后端存储

loki-config.yaml
vim /data/apm/loki/loki-config.yaml
# ========================
# Loki 服务核心配置
# ========================
server:# 监听所有网络接口http_listen_address: 0.0.0.0# 默认 Loki 服务端口http_listen_port: 3100grpc_listen_port: 9096# 设置Loki的日志级别log_level: info# ========================
# Loki 管理租户隔离配置
# - Loki 默认以多租户模式运行。多租户模式在配置中使用 auth_enabled: true 设置。
# - 当配置为 auth_enabled: false 时,Loki 使用单租户。Loki API 请求中不需要 X-Scope-OrgID 标头。单租户 ID 将是字符串 fake(即此时只有一个租户)
# ========================
auth_enabled: false# ========================
# 集群节点发现与通信配置
# ========================
memberlist:join_members: ["read", "write", "backend"]  # 需要连接的初始节点列表(建议使用IP或DNS)dead_node_reclaim_time: 30s     # 节点标记为死亡后保留元数据的时间gossip_to_dead_nodes_time: 15s  # 停止向死亡节点发送gossip包的时间left_ingesters_timeout: 30s     # 离开节点清理超时时间bind_addr: ['0.0.0.0']          # 集群通信绑定地址bind_port: 7946                 # 集群通信端口gossip_interval: 2s             # 节点状态同步间隔# ========================
# 存储日志模式配置
# ========================
schema_config:configs:# `from` 值标记了该 schema 的起始点。该 schema 将一直处于活动状态, 直到另一个条目定义了一个新的 schema 和一个新的 `from` 日期# Loki 使用定义的 schema 来确定在存储和查询数据时使用的格式, 使用 schema 允许 Loki 迭代存储层, 而无需迁移现有数据# 对于没有先前数据的新 Loki 安装, 这是一个包含推荐值的 schema 配置示例, 见https://grafana.org.cn/docs/loki/latest/operations/storage/schema/- from: 2025-03-07# 存储模式, tsdb 是当前唯一推荐的 store 值store: tsdbobject_store: s3# 存储模式的版本, v13 是最新的 schema 和推荐值schema: v13# index用于配置如何创建和存储索引表# 索引表是允许Loki在查询日志时确定读取哪些chunk的目录index:# 所有索引表的前缀prefix: index_# 每个索引表的存储24h的数据(超过标记为过期), 必须为 24hperiod: 24h# ========================
# 数据索引和块存储配置
# ========================
common:# 这个Loki实例在本地哈希环上可以到达的地址instance_addr: 127.0.0.1# 所有HTTP端点的前缀path_prefix: /loki# 数据副本数(生产环境建议 >=3)replication_factor: 1compactor_address: http://backend:3100  # 压缩组件地址# 基础Loki存储系统的配置storage:# S3对象存储s3:endpoint: minio:9000         # S3兼容存储地址insecure: true              # 禁用HTTPS(生产环境不推荐)bucketnames: loki-data      # 主数据存储桶access_key_id: whiteBrocade         # 访问密钥(建议使用环境变量)secret_access_key: whiteBrocade  # 密钥(存在安全隐患)s3forcepathstyle: true      # 强制路径访问模式# 本地文件存储(由于是容器形式启动loki, 这里指的是容器内系统)#filesystem:#  # 数据保存的地方#  chunks_directory: /tmp/loki/chunks#  # 规则保存的地方#  rules_directory: /tmp/loki/rules# 一致性哈希环配置ring:# 使用一个分布式环memberlist, 其它的分布式环列如Consul或etcdkvstore:store: memberlist           # 使用memberlist实现分布式哈希环# ========================
# 告警规则配置
# ========================
ruler:# 告警推送接口, 需要集成alertmanager# alertmanager_url: http://localhost:9093storage:s3:# 独立存储告警规则的桶bucketnames: loki-ruler# ========================
# Compactor 负责索引文件的压缩和应用日志保留
# - Grafana Loki 中的保留是通过 Compactor 实现的。默认情况下, `compactor.retention-enabled` 标志未设置, 因此发送到 Loki 的日志将永久保留。
# - 如果您在对象存储上配置了生命周期策略, 请确保其长于保留期限
# - 仅当索引周期为 24 小时时, 保留才可用。单存储 TSDB 和单存储 BoltDB 需要 24 小时索引周期。
# - 参考官方文档https://grafana.org.cn/docs/loki/latest/operations/storage/retention/
# ========================
compactor:# 保存标记 chunks 和临时表的目录working_directory: /tmp/compactor# 应用压缩/保留的频率。如果 Compactor 落后, 则会尽快进行压缩和/或保留,compaction_interval: 10m# 设置为 true。否则,Compactor 将仅压缩表# 只要 compactor.retention_enabled 设置为 true,API 端点将可用。之后, 可以通过 deletion_mode 租户覆盖为每个租户启用对删除 API 的访问retention_enabled: true# 索引文件延迟过期时间, 2h表示延迟两个小时候过期(过期不一定立马删除, 异步删除)# 在索引上应用保留算法时,chunks 不会被删除。它们由 sweeper 进程异步删除, 并且可以通过设置 -compactor.retention-delete-delay 来配置此延迟retention_delete_delay: 2h# 实例化以删除 chunks 的 goroutine worker 的最大数量retention_delete_worker_count: 150# 应设置为配置删除请求的存储。启用保留时, 这是必需的delete_request_store: s3
# ========================
# 用于设置全局默认资源限制(例如存储、请求速率等
# - 这里的配置全局保留, 该保留应用于所有租户(除非通过配置每个租户的覆盖来覆盖)
# - 有两种设置保留策略的方法
#   - retention_period,全局应用于所有日志流。如果不指定, 那么默认就是774h(30天)的保留期限
#   - retention_stream,仅应用于与选择器匹配的日志流
# - 最短保留期限为 24 小时。
# - 启用保留策略时要非常小心。强烈建议您同时在对象存储中对对象启用版本控制, 以便您可以从意外配置错误的保留设置中恢复。如果您想启用删除但不强制执行保留策略, 请将 retention_period 设置配置为 0s 值。
# ========================
limits_config:# 日志保留期限为7天(7*24=168)retention_period: 168h# 只能在 retention_stream 定义的 selector 字段中使用标签匹配器。不支持任意 LogQL 表达式。retention_stream:- selector: '{namespace="dev"}'priority: 1period: 24h# 运行配置, 可以通过Docker的volumes将这个映射进来per_tenant_override_config: /etc/overrides.yaml# ========================
# 日志条目删除
# - 索引存储配置 TSDB 或 BoltDB Shipper 时, 才支持日志条目删除
# - 通过在 compactor 的配置中将 retention_enabled 设置为 true,并在运行时配置中将 deletion_mode 设置为 filter-only 或 filter-and-delete,来启用日志条目删除。启用保留策略以处理删除请求时, 还需要配置 delete_request_store,这将确定存储删除请求的存储桶
# - 日志条目删除依赖于为 compactor 定义的自定义日志保留工作流的配置。Compactor 查看已过取消期限的未处理请求, 以决定是否删除 chunk
# - 启用保留策略时要非常小心。强烈建议您同时在对象存储中对对象启用版本控制, 以便您可以从意外配置错误的保留设置中恢复。如果您想启用删除但不强制执行保留策略, 请将 retention_period 设置配置为 0s 值。
# - 使用 filter-only,当查询 Loki 时, 与删除请求中的查询匹配的日志行将被过滤掉。它们不会从存储中删除。使用 filter-and-delete,当查询 Loki 时, 与删除请求中的查询匹配的日志行将被过滤掉, 并且它们也会从存储中删除
# - 只要 compactor.retention_enabled 设置为 true,API 端点将可用。之后, 可以通过 deletion_mode 租户覆盖为每个租户启用对删除 API 的访问
# - 参考官方文档https://grafana.org.cn/docs/loki/latest/operations/storage/logs-deletion/
# - https://grafana.org.cn/docs/loki/latest/operations/multi-tenancy/
# ========================
overrides.yaml

注意事项

  • Loki 默认以多租户模式运行。多租户模式在配置中使用 auth_enabled: true 设置
  • 如果没有开启租户的话, 那么其实这个配置的基本没有用
vim /data/apm/loki/overrides.yaml
overrides:# 针对租户29的配置"29":# 保留期限为7天retention_period: 168hretention_stream:# 对于namespace标签prod的六保留保留期限为14天, 优先级2- selector: '{namespace="prod"}'# 优先级2, 数字越大, 优先级越高priority: 2period: 336h# 对于container标签为loki的且namespace 标签不为prod的流的保留期限为3天- selector: '{container="loki"}'priority: 1period: 72h# 具有标签 nginx 和级别 debug 的流的保留期限为 24h# 对于此租户中的其余流, 全局保留期限为 744h,因为没有指定retention_period"30":retention_stream:- selector: '{container="nginx", level="debug"}'priority: 1period: 24h# 除租户 29 和 30 之外的所有租户# 具有 namespace 标签 dev 的流的保留期限为 24h 小时# 除具有 namespace 标签 dev 的流之外, 其余流的保留期限为 744h
创建Tempo相关配置文件
  • Tempo 是一个用于长期保留 trace 的后端存储
  • Grafana Alloy 已设置为使用 Tempo。请参阅用于追踪的 Grafana Alloy 配置
vim /data/apm/tempo/tempo-config.yaml
# http监听端口
server:http_listen_address: 0.0.0.0    # 监听所有网络接口http_listen_port: 3200# 调大grpc的max_frame_sizegrpc_server_max_recv_msg_size: 104857600  # 100MBgrpc_server_max_send_msg_size: 104857600# 支持otlp协议数据的本地接收器http和grpc端口,分别默认为4318和4317
distributor:receivers: # This configuration will listen on all ports and protocols that tempo is capable of.otlp:protocols:http: # default = 0.0.0.0:4318 http protocolendpoint: 0.0.0.0:4318grpc:    # default = 0.0.0.0:4317 http protocolendpoint: 0.0.0.0:4317# 数据压缩存储有效期48小时
compactor:compaction:block_retention: 48h   # configure total trace retention here (Default is 14 days (336h))# 可观测性数据的指标存储配置
metrics_generator:registry:external_labels:source: tempocluster: linux-microservicesstorage:path: /tmp/temporemote_write:- url: http://prometheus:9090/api/v1/writesend_exemplars: true# 支持多种存储方式,如:s3、local等
storage:trace:backend: s3     # 本地存储# S3对象存储s3:endpoint: minio:9000         # S3兼容存储地址bucket: tempo-dataforcepathstyle: true # 强制路径访问模式insecure: true # 禁用HTTPS(生产环境不推荐)access_key: whiteBrocade         # 访问密钥(建议使用环境变量)secret_key: whiteBrocade  # 密钥(存在安全隐患)     # 指标类型配置
overrides:metrics_generator_processors: [service-graphs, span-metrics]
创建Prometheus相关配置文件

普罗米修斯是一个后台存储和服务,用于从各种来源抓取(拉取)指标数据

vim /data/apm/prometheus/prometheus.yaml
global:scrape_interval:     15sevaluation_interval: 15sscrape_configs:- job_name: 'prometheus'static_configs:- targets: [ 'prometheus:9090' ]- job_name: 'tempo'static_configs:- targets: [ 'tempo:3200' ]
创建Mimir相关配置文件

Mimir 是 Prometheus 数据的长期保留存储

Grafana Mimir 是一个开源软件项目,为 Prometheus 和 OpenTelemetry 指标提供水平可扩展、高可用、多租户和长期存储

创建Grafana相关配置文件

Grafana 是一个可视化工具,允许从各种数据源创建仪表盘

grafana-datasource.yaml
vim /data/apm/grafana/grafana-datasource.yaml
apiVersion: 1datasources:- name: Prometheusuid: prometheustype: prometheusaccess: proxyorgId: 1url: http://gateway:9090basicAuth: falseisDefault: falseeditable: falseversion: 1# Loki数据源- name: Lokitype: lokiuid: lokiaccess: proxy # 通过Grafana服务代理访问orgId: 1url: http://gateway:3100 # 通过NG网关访问basicAuth: falseisDefault: trueeditable: falseversion: 1jsonData:derivedFields:- datasourceUid: tempo# 派生字段名name: traceID# 正则匹配matcherRegex: "^.*?traceI[d|D]=(\\w+).*$"url: '$${__value.raw}'httpHeaderName1: "X-Scope-OrgID"  # 多租户头部名称maxLines: 1000secureJsonData:httpHeaderValue1: "tenant1"  # 租户ID- name: Tempouid: tempotype: tempoaccess: proxyorgId: 1url: http://tempo:3200basicAuth: falseisDefault: falseeditable: falseversion: 1apiVersion: 1jsonData:# trase关联logtracesToLogsV2:datasourceUid: 'loki'# 8.3.x 有bug;  8.4.2 开始增加了在界面上配置# loki日志标签tags: ['service.name','http.method', 'namespace']# 标签映射mappedTags: [{ key: 'service.name', value: 'service' },{key: 'http.method',value: 'method'}]# 是否开启tag name映射mapTagNamesEnabled: true# 这两个配置项用于 扩展从Tempo跳转至Loki查询日志的时间范围。当你在Tempo中点击某个Span跳转查看关联日志时,Grafana会基于Span的开始和结束时间,自动向前后扩展时间窗口,确保日志查询覆盖潜在的相关记录# 存在一下情况需要拓展时间范围#   - 时间不同步: 分布式系统中,Span时间戳和日志时间戳可能因服务器时钟不同步而存在偏差(如Span记录UTC时间,而日志使用本地时间#   - 异步任务追踪:若Span触发异步操作(如消息队列消费),日志可能远晚于Span结束时间#   - 跨时区系统:组件分布在多个时区时,需覆盖更大时间跨度# 存在一下情况需要缩小时间范围提高查询性能#   - 精准时间同步环境:若已确保所有组件时钟同步(如NTP),可将值缩小至 5m 甚至 1m#   - 高频短时Span场景:若Span持续时间短(如HTTP请求平均<1秒),但日志量极大,缩小范围可提升查询性能spanStartTimeShift: '-5m'spanEndTimeShift: '5m'# 启用traceID过滤filterByTraceID: true# 不启用spanID过滤filterBySpanID: false# trace关联指标tracesToMetrics:datasourceUid: 'prometheus'spanStartTimeShift: '-5m'spanEndTimeShift: '5m'# 跨度数据标签名tags: [{ key: 'service.name', value: 'service' }, { key: 'job' }, {key: 'service.instance.id', value: 'instance'}]# 查询与之关联的queries:# 查询每分钟CPU使用率- name: 'CPU usage per minute'query: 'rate(jvm_cpu_time_seconds_total{$__tags}[1m]) * 60'# 查询每分钟内存使用- name: 'Memory usage per minute'query: 'sum by(id) (increase(jvm_memory_used_bytes{$__tags}[1m]))'# 查询每分钟线程数- name: 'thread count'query: 'increase(jvm_thread_count{$__tags}[1m]) '# 查询每分钟请求数- name: 'http request'query: 'sum by(http_route) (rate(http_server_request_duration_seconds_count{$__tags}[1m]) * 60)'# trace关联性能文件# tracesToProfiles:#   datasourceUid: 'grafana-pyroscope-datasource'#   tags: ['job', 'instance', 'pod', 'namespace']#   profileTypeId: 'process_cpu:cpu:nanoseconds:cpu:nanoseconds'#   customQuery: true#   query: 'method="$${__span.tags.method}"'# # 服务依赖关系图(Service Map),可视化展示微服务之间的调用关系和拓扑结构serviceMap:datasourceUid: 'prometheus'# 控制是否在Tempo的追踪查询界面隐藏搜索栏。设置为 false 表示保留搜索功能,用户可以直接在Tempo中根据TraceID、服务名等条件搜索追踪数据search:hide: false# 启用节点图, 可视化服务依赖关系nodeGraph:enabled: true# 在Tempo追踪详情页中集成Loki日志查询,允许用户直接从Span跳转到关联的日志(基于时间范围或标签过滤)lokiSearch:datasourceUid: 'loki'# trace查询traceQuery:# 启用追踪查询时间范围动态调整timeShiftEnabled: true# 查询开始时间向前扩展1小时spanStartTimeShift: '-5m'# 查询开始时间向后扩展1小时spanEndTimeShift: '5m'spanBar:# 使用标签值作为Span条形图的分类依据type: 'Tag'# 指定Span标签键为 `http.path`tag: 'http.path'# 启用流式搜索(增量加载追踪数据)streamingEnabled:search: true
安装grafana插件

进入Grafana 所有插件, 分别搜索grafana-lokiexplore-appgrafana-exploretraces-app, 下载zip文件
在这里插入图片描述

上传到Linux中/data/apm/grafana/plugins, 解压两个文件
在这里插入图片描述

重启Grafana

docker-compose文件

apm
  1. loki使用的是读写分离模式部署, 拆分成了read, write, backend三个组件
  2. 存储使用的Minio, 生产中建议对存储日志的桶设置过期策略, 减少存储成本
  3. 使用ng作为网关统一入口, 有些端口生产中不应该开放, 比如说loki的read和write的read访问
version: "3.8"
# ========================
# 自定义网络配置
# ========================
networks:apm:  # 创建专用网络确保服务隔离driver: bridgeservices:# ========================# Loki 读取组件(查询节点)# ========================read:image: grafana/loki:latest# 容器名container_name: loki-read# 指定read模式启动command: "-config.file=/etc/loki/config.yaml -target=read"  # 指定角色为读取节点ports:- 3100    # 映射外部访问端口- 7946    # memberlist 通信端口- 9095    # 指标暴露端口(未映射到宿主机)volumes:- /data/apm/loki/loki-config.yaml:/etc/loki/config.yaml  # 共享配置文件healthcheck:  # 健康检查策略test: ["CMD-SHELL", # 使用 shell 执行命令"wget --no-verbose --tries=1 --spider http://localhost:3100/ready || exit 1"]interval: 10s # 每10秒检查一次timeout: 5s   # 超时时间5秒retries: 5    # 最多重试5次depends_on: # 依赖Minio- minio# 定义网络锚点, 后续直接复用networks: &apm-dns  # 网络别名锚点apm:aliases:- apm  # 其他服务可通过 apm 域名访问# ========================# Loki 写入组件(接收节点)# ========================write:image: grafana/loki:latest# 容器名container_name: loki-write# 指定write模式启动command: "-config.file=/etc/loki/config.yaml -target=write"ports:- 3100    # 与读节点区分端口- 7946    # memberlist 通信端口- 9095    # 指标暴露端口(未映射到宿主机)volumes:- /data/apm/loki/loki-config.yaml:/etc/loki/config.yamlhealthcheck: # 健康检查策略test: ["CMD-SHELL", # 使用 shell 执行命令"wget --no-verbose --tries=1 --spider http://localhost:3100/ready || exit 1"]interval: 10s # 每10秒检查一次timeout: 5s   # 超时时间5秒retries: 5    # 最多重试5次depends_on: # 依赖Minio- minionetworks:<<: *apm-dns  # 复用网络别名配置# ========================# Loki 后台处理组件# ========================backend:image: grafana/loki:latest# 容器名container_name: loki-backendcommand: "-config.file=/etc/loki/config.yaml -target=backend -legacy-read-mode=false"ports:- 3100    # 默认API端口(未映射到宿主机)- 7946    # memberlist端口volumes:- /data/apm/loki/loki-config.yaml:/etc/loki/config.yamldepends_on: # 依赖Minio- minionetworks:- apm# ========================# 日志采集组件(原Grafana Agent)# ========================alloy:image: grafana/alloy:latest# 容器名container_name: alloycommand: run --server.http.listen-addr=0.0.0.0:12345 --storage.path=/var/lib/alloy/data /etc/alloy/config.alloyports:- 12345   # Web UI端口- 4317:4317   # otlp grpc- 4318:4318   # otlp httpvolumes:# 将程序产生的*.log,*.gzd的父目录映射到alloy, 这样才能探测到- /opt/app/logs:/opt/app/logs- /data/apm/alloy/alloy-local-config.yaml:/etc/alloy/config.alloy:ro  # 采集配置- /var/run/docker.sock:/var/run/docker.sock  # 挂载docker socket, 如果不挂载这个, 那么没法获取到容器的日志networks:- apmtempo:image: grafana/tempo:latestcontainer_name: tempocommand: "-config.file=/etc/tempo/tempo-config.yaml"ports:- 3200:3200   # tempovolumes: - /data/apm/tempo/tempo-config.yaml:/etc/tempo/tempo-config.yaml- /data/apm/tempo:/tmp/tempodepends_on:- prometheus- minionetworks:- apmprometheus:image: prom/prometheus:v3.2.1container_name: prometheuscommand:- --config.file=/etc/prometheus/prometheus.yaml# 必须要添加这个参数, 否则Prometheus不开启remove write功能- --web.enable-remote-write-receiver# 接受otlp观测数据- --web.enable-otlp-receiver- --enable-feature=exemplar-storage- --enable-feature=native-histogramsports:- 9090volumes:- /data/apm/prometheus/prometheus.yaml:/etc/prometheus/prometheus.yamlnetworks:- apm# ========================# 对象存储服务(S3兼容)# ========================minio:image: minio/minio:latest# 容器名container_name: minioentrypoint:  # 初始化存储目录- sh          - -euc        # 执行脚本的参数:e(报错退出) u(未定义变量报错) c(执行后续命令)- |           # 多行脚本开始, minio创建目录挂载日志mkdir -p /data/loki-data && \mkdir -p /data/loki-ruler && \mkdir -p /data/tempo-data && \minio server /data --console-address :9001environment:- MINIO_ROOT_USER=whiteBrocade        # 用户名(与Loki配置对应)- MINIO_ROOT_PASSWORD=whiteBrocade    # 密码(需加密处理)- MINIO_PROMETHEUS_AUTH_TYPE=public   # 开放指标volumes:- /data/apm/minio:/data  # 持久化存储路径ports:- 9000    # API端口- 9001    # UI端口networks:- apm# ========================# 可视化平台# ========================grafana:image: grafana/grafana-enterprise:latest# 容器名container_name: grafana# 数据持久化environment:- GF_AUTH_ANONYMOUS_ENABLED=true  # 开启匿名访问(生产环境应关闭)# 设置 Grafana 的管理员(admin)账户的初始密码为admin - GF_SECURITY_ADMIN_PASSWORD=admin# 设置 Grafana 的默认用户界面主题为暗黑模式- GF_USERS_DEFAULT_THEME=dark# 实验性功能开关# traceqlSearch: 启用 TraceQL 搜索功能。TraceQL 是一种用于搜索和分析追踪数据的查询语言,支持复杂的追踪数据查询和过滤(集成Tempo)# traceToMetrics: 启用将追踪数据转换为指标的功能。该功能允许用户将追踪数据(如调用链)转换为可监控的指标,便于进行更高级的分析和监控# traceQLStreaming: 启用 TraceQL 流式查询功能。流式查询允许实时追踪数据的分析,适用于实时监控和快速响应- GF_FEATURE_TOGGLES_ENABLE=traceqlEditor, traceToMetrics, traceQLStreaming# 插件, 这个通过网络下载的方式可能会因为墙的原因下载不下来, 进而导致grafana无法启动, 建议手动下载解压, 然后通过plugins目录进行挂载# grafana-lokiexplore-app:增强 Loki 日志查询功能# grafana-exploretraces-app:优化 Tempo 追踪数据探索# - GF_INSTALL_PLUGINS=grafana-lokiexplore-app, grafana-exploretraces-appvolumes: # 可视化面板目录- /data/apm/grafana/dashboards:/etc/grafana/provisioning/dashboards# 数据源目录- /data/apm/grafana/grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml# 持久化插件目录- /data/apm/grafana/plugins:/var/lib/grafana/pluginsports:- 3000    # Web访问端口depends_on: # 依赖网关服务- gatewaynetworks:- apm# ========================# API网关(流量路由)# ========================gateway:image: nginx:latest# 容器名container_name: nginxvolumes:- /data/apm/nginx/nginx.conf:/etc/nginx/nginx.confports:- 3000:3000	# Grafana UI- 3100:3100   # Loki统一入口端口- 3101:3101   # read 端点- 3102:3102   # write 端点- 9001:9001   # Minio UI- 9090:9090   # Prometheus UI- 12345:12345 # Alloy UIhealthcheck: # 健康检查策略test: ["CMD", "service", "nginx", "status"]interval: 10stimeout: 5sretries: 5depends_on:- read- write- alloy- temponetworks:- apm

apm相关访问路径

启动apm

image-20250325120442241

Grafana UI

  • 访问地址(这里换成你自己的IP): http://192.168.132.10:3000

  • 账号: admin

  • 密码: admin

image-20250306155441031

Minio UI

  • 访问地址(这里换成你自己的IP): http://192.168.132.10:9001
  • 账号: whiteBrocade
  • 密码: whiteBrocade

image-20250306155533136

Grafana Alloy UI

  • 访问地址(这里换成你自己的IP): http://192.168.132.10:12345

image-20250306155931033

Loki Read/Write组件

  • Read访问地址(这里换成你自己的IP): http://192.168.132.10:3101
  • Write访问地址(这里换成你自己的IP): http://192.168.132.10:3102

image-20250306160337569

Java集成OTEL

Spring项目搭建

pom依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.whiteBrocade</groupId><artifactId>oltp</artifactId><version>v1</version><name>oltp</name><description>oltp</description><properties><java.version>11</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.6.13</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--hutool--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.32</version></dependency><!-- 端点监控 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!-- prometheus依赖 --><dependency><groupId>io.micrometer</groupId><artifactId>micrometer-registry-prometheus</artifactId><version>1.11.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>11</source><target>11</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.whitebrocade.otel.OtelApplication</mainClass><skip>false</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build>
</project>
application.yaml
# 本地服务访问
server:# 服务端口port: 8080spring:application:# 应用服务名name: whiteBrocade_OTEL# 日志
logging:level:root: INFOcom.example: DEBUG  # 根据需要调整包名和日志级别pattern:console: "%d{yyyy-MM-dd HH:mm:ss.SSS} %level traceID=%X{trace_id} %thread %class{36}:%L - %m%n%wEx"file: "%d{yyyy-MM-dd HH:mm:ss.SSS} %level traceID=%X{trace_id} %thread %class{36}:%L - %m%n%wEx"# 日志文件存放位置file:name: ./logs/app.log# 是否启用springboot的debug调试模式,会打印详细日志信息
debug: false# 启用服务健康检测,注册中心将通过http://host:port/actuator/health 检测服务的存活,默认10s一次
management:endpoints:web:cors:# 跨域配置开放所有,CORS默认处于禁用状态allowed-origins: "*"allowed-methods: "*"discovery:# 启用一个接口可以返回所有端点信息enabled: trueexposure:include:# 开放所有端点health,info,metrics,通过actuator/+端点名就可以获取相应的信息。开发用*,上生产请取消。默认打开health和info- "*"# 某些端点除外,不做开启exclude:- env- beans- info- configprops- health- heapdump- shutdown- threaddump- loggers- conditionsendpoint:shutdown:enabled: truehealth:# 开启后打印详细信息show-details: always
OtelController控制器
import cn.hutool.http.HttpRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** @author whiteBrocade* @version 1.0*/
@Slf4j
@RestController
public class OtelController {@GetMapping("/hello")public void hello(@RequestParam String name) {log.info("hello方法调用: name={}", name);String url = "http://localhost:8080/hi";HttpRequest.get(url).timeout(5000) // 超时 5 秒.execute();}@GetMapping("/hi")public void hi() {log.info("hi方法调用");}}
OtelApplication启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class OtelApplication {public static void main(String[] args) {SpringApplication.run(OtelApplication.class, args);}}

OpenTelemetry(OTEL)的JDK下载

OTEL是OTLP协议的一个实现

从opentelemetry-java-instrumentation中点击最新版本下载

image-20250325125501373

将下载到的opentelemetry-javaagent.jar上传到主机的/opt/apm-agents/otel/下

image-20250325125743770

部署Java程序

打包并上传Java程序

image-20250325125852139

启动Java程序

关键参数含义

  • -javaagent:/opt/apm-agents/otel/opentelemetry-javaagent.jar: 添加OpenTelemetry代理插桩

  • -Dotel.exporter.otlp.protocol=grpc: 启用gRPC协议发送OTEL遥感数据

  • -Dotel.exporter.otlp.endpoint=http://localhost:4317: OTEL收集地址(这里是alloy进行收集)

  • -Dotel.logs.exporter=none: log日志不走otel协议推送,因为日志一般会输出到日志文件中,从文件中加载日志能记录整个应用程序的启动过程,而otel需要在应用服务启动中并且agent代理生效后,才能正常抓取otel协议日志数据,因此会有部份缺失;通过Alloy直接抓取本地日志文件内容,能保证日志数据的全生命周期流程完整性

java -javaagent:/opt/apm-agents/otel/opentelemetry-javaagent.jar \
-Dotel.service.name=otel_test \
-Dotel.exporter.otlp.protocol=grpc \
-Dotel.exporter.otlp.endpoint=http://localhost:4317 \
-Dotel.traces.exporter=otlp \
-Dotel.metrics.exporter=otlp \
-Dotel.logs.exporter=none \
-Dotel.metric.export.interval=30000 \
-Dotel.exporter.otlp.insecure=true \
-jar /opt/app/oltp-v1.jar;

命令要在/opt/app下执行, 否则会采集不到日志, 因为日志存储目录是通过./这种相对路径配置的

image-20250325132822399

效果

Grafanac查询初始化

访问http://192.168.132.10:3000的Grafana面板, 点击Expore

  • 选择Loki数据源
  • 设置时间颗粒度
  • 设置查询条件

image-20250325131837069

查询日志

发送hi请求

发送GET请求, http://192.168.132.10:8080/hi

image-20250325132908109

log日志查询

app.log日志查询

image-20250325133036823

loki查询日志

查询hi调用后的日志

alloy采集日志是有时间延迟, 需要等待一会Grfana中才能查询到

image-20250325133848077

查询链路

发送hello请求

image-20250325134307775

log日志查询

image-20250325134547178

loki查询日志

image-20250325134705541

Loki日志与Tempo链路

向springboot服务发起http请求后,后端服务会打印日志并输出到日志文件中,opentelemetry-javaagent.jar代理通过探针技术,抓取springboot运行过程中的数据、跨度、指标等,通过otel协议推送到指定Alloy采集端,进行处理并分发到Loki和Tempo中,以下是通过Loki查询出打印日志数据,通过输出日志行中的所带的TraceID(跟踪埋点ID),点击关联上Tempo查询该TraceId全链接执行过程,展示分析出的每一步耗时与跨度信息等

image-20250325135117010

查询指标

Tempo链路与Promethus指标

image-20250325221712522

查看CPU使用率

image-20250325221825926

参考资料

apm

博客

Grafana 系列文章(一):基于 Grafana 的全栈可观察性 Demo

Grafana Loki 简要指南:关于标签您需要了解的一切

开源日志监控:Grafana Loki 简要指南

日志之Loki详细讲解

使用读写分离模式扩展 Grafana Loki
Loki部署模式
grafana loki的理解与配置(2.9)
轻量级日志系统docker-compose搭建Loki+Grafana+Promtail,配置、部署, 查询全流程
轻量级日志系统-Loki

轻量级日志系统笔记apm

选择 Grafana Alloy组件

开源项目推荐:flog
推荐一个小工具:flog
探索Flog:伪装日志流量的神器
gitcode的flog项目

Docker 环境中配置 Grafana:详细教程与常见配置项解析

项目集成grafana,并用非root用户启动

在docker-compose启动grafana,出现权限错误的解决方案

Docker上的Grafana 7.3.0存在权限问题

grafana重启后模板没有数据了 grafana新建dashboard

Docker安装grafana数据持久化+配置SMTP

springboot+Loki+Loki4j+Grafana搭建轻量级日志系统

tempo/example/docker-compose at main · grafana/tempo

loki/examples/getting-started/docker-compose.yaml at main · grafana/loki

Auto-instrumenting a Java Spring Boot application for traces and logs using OpenTelemetry and Grafana Tempo | Grafana Labs

grafana/intro-to-apm:指标、日志、跟踪和配置文件会话配套代码简介。

【GO】LGTM_Grafana_Tempo(2) — 官方用例改后实操

遥测数据采集工具Grafana Alloy

Grafana,Loki,Tempo,Prometheus,Agent搭建日志链路监控平台

Loki 日志块使用 MinIO 对象存储

SpringBoot+Prometheus采集Metrics指标数据

Grafana+Loki+Promtail 搭建日志收集系统

Grafana Tempo | Grafana Tempo 文档

文档 | OpenTelemetry 中文文档

Grafana 9.1 的新增功能:跟踪到指标允许用户从跟踪跨度导航到选定的数据源 |Grafana 实验室

配置 Tempo 数据源

Provision Grafana

Grafana 所有插件

配置 Tempo 数据源
Grafana离线安装部署以及插件安装

Grafana Plugins
grafana/conf/defaults.ini at main · grafana/grafana

视频

【IT老齐636】Grafana Loki vs ELK

【IT老齐710】Grafana apm分布式日志收集架构

【IT老齐711】apm收集Docker所有实例运行日志

Grafana+Loki+Alloy快速构建企业日志系统

k8s + loki 日志解决方案 (持续更新中)

Loki日志系统-安装、使用、告警

http://www.dtcms.com/wzjs/133018.html

相关文章:

  • 手机微网站开发的目的和意义怎么找到当地的微信推广
  • 网站建设资料清单福州网站快速排名提升
  • 自己做个网站怎么赚钱如何优化seo
  • 北京如何优化网站seo引擎优化平台培训
  • 网站图片一般多大seo公司是什么
  • 哪些网站免费做职业测评天津网络广告公司
  • 建设公司网站的原则提高搜索引擎检索效果的方法
  • 用wordpress做视频网站图片优化网站
  • 男生网上赚钱的途径网络搜索引擎优化
  • 自己做网站麻烦吗整站seo排名外包
  • php网站开发百度云电商网站平台搭建
  • 网站制作比较好的公司百度信息流推广
  • 万网定制网站怎么样百度站长管理平台
  • 乌审旗建设局网站百度文章收录查询
  • 网站宣传视频模板网站如何建站
  • 网页设计板式重构seo的工作原理
  • 电话销售做网站犯法吗免费推广网站入口
  • 佛山中小企业网站建设广州seo推广服务
  • 竹子建站怎么样怎么在百度做宣传广告
  • 网站建设一个月做十单网络营销网站
  • steamcn网站是谁做的公众号如何推广运营
  • 中学网上做试卷的网站seo网络贸易网站推广
  • 邢台做企业网站站长之家点击进入
  • 电商网站的制作流程网络推广有哪几种方法
  • 公司做二手网站的用意网站优化技术
  • 网站开发需要什么基础知识seo优化教学视频
  • 智联招聘网站怎么做两份简历模板在线优化工具
  • 做美女图片网站需要备案吗太原网站制作推广
  • 福田网站建设价格口碑营销案例ppt
  • 邯郸网站开发定制上海seo公司排名榜