Springboot + aop + Lua analyse du principe de limitation de courant distribué

1. Quelle est la limite actuelle? Pourquoi limiter le courant?
Je ne sais pas si vous avez déjà fait le métro de la Cité Impériale, c'est-à-dire le genre de file d'attente lorsque vous vous rendez à la station de métro. Pourquoi devez-vous tourner en rond de cette façon? La réponse est de limiter le courant! Parce que la capacité de transport d'un métro est limitée, trop de monde à la fois entraînera un encombrement de la plate-forme et une surcharge du train, et il y aura certains risques pour la sécurité. De la même manière, notre programme est le même et sa capacité à traiter les demandes est limitée. Une fois que le nombre de demandes dépasse sa limite de traitement, il se bloque. Afin de ne pas avoir la pire situation de crash, nous ne pouvons que retarder le temps pour tout le monde d'entrer dans la station.
Springboot + aop + Lua analyse du principe de limitation de courant distribué

La limitation du courant est un moyen important pour assurer une haute disponibilité du système! ! !

En raison de l'énorme trafic des sociétés Internet, le système se connecte pour effectuer une évaluation du trafic de pointe, en particulier comme diverses promotions de pointe. Afin de s'assurer que le système ne soit pas submergé par un trafic énorme, lorsque le trafic du système atteint un certain seuil, il rejettera une partie du trafic. .

La limite actuelle entraînera l'indisponibilité de l'utilisateur pendant une courte période (cette période est de l'ordre des millisecondes). En général, l'indicateur de mesure de la capacité de traitement du système est QPS ou TPS par seconde. En supposant que le seuil de débit du système par seconde est de 1000, théorique Lorsqu'une demande 1001 arrive dans une seconde, la demande sera limitée.

Deuxièmement, le programme de limitation de courant
1. Le compteur
Java peut également utiliser le compteur atomique AtomicInteger, Semaphore semaphore pour faire une limite de courant simple.

// 限流的个数
        private int maxCount = 10;
        // 指定的时间内
        private long interval = 60;
        // 原子类计数器
        private AtomicInteger atomicInteger = new AtomicInteger(0);
        // 起始时间
        private long startTime = System.currentTimeMillis();

        public boolean limit(int maxCount, int interval) {
                atomicInteger.addAndGet(1);
                if (atomicInteger.get() == 1) {
                        startTime = System.currentTimeMillis();
                        atomicInteger.addAndGet(1);
                        return true;
                }
                // 超过了间隔时间,直接重新开始计数
                if (System.currentTimeMillis() - startTime > interval * 1000) {
                        startTime = System.currentTimeMillis();
                        atomicInteger.set(1);
                        return true;
                }
                // 还在间隔时间内,check有没有超过限流的个数
                if (atomicInteger.get() > maxCount) {
                        return false;
                }
                return true;
        }

2.
Algorithme du seau qui fuit L'idée de l'algorithme du seau qui fuit est très simple. Nous comparons l'eau comme une demande et le seau qui fuit comme la limite de la capacité de traitement du système. L'eau entre d'abord dans le seau qui fuit et l'eau dans le seau qui fuit s'écoule à un certain débit. Lorsque le débit est inférieur au débit d'entrée, en raison de la capacité limitée du seau qui fuit, l'eau entrante suivante déborde directement (rejette la demande) pour atteindre la limitation de débit.
Springboot + aop + Lua analyse du principe de limitation de courant distribué

3.
Algorithme de seau à jetons Le principe de l'algorithme de seau à jetons est également relativement simple. Nous pouvons le comprendre comme un hôpital enregistré pour voir un médecin. Ce n'est qu'après avoir obtenu le numéro que le médecin peut être diagnostiqué.
Le système gère un compartiment de jetons et place les jetons dans le compartiment à une vitesse constante. Si une demande arrive et veut être traitée, vous devez d'abord obtenir un jeton du compartiment. ), Lorsqu'aucun jeton n'est disponible dans le compartiment, le service sera refusé. L'algorithme du compartiment de jetons atteint la limite des demandes en contrôlant la capacité du compartiment et le taux d'émission de jetons.
Springboot + aop + Lua analyse du principe de limitation de courant distribué

4. Redis + Lua
Beaucoup d'étudiants ne savent pas ce qu'est Lua? Personnellement, les scripts Lua et les bases de données MySQL ont des procédures stockées similaires. Ils exécutent un ensemble de commandes, et toutes les commandes s'exécutent avec succès ou échouent à atteindre l'atomicité. Vous pouvez également comprendre le script Lua comme un morceau de code avec une logique métier.

Lua lui-même est un langage de programmation. Bien que Redis ne fournisse pas directement l'API correspondante pour la limitation de courant, il prend en charge la fonction des scripts Lua. Il peut être utilisé pour implémenter des algorithmes de compartiment de jeton ou de fuite complexes, qui sont également implémentés dans des systèmes distribués. L'un des principaux moyens de limiter le courant.

Par rapport aux transactions Redis, les avantages des scripts Lua sont:

Réduisez la surcharge du réseau: utilisez le script Lua, n'avez pas besoin d'envoyer plusieurs demandes à Redis, exécutez-le une fois, réduisez
l'opération atomique de transmission réseau : Redis exécute l'intégralité du script Lua comme une commande, atomique, sans se soucier de la
réutilisation simultanée : une fois le script Lua exécuté, Sera définitivement enregistré dans Redis, et d'autres clients peuvent réutiliser les
scripts Lua à peu près comme suit:

-Obtenir la première valeur de clé transmise lors de l'appel du script (utilisé comme clé de limite actuelle) clé
locale = KEYS [1] -Obtenir
la première valeur de paramètre transmise lors de l'appel du script (limiter la taille actuelle)
limite locale = tonumber (ARGV [1])


-Obtenir la taille actuelle du trafic local curentLimit = tonumber (redis.call ('get', key) ou "0")

-- 是否超出限流
    if curentLimit + 1 > limit then
            -- 返回(拒绝)
            return 0
    else
            -- 没有超出 value + 1
            redis.call("INCRBY", key, 1)
            -- 设置过期时间
            redis.call("EXPIRE", key, 2)
            -- 返回(放行)
            return 1
    end

Récupère le paramètre de clé entrante via KEYS [1] Récupère le paramètre de
limite entrante via la méthode ARGV [1]
redis.call, récupère la valeur liée à la clé dans le cache, si elle est nulle, retourne 0
puis juge l'enregistrement dans le cache Si la valeur sera supérieure à la taille limite. Si elle dépasse la limite, cela signifie que le courant est limité.
S'il ne dépasse pas 0 , la valeur de cache de la clé est +1, et le délai d'expiration est défini sur 1 seconde, et la valeur de cache +1
est renvoyée La solution recommandée dans cet article sera expliquée en détail plus loin.

5. La limitation de courant et la
limitation de courant de la couche passerelle sont souvent effectuées au niveau de la couche passerelle, telles que Nginx, Openresty, kong, zuul, Spring Cloud Gateway, etc. Script de limitation de courant Lua intégré.
Springboot + aop + Lua analyse du principe de limitation de courant distribué

Troisièmement, la mise en œuvre de la limitation de courant de Redis + Lua
Ci-dessous, nous atteignons la limitation de courant grâce à des annotations personnalisées, aop, Redis + Lua, les étapes seront plus détaillées, afin de permettre à Bai Bai de démarrer rapidement, les vétérans expérimentés prendront plus de soin.

1. L'
adresse de création du projet Springboot de préparation de l'environnement : https://start.spring.io , un outil très pratique et pratique.

Springboot + aop + Lua analyse du principe de limitation de courant distribué
2. Introduisez le package de dépendance dans le
fichier pom et ajoutez les packages de dépendance suivants: les principaux sont spring-boot-starter-data-redis et spring-boot-starter-aop.

<dependencies>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-web</artifactId>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-data-redis</artifactId>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-aop</artifactId>
                </dependency>
                <dependency>
                        <groupId>com.google.guava</groupId>
                        <artifactId>guava</artifactId>
                        <version>21.0</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-test</artifactId>
                </dependency>
                <dependency>
                        <groupId>org.apache.commons</groupId>
                        <artifactId>commons-lang3</artifactId>
                </dependency>

                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-test</artifactId>
                        <scope>test</scope>
                        <exclusions>
                                <exclusion>
                                        <groupId>org.junit.vintage</groupId>
                                        <artifactId>junit-vintage-engine</artifactId>
                                </exclusion>
                        </exclusions>
                </dependency>
        </dependencies>

3. Configurez application.properties
pour configurer l'adresse de service et le port redis qui ont été créés à l'avance dans le fichier application.properties.

spring.redis.host=127.0.0.1

spring.redis.port=6379
4、配置RedisTemplate实例
@Configuration
public class RedisLimiterHelper {

@Bean
public RedisTemplate<String, Serializable> limitRedisTemplate(LettuceConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Serializable> template = new RedisTemplate<>();
    template.setKeySerializer(new StringRedisSerializer());
    template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    template.setConnectionFactory(redisConnectionFactory);
    return template;
}

}
Classe d'énumération de type limite actuelle

/**
 * @author fu
 * @description 限流类型
 * @date 2020/4/8 13:47
 */
public enum LimitType {

        /**
         * 自定义key
         */
        CUSTOMER,

        /**
         * 请求者IP
         */
        IP;
}

5. Annotations personnalisées
Nous définissons une annotation @Limit, le type d'annotation est ElementType.METHOD, qui agit sur la méthode.

période est la période limite de demande, et count est le nombre de fois où la demande peut être libérée pendant la période. limitType représente le type de limite actuelle. Vous pouvez personnaliser la clé en fonction de l'adresse IP demandée. Si vous ne transmettez pas l'attribut limitType, le nom de la méthode est utilisé par défaut comme clé par défaut.

/**
 * @author fu
 * @description 自定义限流注解
 * @date 2020/4/8 13:15
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Limit {

/**
 * 名字
 */
String name() default "";

/**
 * key
 */
String key() default "";

/**
 * Key的前缀
 */
String prefix() default "";

/**
 * 给定的时间范围 单位(秒)
 */
int period();

/**
 * 一定时间内最多访问次数
 */
int count();

/**
 * 限流的类型(用户自定义key 或者 请求ip)
 */
LimitType limitType() default LimitType.CUSTOMER;
}

6. Mise en œuvre du code aspect
/ **

}
8.
Attente du test de test: trois requêtes consécutives peuvent aboutir, la quatrième requête est rejetée. Voyons ensuite si nous nous attendons à l'effet. L'adresse de la demande:
http://127.0.0.1:8080/limitTest1 . Utilisez postman pour tester. Il en va de même s'il existe une URL de postier directement publiée dans le navigateur.
Springboot + aop + Lua analyse du principe de limitation de courant distribué

On peut voir que lorsque la quatrième demande a été faite, l'application a directement rejeté la demande, indiquant que notre solution de limitation de courant Springboot + aop + lua a été construite avec succès.

Springboot + aop + Lua analyse du principe de limitation de courant distribué
Pour résumer le
Springboot + aop + Lua, la mise en œuvre de la limite de courant est relativement simple, conçue pour que tout le monde sache quelle est la limite de courant? Comment faire une simple fonction de limite de courant, l'entretien doit savoir de quoi il s'agit. Bien que les solutions mentionnées ci-dessus, plusieurs pour atteindre la limitation de courant, mais laquelle choisir doivent être combinées avec des scénarios commerciaux spécifiques, ne peuvent pas être utilisées.

Je suppose que tu aimes

Origine blog.51cto.com/14765930/2486702
conseillé
Classement