如何从其他应用读取ganglia信息?
我已经成功在我的集群上安装并配置了Ganglia。现在我不想仅仅在Ganglia的网页界面上查看所有的性能数据,而是想从其他应用程序中读取集群信息(这些应用程序可能是基于Java或Python的)。我找不到是否可以做到这一点的信息。
有没有什么API可以用来读取Ganglia的数据呢?
为了测试Ganglia,我使用了telnet master 8649
,结果Ganglia在我的控制台上显示了一些漂亮的XML文本。但是,我该如何用Java或Python做到同样的事情呢?我肯定可以通过套接字连接到8649,但之后我需要向Ganglia的守护进程发送什么吗?
1 个回答
我可以帮你理解这个问题。不过在此之前,我得告诉你,我不是Java程序员,我是C/C++程序员。这意味着我可以告诉你在ganglia中是如何工作的,你可以找到Java或Python中相应的方法来重写你想要的代码。
请注意,ganglia中没有API可以实现你想要的功能。
首先,考虑一下下面的ganglia设置,以便更好地理解:
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连接建立”和“数据转换为可读格式”的操作。
上面这个函数的调用流程如下所示:
现在,让我们扩展第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池。
我希望这能给你一个不错的起点,开始你的应用程序。