Springboot + aop + Lua分散電流制限原理分析

1.現在の制限とは何ですか?なぜ電流を制限するのですか?
帝国都市の地下鉄、つまり地下鉄の駅に行くときに列を作らなければならない種類の地下鉄をこれまでに行ったことがあるかどうかはわかりません。なぜこのように円を描く必要があるのですか。答えは電流を制限することです!地下鉄の輸送能力は限られているため、一度に多くの人が混雑すると、プラットホームが混雑し、列車が過負荷になり、特定の安全上のリスクが発生します。同様に、プログラムも同じで、リクエストを処理する機能が制限されています。リクエストの数が処理制限を超えると、クラッシュします。最悪のクラッシュ状況にならないようにするために、私たちは誰もが駅に入る時間を遅らせることしかできません。
Springboot + aop + Lua分散電流制限原理分析

電流制限は、システムの高可用性を確保するための重要な手段です。

インターネット会社の膨大なトラフィックのため、システムはオンラインになり、特にさまざまなスパイクプロモーション活動のように、ピークトラフィック評価を行います。システムが膨大なトラフィックに圧倒されないようにするために、システムトラフィックが特定のしきい値に達すると、一部のトラフィックが拒否されます。

現在の制限により、ユーザーは短期間(この時間はミリ秒のオーダーです)利用できなくなります。一般に、システムの処理能力を測定するためのインジケーターは、QPSまたはTPS /秒​​です。システムの1秒あたりのフローしきい値が理論上1000であると仮定します。 1001リクエストが1秒以内に届くと、リクエストは抑制されます。

2番目に、現在の制限プログラム
1.カウンター
Javaは、アトミックカウンターAtomicInteger、Semaphore semaphoreを使用して、単純な現在の制限を行うこともできます。

// 限流的个数
        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.
リーキーバケットアルゴリズムリーキーバケットアルゴリズムの考え方は非常に単純です。私たちは、要求としての水とシステムの処理能力の限界としてのリーキーバケットを比較します。水は最初にリーキーバケットに入り、リーキーバケット内の水は特定の速度で流出します。流量が流入流量よりも少ない場合、漏れているバケットの容量が限られているため、後続の流入水が直接オーバーフロー(要求を拒否)して流量制限を達成します。
Springboot + aop + Lua分散電流制限原理分析

3.
トークンバケットアルゴリズムトークンバケットアルゴリズムの原理も比較的単純で、登録された病院として診察を受けることができ、番号を取得して初めて医師を診断できます。
システムはトークンバケットを維持し、一定の速度でトークンをバケットに入れます。リクエストが届いて処理したい場合は、まずバケットからトークンを取得する必要があります。 )、バケットでトークンを使用できない場合、リクエストはサービスを拒否されます。トークンバケットアルゴリズムは、バケットの容量とトークンの発行レートを制御することで、リクエストの制限を実現します。
Springboot + aop + Lua分散電流制限原理分析

4. Redis + Lua
多くの学生はLuaが何であるかを知りませんか?個人的には、LuaスクリプトとMySQLデータベースには同様のストアドプロシージャがあり、それらは一連のコマンドを実行し、すべてのコマンドは正常に実行されるか、または不可分性を達成するために失敗します。Luaスクリプトは、ビジネスロジックを備えたコードの一部として理解することもできます。

Lua自体はプログラミング言語です。Redisは電流制限に対応するAPIを直接提供していませんが、Luaスクリプトの機能をサポートしています。これは、分散システムにも実装されている複雑なトークンバケットまたはリークバケットアルゴリズムの実装に使用できます。電流を制限する主な方法の1つ。

Redisトランザクションと比較すると、Luaスクリプトの利点は次のとおりです。

ネットワークのオーバーヘッドを削減する:Luaスクリプトを使用し、Redisに複数のリクエストを送信する必要がなく、1回実行します。ネットワーク転送の
アトミック操作を削減します。Redisは、同時
再利用を心配せずに、Luaスクリプト全体をコマンド、アトミックとして実行します:Luaスクリプトが実行されると、 Redisに永続的に保存され、他のクライアントは
Luaスクリプトをほぼ次のように再利用できます。

-スクリプトを呼び出すときに渡される最初のキー値を取得(現在の制限キーとして使用)
ローカルキー= KEYS [1]-
スクリプトを呼び出すときに渡される最初のパラメーター値を取得(現在のサイズを
制限ローカル制限= tonumber(ARGV [1])


- 現在のトラフィックサイズを取得ローカルcurentLimit = tonumber(redis.call( 'get'、key)または "0")

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

KEYS [1]を介して着信キーパラメータを取得します。ARGV
[1]
redis.callメソッドを介して着信制限パラメータ取得し、キャッシュからキーに関連する値を取得します。それがnullの場合は0を返し
、キャッシュ内のレコードを判断します。値が制限サイズより大きくなるかどうか。制限を超える場合は、電流が制限されていることを意味し
ます。0を超えない場合、キーのキャッシュ値は+1になり、有効期限は1秒後に設定され、キャッシュ値+1
返されます。この記事で推奨されるソリューションについては、後で詳しく説明します。

5.ゲートウェイレイヤーの電流制限と電流
制限は、Nginx、Openresty、kong、zuul、Spring Cloud Gatewayなどのゲートウェイレイヤーで行われることが多く、Spring Cloudゲートウェイゲートウェイの電流制限の基本的な実装原理はRedis + Luaに基づいています。組み込みのLua電流制限スクリプト。
Springboot + aop + Lua分散電流制限原理分析

3つ目は、Redis + Luaの電流制限の実装
カスタムアノテーションaop、Redis + Luaを使用して電流制限実現するための手順です。BaiBaiをすぐに開始できるように、経験豊富なベテランがさらに注意を払います。

1.環境の準備
Springbootプロジェクト作成アドレス:https : //start.spring.io、非常に便利で実用的なツール。

Springboot + aop + Lua分散電流制限原理分析
2.
pomファイルに依存関係パッケージを導入し、次の依存関係パッケージを追加します重要なものは、spring-boot-starter-data-redisと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. application.properties
を設定して、application.propertiesファイルに事前に構築されているredisサービスのアドレスとポートを設定します。

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;
}

}
制限型列挙クラス

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

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

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

5.カスタムアノテーション
@Limit アノテーションを定義しますアノテーションタイプはElementType.METHODで、メソッドに作用します。

periodは要求の制限期間で、countはその期間中に要求を解放できる回数です。limitTypeは、現在の制限のタイプを表します。要求されたIPに応じてキーをカスタマイズできます。limitType属性を渡さない場合、メソッド名がデフォルトでデフォルトのキーとして使用されます。

/**
 * @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.アスペクトコードの実装
/ **

}
8.テスト
テストの期待:3つの連続した要求が成功する可能性があり、4番目の要求は拒否されます。次に、効果が期待できる
かどうかを確認しますリクエストアドレス:http : //127.0.0.1 : 8080 / limitTest1。テストにはpostmanを使用します。ブラウザに直接ポストされたpostman URLがあるかどうかは同じです。
Springboot + aop + Lua分散電流制限原理分析

4番目のリクエストが行われたときに、アプリケーションがリクエストを直接拒否したことがわかります。これは、Springboot + aop + lua電流制限ソリューションが正常に構築されたことを示しています。

Springboot + aop + Lua分散電流制限原理分析

上記のspringboot + aop + Luaの電流制限の実装を要約すると、電流制限とは何かを全員に知らせるように設計されていますか?簡単な電流制限機能を実行する方法、インタビューはこれが何であるかを知っている必要があります。上記は、電流制限を実現するためのいくつかの解決策ですが、どれを選択するかは特定のビジネスシナリオと組み合わせる必要がありますが、使用することはできません。

おすすめ

転載: blog.51cto.com/14765930/2486702