Sentinel集群限流探索(二)

wg204wg
发布于 2022-6-13 17:37
5455浏览
0收藏

 

实现InitFunc接口,重写init方法,代码直接贴出来,这里整体依赖的是Apollo的配置方式,注释的部分是我在测试的时候写死代码的配置方式,也是可以用的。

public class DemoClusterInitFunc implements InitFunc {
    private final String namespace = "application";
    private final String ruleKey = "demo_sentinel";
    private final String ruleServerKey = "demo_cluster";
    private final String defaultRuleValue = "[]";

    @Override
    public void init() throws Exception {
        // 初始化 限流规则
        initDynamicRuleProperty();
        //初始化 客户端配置
        initClientConfigProperty();
        // 初始化 服务端配置信息
        initClientServerAssignProperty();
        registerClusterRuleSupplier();
        // token-server的传输规则
        initServerTransportConfigProperty();
        // 初始化 客户端和服务端状态
        initStateProperty();
    }

    /**
     * 限流规则和热点限流规则配置
     */
    private void initDynamicRuleProperty() {
        ReadableDataSource<String, List<FlowRule>> ruleSource = new ApolloDataSource<>(namespace, ruleKey,
                defaultRuleValue, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
        }));
        FlowRuleManager.register2Property(ruleSource.getProperty());

        ReadableDataSource<String, List<ParamFlowRule>> paramRuleSource = new ApolloDataSource<>(namespace, ruleKey,
                defaultRuleValue, source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {
        }));
        ParamFlowRuleManager.register2Property(paramRuleSource.getProperty());
    }

    /**
     * 客户端配置,注释的部分是通过Apollo配置,只有一个配置我就省略了
     */
    private void initClientConfigProperty() {
//        ReadableDataSource<String, ClusterClientConfig> clientConfigDs = new ApolloDataSource<>(namespace, ruleKey,
//                defaultRuleValue, source -> JSON.parseObject(source, new TypeReference<ClusterClientConfig>() {
//        }));
//        ClusterClientConfigManager.registerClientConfigProperty(clientConfigDs.getProperty());

        ClusterClientConfig clientConfig = new ClusterClientConfig();
        clientConfig.setRequestTimeout(1000);
        ClusterClientConfigManager.applyNewConfig(clientConfig);
    }

    /**
     * client->server 传输配置,设置端口号,注释的部分是写死的配置方式
     */
    private void initServerTransportConfigProperty() {
        ReadableDataSource<String, ServerTransportConfig> serverTransportDs = new ApolloDataSource<>(namespace, ruleServerKey,
                defaultRuleValue, source -> {
            List<ClusterGroupEntity> groupList = JSON.parseObject(source, new TypeReference<List<ClusterGroupEntity>>() {
            });
            ServerTransportConfig serverTransportConfig = Optional.ofNullable(groupList)
                    .flatMap(this::extractServerTransportConfig)
                    .orElse(null);
            return serverTransportConfig;
        });
        ClusterServerConfigManager.registerServerTransportProperty(serverTransportDs.getProperty());
//        ClusterServerConfigManager.loadGlobalTransportConfig(new ServerTransportConfig().setIdleSeconds(600).setPort(transPort));
    }

    private void registerClusterRuleSupplier() {
        ClusterFlowRuleManager.setPropertySupplier(namespace -> {
            ReadableDataSource<String, List<FlowRule>> ds = new ApolloDataSource<>(this.namespace, ruleKey,
                    defaultRuleValue, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
            }));
            return ds.getProperty();
        });
        ClusterParamFlowRuleManager.setPropertySupplier(namespace -> {
            ReadableDataSource<String, List<ParamFlowRule>> ds = new ApolloDataSource<>(this.namespace, ruleKey,
                    defaultRuleValue, source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {
            }));
            return ds.getProperty();
        });
    }

    /**
     * 服务端配置,设置server端口和IP,注释的配置是写死的方式,这个在服务端是不用配置的,只有客户端需要配置用来连接服务端
     */
    private void initClientServerAssignProperty() {
        ReadableDataSource<String, ClusterClientAssignConfig> clientAssignDs = new ApolloDataSource<>(namespace, ruleServerKey,
                defaultRuleValue, source -> {
            List<ClusterGroupEntity> groupList = JSON.parseObject(source, new TypeReference<List<ClusterGroupEntity>>() {
            });

            ClusterClientAssignConfig clusterClientAssignConfig = Optional.ofNullable(groupList)
                    .flatMap(this::extractClientAssignment)
                    .orElse(null);
            return clusterClientAssignConfig;
        });
        ClusterClientConfigManager.registerServerAssignProperty(clientAssignDs.getProperty());

//        ClusterClientAssignConfig serverConfig = new ClusterClientAssignConfig();
//        serverConfig.setServerHost("127.0.0.1");
//        serverConfig.setServerPort(transPort);
//        ConfigSupplierRegistry.setNamespaceSupplier(() -> "trade-center");
//        ClusterClientConfigManager.applyNewAssignConfig(serverConfig);
    }

    private Optional<ClusterClientAssignConfig> extractClientAssignment(List<ClusterGroupEntity> groupList) {
        ClusterGroupEntity tokenServer = groupList.stream().filter(x -> x.getState().equals(ClusterStateManager.CLUSTER_SERVER)).findFirst().get();
        Integer currentMachineState = Optional.ofNullable(groupList).map(s -> groupList.stream().filter(this::machineEqual).findFirst().get().getState()).orElse(ClusterStateManager.CLUSTER_NOT_STARTED);
        if (currentMachineState.equals(ClusterStateManager.CLUSTER_CLIENT)) {
            String ip = tokenServer.getIp();
            Integer port = tokenServer.getPort();
            return Optional.of(new ClusterClientAssignConfig(ip, port));
        }
        return Optional.empty();
    }

    /**
     * 初始化客户端和服务端状态,注释的也是写死的配置方式
     */
    private void initStateProperty() {
        ReadableDataSource<String, Integer> clusterModeDs = new ApolloDataSource<>(namespace, ruleServerKey,
                defaultRuleValue, source -> {
            List<ClusterGroupEntity> groupList = JSON.parseObject(source, new TypeReference<List<ClusterGroupEntity>>() {
            });
            Integer state = Optional.ofNullable(groupList).map(s -> groupList.stream().filter(this::machineEqual).findFirst().get().getState()).orElse(ClusterStateManager.CLUSTER_NOT_STARTED);
            return state;
        });
        ClusterStateManager.registerProperty(clusterModeDs.getProperty());

//            ClusterStateManager.applyState(ClusterStateManager.CLUSTER_SERVER);

    }

    private Optional<ServerTransportConfig> extractServerTransportConfig(List<ClusterGroupEntity> groupList) {
        return groupList.stream()
                .filter(x -> x.getMachineId().equalsIgnoreCase(getCurrentMachineId()) && x.getState().equals(ClusterStateManager.CLUSTER_SERVER))
                .findAny()
                .map(e -> new ServerTransportConfig().setPort(e.getPort()).setIdleSeconds(600));
    }

    private boolean machineEqual(/*@Valid*/ ClusterGroupEntity group) {
        return getCurrentMachineId().equals(group.getMachineId());
    }

    private String getCurrentMachineId() {
        // 通过-Dcsp.sentinel.api.port=8719 配置, 默认8719,随后递增
        return HostNameUtil.getIp() + SEPARATOR + TransportConfig.getPort();
    }
  
    private static final String SEPARATOR = "@";
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.

基础类,定义配置的基础信息。

@Data
public class ClusterGroupEntity {
    private String machineId;
    private String ip;
    private Integer port;
    private Integer state;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

然后是Apollo中的限流规则的配置和server/client集群关系的配置。

需要说明一下的就是flowId,这个是区分限流规则的全局唯一ID,必须要有,否则集群限流会有问题。

thresholdType代表限流模式,默认是0,代表单机均摊,比如这里count限流QPS=20,有3台机器,那么集群限流阈值就是60,如果是1代表全局阈值,也就是count配置的值就是集群限流的上限。

demo_sentinel=[
    {
        "resource": "test_res", //限流资源名
        "count": 20, //集群限流QPS
        "clusterMode": true, //true为集群限流模式
        "clusterConfig": {
            "flowId": 111, //这个必须得有,否则会有问题
            "thresholdType": 1 //限流模式,默认为0单机均摊,1是全局阈值
        }
    }
]
demo_cluster=[
    {
        "ip": "192.168.3.20",
        "machineId": "192.168.3.20@8720",
        "port": 9999, //server和client通信接口
        "state": 1 //指定为server
    },
    {
        "ip": "192.168.3.20",
        "machineId": "192.168.3.20@8721",
        "state": 0
    },
    {
        "ip": "192.168.3.20",
        "machineId": "192.168.3.20@8722",
        "state": 0
    }
]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.

 

OK,到这里代码和配置都已经OK,还需要跑起来Sentinel控制台,这个不用教,还有启动参数。

本地可以直接跑多个客户端,注意修改端口号:-Dserver.port=9100 -Dcsp.sentinel.api.port=8720这两个一块改,至于怎么连Apollo这块我就省略了,自己整吧,公司应该都有,不行的话用代码里的写死的方式也可以用。

-Dserver.port=9100 -Dcsp.sentinel.api.port=8720 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dcsp.sentinel.log.use.pid=true 
  • 1.

 

文章转自公众号:艾小仙

分类
标签
已于2022-6-13 17:37:51修改
收藏
回复
举报
回复
    相关推荐