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

com.alibaba.csp.ahas.sentinel.DefaultSentinelSdkService Maven / Gradle / Ivy

There is a newer version: 1.11.7
Show newest version
package com.alibaba.csp.ahas.sentinel;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import com.alibaba.csp.ahas.sentinel.acm.SentinelSdkInitService;
import com.alibaba.csp.ahas.sentinel.acm.SentinelSdkInitServiceManager;
import com.alibaba.csp.sentinel.Constants;
import com.alibaba.csp.sentinel.adapter.agent.AgentCompatibilityUtils;
import com.alibaba.csp.sentinel.command.handler.*;
import com.alibaba.csp.sentinel.command.handler.cluster.FetchClusterModeCommandHandler;
import com.alibaba.csp.sentinel.command.handler.cluster.ModifyClusterModeCommandHandler;
import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.init.InitOrder;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.setting.handler.FallbackBehaviorCheckCommandHandler;
import com.alibaba.csp.sentinel.spi.SpiOrder;
import com.alibaba.csp.sentinel.util.StringUtil;

import com.taobao.csp.ahas.service.api.constant.AppConstants;
import com.taobao.csp.ahas.service.api.transport.TransportService;
import com.taobao.csp.ahas.service.component.AgwComponent;
import com.taobao.csp.ahas.service.component.AgwComponentManager;
import com.taobao.csp.ahas.service.component.AgwComponentType;
import com.taobao.csp.ahas.service.component.AgwProductCode;
import com.taobao.csp.ahas.service.exception.SentinelDisabledException;
import com.taobao.csp.ahas.service.init.AhasInitFunc;
import com.taobao.csp.ahas.transport.api.Response;
import com.taobao.csp.ahas.transport.api.ServiceConstants.Sentinel;

import static com.alibaba.csp.sentinel.init.InitOrder.HIGHEST_PRECEDENCE;

/**
 * @author changjun.xcj
 * @author leyou
 */
@SpiOrder(-10000)
@InitOrder(HIGHEST_PRECEDENCE)
public class DefaultSentinelSdkService implements InitFunc {

    private static final AgwComponent agwComponent = AgwComponentManager.getAgwComponent();

    private static final AtomicBoolean isAhasInit = new AtomicBoolean(false);
    private static final AtomicBoolean ahasInitSuccess = new AtomicBoolean(false);

    private static final ExecutorService INIT_EXECUTOR =
        Executors.newSingleThreadExecutor(new NamedThreadFactory("AhasSentinelSdkService-init-thread", true));
    private static ScheduledExecutorService hbScheduler = new ScheduledThreadPoolExecutor(2,
        new NamedThreadFactory("ahas-sentinel-heartbeat-send-task", true), new DiscardOldestPolicy());

    private static DefaultSentinelSdkService defaultSentinelSdkService;

    private static String ahasSdkVersion;

    public static synchronized DefaultSentinelSdkService getInstance() {
        if (defaultSentinelSdkService == null) {
            defaultSentinelSdkService = new DefaultSentinelSdkService();
        }
        return defaultSentinelSdkService;
    }

    public DefaultSentinelSdkService() {
        // Agent存在,SDK中不再重复初始化
        // 注意:HeartBeatSender 不在此处初始化,而是由 Sentinel SPI 机制加载
        if (AgentCompatibilityUtils.isAgentPresent()) {
            return;
        }

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    initAhasTransport();
                } catch (Throwable e) {
                    RecordLog.warn("[DefaultSentinelSdkService] Failed to initialize AHAS transport", e);
                    System.err.println("ERROR: AHAS init fail");
                }
            }
        };
        INIT_EXECUTOR.submit(runnable);
    }

    @Override
    public void init() throws Exception {
        // Agent存在,SDK中不再重复初始化
        if (AgentCompatibilityUtils.isAgentPresent()) {
            return;
        }
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                if (!ahasInitSuccess.get()) {
                    return;
                }
                try {
                    SentinelSdkInitService sentinelSdkInitService = SentinelSdkInitServiceManager
                        .getInitService(agwComponent.getClientInfoService());
                    sentinelSdkInitService.init(ahasSdkVersion);
                } catch (Throwable throwable) {
                    RecordLog.warn("[DefaultSentinelSdkService] Init AHAS Sentinel or ACM error", throwable);
                }
            }
        };
        INIT_EXECUTOR.submit(runnable);
    }

    private void initAhasTransport() throws Exception {
        if (!isAhasInit.compareAndSet(false, true)) {
            return;
        }

        // Register command handler in advance.
        registerCommandHandler();

        // Set client version manually.
        // TODO always remember keep the version same as in pom!!!
        // 为了防止 ahas-sentinel-client 被用户 shade 后取得版本不对,这里先 hard code. 切记记得版本更新的时候同步改掉!!!
        ahasSdkVersion = "1.10.10_1.10.10";
        System.setProperty(AppConstants.AHAS_VERSION, ahasSdkVersion);

        // skip init AHAS proxy if ahas.inner.agw.disable has been set.
        if (AgwComponentManager.isInner() && System.getProperty(AppConstants.AHAS_INNER_AGW_DISABLE) != null) {
            RecordLog.info("ahas.inner.agw.disable detected (inner env), so AHAS agw module will not be initialized");
            ahasInitSuccess.set(true);
            return;
        }

        int times = 0;
        while (true) {
            try {
                ((AhasInitFunc) agwComponent.getClientInfoService()).init("JAVA_SDK", null);
                agwComponent.getTransportService().init(agwComponent.getClientInfoService(),AgwProductCode.SENTINEL);
                agwComponent.getHeartbeatService().init(agwComponent);
                break;
            } catch (Throwable throwable) {
                if (throwable instanceof SentinelDisabledException) {
                    RecordLog.warn("[DefaultSentinelSdkService] AHAS Sentinel disabled, stop connect to server.");
                    throw new SentinelDisabledException("AHAS Sentinel disabled");
                } else {
                    RecordLog.error("[DefaultSentinelSdkService] Failed to init AHAS transport, region={}, "
                            + "will retry (current {}) ", agwComponent.getClientInfoService().getRegionId(), times,
                        throwable);
                    times++;
                    if (AgwComponentManager.isInner() && times > 3) {
                        // Proxy transport is not mandatory in inner mode.
                        AhasGlobalContext.setClientInfoService(agwComponent.getClientInfoService());
                        ahasInitSuccess.set(true);
                        RecordLog.warn("AHAS transport module will be skipped during Sentinel initialization");
                        return;
                    }

                    try {
                        Thread.sleep(1000 * 10);
                    } catch (Exception ignore) {
                    }
                }
            }
        }
        RecordLog.info("[DefaultSentinelSdkService] AHAS gateway host: " +
            agwComponent.getClientInfoService().getGatewayHost() +
            ", port:" + agwComponent.getClientInfoService().getGatewayPort());
        AhasGlobalContext.setClientInfoService(agwComponent.getClientInfoService());

        // Since 1.9.2,AHAS SDK 心跳机制不再依赖 Sentinel 本身的 HeartbeatSender SPI,以避免初始化顺序导致读不到配置的问题.
        initHeartbeatTask();

        ahasInitSuccess.set(true);
        RecordLog.info("AHAS transport has been initialized successfully");
    }

    private String getAhasVersion(String defaultVersion) {
        String gwVersion = defaultVersion;
        try {
            String version = DefaultSentinelSdkService.class.getPackage().getImplementationVersion();
            if (StringUtil.isNotBlank(version)) {
                gwVersion = version;
            }
        } catch (Throwable e) {
            RecordLog.warn("[DefaultSentinelSdkService] Using default AHAS version, ignore exception", e);
        }
        return gwVersion;
    }

    /**
     * Get whole version of the SDK.
     *
     * @param ahasVersion AHAS SDK version
     * @return sentinel-core version + AHAS SDK version
     */
    private String getWholeVersion(/*@Valid*/ String ahasVersion) {
        String coreVersion = Constants.SENTINEL_VERSION;
        String wholeVersion = coreVersion + "_" + ahasVersion;
        RecordLog.info("[DefaultSentinelSdkService] wholeVersion: " + wholeVersion);
        return wholeVersion;
    }

    /**
     * Register Sentinel handler to {@link TransportService}
     */
    private void registerCommandHandler() {
        agwComponent.getTransportService().registerHandler(Sentinel.CLUSTER_NODE.getHandlerName(),
            new SentinelRequestHandler(new FetchSimpleClusterNodeCommandHandler()));
        agwComponent.getTransportService().registerHandler(Sentinel.JSON_TREE.getHandlerName(),
            new SentinelRequestHandler(new FetchJsonTreeCommandHandler()));
        agwComponent.getTransportService().registerHandler(Sentinel.METRIC.getHandlerName(),
            new SentinelRequestHandler(new SendMetricCommandHandler()));
        agwComponent.getTransportService().registerHandler(Sentinel.GET_RULES.getHandlerName(),
            new SentinelRequestHandler(new FetchActiveRuleCommandHandler()));
        agwComponent.getTransportService().registerHandler(Sentinel.VERSION.getHandlerName(),
            new SentinelRequestHandler(new VersionCommandHandler()));
        agwComponent.getTransportService().registerHandler(Sentinel.GET_SWITCH.getHandlerName(),
            new SentinelRequestHandler(new OnOffGetCommandHandler()));
        agwComponent.getTransportService().registerHandler(Sentinel.SET_SWITCH.getHandlerName(),
            new SentinelRequestHandler(new OnOffSetCommandHandler()));

        // Cluster handlers.
        agwComponent.getTransportService().registerHandler(Sentinel.SET_CLUSTER_MODE.getHandlerName(),
            new SentinelRequestHandler(new ModifyClusterModeCommandHandler()));
        agwComponent.getTransportService().registerHandler(Sentinel.GET_CLUSTER_MODE.getHandlerName(),
            new SentinelRequestHandler(new FetchClusterModeCommandHandler()));

        // (since 1.9.5)
        agwComponent.getTransportService().registerHandler(Sentinel.CHECK_FALLBACK_BEHAVIOR.getHandlerName(),
                new SentinelRequestHandler(new FallbackBehaviorCheckCommandHandler()));

        // Add customized command handlers for PRIVATE_CLOUD mode.
        if (AgwComponentType.PRIVATE_CLOUD.getType() == SentinelSdkInitServiceManager.getMode()) {
            agwComponent.getTransportService().registerHandler(Sentinel.EXECUTE_SHELL_COMMAND.getHandlerName(),
                new SentinelRequestHandler(new ExecuteShellCommandHandler()));
        }
    }

    private void initHeartbeatTask() {
        int ahasHbIntervalMs = agwComponent.getClientInfoService().getHeartbeatRate() * 1000;
        int intervalMs = ahasHbIntervalMs > 0 ? ahasHbIntervalMs : 8000;

        if (AgwComponentManager.isInner() && agwComponent.getClientInfoService().getUserId() == null) {
            // This indicates that the transport module was not initialized successfully.
            return;
        }
        // 这里不再依赖 Sentinel 本身的 HeartbeatSender 模块.
        hbScheduler.scheduleAtFixedRate(new Runnable() {
            public void run() {
                try {
                    sendHeartbeat();
                } catch (Throwable var2) {
                    RecordLog.warn("[HeartbeatSender] Send heartbeat error", var2);
                }

            }
        }, 3000L, intervalMs, TimeUnit.MILLISECONDS);
        RecordLog.info("AHAS Sentinel heartbeat task started, interval={}ms", intervalMs);
    }

    public boolean sendHeartbeat() throws Exception {
        if (!ahasInitSuccess.get() || agwComponent.getClientInfoService().getSentinalDisable() == 1) {
            return false;
        }
        if (AgwComponentManager.isInner() && agwComponent.getClientInfoService().getUserId() == null) {
            // This indicates that the transport module was not initialized successfully.
            return false;
        }
        Response mapResponse = agwComponent.getHeartbeatService().sendHeartbeat(AgwProductCode.SENTINEL);
        if (!mapResponse.isSuccess()) {
            throw new RuntimeException(mapResponse.toString());
        }
        return mapResponse.isSuccess();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy