使用Prometheus监控NebulaGraph

一、NebulaGraph安装

​ 本次安装选择NebulaGraph最新版本3.8.0,采用docker-compose的方式部署,官方文档,新版本的安装要比之前顺滑很多,赞~

1.1、找一台服务器,安装好docker和docker-compose
1.2、下载项目
$ git clone -b release-3.8 https://github.com/vesoft-inc/nebula-docker-compose.git
1.3、安装
# 创建安装路径
mkdir -p /work/nebula

#复制docker-compose.yaml
cp ../nebula-docker-compose-3.8.0/docker-compose.yaml /work/nebula/

# 复制环境变量文件
cp ../nebula-docker-compose-3.8.0/.env /work/nebula/

# 修改.env,时区使用Asia/Shanghai
vim .env

TZ=Asia/Shanghai

# 启动
docker-compose up -d

# 查看启动结果
docker-compose ps

二、Prometheus安装

2.1、安装
# 创建目录
mkdir -p /work/prometheus

# 创建应用子目录
# 启动脚本路径
mkdir -p /work/prometheus/bin
# 数据文件路径
mkdir -p /work/prometheus/data/prometheus
# 配置文件路径
mkdir -p /work/prometheus/conf
# 日志文件路径
mkdir -p /work/prometheus/logs

# 创建启动脚本
cd /work/prometheus/bin
vim start.sh

#内容
docker run -d --restart=always --name=prometheus \
        -p 9090:9090 \
        --log-opt max-size=10m \
        -v /etc/localtime:/etc/localtime:ro \
        -v /etc/timezone:/etc/timezone \
        -v /work/prometheus/conf/prometheus.yml:/etc/prometheus/prometheus.yml \
        -v /work/prometheus/data/prometheus:/prometheus \
        prom/prometheus --config.file=/etc/prometheus/prometheus.yml --web.enable-lifecycle --storage.tsdb.retention.time=7d
        
# 创建一个空的prometheus.yml
touch prometheus.yml

# 修改/work/prometheus/data/prometheus,目录权限
chown 65534:65534 prometheus/

# 启动
chmod 755 start.sh
./start.sh

# 查看启动日志,确认正常启动
docker logs -f prometheus

三、Grafana安装

3.1、安装
# 创建目录
mkdir -p /work/grafana

# 创建应用子目录
# 启动脚本路径
mkdir -p /work/grafana/bin
# 数据文件路径
mkdir -p /work/grafana/data/grafana
# 日志文件路径
mkdir -p /work/grafana/logs

# 创建启动脚本
cd /work/grafana/bin
vim start.sh

#内容
docker run -d --restart=always --name grafana \
        -p 3000:3000 \
        --log-opt max-size=10m \
        -e GF_AUTH_PROXY_ENABLED=true \
        -e GF_AUTH_ANONYMOUS_ENABLED=true \
        -e GF_SERVER_ENABLE_LOCAL_HEALTH_CHECK=false \
        -v /etc/localtime:/etc/localtime:ro \
        -v /etc/timezone:/etc/timezone \
        -v /work//grafana/data/grafana:/var/lib/grafana \
        harbor.neuqsoft.com/dockerhub/grafana/grafana

# 修改/work//grafana/data/grafana,目录权限
chown 472:472 grafana/

# 启动
chmod 755 start.sh
./start.sh

# 查看启动日志,确认正常启动
docker logs -f grafana

四、整合

4.1、调整NebulaGraph,打开监控
# 关闭服务
docker-compose down

# 编辑docker-compose.yaml文件
vim docker-compose.yaml

# 在graphd服务后边增加 - --enable_space_level_metrics,注意我有三个节点,都需要修改
 - --enable_space_level_metrics

# 调整端口,将ws_http_port对应的端口映射出来
# 使用29669,39669,49669对应graphd服务的三个节点19669
# 以下为部分内容,注意我有三个节点,都需要修改
- 29669:19669
- 39669:19669
- 49669:19669

image

# 启动NebulaGraph
docker-compose up -d
​
# 检查启动状态
docker-compose ps
4.2、配置Prometheus
# 编辑配置文件
vim prometheus.yml

scrape_configs:
  - job_name: 'nebula-graph'
    metrics_path: '/stats'
    static_configs:
     - targets:
       - 127.0.0.1:29669
       - 127.0.0.1:39669
       - 127.0.0.1:49669

# 重启服务
docker restart prometheus
4.3、grafana配置数源

4.4、说实话,我写文章就从来没顺利过,谁懂啊,怪不得没有《使用Prometheus监控NebulaGraph》,相关的文章。

首先,官方自带的metrics接口请求地址和Prometheus要求的不一样,通过修改metrics_path配置,指定到了/stats访问地址

其次,返回数据格式也和Prometheus要求的不一样,导致Prometheus识别节点全部都是down

最后,采集到的数据,也没有被Prometheus存储,grafana也没办法读取到
image

五、填坑

5.1、期间试过很多种方法,失败的就不说了,就说最后成功的。

自己实现一个数据转换服务,将官方的metrics返回数据转换为Prometheus要求的格式。

用go实现了一个转换的工具,上代码

package main

import (
    "flag"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "strings"
)

// 端点和端口进行变量声明
var (
    targetEndpoint string
    port           string
)

func main() {
    // 使用 flag 包解析命令行参数
    flag.StringVar(&port, "port", "8000", "HTTP server 监听端口")
    flag.StringVar(&targetEndpoint, "target", "http://nebula-graph.local:19669/metrics", "目标 metrics 端点地址")
    flag.Parse()

    // 注册 /metrics 路由
    http.HandleFunc("/metrics", handleMetrics)

    // 启动 HTTP 服务器
    fmt.Printf("服务器启动在端口 %s,抓取指标来自 %s\n", port, targetEndpoint)
    if err := http.ListenAndServe(":"+port, nil); err != nil {
        fmt.Printf("启动服务器时遇到错误: %s\n", err)
        os.Exit(1)
    }
}

// handleMetrics 是处理指标抓取的主函数
func handleMetrics(w http.ResponseWriter, r *http.Request) {
    // 从目标端点抓取原始指标数据
    resp, err := http.Get(targetEndpoint)
    if err != nil {
        http.Error(w, "抓取指标失败", http.StatusInternalServerError)
        return
    }
    defer resp.Body.Close()

    // 读取响应体内容
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        http.Error(w, "读取指标失败", http.StatusInternalServerError)
        return
    }

    // 重格式化指标
    metrics := reformatMetrics(string(body))
    fmt.Fprint(w, metrics) // 返回格式化后的指标
}

// reformatMetrics 将原始指标重格式化为 Prometheus 兼容的格式
func reformatMetrics(rawMetrics string) string {
    var formattedLines []string
    lines := strings.Split(rawMetrics, "\n") // 按行拆分

    for _, line := range lines {
        // 跳过注释行和空行
        if strings.HasPrefix(line, "#") || line == "" {
            formattedLines = append(formattedLines, line)
            continue
        }

        // 自定义重格式化逻辑
        // 比如:num_queries_hit_memory_watermark.rate.5=0 -> num_queries_hit_memory_watermark_rate_5{interval="5"} 0
        parts := strings.Split(line, "=")
        if len(parts) != 2 {
            // 跳过无效行
            continue
        }
        metric, value := parts[0], parts[1]

        // 处理 metric 部分,将其拆分为名称和区间
        metricParts := strings.Split(metric, ".")
        if len(metricParts) < 3 {
            continue  // 不符合预期格式则跳过
        }

        // 将名称和区间拼接成 Prometheus 格式
        baseName := strings.Join(metricParts[:len(metricParts)-2], "_") // 将名称部分合并
        interval := metricParts[len(metricParts)-1]
        metricType := metricParts[len(metricParts)-2]

        // 拼接成 Prometheus 格式的字符串
        formattedMetric := fmt.Sprintf("%s_%s{interval=\"%s\"} %s", baseName, metricType, interval, value)
        formattedLines = append(formattedLines, formattedMetric)
    }

    return strings.Join(formattedLines, "\n") // 将所有行合并为一个字符串
}
# 编译后得到linux服务器可执行文件metrics_converter
# 启动服务
./metrics_converter -port=8081 -target=http://127.0.0.1:29669/stats

# 测试
curl http://127.0.0.1:8081/metrics

# ok数据格式对了,不要纠结为啥全是0,刚装的啥也没有。。。

image

5.2、调整Prometheus配置文件,就调整了一个演示一下
# # 编辑配置文件
vim prometheus.yml

scrape_configs:
  - job_name: 'nebula-graph'
    static_configs:
     - targets:
       - 127.0.0.1:8081

# 重启服务
docker restart prometheus

5.3、查看grafana数据指标,已经可以正常制作图表了

5.4、额由于原来不支持Prometheus+grafana,所以官方图表库没有能直接用的,我能力有限。。。就这样了。

六、总结

通过不断的尝试,终于实现了目标,现在运维工作看来确实需要一些开发的基础,希望这篇文章能给需要的人带来一丝丝帮助吧。

注意:全篇文章使用127.0.0.1是为了隐藏IP,各位测试的时候请使用真实IP!!!

8 个赞

超级棒的工作!!!辛苦啦!!!

我们私下聊的时候才知道 @堕落飞鸟 老师不知道 NebulaGraph DashboardStats-Exporter :sob:

1 个赞

不错的尝试,不过使用官方的工具很简单就能实现。。。

1 个赞

也是一种思路,不过有自带的桌面,还是用自带的比较舒服。