欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Redis和Nginx實現(xiàn)限制接口請求頻率的示例

 更新時間:2024年02月03日 09:48:56   作者:????????帥龍之龍  
限流就是限制API訪問頻率,當(dāng)訪問頻率超過某個閾值時進(jìn)行拒絕訪問等操作,本文主要介紹了Redis和Nginx實現(xiàn)限制接口請求頻率的示例,具有一定的參考價值,感興趣的可以了解一下

前言

為啥需要限制接口請求頻率?這個是因為防止接口一直被刷,比如發(fā)送手機(jī)驗證碼的接口,一直被刷的話,費錢費資源的,至少做點基本的防護(hù)工作。以下分別使用Redis和Nginx實現(xiàn)限制接口請求頻率方案。

一、基于Redis實現(xiàn)接口限流

1.ZADD 命令

(1)用法:ZADD key score_1 value_1 score_2 value_2 ...
(2)作用:將一個或多個成員元素及其分?jǐn)?shù)值加入到有序集當(dāng)中。某個成員已經(jīng)是有序集的成員,那么更新這個成員的分?jǐn)?shù)值,并通過重新插入這個成員元素,來保證該成員在正確的位置上。分?jǐn)?shù)值可以是整數(shù)值或雙精度浮點數(shù)。
(3)返回值:被成功添加的新成員的數(shù)量,不包括那些被更新的、已經(jīng)存在的成員。
(4)示例

redis > ZADD runoobkey 1 redis
(integer) 1
redis > ZADD runoobkey 2 mongodb
(integer) 1
redis > ZADD runoobkey 3 mysql
(integer) 1
redis > ZADD runoobkey 3 mysql
(integer) 0
redis > ZADD runoobkey 4 mysql
(integer) 0
redis > ZRANGE runoobkey 0 10 WITHSCORES

1) "redis"
2) "1"
3) "mongodb"
4) "2"
5) "mysql"
6) "4"

2.ZREM 命令

(1)用法:ZREM key value_1 value_2 ...
(2)作用:移除有序集中的一個或多個成員,不存在的成員將被忽略。
(3)返回值:被成功添加的新成員的數(shù)量,不包括那些被更新的、已經(jīng)存在的成員。
(4)示例

redis > ZRANGE runoobkey 0 10 WITHSCORES

1) "redis"
2) "1"
3) "mongodb"
4) "2"
5) "mysql"
6) "4"

redis > ZREM mongodb
(integer) 1

redis > ZRANGE runoobkey 0 10 WITHSCORES
1) "redis"
2) "1"
3) "mysql"
4) "4"

3.ZCARD 命令

(1)用法:ZCARD key
(2)作用:獲取有序集合中成員的數(shù)量。
(3)返回值:當(dāng)key存在且是有序集類型時,返回有序集的基數(shù)。 當(dāng)key不存在時,返回0 。
(4)示例

redis > ZADD myzset 1 "one"
(integer) 1
redis > ZADD myzset 2 "two"
(integer) 1
redis > ZCARD myzset
(integer) 2

4.ZREMRANGEBYSCORE 命令

(1)用法:ZREMRANGEBYSCORE key min max
(2)作用:移除有序集中,指定分?jǐn)?shù)區(qū)間內(nèi)的所有成員。
(3)返回值:被移除成員的數(shù)量。
(4)示例

redis > ZRANGE salary 0 -1 WITHSCORES
1) "tom"
2) "2000"
3) "peter"
4) "3500"
5) "jack"
6) "5000"

redis > ZREMRANGEBYSCORE salary 1500 3500
(integer) 2

redis> ZRANGE salary 0 -1 WITHSCORES
1) "jack"
2) "5000"

5.具體實現(xiàn)

(1)新建一個過濾器,如【/src/main/java/org/example/interceptor/RateLimiterInterceptor.java】

package org.example.interceptor;

import cn.hutool.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * 限流攔截器
 */
@Component
public class RateLimiterInterceptor implements HandlerInterceptor {
    private static final String RATE_LIMITER_PREFIX = "Rate-Limiter:";
    private static final int LIMIT = 10; // 限流閾值
    private static final int TIME_WINDOW = 60; // 時間窗口,單位為秒

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json");

        String key = RATE_LIMITER_PREFIX + request.getRequestURI() + ":" + request.getRemoteAddr(); // Rate-Limiter:/api/sendCode:127.0.0.1

        long currentTime = System.currentTimeMillis(); // 1703036748554
        long beforeTime = currentTime - TIME_WINDOW * 1000; // 1703036748554 - 60000 = 1703036688554

        // Long removeNum = stringRedisTemplate.opsForZSet().removeRangeByScore(K key, double min, double max); // 刪除有序集合中分?jǐn)?shù)在指定范圍內(nèi)的元素,返回刪除元素的數(shù)量
        stringRedisTemplate.opsForZSet().removeRangeByScore(key, 0, beforeTime); // 刪除有序集合中60秒之前存進(jìn)去的所有數(shù)據(jù),如:

        // Long memberNum = stringRedisTemplate.opsForZSet().size(K key); // 獲取有序集合中元素的數(shù)量
        long count = stringRedisTemplate.opsForZSet().size(key); // 3
        if (count >= LIMIT) {
            HashMap<String, Object> responseObj = new HashMap<>();
            responseObj.put("code", HttpStatus.TOO_MANY_REQUESTS.value());
            responseObj.put("success", false);
            responseObj.put("msg", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());
            JSONObject json = new JSONObject(responseObj);
            response.getWriter().println(json);
            return false;
        } else {
            // Boolean addFlag = stringRedisTemplate.opsForZSet().add(K var1, V var2, double var3); // 向有序集合中添加一個或多個元素,并指定其分?jǐn)?shù)
            stringRedisTemplate.opsForZSet().add(key, String.valueOf(currentTime), currentTime);

            // Boolean expireFlag = stringRedisTemplate.expire(K key, long timeout, TimeUnit unit); // 對指定key的數(shù)據(jù)設(shè)置過期時間
            stringRedisTemplate.expire(key, TIME_WINDOW, TimeUnit.SECONDS);

            return true;
        }
    }
}

(2)在SpringMVC配置類中注入此過濾器,如【/src/main/java/org/example/config/ResourceConfig.java】

package org.example.config;

import org.example.interceptor.RateLimiterInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
public class ResourceConfig extends WebMvcConfigurationSupport {
    @Autowired
    private RateLimiterInterceptor rateLimiterInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(rateLimiterInterceptor).addPathPatterns("/abcd/api/sendCode");
    }
}

6.運行效果

// ~

二、基于Nginx實現(xiàn)接口限流

1.在nginx.conf文件中新增限流配置

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;

    # 負(fù)載均衡
    upstream springboot {
        server xxx.xxx.xxx.xxx:8080;
    }

    # limit_req_zone $binary_remote_addr zone=limit_zone:10m rate=10r/s; # 定義了一個名為limit_zone的限流區(qū)域,使用IP地址進(jìn)行限流,該區(qū)域的大小為10MB,限流速率為10個請求每秒。

    limit_req_zone $binary_remote_addr zone=limit_zone:10m rate=10r/m; # 定義了一個名為limit_zone的限流區(qū)域,使用IP地址進(jìn)行限流,該區(qū)域的大小為10MB,限流速率為10個請求每分鐘。


    # 80端口的服務(wù)
    server { 
        listen       80;
        server_name  xxx.xxx.xxx.xxx;

        location / {
            alias  html;
            index  index.html index.htm;
            try_files $uri $uri/ /love/index.html;
            proxy_pass http://localhost;
        }

        location ^~ /love/ {
            root   html/love;
            index  index.html index.htm;
            proxy_pass http://localhost;
        }

        location ^~ /abcd/api/sendCode {
          # 在/xxx/api/sendCode接口的location中使用limit_req指令進(jìn)行限流,限流區(qū)域為limit_zone,同時設(shè)置了一個瞬時突發(fā)流量為20個請求的閾值。
          # 這樣,當(dāng)同一個IP地址在一秒鐘內(nèi)發(fā)送超過10個請求到此接口時,Nginx會返回503錯誤碼,表示請求被限流了。
          # limit_req zone=limit_zone burst=20;

          # 在/xxx/api/sendCode接口的location中使用limit_req指令進(jìn)行限流,限流區(qū)域為limit_zone,同時設(shè)置了一個瞬時突發(fā)流量為5個請求的閾值。
          # 這樣,當(dāng)同一個IP地址在一秒鐘內(nèi)發(fā)送超過10個請求到此接口時,如果在一分鐘內(nèi)有超過10個請求,則允許其中的5個請求通過,nodelay表示不延遲響應(yīng),即立即返回503錯誤碼。
          limit_req zone=limit_zone burst=5 nodelay;

          proxy_pass http://springboot;
        }
    }
}

2.運行效果

// ~

到此這篇關(guān)于Redis和Nginx實現(xiàn)限制接口請求頻率的示例的文章就介紹到這了,更多相關(guān)Redis和Nginx限制接口請求頻率內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 利用Redis如何實現(xiàn)自動補(bǔ)全功能

    利用Redis如何實現(xiàn)自動補(bǔ)全功能

    這篇文章主要給大家介紹了關(guān)于如何利用Redis如何實現(xiàn)自動補(bǔ)全功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Redis具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Redis命令處理過程源碼解析

    Redis命令處理過程源碼解析

    這篇文章主要介紹了Redis命令處理過程源碼解析,本文是基于社區(qū)版redis4.0.8,通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • 一步步教會你redis如何配置密碼

    一步步教會你redis如何配置密碼

    Redis的配置文件中可以設(shè)置密碼來保護(hù)訪問,下面這篇文章主要給大家介紹了關(guān)于redis如何配置密碼的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • redis發(fā)布訂閱_動力節(jié)點Java學(xué)院整理

    redis發(fā)布訂閱_動力節(jié)點Java學(xué)院整理

    這篇文章主要介紹了redis發(fā)布訂閱,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • Linux上安裝Redis詳細(xì)教程

    Linux上安裝Redis詳細(xì)教程

    這篇文章主要給大家詳細(xì)介紹了在Linux上安裝Redis詳細(xì)教程,文中有詳細(xì)的代碼示例和安裝步驟,對我們學(xué)習(xí)安裝redis有一定的幫助,需要的朋友可以參考下
    2023-07-07
  • Redis的Bitmap(位圖)詳解和命令演示

    Redis的Bitmap(位圖)詳解和命令演示

    Redis的位圖是由多個二進(jìn)制位組成的數(shù)組,數(shù)組中的每個二進(jìn)制位都有與之對應(yīng)的偏移量,用戶通過這些偏移量可以對位圖中指定的一個或多個二進(jìn)制位進(jìn)行操作,這篇文章主要給大家介紹了關(guān)于Redis的Bitmap(位圖)詳解和命令演示的相關(guān)資料,需要的朋友可以參考下
    2024-08-08
  • redis.clients.jedis.exceptions.JedisDataException:?NOAUTH?Authentication?required數(shù)據(jù)操作異常的解決方法

    redis.clients.jedis.exceptions.JedisDataException:?NOAUTH?

    本文主要介紹了redis.clients.jedis.exceptions.JedisDataException:?NOAUTH?Authentication?required數(shù)據(jù)操作異常的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-05-05
  • Redis如何使用樂觀鎖(CAS)保證數(shù)據(jù)一致性

    Redis如何使用樂觀鎖(CAS)保證數(shù)據(jù)一致性

    本文主要介紹了Redis如何使用樂觀鎖(CAS)保證數(shù)據(jù)一致性,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Redis 實現(xiàn)同步鎖案例

    Redis 實現(xiàn)同步鎖案例

    這篇文章主要介紹了Redis 實現(xiàn)同步鎖案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • Redis緩存三大異常的處理方案梳理總結(jié)

    Redis緩存三大異常的處理方案梳理總結(jié)

    這篇文章主要介紹了Redis緩存三大異常的處理方案梳理總結(jié),緩存方式,在提高數(shù)據(jù)查詢效率、保護(hù)數(shù)據(jù)庫等方面起到了不可磨滅的作用,但實際應(yīng)用中,可能會出現(xiàn)一些Redis緩存異常的情況,下文對其方案總結(jié)需要的朋友可以參考一下
    2022-06-06

最新評論