sentinel使用总结

sentinel分为两个部分 控制台和客户端

1.可以不使用控制台直接使用客户端
2.生产环境中接入控制台还需注意实现规则持久化和权限控制

1)权限控制可设置白名单
2)sentinel提供多种数据源方式实现规则持久化,可使用本地文件(file),zk,redis,nacos等等。

接入流程

1:项目引入依赖包及配置(sentinel 1.4.0,引用依赖已整合)
zk拉模式

https://download.csdn.net/download/hsh124578/10856822

控制台改造

package com.taobao.csp.sentinel.dashboard.datasource.zookeeper;

import com.taobao.csp.sentinel.dashboard.client.SentinelApiClient;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * Zookeeper config sender
 *
 */
@Component
public class ZookeeperConfigSender {

    private static Logger logger = LoggerFactory.getLogger(ZookeeperConfigSender.class);

    private CuratorFramework getZkClient(){
        return CuratorFrameworkFactory.newClient(PathConstant.REMOTE_ADDRESS,
                new ExponentialBackoffRetry(3, 1000));
    }

    public void publishRule(String app,String ruleType, String data) throws Exception {
        logger.info("zk remoteAddress = " + PathConstant.REMOTE_ADDRESS);
        CuratorFramework zkClient = getZkClient();
        zkClient.start();
        String path;
        switch (ruleType){
            case SentinelApiClient.FLOW_RULE_TYPE:
                path = PathConstant.ROOT_PATH + app + PathConstant.FLOW_PATH;
                break;
            case SentinelApiClient.DEGRADE_RULE_TYPE:
                path = PathConstant.ROOT_PATH + app + PathConstant.DEGRADE_PATH;
                break;
            case SentinelApiClient.SYSTEM_RULE_TYPE:
                path = PathConstant.ROOT_PATH + app + PathConstant.SYSTEM_PATH;
                break;
            case SentinelApiClient.PARAM_RULE_TYPE:
                path = PathConstant.ROOT_PATH + app + PathConstant.PARAM_PATH;
                break;
            case SentinelApiClient.AUTHORITY_TYPE:
                path = PathConstant.ROOT_PATH + app + PathConstant.AUTHORITY_PATH;
                break;
            default:
                return;
        }
        Stat stat = zkClient.checkExists().forPath(path);
        if (stat == null) {
            zkClient.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, null);
        }
        zkClient.setData().forPath(path, data.getBytes());
        zkClient.close();
    }

}

/*
 * Copyright 1999-2018 Alibaba Group Holding 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.taobao.csp.sentinel.dashboard.client;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.command.vo.NodeVo;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.fastjson.JSON;

import com.taobao.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
import com.taobao.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
import com.taobao.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.taobao.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity;
import com.taobao.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity;
import com.taobao.csp.sentinel.dashboard.datasource.zookeeper.ZookeeperConfigSender;
import com.taobao.csp.sentinel.dashboard.domain.cluster.ClusterServerStateVO;
import com.taobao.csp.sentinel.dashboard.domain.cluster.ClusterStateSimpleEntity;
import com.taobao.csp.sentinel.dashboard.domain.cluster.config.ClusterClientConfig;
import com.taobao.csp.sentinel.dashboard.domain.cluster.config.ServerFlowConfig;
import com.taobao.csp.sentinel.dashboard.domain.cluster.config.ServerTransportConfig;
import com.taobao.csp.sentinel.dashboard.util.RuleUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Communicate with Sentinel client.
 *
 * @author leyou
 */
@Component
public class SentinelApiClient {

    private static Logger logger = LoggerFactory.getLogger(SentinelApiClient.class);

    private static final Charset DEFAULT_CHARSET = Charset.forName(SentinelConfig.charset());

    private static final String RESOURCE_URL_PATH = "jsonTree";
    private static final String CLUSTER_NODE_PATH = "clusterNode";
    private static final String GET_RULES_PATH = "getRules";
    private static final String SET_RULES_PATH = "setRules";
    private static final String GET_PARAM_RULE_PATH = "getParamFlowRules";
    private static final String SET_PARAM_RULE_PATH = "setParamFlowRules";

    private static final String FETCH_CLUSTER_MODE_PATH = "getClusterMode";
    private static final String MODIFY_CLUSTER_MODE_PATH = "setClusterMode";
    private static final String FETCH_CLUSTER_CLIENT_CONFIG_PATH = "cluster/client/fetchConfig";
    private static final String MODIFY_CLUSTER_CLIENT_CONFIG_PATH = "cluster/client/modifyConfig";

    private static final String FETCH_CLUSTER_SERVER_ALL_CONFIG_PATH = "cluster/server/fetchConfig";
    private static final String FETCH_CLUSTER_SERVER_BASIC_INFO_PATH = "cluster/server/info";

    private static final String MODIFY_CLUSTER_SERVER_TRANSPORT_CONFIG_PATH = "cluster/server/modifyTransportConfig";
    private static final String MODIFY_CLUSTER_SERVER_FLOW_CONFIG_PATH = "cluster/server/modifyFlowConfig";
    private static final String MODIFY_CLUSTER_SERVER_NAMESPACE_SET_PATH = "cluster/server/modifyNamespaceSet";

    public static final String FLOW_RULE_TYPE = "flow";
    public static final String DEGRADE_RULE_TYPE = "degrade";
    public static final String SYSTEM_RULE_TYPE = "system";
    public static final String AUTHORITY_TYPE = "authority";
    public static final String PARAM_RULE_TYPE = "paramRule";


    private CloseableHttpAsyncClient httpClient;

    @Autowired
    private ZookeeperConfigSender zookeeperConfigSender;

    private final boolean enableHttps = false;

    public SentinelApiClient() {
        IOReactorConfig ioConfig = IOReactorConfig.custom().setConnectTimeout(3000).setSoTimeout(3000)
            .setIoThreadCount(Runtime.getRuntime().availableProcessors() * 2).build();
        httpClient = HttpAsyncClients.custom().setRedirectStrategy(new DefaultRedirectStrategy() {
            @Override
            protected boolean isRedirectable(final String method) {
                return false;
            }
        }).setMaxConnTotal(4000).setMaxConnPerRoute(1000).setDefaultIOReactorConfig(ioConfig).build();
        httpClient.start();
    }

    public List<NodeVo> fetchResourceOfMachine(String ip, int port, String type) {
        String url = "http://" + ip + ":" + port + "/" + RESOURCE_URL_PATH + "?type=" + type;
        String body = httpGetContent(url);
        if (body == null) {
            return null;
        }
        try {
            return JSON.parseArray(body, NodeVo.class);
        } catch (Exception e) {
            logger.info("parse ResourceOfMachine error", e);
            return null;
        }
    }

    /**
     * Fetch cluster node.
     *
     * @param ip          ip to fetch
     * @param port        port of the ip
     * @param includeZero whether zero value should in the result list.
     * @return
     */
    public List<NodeVo> fetchClusterNodeOfMachine(String ip, int port, boolean includeZero) {
        String type = "noZero";
        if (includeZero) {
            type = "zero";
        }
        String url = "http://" + ip + ":" + port + "/" + CLUSTER_NODE_PATH + "?type=" + type;
        String body = httpGetContent(url);
        if (body == null) {
            return null;
        }
        try {
            return JSON.parseArray(body, NodeVo.class);
        } catch (Exception e) {
            logger.info("parse ClusterNodeOfMachine error", e);
            return null;
        }
    }

    public List<FlowRuleEntity> fetchFlowRuleOfMachine(String app, String ip, int port) {
        String url = "http://" + ip + ":" + port + "/" + GET_RULES_PATH + "?type=" + FLOW_RULE_TYPE;
        String body = httpGetContent(url);
        logger.info("FlowRule Body:{}", body);
        List<FlowRule> rules = RuleUtils.parseFlowRule(body);
        if (rules != null) {
            return rules.stream().map(rule -> FlowRuleEntity.fromFlowRule(app, ip, port, rule))
                .collect(Collectors.toList());
        } else {
            return null;
        }
    }

    public List<DegradeRuleEntity> fetchDegradeRuleOfMachine(String app, String ip, int port) {
        String url = "http://" + ip + ":" + port + "/" + GET_RULES_PATH + "?type=" + DEGRADE_RULE_TYPE;
        String body = httpGetContent(url);
        logger.info("Degrade Body:{}", body);
        List<DegradeRule> rules = RuleUtils.parseDegradeRule(body);
        if (rules != null) {
            return rules.stream().map(rule -> DegradeRuleEntity.fromDegradeRule(app, ip, port, rule))
                .collect(Collectors.toList());
        } else {
            return null;
        }
    }

    public List<SystemRuleEntity> fetchSystemRuleOfMachine(String app, String ip, int port) {
        String url = "http://" + ip + ":" + port + "/" + GET_RULES_PATH + "?type=" + SYSTEM_RULE_TYPE;
        String body = httpGetContent(url);
        logger.info("SystemRule Body:{}", body);
        List<SystemRule> rules = RuleUtils.parseSystemRule(body);
        if (rules != null) {
            return rules.stream().map(rule -> SystemRuleEntity.fromSystemRule(app, ip, port, rule))
                .collect(Collectors.toList());
        } else {
            return null;
        }
    }

    /**
     * Fetch all parameter flow rules from provided machine.
     *
     * @param app  application name
     * @param ip   machine client IP
     * @param port machine client port
     * @return all retrieved parameter flow rules
     * @since 0.2.1
     */
    public CompletableFuture<List<ParamFlowRuleEntity>> fetchParamFlowRulesOfMachine(String app, String ip, int port) {
        try {
            AssertUtil.notEmpty(app, "Bad app name");
            AssertUtil.notEmpty(ip, "Bad machine IP");
            AssertUtil.isTrue(port > 0, "Bad machine port");
            URIBuilder uriBuilder = new URIBuilder();
            String commandName = GET_PARAM_RULE_PATH;
            uriBuilder.setScheme("http").setHost(ip).setPort(port)
                .setPath(commandName);
            return executeCommand(commandName, uriBuilder.build())
                .thenApply(RuleUtils::parseParamFlowRule)
                .thenApply(rules -> rules.stream()
                    .map(e -> ParamFlowRuleEntity.fromAuthorityRule(app, ip, port, e))
                    .collect(Collectors.toList())
                );
        } catch (Exception e) {
            logger.error("Error when fetching parameter flow rules", e);
            return newFailedFuture(e);
        }
    }

    /**
     * Fetch all authority rules from provided machine.
     *
     * @param app  application name
     * @param ip   machine client IP
     * @param port machine client port
     * @return all retrieved authority rules
     * @since 0.2.1
     */
    public List<AuthorityRuleEntity> fetchAuthorityRulesOfMachine(String app, String ip, int port) {
        AssertUtil.notEmpty(app, "Bad app name");
        AssertUtil.notEmpty(ip, "Bad machine IP");
        AssertUtil.isTrue(port > 0, "Bad machine port");
        URIBuilder uriBuilder = new URIBuilder();
        uriBuilder.setScheme("http").setHost(ip).setPort(port)
            .setPath(GET_RULES_PATH)
            .setParameter("type", AUTHORITY_TYPE);
        try {
            String body = httpGetContent(uriBuilder.build().toString());
            return Optional.ofNullable(body)
                .map(RuleUtils::parseAuthorityRule)
                .map(rules -> rules.stream()
                    .map(e -> AuthorityRuleEntity.fromAuthorityRule(app, ip, port, e))
                    .collect(Collectors.toList())
                )
                .orElse(null);
        } catch (URISyntaxException e) {
            logger.error("Error when fetching authority rules", e);
            return null;
        }
    }

    /**
     * set rules of the machine. rules == null will return immediately;
     * rules.isEmpty() means setting the rules to empty.
     *
     * @param app
     * @param ip
     * @param port
     * @param rules
     * @return whether successfully set the rules.
     */
    public boolean setFlowRuleOfMachine(String app, String ip, int port, List<FlowRuleEntity> rules) {
        if (rules == null) {
            return true;
        }
        if (ip == null) {
            throw new IllegalArgumentException("ip is null");
        }
        String data = JSON.toJSONString(rules.stream().map(FlowRuleEntity::toFlowRule).collect(Collectors.toList()));
        try {
            zookeeperConfigSender.publishRule(app, FLOW_RULE_TYPE, data);
        }catch (Throwable throwable) {
            logger.error("push zk error:", throwable);
        }
        try {
            data = URLEncoder.encode(data, DEFAULT_CHARSET.name());
        } catch (UnsupportedEncodingException e) {
            logger.info("encode rule error", e);
            return false;
        }
        String url = "http://" + ip + ":" + port + "/" + SET_RULES_PATH + "?type=" + FLOW_RULE_TYPE + "&data=" + data;
        String result = httpGetContent(url);
        logger.info("setFlowRule: " + result);
        return true;
    }

    /**
     * set rules of the machine. rules == null will return immediately;
     * rules.isEmpty() means setting the rules to empty.
     *
     * @param app
     * @param ip
     * @param port
     * @param rules
     * @return whether successfully set the rules.
     */
    public boolean setDegradeRuleOfMachine(String app, String ip, int port, List<DegradeRuleEntity> rules) {
        if (rules == null) {
            return true;
        }
        if (ip == null) {
            throw new IllegalArgumentException("ip is null");
        }
        String data = JSON.toJSONString(
            rules.stream().map(DegradeRuleEntity::toDegradeRule).collect(Collectors.toList()));
        try {
            zookeeperConfigSender.publishRule(app, DEGRADE_RULE_TYPE, data);
        }catch (Throwable throwable) {
            logger.error("push zk error:", throwable);
        }
        try {
            data = URLEncoder.encode(data, DEFAULT_CHARSET.name());
        } catch (UnsupportedEncodingException e) {
            logger.info("encode rule error", e);
            return false;
        }
        String url = "http://" + ip + ":" + port + "/" + SET_RULES_PATH + "?type=" + DEGRADE_RULE_TYPE + "&data="
            + data;
        String result = httpGetContent(url);
        logger.info("setDegradeRule: " + result);
        return true;
    }

    /**
     * set rules of the machine. rules == null will return immediately;
     * rules.isEmpty() means setting the rules to empty.
     *
     * @param app
     * @param ip
     * @param port
     * @param rules
     * @return whether successfully set the rules.
     */
    public boolean setSystemRuleOfMachine(String app, String ip, int port, List<SystemRuleEntity> rules) {
        if (rules == null) {
            return true;
        }
        if (ip == null) {
            throw new IllegalArgumentException("ip is null");
        }
        String data = JSON.toJSONString(
            rules.stream().map(SystemRuleEntity::toSystemRule).collect(Collectors.toList()));
        try {
            zookeeperConfigSender.publishRule(app, SYSTEM_RULE_TYPE, data);
        }catch (Throwable throwable) {
            logger.error("push zk error:", throwable);
        }
        try {
            data = URLEncoder.encode(data, DEFAULT_CHARSET.name());
        } catch (UnsupportedEncodingException e) {
            logger.info("encode rule error", e);
            return false;
        }
        String url = "http://" + ip + ":" + port + "/" + SET_RULES_PATH + "?type=" + SYSTEM_RULE_TYPE + "&data=" + data;
        String result = httpGetContent(url);
        logger.info("setSystemRule: " + result);
        return true;
    }

    public boolean setAuthorityRuleOfMachine(String app, String ip, int port, List<AuthorityRuleEntity> rules) {
        if (rules == null) {
            return true;
        }
        if (StringUtil.isBlank(ip) || port <= 0) {
            throw new IllegalArgumentException("Invalid IP or port");
        }
        String data = JSON.toJSONString(
            rules.stream().map(AuthorityRuleEntity::getRule).collect(Collectors.toList()));
        try {
            zookeeperConfigSender.publishRule(app, AUTHORITY_TYPE, data);
        }catch (Throwable throwable) {
            logger.error("push zk error:", throwable);
        }
        try {
            data = URLEncoder.encode(data, DEFAULT_CHARSET.name());
        } catch (UnsupportedEncodingException e) {
            logger.info("Encode rule error", e);
            return false;
        }
        String url = "http://" + ip + ":" + port + "/" + SET_RULES_PATH + "?type=" + AUTHORITY_TYPE + "&data=" + data;
        String result = httpGetContent(url);
        logger.info("Push authority rules: " + result);
        return true;
    }

    public CompletableFuture<Void> setParamFlowRuleOfMachine(String app, String ip, int port, List<ParamFlowRuleEntity> rules) {
        if (rules == null) {
            return CompletableFuture.completedFuture(null);
        }
        if (StringUtil.isBlank(ip) || port <= 0) {
            return newFailedFuture(new IllegalArgumentException("Invalid parameter"));
        }
        try {
            String data = JSON.toJSONString(
                rules.stream().map(ParamFlowRuleEntity::getRule).collect(Collectors.toList())
            );
            try {
                zookeeperConfigSender.publishRule(app, PARAM_RULE_TYPE, data);
            }catch (Throwable throwable) {
                logger.error("push zk error:", throwable);
            }
            data = URLEncoder.encode(data, DEFAULT_CHARSET.name());
            URIBuilder uriBuilder = new URIBuilder();
            uriBuilder.setScheme("http").setHost(ip).setPort(port)
                .setPath(SET_PARAM_RULE_PATH)
                .setParameter("data", data);
            return executeCommand(SET_PARAM_RULE_PATH, uriBuilder.build())
                .thenCompose(e -> {
                    if ("success".equals(e)) {
                        return CompletableFuture.completedFuture(null);
                    } else {
                        logger.warn("Push parameter flow rules to client failed: " + e);
                        return newFailedFuture(new RuntimeException(e));
                    }
                });
        } catch (Exception ex) {
            logger.warn("Error when setting parameter flow rule", ex);
            return newFailedFuture(ex);
        }
    }

    private boolean isSuccess(int statusCode) {
        return statusCode >= 200 && statusCode < 300;
    }

    private CompletableFuture<String> executeCommand(String command, URI uri) {
        CompletableFuture<String> future = new CompletableFuture<>();
        if (StringUtil.isBlank(command) || uri == null) {
            future.completeExceptionally(new IllegalArgumentException("Bad URL or command name"));
            return future;
        }
        final HttpGet httpGet = new HttpGet(uri);
        httpClient.execute(httpGet, new FutureCallback<HttpResponse>() {
            @Override
            public void completed(final HttpResponse response) {
                int statusCode = response.getStatusLine().getStatusCode();
                try {
                    String value = getBody(response);
                    if (isSuccess(statusCode)) {
                        future.complete(value);
                    } else {
                        if (statusCode == 400) {
                            future.completeExceptionally(new CommandNotFoundException(command));
                        } else {
                            future.completeExceptionally(new IllegalStateException(value));
                        }
                    }

                } catch (Exception ex) {
                    future.completeExceptionally(ex);
                    logger.error("HTTP request failed: " + uri.toString(), ex);
                }
            }

            @Override
            public void failed(final Exception ex) {
                future.completeExceptionally(ex);
                logger.error("HTTP request failed: " + uri.toString(), ex);
            }

            @Override
            public void cancelled() {
                future.complete(null);
            }
        });
        return future;
    }

    private String httpGetContent(String url) {
        final HttpGet httpGet = new HttpGet(url);
        final CountDownLatch latch = new CountDownLatch(1);
        final AtomicReference<String> reference = new AtomicReference<>();
        httpClient.execute(httpGet, new FutureCallback<HttpResponse>() {
            @Override
            public void completed(final HttpResponse response) {
                try {
                    reference.set(getBody(response));
                } catch (Exception e) {
                    logger.info("httpGetContent " + url + " error:", e);
                } finally {
                    latch.countDown();
                }
            }

            @Override
            public void failed(final Exception ex) {
                latch.countDown();
                logger.info("httpGetContent " + url + " failed:", ex);
            }

            @Override
            public void cancelled() {
                latch.countDown();
            }
        });
        try {
            latch.await(5, TimeUnit.SECONDS);
        } catch (Exception e) {
            logger.info("wait http client error:", e);
        }
        return reference.get();
    }

    private String getBody(HttpResponse response) throws Exception {
        Charset charset = null;
        try {
            String contentTypeStr = response.getFirstHeader("Content-type").getValue();
            ContentType contentType = ContentType.parse(contentTypeStr);
            charset = contentType.getCharset();
        } catch (Exception ignore) {
        }
        return EntityUtils.toString(response.getEntity(), charset != null ? charset : DEFAULT_CHARSET);
    }

    public void close() throws Exception {
        httpClient.close();
    }

    private <R> CompletableFuture<R> newFailedFuture(Throwable ex) {
        CompletableFuture<R> future = new CompletableFuture<>();
        future.completeExceptionally(ex);
        return future;
    }

    // Cluster related

    public CompletableFuture<ClusterStateSimpleEntity> fetchClusterMode(String app, String ip, int port) {
        if (StringUtil.isBlank(ip) || port <= 0) {
            return newFailedFuture(new IllegalArgumentException("Invalid parameter"));
        }
        try {
            URIBuilder uriBuilder = new URIBuilder();
            uriBuilder.setScheme("http").setHost(ip).setPort(port)
                .setPath(FETCH_CLUSTER_MODE_PATH);
            return executeCommand(FETCH_CLUSTER_MODE_PATH, uriBuilder.build())
                .thenApply(r -> JSON.parseObject(r, ClusterStateSimpleEntity.class));
        } catch (Exception ex) {
            logger.warn("Error when fetching cluster mode", ex);
            return newFailedFuture(ex);
        }
    }

    public CompletableFuture<Void> modifyClusterMode(String app, String ip, int port, int mode) {
        if (StringUtil.isBlank(ip) || port <= 0) {
            return newFailedFuture(new IllegalArgumentException("Invalid parameter"));
        }
        try {
            URIBuilder uriBuilder = new URIBuilder();
            uriBuilder.setScheme("http").setHost(ip).setPort(port)
                .setPath(MODIFY_CLUSTER_MODE_PATH)
                .setParameter("mode", String.valueOf(mode));
            return executeCommand(MODIFY_CLUSTER_MODE_PATH, uriBuilder.build())
                .thenCompose(e -> {
                    if ("success".equals(e)) {
                        return CompletableFuture.completedFuture(null);
                    } else {
                        logger.warn("Error when modifying cluster mode: " + e);
                        return newFailedFuture(new RuntimeException(e));
                    }
                });
        } catch (Exception ex) {
            logger.warn("Error when modifying cluster mode", ex);
            return newFailedFuture(ex);
        }
    }

    public CompletableFuture<ClusterClientConfig> fetchClusterClientConfig(String app, String ip, int port) {
        if (StringUtil.isBlank(ip) || port <= 0) {
            return newFailedFuture(new IllegalArgumentException("Invalid parameter"));
        }
        try {
            URIBuilder uriBuilder = new URIBuilder();
            uriBuilder.setScheme("http").setHost(ip).setPort(port)
                .setPath(FETCH_CLUSTER_CLIENT_CONFIG_PATH);
            return executeCommand(FETCH_CLUSTER_CLIENT_CONFIG_PATH, uriBuilder.build())
                .thenApply(r -> JSON.parseObject(r, ClusterClientConfig.class));
        } catch (Exception ex) {
            logger.warn("Error when fetching cluster client config", ex);
            return newFailedFuture(ex);
        }
    }

    public CompletableFuture<Void> modifyClusterClientConfig(String app, String ip, int port, ClusterClientConfig config) {
        if (StringUtil.isBlank(ip) || port <= 0) {
            return newFailedFuture(new IllegalArgumentException("Invalid parameter"));
        }
        try {
            URIBuilder uriBuilder = new URIBuilder();
            uriBuilder.setScheme("http").setHost(ip).setPort(port)
                .setPath(MODIFY_CLUSTER_CLIENT_CONFIG_PATH)
                .setParameter("data", JSON.toJSONString(config));
            return executeCommand(MODIFY_CLUSTER_MODE_PATH, uriBuilder.build())
                .thenCompose(e -> {
                    if ("success".equals(e)) {
                        return CompletableFuture.completedFuture(null);
                    } else {
                        logger.warn("Error when modifying cluster client config: " + e);
                        return newFailedFuture(new RuntimeException(e));
                    }
                });
        } catch (Exception ex) {
            logger.warn("Error when modifying cluster client config", ex);
            return newFailedFuture(ex);
        }
    }

    public CompletableFuture<Void> modifyClusterServerFlowConfig(String app, String ip, int port, ServerFlowConfig config) {
        if (StringUtil.isBlank(ip) || port <= 0) {
            return newFailedFuture(new IllegalArgumentException("Invalid parameter"));
        }
        try {
            URIBuilder uriBuilder = new URIBuilder();
            uriBuilder.setScheme("http").setHost(ip).setPort(port)
                .setPath(MODIFY_CLUSTER_SERVER_FLOW_CONFIG_PATH)
                .setParameter("data", JSON.toJSONString(config));
            return executeCommand(MODIFY_CLUSTER_SERVER_FLOW_CONFIG_PATH, uriBuilder.build())
                .thenCompose(e -> {
                    if ("success".equals(e)) {
                        return CompletableFuture.completedFuture(null);
                    } else {
                        logger.warn("Error when modifying cluster server flow config: " + e);
                        return newFailedFuture(new RuntimeException(e));
                    }
                });
        } catch (Exception ex) {
            logger.warn("Error when modifying cluster server flow config", ex);
            return newFailedFuture(ex);
        }
    }

    public CompletableFuture<Void> modifyClusterServerTransportConfig(String app, String ip, int port, ServerTransportConfig config) {
        if (StringUtil.isBlank(ip) || port <= 0) {
            return newFailedFuture(new IllegalArgumentException("Invalid parameter"));
        }
        try {
            URIBuilder uriBuilder = new URIBuilder();
            uriBuilder.setScheme("http").setHost(ip).setPort(port)
                .setPath(MODIFY_CLUSTER_SERVER_TRANSPORT_CONFIG_PATH)
                .setParameter("port", config.getPort().toString())
                .setParameter("idleSeconds", config.getIdleSeconds().toString());
            return executeCommand(MODIFY_CLUSTER_SERVER_TRANSPORT_CONFIG_PATH, uriBuilder.build())
                .thenCompose(e -> {
                    if ("success".equals(e)) {
                        return CompletableFuture.completedFuture(null);
                    } else {
                        logger.warn("Error when modifying cluster server transport config: " + e);
                        return newFailedFuture(new RuntimeException(e));
                    }
                });
        } catch (Exception ex) {
            logger.warn("Error when modifying cluster server transport config", ex);
            return newFailedFuture(ex);
        }
    }

    public CompletableFuture<Void> modifyClusterServerNamespaceSet(String app, String ip, int port, Set<String> set) {
        if (StringUtil.isBlank(ip) || port <= 0) {
            return newFailedFuture(new IllegalArgumentException("Invalid parameter"));
        }
        try {
            URIBuilder uriBuilder = new URIBuilder();
            uriBuilder.setScheme("http").setHost(ip).setPort(port)
                .setPath(MODIFY_CLUSTER_SERVER_NAMESPACE_SET_PATH)
                .setParameter("data", JSON.toJSONString(set));
            return executeCommand(MODIFY_CLUSTER_SERVER_NAMESPACE_SET_PATH, uriBuilder.build())
                .thenCompose(e -> {
                    if ("success".equals(e)) {
                        return CompletableFuture.completedFuture(null);
                    } else {
                        logger.warn("Error when modifying cluster server NamespaceSet: " + e);
                        return newFailedFuture(new RuntimeException(e));
                    }
                });
        } catch (Exception ex) {
            logger.warn("Error when modifying cluster server NamespaceSet", ex);
            return newFailedFuture(ex);
        }
    }

    public CompletableFuture<ClusterServerStateVO> fetchClusterServerBasicInfo(String app, String ip, int port) {
        if (StringUtil.isBlank(ip) || port <= 0) {
            return newFailedFuture(new IllegalArgumentException("Invalid parameter"));
        }
        try {
            URIBuilder uriBuilder = new URIBuilder();
            uriBuilder.setScheme("http").setHost(ip).setPort(port)
                .setPath(FETCH_CLUSTER_SERVER_BASIC_INFO_PATH);
            return executeCommand(FETCH_CLUSTER_SERVER_BASIC_INFO_PATH, uriBuilder.build())
                .thenApply(r -> JSON.parseObject(r, ClusterServerStateVO.class));
        } catch (Exception ex) {
            logger.warn("Error when fetching cluster sever all config and basic info", ex);
            return newFailedFuture(ex);
        }
    }
}

本地文件模式

package com.***.***.sentinel;

import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
import com.alibaba.csp.sentinel.datasource.FileWritableDataSource;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.WritableDataSource;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;


public class FileDataSourceInit implements InitFunc{

   private static final Logger logger  = LoggerFactory.getLogger(FileDataSourceInit.class);

   private static String ROOT_DIR = "/data/www/conf/sentinel/rules";

   @Override
   public void init() throws Exception{
       if(!createPath()){
           logger.error("sentinel path create error");
           return;
       }
       initFlowRule();
       initDegradeRule();
       initSystemRule();
       initAuthorityRule();
       logger.info("sentinel rule init success");
   }

   private  void initFlowRule(){
       String flowRuleFile = "flowRule.json";
       String flowRulePath = ROOT_DIR + File.separator + flowRuleFile;

       if(!createFile(flowRulePath)){
           logger.error("create flowRulePath error ");
           return;
       }
       ReadableDataSource<String, List<FlowRule>> ds = null;
       try {
           ds = new FileRefreshableDataSource<>(
                   flowRulePath, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {})
           );
       } catch (FileNotFoundException e) {
           logger.error("Sentinel flow file {} not find",flowRulePath,e);
       }
       // Register to flow rule manager.
       FlowRuleManager.register2Property(ds.getProperty());
       WritableDataSource<List<FlowRule>> wds = new FileWritableDataSource<>(flowRulePath, this::encodeJson);
       // Register to writable data source registry so that rules can be updated to file
       // when there are rules pushed from the Sentinel Dashboard.
       WritableDataSourceRegistry.registerFlowDataSource(wds);
   }

   private  void initDegradeRule(){

       String deGradeRuleFile = "deGradeRule.json";
       String deGradeRulePath = ROOT_DIR +  File.separator + deGradeRuleFile;

       if(!createFile(deGradeRulePath)){
           logger.error("create deGradeRulePath error ");
           return;
       }
       ReadableDataSource<String, List<DegradeRule>> dg = null;
       try {
           dg = new FileRefreshableDataSource<>(
                   deGradeRulePath, source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {})
           );
       } catch (FileNotFoundException e) {
           logger.error("Sentinel degrade file {} not find",deGradeRulePath,e);
       }
       // Register to flow rule manager.
       DegradeRuleManager.register2Property(dg.getProperty());
       WritableDataSource<List<DegradeRule>> dgs = new FileWritableDataSource<>(deGradeRulePath, this::encodeJson);
       // Register to writable data source registry so that rules can be updated to file
       // when there are rules pushed from the Sentinel Dashboard.
       WritableDataSourceRegistry.registerDegradeDataSource(dgs);
   }

   private  void initAuthorityRule(){

       String authorityRuleFile = "authorityRule.json";
       String authorityPath = ROOT_DIR + File.separator + authorityRuleFile;

       if(!createFile(authorityPath)){
           logger.error("create authorityPath error ");
           return;
       }

       ReadableDataSource<String, List<AuthorityRule>> dg = null;
       try {
           dg = new FileRefreshableDataSource<>(
                   authorityPath, source -> JSON.parseObject(source, new TypeReference<List<AuthorityRule>>() {})
           );
       } catch (FileNotFoundException e) {
           logger.error("Sentinel authority file {} not find",authorityPath,e);
       }
       // Register to flow rule manager.
       AuthorityRuleManager.register2Property(dg.getProperty());
       WritableDataSource<List<AuthorityRule>> dgs = new FileWritableDataSource<>(authorityPath, this::encodeJson);
       // Register to writable data source registry so that rules can be updated to file
       // when there are rules pushed from the Sentinel Dashboard.
       WritableDataSourceRegistry.registerAuthorityDataSource(dgs);
   }

   private  void initSystemRule(){

       String systemRuleFile = "systemRule.json";
       String systemRulePath = ROOT_DIR + File.separator + systemRuleFile;

       if(!createFile(systemRulePath)){
           logger.error("create systemRulePath error ");
           return;
       }
       ReadableDataSource<String, List<SystemRule>> dg = null;
       try {
           dg = new FileRefreshableDataSource<>(
                   systemRulePath, source -> JSON.parseObject(source, new TypeReference<List<SystemRule>>() {})
           );
       } catch (FileNotFoundException e) {
           logger.error("Sentinel system file {} not find",systemRulePath,e);
       }
       // Register to flow rule manager.
       SystemRuleManager.register2Property(dg.getProperty());
       WritableDataSource<List<SystemRule>> dgs = new FileWritableDataSource<>(systemRulePath, this::encodeJson);
       // Register to writable data source registry so that rules can be updated to file
       // when there are rules pushed from the Sentinel Dashboard.
       WritableDataSourceRegistry.registerSystemDataSource(dgs);
   }

   private boolean createPath(){
       boolean exists = true;
       File path = new File(ROOT_DIR);
       if(!path.exists()){
           exists = path.mkdirs();
       }
       return exists;
   }
   private boolean createFile(String path){
       boolean exists = true;
       File file = new File(path);
       if(!file.exists()) {
           try {
               exists = file.createNewFile();
           } catch (IOException e) {
               logger.error("create file:"+path+ "error",e);
               exists = false;
           }
       }
       return exists;
   }


   private <T> String encodeJson(T t) {
       return JSON.toJSONString(t);
   }
}

在 Web 容器中的 web.xml 配置文件中进行如下配置开启 Sentinel 对web接口的支持:

<filter>
	<filter-name>SentinelCommonFilter</filter-name>
	<filter-class>com.alibaba.csp.sentinel.adapter.servlet.CommonFilter</filter-class>
</filter>

<filter-mapping>
	<filter-name>SentinelCommonFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

2.添加jvm启动参数

-Dcsp.sentinel.api.port=XXXX -Dcsp.sentinel.dashboard.server=XXXXXX:XXXX-Dproject.name=XXXX
-Dproject.name=XXXX 项目名称(最好与dubbo application名称一致)

-Dcsp.sentinel.dashboard.server=dashboard的IP:dashboard的启动端口 客户端访问dashboard的参数
-Dcsp.sentinel.api.port=xxxx (默认是 8719,已被占用时自动递增)客户端提供给dashboard访问或者查看sentinel的运行访问的参数,服务器必须要放开此端口

3.控制台刷新

必须保证项目有访问量,控制台中才能看到项目

常见错误:

    1.启动报错 Could not initialize class com.alibaba.csp.sentinel.context.ContextUtil

     检查zookeeper jar版本,如果3.3.x,改为:3.4.13

    2.[ZookeeperDataSource] WARN: initial config is null, you may have to check your data source

     资源配置不生效,将fastjson版本升到40以上
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值