content: package com.sohu.cache.inspect.impl;
  
  import com.sohu.cache.alert.impl.BaseAlertService;
  import com.sohu.cache.entity.AppDesc;
  import com.sohu.cache.entity.InstanceInfo;
  import com.sohu.cache.entity.InstanceStats;
  import com.sohu.cache.inspect.InspectParamEnum;
  import com.sohu.cache.inspect.Inspector;
  import com.sohu.cache.stats.app.AppStatsCenter;
  import com.sohu.cache.stats.instance.InstanceStatsCenter;
  import com.sohu.cache.util.ConstUtils;
  import com.sohu.cache.util.TypeUtil;
  import com.sohu.cache.web.vo.AppDetailVO;
  
  import org.apache.commons.collections.CollectionUtils;
  import org.apache.commons.collections.MapUtils;
  
  import java.util.Arrays;
  import java.util.List;
  import java.util.Map;
  
  /**
   * 应用客户端连接监控
   * 
   * @author leifu
   * @Date 2016年6月16日
   * @Time 上午9:44:34
   */
  public class AppClientConnInspector extends BaseAlertService implements Inspector {
  
      /**
       * app统计相关
       */
      private AppStatsCenter appStatsCenter;
  
      /**
       * 实例统计相关
       */
      private InstanceStatsCenter instanceStatsCenter;
  
      @Override
      public boolean inspect(Map<InspectParamEnum, Object> paramMap) {
          Long appId = MapUtils.getLong(paramMap, InspectParamEnum.SPLIT_KEY);
          AppDetailVO appDetailVO = appStatsCenter.getAppDetail(appId);
          if (appDetailVO == null) {
              logger.warn("appId {} appDetailVO is empty", appId);
              return true;
          }
          List<InstanceInfo> appInstanceInfoList = (List<InstanceInfo>) paramMap.get(InspectParamEnum.INSTANCE_LIST);
          if (CollectionUtils.isEmpty(appInstanceInfoList)) {
              logger.warn("appId {} instanceList is empty", appId);
              return true;
          }
          // 报警阀值
          int appClientConnThreshold = getClientConnThreshold(appDetailVO.getAppDesc());
          int appClientConnNum = appDetailVO.getConn();
          // 阀值乘以分片个数
          int instanceCount = appInstanceInfoList.size();
          if (appClientConnNum > appClientConnThreshold * instanceCount) {
              alertAppClientConn(appDetailVO, appClientConnThreshold, instanceCount);
          } else {
              for (InstanceInfo instanceInfo : appInstanceInfoList) {
                  if (instanceInfo == null) {
                      continue;
                  }
                  if (instanceInfo.isOffline()) {
                      continue;
                  }
                  if (!TypeUtil.isRedisType(instanceInfo.getType())) {
                      continue;
                  }
                  // 忽略sentinel观察者
                  if (TypeUtil.isRedisSentinel(instanceInfo.getType())) {
                      continue;
                  }
                  long instanceId = instanceInfo.getId();
                  InstanceStats instanceStats = instanceStatsCenter.getInstanceStats(instanceId);
                  if (instanceStats == null) {
                      continue;
                  }
                  double instanceClientConnNum = instanceStats.getCurrConnections();
                  // 大于标准值
                  if (instanceClientConnNum > appClientConnThreshold) {
                      alertInstanceClientConn(instanceStats, appDetailVO, appClientConnThreshold);
                  }
              }
          }
          return true;
      }
  
      /**
       * 获取报警阀值(如果用户预设超过系统预设，以系统为准，反之以用户为准)
       * @param appDesc
       * @return
       */
      private int getClientConnThreshold(AppDesc appDesc) {
          int userClientConnThreshold = appDesc.getClientConnAlertValue();
          int systemClientConnThreshold =  ConstUtils.APP_CLIENT_CONN_THRESHOLD;
          return userClientConnThreshold > systemClientConnThreshold ? systemClientConnThreshold : userClientConnThreshold;
      }
  
      /**
       * 应用连接数报警
       * @param appDetailVO
       * @param appClientConnThreshold
       * @param instanceCount
       */
      private void alertAppClientConn(final AppDetailVO appDetailVO, final int appClientConnThreshold, final int instanceCount) {
          AppDesc appDesc = appDetailVO.getAppDesc();
          String content = String.format("应用(%s)-客户端连接数报警-预设阀值每个分片为%s-现已达到%s(分片个数:%s)-请及时关注",
                  appDesc.getAppId(), appClientConnThreshold, appDetailVO.getConn(), instanceCount);
          String title = "CacheCloud系统-客户端连接数报警";
          logger.warn("app title {}", title);
          logger.warn("app content {}", content);
          emailComponent.sendMail(title, content, appDetailVO.getEmailList(),
                  Arrays.asList(emailComponent.getAdminEmail().split(ConstUtils.COMMA)));
      }
  
      /**
       * 单个分片连接数报警
       * @param instanceStats
       * @param appDetailVO
       * @param appClientConnThreshold
       */
      private void alertInstanceClientConn(final InstanceStats instanceStats, final AppDetailVO appDetailVO,
              final int appClientConnThreshold) {
          String instanceHostPort = instanceStats.getIp() + ":" + instanceStats.getPort();
          String content = String.format("分片(%s,应用(%s))客户端连接数报警-预设%s-现已达到%s-请及时关注", instanceHostPort,
                  instanceStats.getAppId(), appClientConnThreshold, instanceStats.getCurrConnections());
          String title = "CacheCloud系统-分片客户端连接数报警";
          logger.warn("instance title {}", title);
          logger.warn("instace content {}", content);
          emailComponent.sendMail(title, content, appDetailVO.getEmailList(),
                  Arrays.asList(emailComponent.getAdminEmail().split(ConstUtils.COMMA)));
      }
  
      public void setAppStatsCenter(AppStatsCenter appStatsCenter) {
          this.appStatsCenter = appStatsCenter;
      }
  
      public void setInstanceStatsCenter(InstanceStatsCenter instanceStatsCenter) {
          this.instanceStatsCenter = instanceStatsCenter;
      }
  
  }
  