Spring Alibaba Sentinel实现集群限流demo

1.背景

1.什么是单机限流?

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

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

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

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

 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

<?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,重新导入高版本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 配置动态感知-->
        <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
#应用名称
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<String> namespaceSet = new HashSet<String>();
		namespaceSet.add("user-service"); //dataId=user-service-flow-rules
		ClusterServerConfigManager.loadServerNamespaceSet( namespaceSet ); 
		tokenServer.start();
	}
}

SpringBoot启动类:

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

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<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)设置如下:

[
    {
    "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

导包

        <!--nacos配置中心-->
        <dependency>
			<groupId>com.alibaba.boot</groupId>
			<artifactId>nacos-config-spring-boot-starter</artifactId>
			<version>0.2.12</version>
			<!--由于jar包冲突,此处排除冲突jar,重新导入高版本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 配置动态感知-->
        <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> 

 加载集群流控规则:

 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<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>>() { 
			@Override
			public List<FlowRule> convert(String source) {
				// TODO Auto-generated method stub
				System.out.println("source:"+source); 
				List<FlowRule> rules = JSON.parseObject(source,new TypeReference<List<FlowRule>>() {}); 
				return rules;
			}
		});    
		FlowRuleManager.register2Property(readableDataSource.getProperty());
	} 
	
}

Controller:

至此,Token Client配置完成。

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

 

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

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

 压测结果如下,可以看到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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/52590.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【*1900 图论+枚举思想】CF1328 E

Problem - E - Codeforces 题意&#xff1a; 思路&#xff1a; 注意到题目的性质&#xff1a;满足条件的路径个数是极少的&#xff0c;因为每个点离路径的距离<1 先考虑一条链&#xff0c;那么直接就选最深那个点作为端点即可 为什么&#xff0c;因为我们需要遍历所有点…

桥接模式——处理多维度变化

1、简介 1.1、概述 桥接模式是一种很实用的结构型设计模式。如果软件系统中某个类存在两个独立变化的维度&#xff0c;通过该模式可以将这两个维度分离出来&#xff0c;使两者可以独立扩展&#xff0c;让系统更加符合单一职责原则。与多层继承方案不同&#xff0c;它将两个独…

nosql之redis集群

nosql之redis集群 一.redis集群 1.单节点redis服务器带来的问题 &#xff08;1&#xff09;单点故障、服务不可用 &#xff08;2&#xff09;无法处理大量的并发数据请求 &#xff08;3&#xff09;数据丢失 2.集群redis &#xff08;1&#xff09;提供在多个redis节点间…

网络运维基础问题及解答

前言 本篇文章是对于网络运维基础技能的一些常见问题的解答&#xff0c;希望能够为进行期末复习或者对网络运维感兴趣的同学或专业人员提供一定的帮助。 问题及解答 1. 列举 3 种常用字符编码&#xff0c;简述怎样在 str 和 bytes 之间进行编码和解码。 答&#xff1a;常用的…

【数学建模】时间序列分析

文章目录 1. 条件2. 模型分类3. SPSS处理时间序列 1. 条件 1.使用于具有时间、数值两种要素 2.数据具有周期性可以使用时间序列分解 2. 模型分类 叠加模型【YTSCI】 序列的季节波动变化越来越大&#xff0c;反映变动之间的关系发生变化乘积序列【YTSC*I】 时间序列波动保持恒…

Scaling Instruction-Finetuned Language Models

Paper name Scaling Instruction-Finetuned Language Models Paper Reading Note Paper URL: https://arxiv.org/pdf/2210.11416.pdf TL;DR 2022 年谷歌出的文章&#xff0c;对指令微调的影响因素进行分析&#xff0c;提出了一些提升指令微调效果的方案。与该文章一起出品…

Linux--验证命令行上运行的程序的父进程是bash

1.输入以下代码&#xff1a; #include <stdio.h> #include <unistd.h> int main() {printf("hello world: pid: %d, ppid: %d\n",getpid(),getppid());return 0; }2.编译得到可执行程序​​​ 3.运行得到ppid 4.输入指令 ps axj | head -1 &&am…

【图论】差分约束

一.情景导入 x1-x0<9 ; x2-x0<14 ; x3-x0<15 ; x2-x1<10 ; x3-x2<9; 求x3-x0的最大值&#xff1b; 二.数学解法 联立式子2和5&#xff0c;可得x3-x0<23;但式子3可得x3-x0<15。所以最大值为15&#xff1b; 三.图论 但式子多了我们就不好解了&#xff0…

Linux标准库API

目录 1.字符串函数 2.数据转换函数 3.格式化输入输出函数 4.权限控制函数 5.IO函数 6.进程控制函数 7.文件和目录函数 1.字符串函数 2.数据转换函数 3.格式化输入输出函数 #include<stdarg.h>void test(const char * format , ...){va_list ap;va_start(ap,format…

测试的概念

测试职责 需求分析 测试分析 设计测试用例 执行测试用例 掌握自动化测试技术 验证产品是否实现了应该实现的功能,或者实现了不应该实现的功能 在整个软件生命周期中&#xff0c;测试是一个贯穿始终的过程&#xff0c;它包含了不同阶段和不同类型的测试,以此来保证软件工程的稳…

黑马头条---day1

手机端查看 docker 容器&#xff0c;镜像操作命令 1、docker删除所有镜像命令 删除所有镜像的命令是Docker中一个非常常见的操作。下面是具体的实现步骤和命令示例&#xff1a; $ docker stop $(docker ps -aq) 停止所有正在运行的容器。 $ docker rm $(docker ps -aq) 删…

靶机精讲之NYX

主机发现 端口扫描 服务扫描 -sV漏洞脚本扫描 UDP扫描 那些开发那些关闭 脚本扫描 或许有价值.php web渗透 看源码 目录爆破 没有扫到有价值的信息 继续web渗透&#xff0c;访问admin目录 继续目录扫描 sudo gobuster dir -u http://192.168.10.206 -x txt,sql,php,jsp -w…

20.1 HTML 介绍

1. W3C组织 万维网联盟(World Wide Web Consortium, W3C): 是一个国际性的标准化组织, 致力于开发和推广Web标准.W3C的使命是通过制定和推广Web技术标准, 促进Web的长期发展和互操作性, 它由许多组织和个人组成, 包括浏览器制造商, 软件开发商, 网络服务提供商, 学术机构和个…

线性代数(应用篇):第五章:特征值与特征向量、第六章:二次型

文章目录 第5章 特征值与特征向量、相似矩阵(一) 特征值与特征向量1.定义2.性质3.求解(1)具体型矩阵试根法、多项式带余除法&#xff1a;三阶多项式分解因式 (2)抽象型矩阵 (二) 相似1.矩阵相似(1)定义(2)性质 2.相似对角化(1)定义(2)相似对角化的条件&#xff08;n阶矩阵A可相…

python机器学习(五)逻辑回归、决策边界、代价函数、梯度下降法实现线性和非线性逻辑回归

线性回归所解决的问题是把数据集的特征传入到模型中&#xff0c;预测一个值使得误差最小&#xff0c;预测值无限接近于真实值。比如把房子的其他特征传入到模型中&#xff0c;预测出房价&#xff0c; 房价是一系列连续的数值&#xff0c;线性回归解决的是有监督的学习。有很多场…

【微服务】springboot整合mongodb使用详解

目录 一、mongodb简介 1.1 什么是mongodb 1.2 mongodb特点 二、mongodb中的核心术语 2.1 mogodb与数据库对比 2.2 mongodb中的核心概念 2.3 与关系数据库的差异 2.3.1 半结构化 2.3.2 支持多级嵌套 2.3.3 关系弱化 三、mongodb 技术优势和应用场景 3.1 mongodb 技术…

【C#】并行编程实战:并行编程中的模式

本章将介绍并行编程模式&#xff0c;重点是理解并行代码问题场景并使用并行编程/异步技术解决他们。本章会介绍几种最重要的编程模式。 本教程学习工程&#xff1a;魔术师Dix / HandsOnParallelProgramming GitCode 1、MapReduce 模式 引入 MapReduce 是为了解决处理大数据的问…

睡眠健康数据分析

项目背景 背景描述 本数据集涵盖了与睡眠和日常习惯有关的诸多变量。如性别、年龄、职业、睡眠时间、睡眠质量、身体活动水平、压力水平、BMI类别、血压、心率、每日步数、以及是否有睡眠障碍等细节。 数据集的主要特征&#xff1a; 综合睡眠指标&#xff1a; 探索睡眠持续时…

UNISOT让食品欺诈无处遁形

​​发表时间&#xff1a;2023年5月11日 全世界的消费者开始越来越关注食物的来源和采购方式。这是因为人们渴望吃得更健康、更用心&#xff0c;同时人们也认识到了购买可持续且合乎伦理道德的产品的必要性。 近年来&#xff0c;人们对食品溯源的渴望进一步加速&#xff0c;原…

Python读取csv、Excel文件生成图表

简介 本文章介绍了通过读取 csv 或 Excel 文件内容&#xff0c;将其转换为折线图或柱状图的方法&#xff0c;并写入 html 文件中。 目录 1. 读取CSV文件 1.1. 生成折线图 1.1.1. 简单生成图表 1.1.2. 设置折线图格式 1.2. 生成柱状图 1.2.1. 简单生成图表 1.2.2. 设置柱…