首頁 > 軟體

Redis+AOP+自定義註解實現限流

2022-06-28 18:01:44

Redis安裝

一提到Redis,相信大家都不會感到陌生吧。今天就讓我們在阿里雲上安裝一下Redis,為以後使用它做個準備。

下載

1,下載頁面

2,下載

解壓

tar -xzvf redis-5.0.7.tar.gz

準備編譯

1, 請在操作前確認gcc是否已安裝,gcc -v

如未安裝,可以執行這個命令安裝:yum install gcc

2,請在操作前確認tcl是否已安裝如未安裝,可以執行這個命令安裝:yum install tcl

編譯

[root@localhost source]# cd redis-5.0.7/
[root@localhost redis-5.0.7]# make MALLOC=libc

make 後加 MALLOC的引數的原因:

避擴音示找不到 jemalloc/jemalloc.h

測試編譯

[root@localhost redis-5.0.7]# make test

如果看到以下字樣:表示無錯誤:o/ All tests passed without errors!

安裝

[root@localhost redis-5.0.7]# mkdir /usr/local/soft/redis5 可分步建立
[root@localhost redis-5.0.7]# cd /usr/local/soft/redis5/
[root@localhost redis5]# mkdir bin
[root@localhost redis5]# mkdir conf
[root@localhost redis5]# cd bin/

find / -name redis-cli 查詢檔案位置

[root@localhost bin]# cp /root/redis-5.0.7/src/redis-cli ./
[root@localhost bin]# cp /root/redis-5.0.7/src/redis-server ./
[root@localhost bin]# cd …/conf/
[root@localhost conf]# cp /root/redis-5.0.7/redis.conf ./

設定

[root@localhost conf]# vi redis.conf

設定以下兩個地方:

# daemonize no 
 daemonize yes  
# maxmemory <bytes>
maxmemory 128MB

說明:分別是以daemon方式獨立執行 / 記憶體的最大使用限制

執行

[root@localhost conf]# /usr/local/soft/redis5/bin/redis-server /usr/local/soft/redis5/conf/redis.conf

檢查埠是否在使用中

[root@localhost conf]# netstat -anp | grep 6379
​​​​​​​tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 16073/redis-server

檢視redis的當前版本:

[root@localhost conf]# /usr/local/soft/redis5/bin/redis-server -v
​​​​​​​Redis server v=5.0.7 sha=00000000:0 malloc=libc bits=64 build=8e31d2ed9a4c9593

使redis可以用systemd方式啟動和管理

1,編輯service檔案

[root@localhost liuhongdi]# vim /lib/systemd/system/redis.service

2,service檔案內容:

[Unit]Description=RedisAfter=network.target
[Service]Type=forkingPIDFile=/var/run/redis_6379.pidExecStart=/usr/local/soft/redis5/bin/redis-server /usr/local/soft/redis5/conf/redis.confExecReload=/bin/kill -s HUP $MAINPIDExecStop=/bin/kill -s QUIT $MAINPIDPrivateTmp=true
[Install]WantedBy=multi-user.target

3.過載系統服務

[root@localhost liuhongdi]# systemctl daemon-reload

4,用來管理redis

啟動

systemctl start redis

檢視狀態

systemctl status redis

使開機啟動

systemctl enable redis

檢視本地centos的版本:

[root@localhost lib]# cat /etc/redhat-release
CentOS Linux release 8.1.1911 (Core)

使用者端連線redis

1、阿里雲得設定redis.conf中的bind 後跟著的127.0.0.1修改為0.0.0.0,重啟redis

2、開放埠:開放伺服器的埠號,步驟如下:

開啟範例列表,點選“ 更多”按鈕,選擇“ 網路和安全組 ”中的“安全組設定”,選擇 “安全組列表”tab頁面,點選 “設定規則”按鈕,點選 “快速新增”按鈕,勾選“Redis(6379)”,點選 “確定”之後就可以正常連線了。

3、給redis設定連線密碼:

查詢到# requirepass foobared 註釋去掉並寫入要設定的密碼,例如:requirepass 123456

redis啟動之後測試是否可以連線命令

./redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> auth 123456//此處是你的密碼

注意: 如果是阿里雲的話一定要設定密碼,否則很可能被礦機程式注入定時任務,用你的伺服器挖礦,阿里雲一直會有資訊提示你。

Redis限流

伺服器上的Redis已經安裝完成了(安裝步驟見上文),今天就讓我們使用Redis來做個小功能:自定義攔截器限制存取次數,也就是限流。

首先我們要在專案中引入Redis

1、引入依賴

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- redis依賴commons-pool 這個依賴一定要新增 -->
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-pool2</artifactId>
</dependency>

2、application.yml設定

server:
port: 8181

spring:
redis:
  host: 127.0.0.1
  port: 6379
  timeout: 10s
  lettuce:
    pool:
    # 連線池中的最小空閒連線 預設0
      min-idle: 0
      # 連線池中的最大空閒連線 預設8
      max-idle: 8
      # 連線池最大連線數 預設8 ,負數表示沒有限制
      max-active: 8
      # 連線池最大阻塞等待時間(使用負值表示沒有限制) 預設-1
      max-wait: -1ms
  #選擇哪個庫儲存,預設是0
  database: 0
  password: 123456

3、建立redisConfig,引入redisTemplate

@Configuration
public class RedisConfig {
   @Bean
   public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
       RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
       redisTemplate.setKeySerializer(new StringRedisSerializer());
       redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
       redisTemplate.setHashKeySerializer(new StringRedisSerializer());
       redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
       redisTemplate.setConnectionFactory(redisConnectionFactory);
       return redisTemplate;
  }
}

自定義註解和攔截器

1、自定義註解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AccessLimit {
   int seconds(); //秒數
   int maxCount(); //最大存取次數
   boolean needLogin()default true;//是否需要登入
}

2、建立攔截器

@Component
public class FangshuaInterceptor extends HandlerInterceptorAdapter {

   @Autowired
   private RedisTemplate redisTemplate;

   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       //判斷請求是否屬於方法的請求
       if(handler instanceof HandlerMethod){
           HandlerMethod hm = (HandlerMethod) handler;
           //獲取方法中的註解,看是否有該註解
           AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
           if(accessLimit == null){
               return true;
          }
           int seconds = accessLimit.seconds();
           int maxCount = accessLimit.maxCount();
           boolean login = accessLimit.needLogin();
           String key = request.getRequestURI();
           //如果需要登入
           if(login){
               //獲取登入的session進行判斷,此處只是例子,不寫具體的業務
               //.....
               key+=""+"1";  //這裡假設使用者是1,專案中是動態獲取的userId
          }

           //從redis中獲取使用者存取的次數
           Integer count;
           if(Objects.isNull(redisTemplate.opsForValue().get(key))){
               count = 0;
          }else{
               count = (Integer) redisTemplate.opsForValue().get(key);
          }
           if(count == 0){
               redisTemplate.opsForValue().set(key,1,seconds, TimeUnit.SECONDS);
          }else if(count<maxCount){
               //key的值加1
               redisTemplate.opsForValue().increment(key);
          }else{
               //超出存取次數
               Map<String,Object> errMap=new HashMap<>();
               errMap.put("code",400);
               errMap.put("msg","請求超時,請稍後再試");
               render(response,errMap); //這裡的CodeMsg是一個返回引數
               return false;
          }
      }
       return true;
  }


   private void render(HttpServletResponse response, Map<String,Object> errMap) throws Exception {
       response.setContentType("application/json;charset=UTF-8");
       OutputStream out = response.getOutputStream();
       String str = JSON.toJSONString(errMap);
       out.write(str.getBytes("UTF-8"));
       out.flush();
       out.close();
  }
}

3、將自定義攔截器加入到攔截器列表中

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

   @Autowired
   private FangshuaInterceptor interceptor;

   @Override
   public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(interceptor);
  }
}

最後做一下簡單的測試

@RestController
@RequestMapping("test")
public class TestController {

   //每三十秒最多可以請求三次,不需要登入
   @AccessLimit(seconds=30, maxCount=3, needLogin=false)
   @PostMapping("/fangshua")
   public String fangshua(){
       return "成功";
  }
}

以上就是Redis+AOP+自定義註解實現限流的詳細內容,更多關於Redis限流的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com