如何从其他应用读取ganglia信息?

1 投票
1 回答
889 浏览
提问于 2025-04-18 12:47

我已经成功在我的集群上安装并配置了Ganglia。现在我不想仅仅在Ganglia的网页界面上查看所有的性能数据,而是想从其他应用程序中读取集群信息(这些应用程序可能是基于Java或Python的)。我找不到是否可以做到这一点的信息。

有没有什么API可以用来读取Ganglia的数据呢?

为了测试Ganglia,我使用了telnet master 8649,结果Ganglia在我的控制台上显示了一些漂亮的XML文本。但是,我该如何用Java或Python做到同样的事情呢?我肯定可以通过套接字连接到8649,但之后我需要向Ganglia的守护进程发送什么吗?

1 个回答

4

我可以帮你理解这个问题。不过在此之前,我得告诉你,我不是Java程序员,我是C/C++程序员。这意味着我可以告诉你在ganglia中是如何工作的,你可以找到Java或Python中相应的方法来重写你想要的代码。

请注意,ganglia中没有API可以实现你想要的功能。

首先,考虑一下下面的ganglia设置,以便更好地理解:

ganglia minimal setup

GS1和GS2负责收集系统的指标,并将它们推送到GM。所以,根据你的问题,如果你想通过自己的Java或Python应用程序收集所有这些指标,那么你可能需要在主服务器上安装这个应用程序(也就是用你自己的应用程序替换GS)。

GS1和GS2通过UDP单播通道或UDP组播通道发送所有收集到的指标。建议在每个gmond.conf中启用UDP单播,以便更容易扩展。

我不会多讨论GS1和GS2,因为你的问题更关心如何用你自己的工具替换GM。

GM大量使用两个重要的库来建立UDP连接并将数据转换为它自己可读的格式。它们是APR(Apache可移植运行时),用于建立UDP连接并执行相关操作,以及XDR(外部数据表示),用于在网络间发送数据并执行远程过程调用(RPC)。

你需要先找到Java和Python中APR和XDR的等效库。XDR在Java中已经可用,而APR可以通过你自己的基本实现来替代,以执行网络间的操作(例如,创建UDP套接字等)。

打开gmond.c源文件,找到第1436行。你会看到一个C函数:

static void process_udp_recv_channel(const apr_pollfd_t *desc, apr_time_t now)

这个函数基本上执行“UDP连接建立”和“数据转换为可读格式”的操作。

上面这个函数的调用流程如下所示:
Call flow

现在,让我们扩展第1436行的函数,以便更深入理解。

这个函数的第一个参数包含网络参数,比如IP、端口等。下面是这个结构的扩展。你在Java中也可以找到类似的对象。

struct apr_pollfd_t {
    apr_pool_t *p;              /**< associated pool */
    apr_datatype_e desc_type;   /**< descriptor type */
    apr_int16_t reqevents;      /**< requested events */
    apr_int16_t rtnevents;      /**< returned events */
    apr_descriptor desc;        /**< @see apr_descriptor */
    void *client_data;          /**< allows app to associate context */
};

如果SFLOW被禁用,第二个参数就没有关系。

所以,首先创建一个APR池、UDP连接等。

  socket         = desc->desc.s;
  channel       = desc->client_data;

  apr_pool_create(&p, global_context);
  status = apr_socket_addr_get(&remotesa, APR_LOCAL, socket);

  status = apr_sockaddr_info_get(&remotesa, NULL, remotesa->family, remotesa->port, 0, p);

  /* Grab the data */
  status = apr_socket_recvfrom(remotesa, socket, 0, buf, &len);
  if(status != APR_SUCCESS)
    {
      apr_pool_destroy(p);
      return;
    }  

  apr_sockaddr_ip_buffer_get(remoteip, 256, remotesa);

  /* Check the ACL */
  if(Ganglia_acl_action( channel->acl, remotesa) != GANGLIA_ACCESS_ALLOW)
    {
      apr_pool_destroy(p);
      return;
    }

所有变量的声明可以在扩展的函数开头找到(第1439到1456行)。

然后,创建XDR流:

xdrmem_create(&x, buf, max_udp_message_len, XDR_DECODE);

刷新保存元数据和指标值的结构的数据:

memset( &fmsg, 0, sizeof(Ganglia_metadata_msg));
memset( &vmsg, 0, sizeof(Ganglia_value_msg));

fmsg(Ganglia_metadata_msg)和vmsg(Ganglia_value_msg)的结构定义可以在gm_protocol.h头文件中找到。用Java重写它们。

然后,判断接收到的消息是“元数据”还是“指标值”。

xdr_Ganglia_msg_formats(&x, &id); // this function is located in the source file gm_protocol_xdr.c and this file is generated by rpcgen.

注意:rpcgen是一个RPC编译器,相关解释可以在这个问题中找到。

注意:这里是gm_protocol_xdr.c的链接。

这里,id是一个enum,它的声明如下:

enum Ganglia_msg_formats {
    gmetadata_full = 128,
    gmetric_ushort = 128 + 1,
    gmetric_short = 128 + 2,
    gmetric_int = 128 + 3,
    gmetric_uint = 128 + 4,
    gmetric_string = 128 + 5,
    gmetric_float = 128 + 6,
    gmetric_double = 128 + 7,
    gmetadata_request = 128 + 8,
};
typedef enum Ganglia_msg_formats Ganglia_msg_formats;

根据id的值,你可以确定数据包的类型。为此,这个函数会调用另一个函数(实际上是rpcgen生成的)来确定数据包的类型,如果找到,它也会将其转换为人类可读的格式。

这个函数是:

xdr_Ganglia_value_msg(&x, &vmsg);

你可以在gm_protocol_xdr.c的第275行找到这个函数的完整扩展。

之后,你可以对这些数据包做任何你想做的事情。

最后,你必须释放所有分配的XDR变量和APR池。

我希望这能给你一个不错的起点,开始你的应用程序。

撰写回答