seo關(guān)鍵詞如何設(shè)置seo研究中心教程
1.背景
1.什么是單機(jī)限流?
小伙伴們或許遇到過下圖這樣的限流配置
又或者是這樣的Nacos動(dòng)態(tài)配置限流規(guī)則:
?以上這些是什么限流?沒錯(cuò),就是單機(jī)限流,那么單機(jī)限流有什么弊端呢?
假設(shè)我們集群部署3臺(tái)機(jī)器(NodeA/NodeB/NodeC),在某時(shí)刻,同時(shí)有25個(gè)請(qǐng)求進(jìn)來,假設(shè)NodeA收到12個(gè)請(qǐng)求,NodeB 8個(gè),NodeC 5個(gè),并且每個(gè)單機(jī)限流qps=10,那么這個(gè)時(shí)候,NodeA將會(huì)觸發(fā)限流,有兩個(gè)請(qǐng)求BLOCK掉,這是由于可能發(fā)生的流量不均導(dǎo)致NodeA節(jié)點(diǎn)流量過高導(dǎo)致限流,這是因?yàn)槊總€(gè)機(jī)器都是自己管自己,有沒有一種方法能夠統(tǒng)籌調(diào)度呢?這就得提到集群限流了
?2.什么是集群限流
?集群限流就是,弄一臺(tái)Token Server,每個(gè)客戶端機(jī)器作為Token Client,有請(qǐng)求進(jìn)來,Token Client就會(huì)向Token Server拿令牌,拿到令牌則不限流,反正則限流。其中Token Server可以作為獨(dú)立運(yùn)行的項(xiàng)目,也可以內(nèi)嵌式內(nèi)嵌至每個(gè)節(jié)點(diǎn)中(需將其中一臺(tái)機(jī)器設(shè)置為Token Server,如果Token Server節(jié)點(diǎn)所在機(jī)器宕機(jī),可以將其他Client節(jié)點(diǎn)設(shè)置成server,sentinel有相關(guān)api提供該操作)
例如上面的例子,集群內(nèi)有3個(gè)節(jié)點(diǎn),如果每個(gè)節(jié)點(diǎn)能承受10的請(qǐng)求,那么加起來就是3x10=30個(gè)請(qǐng)求。也就是說只要qps不超過30個(gè)請(qǐng)求都不會(huì)觸發(fā)限流。
2.sentinel實(shí)現(xiàn)集群限流
1. 以spring-boot項(xiàng)目構(gòu)建 sentinel-token-server
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion> <groupId>com.lee.sentinel.tokenserver</groupId><artifactId>sentinel-token-server</artifactId><version>0.0.1-SNAPSHOT</version><name>sentinel-token-server</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><spring-boot.version>2.3.7.RELEASE</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><groupId>com.alibaba.spring</groupId><artifactId>spring-context-support</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--slf4j--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></dependency> <!--nacos配置中心--><dependency><groupId>com.alibaba.boot</groupId><artifactId>nacos-config-spring-boot-starter</artifactId><version>0.2.12</version><!--由于jar包沖突,此處排除沖突jar,重新導(dǎo)入高版本jar--><!--nacos-spring-context-1.1.1.jar需要比spring-context-support-1.0.8.jar更高版本的jar--><exclusions><exclusion><groupId>com.alibaba.spring</groupId><artifactId>spring-context-support</artifactId></exclusion></exclusions></dependency><!--重新引入jar包--><dependency><groupId>com.alibaba.spring</groupId><artifactId>spring-context-support</artifactId><version>1.0.11</version></dependency><!--sentinel-cluster--><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-cluster-server-default</artifactId><version>1.8.5</version></dependency> <!--sentinel dashboard--><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-transport-simple-http</artifactId><version>1.8.5</version></dependency><!--sentinel dashboard -> nacos 配置動(dòng)態(tài)感知--><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId><version>1.8.5</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
application.properties
server.port=9009
#應(yīng)用名稱
spring.application.name=sentinel-token-server
#nacos config center
nacos.config.server-addr=192.168.1.105:8848
ClusterServer啟動(dòng)類
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 ); //可以設(shè)置多個(gè)namespaceSet<String> namespaceSet = new HashSet<String>();namespaceSet.add("user-service"); //dataId=user-service-flow-rulesClusterServerConfigManager.loadServerNamespaceSet( namespaceSet ); tokenServer.start();}
}
SpringBoot啟動(dòng)類:
?基于spring-boot SPI機(jī)制初始化限流規(guī)則:
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";@Overridepublic void init() throws Exception {// TODO Auto-generated method stubloadFlowRuleByNacos();}private void loadFlowRuleByNacos() {// TODO Auto-generated method stub// 從Nacos上獲取配置進(jìn)行加載ClusterFlowRuleManager.setPropertySupplier(namespace -> {// namespace在ClusterServer.java中已配置String dataId = namespace + dataId_postfix; // user-service-flow-rules、 coupon-service-flow-rulesReadableDataSource<String, List<FlowRule>> readableDataSource = new NacosDataSource<>(remoteAddress,groupId, dataId, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));return readableDataSource.getProperty();});}}
其中,我的Nacos配置(dataId=user-service-flow-rules)設(shè)置如下:
[{"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搭建完成,啟動(dòng)服務(wù)
2. 配置客戶端Token Client
導(dǎo)包
<!--nacos配置中心--><dependency><groupId>com.alibaba.boot</groupId><artifactId>nacos-config-spring-boot-starter</artifactId><version>0.2.12</version><!--由于jar包沖突,此處排除沖突jar,重新導(dǎo)入高版本jar--><!--nacos-spring-context-1.1.1.jar需要比spring-context-support-1.0.8.jar更高版本的jar--><exclusions><exclusion><groupId>com.alibaba.spring</groupId><artifactId>spring-context-support</artifactId></exclusion></exclusions></dependency><!--重新引入jar包--><dependency><groupId>com.alibaba.spring</groupId><artifactId>spring-context-support</artifactId><version>1.0.11</version></dependency><!--sentinel-dubbo-adapter --><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-apache-dubbo-adapter</artifactId><version>1.8.5</version></dependency><!--sentinel dashboard--><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-transport-simple-http</artifactId><version>1.8.5</version></dependency><!--sentinel dashboard -> nacos 配置動(dòng)態(tài)感知--><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId><version>1.8.5</version></dependency><!--sentinel-token-cluster--><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-cluster-client-default</artifactId><version>1.8.5</version></dependency>
?加載集群流控規(guī)則:
?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";@Overridepublic void init() throws Exception {// TODO Auto-generated method stub//聲明為Token ClientClusterStateManager.applyState(ClusterStateManager.CLUSTER_CLIENT);//加載集群限流Token Server loadClusterClientConfig(); //加載單機(jī)限流規(guī)則(如果Token Server不可用,退化到單機(jī)限流)initFlowRulesWithDatasource(); }/*** 集群限流規(guī)則* */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);}/*** 單機(jī)限流規(guī)則* */private void initFlowRulesWithDatasource() { String dataId = APP_NAME + FLOW_POSTFIX;
// ReadableDataSource<String, List<FlowRule>> readableDataSource = new NacosDataSource<>(
// remoteAddress, groupId, dataId
// ,source->JSON.parseObject(source,new TypeReference<List<FlowRule>>() {}));ReadableDataSource<String, List<FlowRule>> readableDataSource = new NacosDataSource<>(remoteAddress, groupId, dataId, new Converter<String, List<FlowRule>>() { @Overridepublic List<FlowRule> convert(String source) {// TODO Auto-generated method stubSystem.out.println("source:"+source); List<FlowRule> rules = JSON.parseObject(source,new TypeReference<List<FlowRule>>() {}); return rules;}}); FlowRuleManager.register2Property(readableDataSource.getProperty());} }
Controller:
至此,Token Client配置完成。
接下來啟動(dòng)3個(gè)客戶端,模擬集群:
?
?Sentinel-Dashboard上可以看到user-service有三臺(tái)集群機(jī)器:
使用jmeter壓測(cè)工具進(jìn)行壓測(cè):
?壓測(cè)結(jié)果如下,可以看到com.lee.demo.dubbo.demo.user.ISentinelService.testSentinel() 接口的qps一直不會(huì)超過6個(gè)請(qǐng)求,這個(gè)峰值是怎么計(jì)算的來的呢?因?yàn)槲疑厦嫣岬降腘acos集群限流配置dataId=user-service-flow-rules中配置com.lee.demo.dubbo.demo.user.ISentinelService的qps=2,而我們總共有3臺(tái)機(jī)器,因此集群限流max qps:2x3=6
?至此,sentinel上線集群限流demo已完成,如有疑問請(qǐng)?jiān)谠u(píng)論區(qū)評(píng)論。