/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.alibaba.jstorm.daemon.supervisor; import java.io.IOException; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import backtype.storm.utils.LocalState; import backtype.storm.utils.Utils; import com.alibaba.jstorm.client.ConfigExtension; import com.alibaba.jstorm.cluster.Common; import com.alibaba.jstorm.daemon.worker.LocalAssignment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import backtype.storm.Config; import com.alibaba.jstorm.callback.RunnableCallback; import com.alibaba.jstorm.cluster.StormClusterState; import com.alibaba.jstorm.cluster.StormConfig; import com.alibaba.jstorm.utils.JStormServerUtils; import com.alibaba.jstorm.utils.JStormUtils; import com.alibaba.jstorm.utils.TimeUtils; /** * supervisor Heartbeat, just write SupervisorInfo to ZK * * @author Johnfang (xiaojian.fxj@alibaba-inc.com) */ class Heartbeat extends RunnableCallback { private static Logger LOG = LoggerFactory.getLogger(Heartbeat.class); private static final int CPU_THREADHOLD = 4; private static final long MEM_THREADHOLD = 8 * JStormUtils.SIZE_1_G; private Map<Object, Object> conf; private StormClusterState stormClusterState; private String supervisorId; private String myHostName; private final int startTime; private final int frequence; private SupervisorInfo supervisorInfo; private AtomicBoolean hbUpdateTrigger; //protected HealthStatus oldHealthStatus; //protected volatile HealthStatus healthStatus; protected MachineCheckStatus oldCheckStatus; protected volatile MachineCheckStatus checkStatus; private LocalState localState; /** * @param conf * @param stormClusterState * @param supervisorId * @param status */ @SuppressWarnings({"rawtypes", "unchecked"}) public Heartbeat(Map conf, StormClusterState stormClusterState, String supervisorId, LocalState localState, MachineCheckStatus status) { String myHostName = JStormServerUtils.getHostName(conf); this.stormClusterState = stormClusterState; this.supervisorId = supervisorId; this.conf = conf; this.myHostName = myHostName; this.startTime = TimeUtils.current_time_secs(); this.frequence = JStormUtils.parseInt(conf.get(Config.SUPERVISOR_HEARTBEAT_FREQUENCY_SECS)); this.hbUpdateTrigger = new AtomicBoolean(true); this.localState = localState; this.checkStatus = status; oldCheckStatus = new MachineCheckStatus(); oldCheckStatus.SetType(this.checkStatus.getType()); initSupervisorInfo(conf); LOG.info("Successfully init supervisor heartbeat thread, " + supervisorInfo); } private void initSupervisorInfo(Map conf) { List<Integer> portList = JStormUtils.getSupervisorPortList(conf); if (!StormConfig.local_mode(conf)) { try { boolean isLocalIP = myHostName.equals("127.0.0.1") || myHostName.equals("localhost"); if (isLocalIP) { throw new Exception("the hostname which supervisor get is localhost"); } } catch (Exception e1) { LOG.error("get supervisor host error!", e1); throw new RuntimeException(e1); } Set<Integer> ports = JStormUtils.listToSet(portList); supervisorInfo = new SupervisorInfo(myHostName, supervisorId, ports, conf); } else { Set<Integer> ports = JStormUtils.listToSet(portList); supervisorInfo = new SupervisorInfo(myHostName, supervisorId, ports, conf); } supervisorInfo.setVersion(Utils.getVersion()); String buildTs = Utils.getBuildTime(); supervisorInfo.setBuildTs(buildTs); LOG.info("jstorm version:{}, build ts:{}", supervisorInfo.getVersion(), supervisorInfo.getBuildTs()); } @SuppressWarnings("unchecked") public void update() { supervisorInfo.setTimeSecs(TimeUtils.current_time_secs()); supervisorInfo.setUptimeSecs(TimeUtils.current_time_secs() - startTime); updateSupervisorInfo(); if (checkStatus.getType() == MachineCheckStatus.StatusType.warning || checkStatus.getType() == MachineCheckStatus.StatusType.error || checkStatus.getType() == MachineCheckStatus.StatusType.panic) { Set<Integer> ports = new HashSet<Integer>(); supervisorInfo.setWorkerPorts(ports); if (!checkStatus.equals(oldCheckStatus)) { LOG.warn("due to no enough resource, limit supervisor's ports and block scheduling"); oldCheckStatus.SetType(checkStatus.getType()); } } try { stormClusterState.supervisor_heartbeat(supervisorId, supervisorInfo); } catch (Exception e) { LOG.error("Failed to update SupervisorInfo to ZK", e); } } private void updateSupervisorInfo() { List<Integer> portList = calculatorAvailablePorts(); LOG.debug("portList : {}", portList); Set<Integer> ports = JStormUtils.listToSet(portList); supervisorInfo.setWorkerPorts(ports); } public MachineCheckStatus getCheckStatus() { return checkStatus; } @Override public Object getResult() { return frequence; } @Override public void run() { boolean updateHb = hbUpdateTrigger.getAndSet(false); if (updateHb) { update(); } } public int getStartTime() { return startTime; } public SupervisorInfo getSupervisorInfo() { return supervisorInfo; } public void updateHbTrigger(boolean update) { hbUpdateTrigger.set(update); } private List<Integer> calculatorAvailablePorts() { List<Integer> defaultPortList = JStormUtils.getSupervisorPortList(conf); double cpuUsage = JStormUtils.getTotalCpuUsage(); int reserveCpuUsage = ConfigExtension.getStormMachineReserveCpuPercent(conf); if (cpuUsage <= 0.0 || !ConfigExtension.isSupervisorEnableAutoAdjustSlots(conf)) { return defaultPortList; } long freeMemory = JStormUtils.getFreePhysicalMem() * 1024L; long reserveMemory = ConfigExtension.getStormMachineReserveMem(conf); if (freeMemory < reserveMemory) { List<Integer> list = null; try { list = getLocalAssignmentPortList(); } catch (IOException e) { return defaultPortList; } if (list == null) return new ArrayList<Integer>(); return list; } if (cpuUsage > (100D - reserveCpuUsage)) { List<Integer> list = null; try { list = getLocalAssignmentPortList(); } catch (IOException e) { return defaultPortList; } if (list == null) return new ArrayList<Integer>(); return list; } Long conversionAvailableCpuNum = Math.round((100 - cpuUsage) / 100 * JStormUtils.getNumProcessors()); Long availablePhysicalMemorySize = freeMemory - reserveMemory; int portNum = JStormUtils.getSupervisorPortNum( conf, conversionAvailableCpuNum.intValue(), availablePhysicalMemorySize, true); List<Integer> portList = new ArrayList<>(); portList.addAll(defaultPortList); List<Integer> usedList = null; try { usedList = getLocalAssignmentPortList(); } catch (Exception e) { return defaultPortList; } portList.removeAll(usedList); Collections.sort(portList); //Collections.sort(usedList); if (portNum >= portList.size()) { return defaultPortList; } else { List<Integer> reportPortList = new ArrayList<Integer>(); reportPortList.addAll(usedList); for (int i = 1; i <= portNum; i++) { reportPortList.add(portList.get(i)); } return reportPortList; } } private List<Integer> getLocalAssignmentPortList() throws IOException { Map<Integer, LocalAssignment> localAssignment = null; try { localAssignment = (Map<Integer, LocalAssignment>) localState.get(Common.LS_LOCAL_ASSIGNMENTS); } catch (IOException e) { LOG.error("get LS_LOCAL_ASSIGNMENTS of localState failed ."); throw e; } if (localAssignment == null) { return null; } return JStormUtils.mk_list(localAssignment.keySet()); } }