Spring cloud 整合Sentinel 实现redis缓存限流规则(最新一)

作者:青山常在人不老   阅读 (2301)  |  收藏 (0)  |  点赞 (0)

摘要

Spring cloud gateway 整合 sentinel 做限流和熔断,同时将规则缓存到Redis中最新教程,本文为作者结合最新的Sentinel v1.7.2整合的Redis持久化Sentinel限流规则、用redis持久化Sentinel规则的教程。


原文链接:Spring cloud 整合Sentinel 实现redis缓存限流规则(最新一)

不同于网上的其他文章,抄来抄去都是一样的,本文是严格参照官方最新文档,代码都是经过自己实际测试,并非抄袭网上的现有文章来做的,如果您觉得文章对您有帮助,还请多多转发,让更多的朋友能够借助本文少走弯路。

前言

大致先普及一下Senttinel的服务端和客户端规则交互的方式,已经熟悉的请跳过此前言部分。

我们知道Sentinel具有监控,限流、熔断规则管理和推送(拉模式不在本篇文章的探讨范围之内)的功能,而规则的推送,Sentinel有三种方式:原始模式、pull模式、push模式。

这三种模式的比较如下(详见官方文档):

推送模式说明有点缺点
原始模式API 将规则推送至客户端并直接更新到内存中,扩展写数据源(WritableDataSource)简单,无任何依赖不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境
Pull 模式扩展写数据源(WritableDataSource), 客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件等简单,无任何依赖;规则持久化不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题。
Push 模式扩展读数据源(ReadableDataSource),规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源。规则持久化;一致性;快速引入第三方依赖

参考上述对比,我们可以知道,如果您要把Sentinel部署至生产环境,官方是推荐使用Push模式的,当然这种方式使用起来是有一定的成本的。

在我的上一篇文章中,我们也说了Sentinel支持多种持久化工具,包含静态文件数据源、ZooKeeper 数据源、Redis 数据源、Nacos 数据源、Apollo 数据源、Spring Cloud Config 数据源、Etcd 数据源、Consul 数据源这几种,我们本篇文章将会讲解如何使用Redis数据源来持久化Sentinel规则。

需要注意的是,Sentinel官方明确说明:Sentinel结合这些数据源做持久化一般是需要修改Sentinel dashboard源码的,本文就是需要在修改Sentinel dashboard源码的基础上,增加了适合Redis持久化Sentinel限流规则和熔断规则的逻辑。需要会修改flowRuleRedisProvider和flowRuleRedisPublisher,以及一些其他的文件,具体修改的那些地方,在下文会有详细的说明。

开始使用

修改的地方有两个,一个是Sentinel dashboard项目,一个是你自己的项目(客户端)

修改Sentinel dashboard项目

首先你需要down下来Sentinel整个项目源码,本文使用的为Sentinel 1.7.2的源码,源码下载路径为:官方Sentinel ,下载后请导入到开发工具(Eclipse 或者 idea)中准备修改源码并编译。

导入的项目结构如下:

Sentinel 结合Redis持久化限流规则和熔断规则的最新教程


我们将将要修改的代码就在sentinel-dashboard项目中。

此项目中要修改得地方有

  • application.properties(增加Redis配置参数)

  • pom.xml(增加Redis的依赖)

  • FlowRuleRedisProvider.java(新增,自定义的Redis拉取规则)

  • FlowRuleRedisPublisher.java(新增,自定义的Redis推送规则)

  • RedisConfig.java(新增,定义的Redis配置类)

  • RuleConstants.java(新增,Redis的常量)

  • FlowControllerV1.java(修改,修改规则推送逻辑和拉取逻辑)

所有的修改内容已经罗列在上面了,下面咱们就详细说说如何修改:

application.properties文件

此文件在sentinel-dashboard项目下的resource中,在此文件最下面添加下面的配置:

# Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09
spring.redis.database=0
# Redis\u670D\u52A1\u5668\u5730\u5740
spring.redis.host=127.0.0.1
# Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3
spring.redis.port=6379
# \u8FDE\u63A5\u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09
spring.redis.timeout=30000

#\u6D41\u63A7\u89C4\u5219key\u524D\u7F00
rule.flow=sentinel_rule_flow_

注意,上面的配置中,前四个配置为redis的配置,不在解释,自己修改成自己的就可以,“rule.flow=sentinel_rule_flow_”为你要存到Redis中的KEY,这个配置在RuleConstants.java被引用了

pom.xml

此文件在sentinel-dashboard项目下,请添加以下依赖:

<!-- 集成redis -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-redis</artifactId>
    <version>1.7.1</version>
</dependency>
<!--redis依赖-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
   <version>${spring.boot.version}</version>
</dependency>

注意,此处的${spring.boot.version}表示使用此项目本身配置的版本,以适应他的jar要求,防止jar依赖出问题。

FlowRuleRedisProvider.java

此文件新增,新增的位置com.alibaba.csp.sentinel.dashboard.rule.redis(注意,redis路径需要新增),如图:

Sentinel 结合Redis持久化限流规则和熔断规则的最新教程

上面所说的几个新增的类同样需要放在此路径下,这个类的作用是自定义基于Redis实现拉取限流规则的逻辑

package com.alibaba.csp.sentinel.dashboard.rule.redis;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.fastjson.JSONObject;

/**
 * @project: xxx
 * @description: 自定义实现基于redis的拉取规则
 * @version 1.0.0
 * @errorcode
 *            错误码: 错误描述
 * @author
 *         <li>2020-07-17 guopengfei@bobfintech.com.cn Create 1.0
 * @copyright ©2019-2020 xxxx,版权所有。
 */
@Component("flowRuleRedisProvider")
public class FlowRuleRedisProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RuleConstants ruleConstants;

    @Override
    public List<FlowRuleEntity> getRules(String appName) throws Exception {
        System.out.println("Sentinel 从Redis拉取规则 begin >>>>>>>>>>>>>>>>>>>>");
        Object value1 =  redisTemplate.opsForValue().get(ruleConstants.ruleFlow + appName);
        String value = (String) redisTemplate.opsForValue().get(ruleConstants.ruleFlow + appName);
        if (StringUtils.isEmpty(value)){
            return new ArrayList<>();
        }
        System.out.println("Sentinel 从Redis拉取规则 end >>>>>>>>>>>>>>>>>>>>");
        return JSONObject.parseArray(value,FlowRuleEntity.class);
    }
}

FlowRuleRedisPublisher.java

此文件新增,新增的位置com.alibaba.csp.sentinel.dashboard.rule.redis,这个类的作用是自定义基于Redis实现推送限流规则的逻辑

package com.alibaba.csp.sentinel.dashboard.rule.redis;

import java.util.List;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonAlias;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;

/**
 * @project: xxxx
 * @description: 自定义实现限流配置推送规则
 * @version 1.0.0
 * @errorcode
 *            错误码: 错误描述
 * @author
 *         <li>2020-07-17 guopengfei@bobfintech.com.cn Create 1.0
 * @copyright ©2019-2020 xxxx,版权所有。
 */
@Component("flowRuleRedisPublisher")
public class FlowRuleRedisPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RuleConstants ruleConstants;

    @Override
    public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
        System.out.println("Sentinel 向Redis推送规则 begin >>>>>>>>>>>>>>>>>>>>");
        if (rules == null){
            return;
        }
        redisTemplate.multi();
        redisTemplate.opsForValue().set(ruleConstants.ruleFlow+app, JSONObject.toJSONString(rules));
        redisTemplate.convertAndSend(app,rules);
        redisTemplate.exec();
        System.out.println("Sentinel 向Redis推送规则 end >>>>>>>>>>>>>>>>>>>>");
    }
}

RedisConfig.java

此文件新增,新增的位置com.alibaba.csp.sentinel.dashboard.rule.redis,这个类的作用是定义Redis的配置(这个类可用可不用)

package com.alibaba.csp.sentinel.dashboard.rule.redis;

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * @project: xxxx
 * @description: Redis配置
 * @version 1.0.0
 * @errorcode
 *            错误码: 错误描述
 * @author
 *         <li>2020-07-17 guopengfei@bobfintech.com.cn Create 1.0
 * @copyright ©2019-2020 xxxx,版权所有。
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport
{
 
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory)
    {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(factory);
        // 打开事务
        redisTemplate.setEnableTransactionSupport(true);
        // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
        Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
        
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        serializer.setObjectMapper(mapper);

        redisTemplate.setValueSerializer(serializer);
        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(serializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

RuleConstants.java

此文件新增,新增的位置com.alibaba.csp.sentinel.dashboard.rule.redis,这个类的作用是定义Redis中使用的常量,里面只定义了一个,就是上文说的Redis保存规则的KEY

package com.alibaba.csp.sentinel.dashboard.rule.redis;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @project: xxxx
 * @description: Redis常量
 * @version 1.0.0
 * @errorcode
 *            错误码: 错误描述
 * @author
 *         <li>2020-07-17 guopengfei@bobfintech.com.cn Create 1.0
 * @copyright ©2019-2020 xxxx,版权所有。
 */
@Component
public class RuleConstants {

    /**
     * 流控规则key前缀
     */
    @Value("${rule.flow}")
    public String ruleFlow;

}

FlowControllerV1.java

注意,这个类原本就存在,位于com.alibaba.csp.sentinel.dashboard.controller路径下,我们需要修改它的推送逻辑和拉取逻辑(此类基于sentinel 1.7.2修改,如果未来的您使用的版本比这个高,或者地,请谨慎修改---只动推送和拉取的逻辑)

Srping cloud 整合Sentinel 实现redis缓存限流规则(最新二)

分类   Spring boot 开发
字数   8906

博客标签    Redis 持久化 Sentinel  

评论