Skip to content
Closed

test #126

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions handlers/handler-performance-stats/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!-- ~ Copyright 2017 Huawei Technologies Co., Ltd ~ ~ Licensed under the
Apache License, Version 2.0 (the "License"); ~ you may not use this file
except in compliance with the License. ~ You may obtain a copy of the License
at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~ Unless required by
applicable law or agreed to in writing, software ~ distributed under the
License is distributed on an "AS IS" BASIS, ~ WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied. ~ See the License for the specific
language governing permissions and ~ limitations under the License. -->

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.servicecomb</groupId>
<artifactId>handlers</artifactId>
<version>0.1.0-m3-SNAPSHOT</version>
</parent>
<artifactId>cse-handler-performance-stats</artifactId>
<dependencies>
<dependency>
<groupId>io.servicecomb</groupId>
<artifactId>java-chassis-core</artifactId>
</dependency>
<dependency>
<groupId>io.servicecomb</groupId>
<artifactId>foundation-metrics</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-core</artifactId>
</dependency>
<dependency>
<groupId>com.huawei.paas.cse</groupId>
<artifactId>foundation-auth</artifactId>
<version>0.1</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright 2017 Huawei Technologies Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.huawei.paas.cse.handler.stats;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.servicecomb.core.Invocation;
import io.servicecomb.core.handler.impl.AbstractHandler;
import io.servicecomb.foundation.metrics.Metrics;
import io.servicecomb.foundation.metrics.performance.PerfStatContext;
import io.servicecomb.foundation.metrics.performance.PerfStatSuccFail;
import io.servicecomb.swagger.invocation.AsyncResponse;
import io.servicecomb.swagger.invocation.exception.InvocationException;

/**
* 统计成功、失败的tps、时延等等参数
* @author
* @version [版本号, 2016年12月5日]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class PerfStatsHandler extends AbstractHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(PerfStatsHandler.class);

/**
* {@inheritDoc}
*/
@Override
public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception {
String name = invocation.getOperationMeta().getMicroserviceQualifiedName();
// 先确认是否需要跟踪?
if (!isNeedPerfStat(name)) {
invocation.next(asyncResp);
return;
}

PerfStatContext context = new PerfStatContext();

// TODO:
// 1.如果能确定是放在exceptionHandler前面,则这里不必catch
// 2.作为handler,框架上的异常场景统计不到
// 3.这里只统计了调用的tps,而业务层的消息数,如何感知支撑?
// 使用标准的metrics方案,可以解决这些问题
try {
invocation.next(resp -> {
asyncResp.handle(resp);

onStat(invocation, resp.isSuccessed(), context);
});
} catch (Throwable e) {
if (!InvocationException.class.isInstance(e)) {
LOGGER.error("invoke failed,", e);
}
onStat(invocation, false, context);
asyncResp.fail(invocation.getInvocationType(), e);
}
}

protected void onStat(Invocation invocation, boolean isSucc, PerfStatContext context) {
context.setMsgCount(1);

// 统计标识带上transport名称,方便识别场景
String statName = invocation.getInvocationQualifiedName();

// TODO:同优先级的,后加入的应该在最后
PerfStatSuccFail stat = Metrics.getOrCreateLocalPerfStat(statName, 0);
stat.add(isSucc, context);
}

// TODO:由客户端带过来?不应该要求两端都配置?
/**
* <一句话功能简述>
* <功能详细描述>
* @param name
* @return
*/
private boolean isNeedPerfStat(String name) {
return true;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package com.huawei.paas.cse.handler.stats.monitor;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.ThreadMXBean;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.huawei.paas.foundation.auth.AuthHeaderUtils;
import com.huawei.paas.foundation.auth.HttpClientFactory;
import com.netflix.config.DynamicBooleanProperty;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
import com.netflix.hystrix.HystrixCommandMetrics;

import io.netty.util.concurrent.DefaultThreadFactory;
import io.servicecomb.serviceregistry.RegistryUtils;
import io.vertx.core.json.Json;

/**
* 数据生成工厂,启动一个线程池,定时发送数据
* @author w00293972
*/
class DataFactory {

private static final Logger LOGGER = LoggerFactory.getLogger(DataFactory.class);
private static final int CORE_SIZE = 1;
private static final int SLEEP_MINI_TIME = 1;
private static final int SLEEP_MAX_TIME = 10;
private static final int DELAY_TIME_MILLISECONDS = 1000;

private static final String SSL_KEY = "mc.consumer";
private boolean hasStart = false;
private boolean firestError = true;

private static DataFactory INSTANCE = new DataFactory();

private ScheduledExecutorService executorService = null;

private DataFactory() {
ThreadFactory tf = new DefaultThreadFactory("cse-monitor-datafactory");
executorService = Executors.newScheduledThreadPool(CORE_SIZE, tf);
}

public static DataFactory getInstance() {
return INSTANCE;
}

/**
* 开启数据上报
*/
void start() {
if (!hasStart) {
LOGGER.info("Start collect monitor data, send to Monitor Sender!");
executorService.scheduleWithFixedDelay(() -> {
int elapsedTime = sendData(getData());
delayTime(elapsedTime);
}, DELAY_TIME_MILLISECONDS, DELAY_TIME_MILLISECONDS, TimeUnit.MILLISECONDS);
hasStart = true;
}
}

private void delayTime(int elapsedTime) {
int sleepTime = elapsedTime / 1000;
try {
if (sleepTime < SLEEP_MINI_TIME) {
return;
}
if (sleepTime > SLEEP_MAX_TIME) {
sleepTime = SLEEP_MAX_TIME;
}
Thread.sleep(sleepTime * 1000);
} catch (InterruptedException e) {
LOGGER.error("Sleep delay time error");
}
}

/**
* 发送数据
* @param monitorData
*/
int sendData(MonitorData monitorData) {
if (!getEnableMonitor()) {
return 0;
}
HttpClient monitorClient = HttpClientFactory.getOrCreateHttpClient(SSL_KEY);
HttpPost httpPost = new HttpPost(getServerUrl() + "/csemonitor/v1/metric?service=" + monitorData.getName());
httpPost.addHeader("Content-Type", "application/json");
Map<String, String> akskHeaders = AuthHeaderUtils.getInstance().genAuthHeaders();
for (Map.Entry<String, String> header : akskHeaders.entrySet()) {
httpPost.setHeader(header.getKey(), header.getValue());
}
HttpEntity entity;
long startTime = System.currentTimeMillis();
try {
entity = new StringEntity(Json.encode(monitorData));
httpPost.setEntity(entity);
HttpResponse response = monitorClient.execute(httpPost);
LOGGER.debug(response.getStatusLine().toString());
EntityUtils.consume(response.getEntity());
} catch (IOException e) {
if (firestError) {
LOGGER.error("Upload monitor data error!");
firestError = false;
}
}
long endTime = System.currentTimeMillis();
int time = (int) (endTime - startTime);
return time;
}

/**
* 构造数据
* @return 监控数据
*/
MonitorData getData() {
Collection<HystrixCommandMetrics> instances = HystrixCommandMetrics.getInstances();
MonitorData monitorData = new MonitorData();
monitorData.setName(RegistryUtils.getMicroservice().getServiceName());
monitorData.setInstance(RegistryUtils.getMicroserviceInstance().getHostName());
exactProcessInfo(monitorData);
if (instances == null || instances.isEmpty()) {
return monitorData;
}
for (HystrixCommandMetrics instance : instances) {
monitorData.appendInterfaceInfo(instance);
}
return monitorData;
}

private void exactProcessInfo(MonitorData monitorData) {
MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
MemoryUsage memoryHeapUsage = memBean.getHeapMemoryUsage();
MemoryUsage memoryNonHeapUsage = memBean.getNonHeapMemoryUsage();
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
int threadCount = threadBean.getThreadCount();
OperatingSystemMXBean osMxBean = ManagementFactory.getOperatingSystemMXBean();
// this method only work well on Unix operation system
double cpu = osMxBean.getSystemLoadAverage();
monitorData.setCpu(cpu);
monitorData.setThreadCount(threadCount);
Map<String, Long> memoryInfo = new HashMap<>();
memoryInfo.put("heapInit", memoryHeapUsage.getInit());
memoryInfo.put("heapMax", memoryHeapUsage.getMax());
memoryInfo.put("heapCommit", memoryHeapUsage.getCommitted());
memoryInfo.put("heapUsed", memoryHeapUsage.getUsed());
memoryInfo.put("nonHeapInit", memoryNonHeapUsage.getInit());
memoryInfo.put("nonHeapCommit", memoryNonHeapUsage.getCommitted());
memoryInfo.put("nonHeapUsed", memoryNonHeapUsage.getUsed());
monitorData.setMemory(memoryInfo);
}

/**
* 获取数据上报地址
* @return
*/
public String getServerUrl() {
DynamicStringProperty property = DynamicPropertyFactory.getInstance()
.getStringProperty("cse.monitor.client.serverUri", "https://cse-dashbord-service:30109");
return property.getValue();
}

/**
* 获取是否上报数据
* @return
*/
public boolean getEnableMonitor() {
DynamicBooleanProperty property = DynamicPropertyFactory.getInstance()
.getBooleanProperty("cse.monitor.client.enable", true);
return property.getValue();
}
}
Loading