背景:
公司自建 IDC 机房, 基于 IDC 机房构建大数据集群; 需要对集群资源进行监控, 集群采用的是 CDH 集群, 采集主要分两块进行:
HDFS 和 YARN 相关的指标进行采集
IDC 机器自身的指标进行采集
注意: 也许有人会有疑惑, CM 界面已经提供了监控的图表, 为什么还需要自己进行展示. 原因在于, 这些信息需要集成到内部的数据平台上面去, 做成对应的数据报表, 可视化的方式展示在自己的数据平台上
实现思路大致可以分为两种:
使用 CM 所提供的 Java API 去获取
使用 CM 提供的 REST API 去获取
其实两者本质上是一样的, CM 所提供的 Java API 也是按照 REST API 那套来实现的, 两者是保持一致的
核心代码如下:
- public class IdcHostResource {
- private static final Logger LOGGER = LoggerFactory.getLogger(IdcHostResource.class);
- static RootResourceV18 apiRoot;
- // TODO... 写死了, 需要改进
- static {
- apiRoot = new ClouderaManagerClientBuilder()
- .withHost("cm ip")
- .withPort(7180)
- .withUsernamePassword("user", "passwd")
- .build()
- .getRootV18();
- }
- /**
- * 固定获取 Host 的基本资源信息
- */
- public static List<IdcHostBasicInfo> getAllHostResource() {
- List<IdcHostBasicInfo> hosts = new ArrayList<IdcHostBasicInfo>();
- HostsResourceV10 hostsResourceV10 = apiRoot.getHostsResource();
- List<ApiHost> hostLists = hostsResourceV10.readHosts(DataView.SUMMARY).getHosts();
- LOGGER.info("Total" + hostLists.size() + "Host");
- for (ApiHost hostList : hostLists) {
- IdcHostBasicInfo host = formatHost(hostsResourceV10.readHost(hostList.getHostId()));
- LOGGER.info("Host Name:" + host.getHostName());
- LOGGER.info("Host Health Summary:" + host.gethostHealthSummary());
- LOGGER.info("Host Physical Memory:" + host.getTotalPhysMemBytes());
- hosts.add(host);
- }
- return hosts;
- }
- public static IdcHostBasicInfo formatHost(ApiHost apiHost) {
- IdcHostBasicInfo idcHostBasicInfo = new IdcHostBasicInfo();
- idcHostBasicInfo.sethostHealthSummary(apiHost.getHealthSummary().toString());
- idcHostBasicInfo.setHostName(apiHost.getHostname());
- idcHostBasicInfo.setTotalPhysMemBytes(apiHost.getTotalPhysMemBytes());
- return idcHostBasicInfo;
- }
- /**
- * 通过 tsquery 来动态获取对应的 metrics info
- *
- * @param query
- * @param startTime
- * @param endTime
- * @return
- */
- public static List<IdcMetricInfo> getHostMetrics(String query, String startTime, String endTime) throws ParseException {
- TimeSeriesResourceV11 timeSeriesResourceV11 = apiRoot.getTimeSeriesResource();
- ApiTimeSeriesResponseList responseList = timeSeriesResourceV11.queryTimeSeries(query, startTime, endTime);
- List<ApiTimeSeriesResponse> apiTimeSeriesResponseList = responseList.getResponses();
- List<IdcMetricInfo> metrics = formatApiTimeSeriesResponseList(apiTimeSeriesResponseList);
- return metrics;
- }
- public static List<IdcMetricInfo> formatApiTimeSeriesResponseList(List<ApiTimeSeriesResponse> apiTimeSeriesResponseList) throws ParseException {
- List<IdcMetricInfo> metrics = new ArrayList<IdcMetricInfo>();
- DateUtils dateUtils = new DateUtils();
- for (ApiTimeSeriesResponse apiTimeSeriesResponse : apiTimeSeriesResponseList) {
- List<MetricData> dataList = new ArrayList<MetricData>();
- List<ApiTimeSeries> apiTimeSeriesResponseLists = apiTimeSeriesResponse.getTimeSeries();
- for (ApiTimeSeries apiTimeSeries : apiTimeSeriesResponseLists) {
- LOGGER.info("query sql is:" + apiTimeSeries.getMetadata().getExpression());
- IdcMetricInfo metric = new IdcMetricInfo();
- metric.setMetricName(apiTimeSeries.getMetadata().getMetricName());
- metric.setEntityName(apiTimeSeries.getMetadata().getEntityName());
- metric.setStartTime(apiTimeSeries.getMetadata().getStartTime().toString());
- metric.setEndTime(apiTimeSeries.getMetadata().getEndTime().toString());
- for (ApiTimeSeriesData apiTimeSeriesData : apiTimeSeries.getData()) {
- MetricData data = new MetricData();
- // 在 Data 中插入 EntityName, 避免重复数据的产生
- data.seHostname(apiTimeSeries.getMetadata().getEntityName());
- // CM 默认得到的时间格式为 EEE MMM dd HH:mm:ss 'CST' yyyy, 转换时间格式为 yyyy-MM-dd HH:mm:ss
- data.setTimestamp(dateUtils.parse(apiTimeSeriesData.getTimestamp().toString()));
- data.setType(apiTimeSeriesData.getType());
- data.setValue(apiTimeSeriesData.getValue());
- dataList.add(data);
- }
- metric.setData(dataList);
- metrics.add(metric);
- }
- }
- return metrics;
- }
注意:
代码中涉及到的 DateUtils 需要自己去进行实现
通过这部分代码可以通过传入 tsquery 的方式去获取对应的 idc 集群的 metric 信息; 接下来的代码我们只需要通过 ServiceImpl 去实现对应的监控指标的获取代码即可
如果想通过 cm API 与 spring boot 整合的, 这其中还会遇到 2 个问题:
依赖冲突问题, 主要表现在 jackson 与 cxf 的冲突; 通过排 jar 包的方式可以解决
正则解析错误, 该问题为 cm 使用过程中的一个坑, 目前仍在排查当中, 具体表现形式为:
这里面有个空格, 因此在编译的过程中直接会报正则解析的错误; 但是我们可以发现在 cm 6.x 的 API 版本中已经没有这个问题了:
因此可以直接升级 API 的版本来解决该问题, 但是随之带来的问题就是与线上运行的 cm 版本不一致 (线上的版本为 5.13.2), 因此对于如何解决仍然需要思考; 不过经过测试发现, 使用 cm 6.x 版本的 API, 对于目前线上那套版本的相关指标并不影响
来源: http://www.bubuko.com/infodetail-3109618.html