Spring Alibaba Sentinel实现集群限流demo

1.背景

1.什么是单机限流?

小伙伴们或许遇到过下图这样的限流配置

Spring Alibaba Sentinel实现集群限流demo_第1张图片

又或者是这样的Nacos动态配置限流规则:

Spring Alibaba Sentinel实现集群限流demo_第2张图片

 以上这些是什么限流?没错,就是单机限流,那么单机限流有什么弊端呢?

假设我们集群部署3台机器(NodeA/NodeB/NodeC),在某时刻,同时有25个请求进来,假设NodeA收到12个请求,NodeB 8个,NodeC 5个,并且每个单机限流qps=10,那么这个时候,NodeA将会触发限流,有两个请求BLOCK掉,这是由于可能发生的流量不均导致NodeA节点流量过高导致限流,这是因为每个机器都是自己管自己,有没有一种方法能够统筹调度呢?这就得提到集群限流了

Spring Alibaba Sentinel实现集群限流demo_第3张图片

 2.什么是集群限流

 集群限流就是,弄一台Token Server,每个客户端机器作为Token Client,有请求进来,Token Client就会向Token Server拿令牌,拿到令牌则不限流,反正则限流。其中Token Server可以作为独立运行的项目,也可以内嵌式内嵌至每个节点中(需将其中一台机器设置为Token Server,如果Token Server节点所在机器宕机,可以将其他Client节点设置成server,sentinel有相关api提供该操作)

例如上面的例子,集群内有3个节点,如果每个节点能承受10的请求,那么加起来就是3x10=30个请求。也就是说只要qps不超过30个请求都不会触发限流。

2.sentinel实现集群限流

1. 以spring-boot项目构建 sentinel-token-server

pom.xml



	4.0.0 
	com.lee.sentinel.tokenserver
	sentinel-token-server
	0.0.1-SNAPSHOT
	sentinel-token-server
	Demo project for Spring Boot
	
		1.8
		2.3.7.RELEASE
	
	
		
		
			org.springframework.boot
			spring-boot-starter
			
				
					com.alibaba.spring
					spring-context-support
				
			
		

		
			org.springframework.boot
			spring-boot-starter-web 
		
		
		
			org.springframework.boot
			spring-boot-starter-test
			test
		
		 
		
		
            org.slf4j
            slf4j-log4j12
         
        
        
        
			com.alibaba.boot
			nacos-config-spring-boot-starter
			0.2.12
			
			
			
				
					com.alibaba.spring
					spring-context-support
				
			
		
		
		
		
			com.alibaba.spring
			spring-context-support
			1.0.11
		
		
		
		
            com.alibaba.csp
            sentinel-cluster-server-default
            1.8.5
         
        
        
            com.alibaba.csp
            sentinel-transport-simple-http
            1.8.5
        
        
        
            com.alibaba.csp
            sentinel-datasource-nacos
            1.8.5
        
         
	

 	
        
            
                org.springframework.boot
                spring-boot-dependencies
                ${spring-boot.version}
                pom
                import
            
        
    
    
	
		
			
				org.springframework.boot
				spring-boot-maven-plugin
			
		
	


application.properties

server.port=9009
#应用名称
spring.application.name=sentinel-token-server
#nacos config center
nacos.config.server-addr=192.168.1.105:8848

ClusterServer启动类


import java.util.HashSet;
import java.util.Set;

import com.alibaba.csp.sentinel.cluster.server.ClusterTokenServer;
import com.alibaba.csp.sentinel.cluster.server.SentinelDefaultTokenServer;
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;

public class ClusterServer {
	 
	private static final int TOKEN_SERVER_PORT = 7777;
	private static final int IDLE_SECONDS = 600;
	
	public static void main(String[] args) throws Exception {
		ClusterTokenServer tokenServer = new SentinelDefaultTokenServer();
		ServerTransportConfig serverConfig = new ServerTransportConfig(TOKEN_SERVER_PORT, IDLE_SECONDS); 
		ClusterServerConfigManager.loadGlobalTransportConfig( serverConfig ); 
		 //可以设置多个namespace
		Set namespaceSet = new HashSet();
		namespaceSet.add("user-service"); //dataId=user-service-flow-rules
		ClusterServerConfigManager.loadServerNamespaceSet( namespaceSet ); 
		tokenServer.start();
	}
}

SpringBoot启动类:

Spring Alibaba Sentinel实现集群限流demo_第4张图片

 基于spring-boot SPI机制初始化限流规则:

Spring Alibaba Sentinel实现集群限流demo_第5张图片

ClusterTokenInitFunc:从

import java.util.List;

import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterFlowRuleManager;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;

public class ClusterTokenInitFunc implements InitFunc {

	private String remoteAddress = "192.168.1.105:8848";// nacos配置中心地址
	private String groupId = "SENTINEL_GROUP";
	private String dataId_postfix = "-flow-rules";

	@Override
	public void init() throws Exception {
		// TODO Auto-generated method stub
		loadFlowRuleByNacos();
	}

	private void loadFlowRuleByNacos() {
		// TODO Auto-generated method stub
		// 从Nacos上获取配置进行加载
		ClusterFlowRuleManager.setPropertySupplier(namespace -> {
			// namespace在ClusterServer.java中已配置
			String dataId = namespace + dataId_postfix; // user-service-flow-rules、 coupon-service-flow-rules
			ReadableDataSource> readableDataSource = new NacosDataSource<>(remoteAddress,
					groupId, dataId, source -> JSON.parseObject(source, new TypeReference>() {
					}));
			return readableDataSource.getProperty();
		});
	}

}

其中,我的Nacos配置(dataId=user-service-flow-rules)设置如下:

Spring Alibaba Sentinel实现集群限流demo_第6张图片

[
    {
    "resource":"com.lee.demo.dubbo.demo.user.ISentinelService",
    "grade":1,
    "count":2,
    "clusterMode":true,
    "clusterConfig":{
        "flowId":"1001",
        "thresholdType":1,
        "fallbackToLocalWhenFail":true
    }
    },{
    "resource":"com.lee.demo.dubbo.demo.user.IHelloService",
    "grade":1,
    "count":30,
    "clusterMode":true,
    "clusterConfig":{
        "flowId":"1002",
        "thresholdType":1,
        "fallbackToLocalWhenFail":true
    }
    }
]

至此sentinel-token-server搭建完成,启动服务

2. 配置客户端Token Client

导包

        
        
			com.alibaba.boot
			nacos-config-spring-boot-starter
			0.2.12
			
			
			
				
					com.alibaba.spring
					spring-context-support
				
			
		
		
		
		
			com.alibaba.spring
			spring-context-support
			1.0.11
		

        
        
			 com.alibaba.csp
			 sentinel-apache-dubbo-adapter
			 1.8.5
		
		
		
            com.alibaba.csp
            sentinel-transport-simple-http
            1.8.5
        
        
        
            com.alibaba.csp
            sentinel-datasource-nacos
            1.8.5
        
        
		
            com.alibaba.csp
            sentinel-cluster-client-default
            1.8.5
         

 加载集群流控规则:

Spring Alibaba Sentinel实现集群限流demo_第7张图片

 ClusterFlowRuleInitFunc.java

import java.util.List;

import com.alibaba.csp.sentinel.cluster.ClusterStateManager;
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientAssignConfig;
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientConfig;
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientConfigManager;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;

public class ClusterFlowRuleInitFunc implements InitFunc{

	private static final String CLUSTER_SERVER_HOST = "localhost";
	private static final int CLUSTER_SERVER_PORT = 7777;
	private static final int REQUEST_TIME_OUT = 20000;
	
	private static final String remoteAddress = "192.168.1.105:8848";
	private static final String groupId = "SENTINEL_GROUP";  
	private static final String FLOW_POSTFIX="-flow-rules";
    private static final String APP_NAME="user-service";
	
	@Override
	public void init() throws Exception {
		// TODO Auto-generated method stub
        //声明为Token Client
		ClusterStateManager.applyState(ClusterStateManager.CLUSTER_CLIENT);
		//加载集群限流Token Server 
		loadClusterClientConfig(); 
		//加载单机限流规则(如果Token Server不可用,退化到单机限流)
		initFlowRulesWithDatasource(); 
	}
	
	
	/**
	 * 集群限流规则
	 * */
	private void loadClusterClientConfig() {
		ClusterClientAssignConfig assignConfig  = new ClusterClientAssignConfig();
		assignConfig.setServerHost(CLUSTER_SERVER_HOST);
		assignConfig.setServerPort(CLUSTER_SERVER_PORT);
		ClusterClientConfigManager.applyNewAssignConfig(assignConfig);
		
		ClusterClientConfig clientConfig = new ClusterClientConfig();
		clientConfig.setRequestTimeout(REQUEST_TIME_OUT);
		ClusterClientConfigManager.applyNewConfig(clientConfig);
	}
	
	/**
	 * 单机限流规则
	 * */
	private void initFlowRulesWithDatasource() {  
		String dataId = APP_NAME + FLOW_POSTFIX;
//		ReadableDataSource> readableDataSource = new NacosDataSource<>(
//				remoteAddress, groupId, dataId
//				,source->JSON.parseObject(source,new TypeReference>() {}));
		ReadableDataSource> readableDataSource = new NacosDataSource<>(
				remoteAddress, groupId, dataId, new Converter>() { 
			@Override
			public List convert(String source) {
				// TODO Auto-generated method stub
				System.out.println("source:"+source); 
				List rules = JSON.parseObject(source,new TypeReference>() {}); 
				return rules;
			}
		});    
		FlowRuleManager.register2Property(readableDataSource.getProperty());
	} 
	
}

Controller:

Spring Alibaba Sentinel实现集群限流demo_第8张图片

至此,Token Client配置完成。

接下来启动3个客户端,模拟集群:

 Spring Alibaba Sentinel实现集群限流demo_第9张图片

 Sentinel-Dashboard上可以看到user-service有三台集群机器:

Spring Alibaba Sentinel实现集群限流demo_第10张图片

使用jmeter压测工具进行压测:

Spring Alibaba Sentinel实现集群限流demo_第11张图片

 压测结果如下,可以看到com.lee.demo.dubbo.demo.user.ISentinelService.testSentinel() 接口的qps一直不会超过6个请求,这个峰值是怎么计算的来的呢?因为我上面提到的Nacos集群限流配置dataId=user-service-flow-rules中配置com.lee.demo.dubbo.demo.user.ISentinelService的qps=2,而我们总共有3台机器,因此集群限流max qps:2x3=6

Spring Alibaba Sentinel实现集群限流demo_第12张图片

 至此,sentinel上线集群限流demo已完成,如有疑问请在评论区评论。

你可能感兴趣的:(sentinel,sentinel集群限流,集群限流)