All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vip.saturn.job.console.service.impl.statistics.StatisticsRefreshServiceImpl Maven / Gradle / Ivy

/**
 * Copyright 2016 vip.com.
 * 

* 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.vip.saturn.job.console.service.impl.statistics; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.vip.saturn.job.console.domain.*; import com.vip.saturn.job.console.exception.SaturnJobConsoleException; import com.vip.saturn.job.console.mybatis.entity.DashboardHistory; import com.vip.saturn.job.console.mybatis.entity.SaturnStatistics; import com.vip.saturn.job.console.mybatis.service.SaturnStatisticsService; import com.vip.saturn.job.console.repository.zookeeper.CuratorRepository; import com.vip.saturn.job.console.service.*; import com.vip.saturn.job.console.service.helper.DashboardConstants; import com.vip.saturn.job.console.service.helper.ZkClusterMappingUtils; import com.vip.saturn.job.console.service.impl.DashboardServiceImpl; import com.vip.saturn.job.console.service.impl.statistics.analyzer.*; import com.vip.saturn.job.console.utils.ConsoleThreadFactory; import com.vip.saturn.job.console.utils.JobNodePath; import com.vip.saturn.job.console.utils.StatisticsTableKeyConstant; import com.vip.saturn.job.integrate.service.ReportAlarmService; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpStatus; import org.apache.http.StatusLine; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; import java.io.IOException; import java.util.*; import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import java.util.concurrent.*; /** * @author timmy.hu */ public class StatisticsRefreshServiceImpl implements StatisticsRefreshService { private static final Logger log = LoggerFactory.getLogger(StatisticsRefreshServiceImpl.class); private static final int CONNECT_TIMEOUT_MS = 10000; private static final int SO_TIMEOUT_MS = 180_000; private static final int STAT_THREAD_NUM = 20; private Timer refreshStatisticsTimer; private Timer cleanAbnormalShardingCacheTimer; private Map abnormalShardingStateCache = new ConcurrentHashMap<>(); @Resource private SaturnStatisticsService saturnStatisticsService; @Resource private StatisticsPersistence statisticsPersistence; @Resource private SystemConfigService systemConfigService; @Resource private RegistryCenterService registryCenterService; @Resource private JobService jobService; @Resource private ReportAlarmService reportAlarmService; private ExecutorService statExecutorService; @Resource private DashboardService dashboardService; @PostConstruct public void init() { initStatExecutorService(); startRefreshStatisticsTimer(); startCleanAbnormalShardingCacheTimer(); } @PreDestroy public void destroy() { if (statExecutorService != null) { statExecutorService.shutdownNow(); } if (refreshStatisticsTimer != null) { refreshStatisticsTimer.cancel(); } if (cleanAbnormalShardingCacheTimer != null) { cleanAbnormalShardingCacheTimer.cancel(); } } private void initStatExecutorService() { if (statExecutorService != null) { statExecutorService.shutdownNow(); } ThreadPoolExecutor tp = new ThreadPoolExecutor(STAT_THREAD_NUM, STAT_THREAD_NUM, DashboardConstants.REFRESH_INTERVAL_IN_MINUTE + 1, TimeUnit.MINUTES, new LinkedBlockingQueue(), new ConsoleThreadFactory("dashboard-statistics-thread", true)); tp.allowCoreThreadTimeOut(true); statExecutorService = tp; } private void startRefreshStatisticsTimer() { TimerTask timerTask = new TimerTask() { @Override public void run() { try { log.info("start refresh statistics on timer"); Date start = new Date(); Collection zkClusterList = registryCenterService.getZkClusterList(); if (zkClusterList != null) { for (ZkCluster zkCluster : zkClusterList) { if (zkCluster.isOffline()) { log.info("zkcluster:{} is offline, skip statistics refresh.", zkCluster.getZkClusterKey()); continue; } if (registryCenterService.isDashboardLeader(zkCluster.getZkClusterKey())) { refreshStatistics2DB(zkCluster); } } } log.info("end refresh statistics on timer which takes {}ms", new Date().getTime() - start.getTime()); } catch (Throwable t) { log.error(t.getMessage(), t); } } }; refreshStatisticsTimer = new Timer("refresh-statistics-to-db-timer", true); refreshStatisticsTimer .scheduleAtFixedRate(timerTask, 1000L * 15, 1000L * 60 * DashboardConstants.REFRESH_INTERVAL_IN_MINUTE); } private void startCleanAbnormalShardingCacheTimer() { TimerTask timerTask = new TimerTask() { @Override public void run() { try { for (Entry entrySet : abnormalShardingStateCache.entrySet()) { AbnormalShardingState shardingState = entrySet.getValue(); if (shardingState.getAlertTime() + DashboardConstants.ALLOW_DELAY_MILLIONSECONDS * 2 < System .currentTimeMillis()) { abnormalShardingStateCache.remove(entrySet.getKey()); log.info("Clean AbnormalShardingCache with key: {}, alertTime: {}, zkNodeCVersion: {}: ", entrySet.getKey(), shardingState.getAlertTime(), shardingState.getZkNodeCVersion()); } } } catch (Throwable t) { log.error("Clean AbnormalShardingCache error", t); } } }; cleanAbnormalShardingCacheTimer = new Timer("clean-abnormalShardingCache-timer", true); cleanAbnormalShardingCacheTimer .scheduleAtFixedRate(timerTask, 0, DashboardConstants.ALLOW_DELAY_MILLIONSECONDS); } @Override public void refresh(String zkClusterKey, boolean isForce) throws SaturnJobConsoleException { if (isForce) { refresh(zkClusterKey); return; } boolean isSameIdc = ZkClusterMappingUtils.isCurrentConsoleInTheSameIdc(systemConfigService, zkClusterKey); if (isSameIdc) { log.info("the zk and the console are in the same IDC, refreshStatistics in the current Console"); refresh(zkClusterKey); } else { log.info("the zk and the console are in different IDC, forward the refresh request to remote console"); try { forwardDashboardRefreshToRemote(zkClusterKey); } catch (SaturnJobConsoleException e) { log.warn("remote refresh request error, so refreshStatistics in the current Console, cause by {}", e); refresh(zkClusterKey); } } } private void refresh(String zkClusterKey) throws SaturnJobConsoleException { ZkCluster zkCluster = registryCenterService.getZkCluster(zkClusterKey); if (zkCluster != null) { refreshStatistics2DB(zkCluster); } else { throw new SaturnJobConsoleException("zk cluster not found by zkClusterKey:" + zkClusterKey); } } protected void postRefreshStatistics2DB(StatisticsModel statisticsModel, ZkCluster zkCluster) { statisticsModel.getOutdatedNoRunningJobAnalyzer().reportAlarmOutdatedNoRunningJobs(); calculateDashboardHistory(statisticsModel, zkCluster); } private void calculateDashboardHistory(StatisticsModel statisticsModel, ZkCluster zkCluster) { List dashboardHistories = new ArrayList<>(); Date currentDate = new Date(); calculateRunTimes(statisticsModel, zkCluster, dashboardHistories, currentDate); calculateContainerCount(statisticsModel, zkCluster, dashboardHistories, currentDate); calculateJobCount(statisticsModel, zkCluster, dashboardHistories, currentDate); calculateDomainCount(statisticsModel, zkCluster, dashboardHistories, currentDate); dashboardService.batchSaveDashboardHistory(dashboardHistories); } private void calculateDomainCount(StatisticsModel statisticsModel, ZkCluster zkCluster, List dashboardHistories, Date currentDate) { Map domainContent = new HashMap<>(1); int domainCount = registryCenterService.domainCount(zkCluster.getZkClusterKey()); domainContent.put("domainCount", domainCount); DashboardHistory domainHistory = new DashboardHistory(zkCluster.getZkClusterKey(), DashboardServiceImpl.DashboardType.DOMAIN.name(), DashboardServiceImpl.DashboardTopic.DOMAIN_COUNT.name(), JSON.toJSONString(domainContent), currentDate); dashboardHistories.add(domainHistory); } private void calculateJobCount(StatisticsModel statisticsModel, ZkCluster zkCluster, List dashboardHistories, Date currentDate) { Map jobContent = new HashMap<>(1); int jobCount = statisticsModel.getJobStatisticsAnalyzer().getJobList().size(); jobContent.put("jobCount", jobCount); DashboardHistory jobHistory = new DashboardHistory(zkCluster.getZkClusterKey(), DashboardServiceImpl.DashboardType.JOB.name(), DashboardServiceImpl.DashboardTopic.JOB_COUNT.name(), JSON.toJSONString(jobContent), currentDate); dashboardHistories.add(jobHistory); } private void calculateContainerCount(StatisticsModel statisticsModel, ZkCluster zkCluster, List dashboardHistories, Date currentDate) { Map executorContent = new HashMap<>(2); int inDocker = statisticsModel.getExecutorInfoAnalyzer().getExeInDocker(); int notInDocker = statisticsModel.getExecutorInfoAnalyzer().getExeNotInDocker(); executorContent.put("dockerCount", inDocker); executorContent.put("otherCount", notInDocker); DashboardHistory executorHistory = new DashboardHistory(zkCluster.getZkClusterKey(), DashboardServiceImpl.DashboardType.EXECUTOR.name(), DashboardServiceImpl.DashboardTopic.EXECUTOR_COUNT.name(), JSON.toJSONString(executorContent), currentDate); dashboardHistories.add(executorHistory); } private void calculateRunTimes(StatisticsModel statisticsModel, ZkCluster zkCluster, List dashboardHistories, Date currentDate) { long successCount = statisticsModel.getZkClusterDailyCountAnalyzer().getTotalCount(); long failCount = statisticsModel.getZkClusterDailyCountAnalyzer().getErrorCount(); Map content = new HashMap<>(2); content.put("count", successCount); content.put("failCount", failCount); DashboardHistory allDomainHistory = new DashboardHistory(zkCluster.getZkClusterKey(), DashboardServiceImpl.DashboardType.DOMAIN.name(), DashboardServiceImpl.DashboardTopic.DOMAIN_OVERALL_COUNT.name(), JSON.toJSONString(content), currentDate); dashboardHistories.add(allDomainHistory); } private void forwardDashboardRefreshToRemote(String zkClusterKey) throws SaturnJobConsoleException { CloseableHttpClient httpClient = null; String url = null; try { String domain = ZkClusterMappingUtils.getConsoleDomainByZkClusterKey(systemConfigService, zkClusterKey); if (StringUtils.isBlank(domain)) { throw new SaturnJobConsoleException( String.format("The console domain is not found by zkClusterKey(%s)", zkClusterKey)); } url = domain + "/rest/v1/dashboard/refresh?zkClusterKey=" + zkClusterKey; httpClient = HttpClientBuilder.create().build(); HttpPost httpPost = createHttpRequest(url); CloseableHttpResponse httpResponse = httpClient.execute(httpPost); handleResponse(url, httpResponse); } catch (SaturnJobConsoleException se) { throw se; } catch (Exception e) { throw new SaturnJobConsoleException("Fail to execute forwardDashboardRefreshToRemote, Url: " + url, e); } finally { IOUtils.closeQuietly(httpClient); } } private void handleResponse(String url, CloseableHttpResponse httpResponse) throws IOException, SaturnJobConsoleException { StatusLine statusLine = httpResponse.getStatusLine(); Integer statusCode = statusLine != null ? statusLine.getStatusCode() : null; log.info("the statusCode of remote request is:" + statusCode); if (statusLine != null && statusCode == HttpStatus.SC_OK) { String takeTime = IOUtils.toString(httpResponse.getEntity().getContent(), "UTF-8"); log.info("forwardDashboardRefreshToRemote Url " + url + ", spend time:" + takeTime); return; } if (statusCode >= HttpStatus.SC_BAD_REQUEST && statusCode <= HttpStatus.SC_INTERNAL_SERVER_ERROR) { String responseBody = EntityUtils.toString(httpResponse.getEntity()); if (StringUtils.isNotBlank(responseBody)) { String errMsg = JSONObject.parseObject(responseBody).getString("message"); throw new SaturnJobConsoleException(errMsg); } else { throw new SaturnJobConsoleException("internal server error"); } } else { throw new SaturnJobConsoleException("unexpected status returned from Saturn Server."); } } private HttpPost createHttpRequest(String url) { HttpPost httpPost = new HttpPost(url); RequestConfig cfg = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT_MS).setSocketTimeout(SO_TIMEOUT_MS) .build(); httpPost.setConfig(cfg); return httpPost; } private void refreshStatistics2DB(ZkCluster zkCluster) { log.info("start refresh statistics by zkClusterKey:{}", zkCluster.getZkClusterKey()); Date start = new Date(); StatisticsModel statisticsModel = initStatisticsModel(); List> callableList = getStatCallableList(zkCluster, statisticsModel); try { if (callableList != null && !callableList.isEmpty()) { statExecutorService.invokeAll(callableList); } statisticsPersistence.persist(statisticsModel, zkCluster); postRefreshStatistics2DB(statisticsModel, zkCluster); } catch (InterruptedException e) { log.warn("the refreshStatistics2DB thread is interrupted", e); Thread.currentThread().interrupt(); } log.info("end refresh statistics by zkClusterKey:{}, takes {}", zkCluster.getZkClusterKey(), new Date().getTime() - start.getTime()); } private List> getStatCallableList(final ZkCluster zkCluster, final StatisticsModel statisticsModel) { List> callableList = Lists.newArrayList(); for (final RegistryCenterConfiguration config : zkCluster.getRegCenterConfList()) { // 过滤非当前zk连接 if (!zkCluster.getZkAddr().equals(config.getZkAddressList())) { continue; } Callable callable = new Callable() { @Override public Boolean call() throws Exception { return analyzeStatistics(statisticsModel, zkCluster, config); } }; callableList.add(callable); } return callableList; } private boolean analyzeStatistics(StatisticsModel statisticsModel, ZkCluster zkCluster, RegistryCenterConfiguration config) { String namespace = config.getNamespace(); try { DomainStatistics domain = statisticsModel.getDomainStatisticsAnalyzer().initDomain(zkCluster, config); CuratorRepository.CuratorFrameworkOp curatorFrameworkOp = registryCenterService .getCuratorFrameworkOp(namespace); List oldAbnormalJobs = getOldAbnormalJobs(zkCluster); List oldTimeout4AlarmJobs = getOldTimeout4AlarmJobs(zkCluster); statisticsModel.analyzeExecutor(curatorFrameworkOp, config); List jobs = jobService.getUnSystemJobNames(config.getNamespace()); for (String job : jobs) { if (!curatorFrameworkOp.checkExists(JobNodePath.getConfigNodePath(job))) { continue; } try { Boolean localMode = Boolean .valueOf(curatorFrameworkOp.getData(JobNodePath.getConfigNodePath(job, "localMode"))); JobStatistics jobStatistics = statisticsModel .analyzeJobStatistics(curatorFrameworkOp, job, localMode, config); String jobDegree = String.valueOf(jobStatistics.getJobDegree()); statisticsModel.analyzeShardingCount(curatorFrameworkOp, domain); if (!localMode) {// 非本地作业才参与判断 statisticsModel.analyzeOutdatedNoRunningJob(curatorFrameworkOp, oldAbnormalJobs, job, jobDegree, config); } statisticsModel .analyzeTimeout4AlarmJob(curatorFrameworkOp, oldTimeout4AlarmJobs, job, jobDegree, config); statisticsModel.analyzeUnableFailoverJob(curatorFrameworkOp, job, jobDegree, config); } catch (Exception e) { log.info(String.format("analyzeStatistics namespace(%s) jobName(%s) error", namespace, job), e); } } statisticsModel.analyzeProcessCount(domain, jobs, config); } catch (Exception e) { log.info(String.format("analyzeStatistics namespace(%s) error", namespace), e); return false; } return true; } private List getOldAbnormalJobs(ZkCluster zkCluster) { SaturnStatistics saturnStatistics = saturnStatisticsService .findStatisticsByNameAndZkList(StatisticsTableKeyConstant.UNNORMAL_JOB, zkCluster.getZkAddr()); List oldAbnormalJobs = new ArrayList<>(); if (saturnStatistics != null) { String result = saturnStatistics.getResult(); if (StringUtils.isNotBlank(result)) { oldAbnormalJobs = JSON.parseArray(result, AbnormalJob.class); } } return oldAbnormalJobs; } private List getOldTimeout4AlarmJobs(ZkCluster zkCluster) { SaturnStatistics saturnStatistics = saturnStatisticsService .findStatisticsByNameAndZkList(StatisticsTableKeyConstant.TIMEOUT_4_ALARM_JOB, zkCluster.getZkAddr()); List oldTimeout4AlarmJobs = new ArrayList<>(); if (saturnStatistics != null) { String result = saturnStatistics.getResult(); if (StringUtils.isNotBlank(result)) { oldTimeout4AlarmJobs = JSON.parseArray(result, Timeout4AlarmJob.class); } } return oldTimeout4AlarmJobs; } protected StatisticsModel initStatisticsModel() { StatisticsModel statisticsModel = new StatisticsModel(); ExecutorInfoAnalyzer executorInfoAnalyzer = new ExecutorInfoAnalyzer(); statisticsModel.setExecutorInfoAnalyzer(executorInfoAnalyzer); OutdatedNoRunningJobAnalyzer outdatedNoRunningJobAnalyzer = new OutdatedNoRunningJobAnalyzer(); outdatedNoRunningJobAnalyzer.setAbnormalShardingStateCache(abnormalShardingStateCache); outdatedNoRunningJobAnalyzer.setReportAlarmService(reportAlarmService); outdatedNoRunningJobAnalyzer.setJobService(jobService); statisticsModel.setOutdatedNoRunningJobAnalyzer(outdatedNoRunningJobAnalyzer); UnableFailoverJobAnalyzer unableFailoverJobAnalyzer = new UnableFailoverJobAnalyzer(); unableFailoverJobAnalyzer.setJobService(jobService); statisticsModel.setUnableFailoverJobAnalyzer(unableFailoverJobAnalyzer); Timeout4AlarmJobAnalyzer timeout4AlarmJobAnalyzer = new Timeout4AlarmJobAnalyzer(); timeout4AlarmJobAnalyzer.setReportAlarmService(reportAlarmService); statisticsModel.setTimeout4AlarmJobAnalyzer(timeout4AlarmJobAnalyzer); JobStatisticsAnalyzer jobStatisticsAnalyzer = new JobStatisticsAnalyzer(); statisticsModel.setJobStatisticsAnalyzer(jobStatisticsAnalyzer); DomainStatisticsAnalyzer domainStatisticsAnalyzer = new DomainStatisticsAnalyzer(); statisticsModel.setDomainStatisticsAnalyzer(domainStatisticsAnalyzer); ZkClusterDailyCountAnalyzer zkClusterDailyCountAnalyzer = new ZkClusterDailyCountAnalyzer(); statisticsModel.setZkClusterDailyCountAnalyzer(zkClusterDailyCountAnalyzer); return statisticsModel; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy