最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實(shí)現(xiàn)分布式系統(tǒng)限流

 更新時(shí)間:2022年08月12日 11:33:43   作者:陳虎_63  
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)分布式系統(tǒng)限流,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

為何使用分布式系統(tǒng)限流:

在分布式環(huán)境中,我們的系統(tǒng)都是集群化部署,那么使用了單機(jī)版的限流策略,比如我們對(duì)某一個(gè)接口的限流方案是每秒鐘最多10次請(qǐng)求,那么因?yàn)楦鱾€(gè)實(shí)例都會(huì)自己維護(hù)一份請(qǐng)求次數(shù),所以真實(shí)每秒的請(qǐng)求數(shù)是:
節(jié)點(diǎn)數(shù) * 每秒最多請(qǐng)求數(shù),這樣的話就超出了我們的預(yù)期;

分布式限流解決方案:

● 可以基于redis,做分布式限流
● 可以基于nginx做分布式限流
● 可以使用阿里開(kāi)源的 sentinel 中間件

本次介紹使用 redis 做分布式限流

實(shí)現(xiàn)思路:

設(shè)計(jì)思路:假設(shè)一個(gè)用戶(用IP判斷)每分鐘訪問(wèn)某一個(gè)服務(wù)接口的次數(shù)不能超過(guò)10次,那么我們可以在Redis中根據(jù)該用戶IP創(chuàng)建一個(gè)鍵,并此時(shí)我們就設(shè)置這個(gè)鍵的過(guò)期時(shí)間為60秒,當(dāng)用戶請(qǐng)求到來(lái)的時(shí)候,先去redis中根據(jù)用戶ip獲取這個(gè)用戶當(dāng)前分鐘請(qǐng)求了多少次,如果獲取不到,則說(shuō)明這個(gè)用戶當(dāng)前分鐘第一次訪問(wèn),就創(chuàng)建這個(gè)健,并+1,如果獲取到了就判斷當(dāng)前有沒(méi)有超過(guò)我們限制的次數(shù),如果到了我們限制的次數(shù)則禁止訪問(wèn)。

使用技術(shù):使用redis提供的:incr命令 實(shí)現(xiàn)

先引入redis的依賴:

<dependency>
? ? ? ? ? ? <groupId>redis.clients</groupId>
? ? ? ? ? ? <artifactId>jedis</artifactId>
? ? ? ? ? ? <version>2.9.0</version>
? ? ? ? </dependency>

? ? ? ? <dependency>
? ? ? ? ? ? <groupId>com.alibaba</groupId>
? ? ? ? ? ? <artifactId>fastjson</artifactId>
? ? ? ? ? ? <version>1.2.70</version>
</dependency>

redis配置類:

package org.xhs.redis;


import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
?* @Author: hu.chen
?* @Description:
?**/
public class RedisConfig {

? ? // 服務(wù)器IP地址
? ? private static String ADDR = "127.0.0.1";
? ? // 端口
? ? private static int PORT = 6379;
? ? // 密碼
? ? private static String AUTH = null;
? ? // 連接實(shí)例的最大連接數(shù)
? ? private static int MAX_ACTIVE = 1024;
? ? // 控制一個(gè)pool最多有多少個(gè)狀態(tài)為idle(空閑的)的jedis實(shí)例,默認(rèn)值也是8。
? ? private static int MAX_IDLE = 200;
? ? // 等待可用連接的最大時(shí)間,單位毫秒,默認(rèn)值為-1,表示永不超時(shí)。如果超過(guò)等待時(shí)間,則直接拋出JedisConnectionException
? ? private static int MAX_WAIT = 10000;
? ? // 連接超時(shí)的時(shí)間
? ? private static int TIMEOUT = 10000;
? ? // 在borrow一個(gè)jedis實(shí)例時(shí),是否提前進(jìn)行validate操作;如果為true,則得到的jedis實(shí)例均是可用的;
? ? private static boolean TEST_ON_BORROW = true;

? ? ? ? private static JedisPool jedisPool = null;
? ? // 數(shù)據(jù)庫(kù)模式是16個(gè)數(shù)據(jù)庫(kù) 0~15
? ? public static final int DEFAULT_DATABASE = 0;

? ? /**
? ? ?* 初始化Redis連接池
? ? ?*/

? ? static {

? ? ? ? try {

? ? ? ? ? ? JedisPoolConfig config = new JedisPoolConfig();
? ? ? ? ? ? config.setMaxTotal(MAX_ACTIVE);
? ? ? ? ? ? config.setMaxIdle(MAX_IDLE);
? ? ? ? ? ? config.setMaxWaitMillis(MAX_WAIT);
? ? ? ? ? ? config.setTestOnBorrow(TEST_ON_BORROW);
? ? ? ? ? ? jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH, DEFAULT_DATABASE);

? ? ? ? } catch (Exception e) {

? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }

? ? /**
? ? ?* 獲取Jedis實(shí)例
? ? ?*/
? ? public static Jedis getJedis() {
? ? ? ? try {

? ? ? ? ? ? if (jedisPool != null) {
? ? ? ? ? ? ? ? Jedis resource = jedisPool.getResource();
? ? ? ? ? ? ? ? return resource;
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? return null;
? ? ? ? ? ? }
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? return null;
? ? ? ? }

? ? }

}

redis工具類:

package org.xhs.redis;

import redis.clients.jedis.Jedis;

/**
?* @Author: hu.chen
?* @Description:
?* @DateTime: 2022/1/21 1:06 PM
?**/
public class RedisUtils {

? ? /**
? ? ?* 將指定的key遞增1(可用于樂(lè)觀鎖)
? ? ?*
? ? ?* @param key
? ? ?* @return
? ? ?*/
? ? public static Long incr(final String key) {

? ? ? ? Jedis jedis = RedisConfig.getJedis();
? ? ? ? Long ?incr = jedis.incr(key);

? ? ? ? returnJedis(jedis);
? ? ? ? return incr;
? ? }


? ? /**
? ? ?* 給指定key設(shè)置過(guò)期時(shí)間
? ? ?*
? ? ?* @param key
? ? ?* @param seconds
? ? ?* @author ruan 2013-4-11
? ? ?*/
? ? public static void expire(String key, int seconds) {
? ? ? ? if (seconds <= 0) {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? Jedis jedis = RedisConfig.getJedis();
? ? ? ? jedis.expire(key, seconds);
? ? ? ? // 將連接還回連接池
? ? ? ? returnJedis(jedis);
? ? }


? ? /**
? ? ?* 回收jedis
? ? ?*
? ? ?* @param jedis
? ? ?*/
? ? private static void returnJedis(Jedis jedis) {
? ? ? ? if (jedis != null) {
? ? ? ? ? ? jedis.close();
? ? ? ? }
? ? }
}

實(shí)現(xiàn):

package org.xhs.redis;


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


/**
?* @Author: hu.chen
?* @Description:
?**/
public class TestRedis {
? ? /**
? ? ?* 超時(shí)時(shí)間(單位秒)
? ? ?*/
? ? private static int TIMEOUT = 30;

? ? /**
? ? ?* 每分鐘的請(qǐng)求次數(shù)限制
? ? ?*/
? ? private static int COUNT = 10;


? ? public static void main(String[] args) {

? ? ? ? List<UserRequest> tasks = new ArrayList();
? ? ? ? // 準(zhǔn)備工作,先初始化 10個(gè)線程(用戶),這10個(gè)用戶同時(shí)訪問(wèn)一個(gè)接口
? ? ? ? for (int i = 1; i <= 12; i++) {
? ? ? ? ? ? String ip = "127.0.0." + i;
? ? ? ? ? ? String userName = "chenhu_";
? ? ? ? ? ? String interfaceName = "user/find_" + i;
? ? ? ? ? ? tasks.add(new UserRequest(ip, userName, interfaceName));
? ? ? ? }


? ? ? ? for (UserRequest request : tasks) {
? ? ? ? ? ? // 以用戶名為鍵
? ? ? ? ? ? if (isAccess(request.getUserName(), COUNT)) {
? ? ? ? ? ? ? ? System.err.println("用戶:"+request.getUserName()+" 當(dāng)前時(shí)間訪問(wèn)次數(shù)還未達(dá)到上限,可以訪問(wèn)");
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? System.err.println("當(dāng)前時(shí)間訪問(wèn)失敗,"+request.getUserName()+"無(wú)法獲取令牌");
? ? ? ? ? ? }


? ? ? ? }
? ? }

? ? /**
? ? ?* 是否可以訪問(wèn)
? ? ?*
? ? ?* @return
? ? ?*/
? ? private static boolean isAccess(String userName, long count) {
? ? ? ? Long incr = RedisUtils.incr(userName);
? ? ? ? if (incr == 1) {
? ? ? ? ? ? RedisUtils.expire(userName, TIMEOUT);
? ? ? ? }
? ? ? ? if (count < incr) {
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? return true;
? ? }


? ? /**
? ? ?* 實(shí)體對(duì)象
? ? ?*/
? ? private static class UserRequest {
? ? ? ? /**
? ? ? ? ?* 請(qǐng)求用戶ip
? ? ? ? ?*/
? ? ? ? private String ip;
? ? ? ? /**
? ? ? ? ?* 用戶名
? ? ? ? ?*/
? ? ? ? private String userName;
? ? ? ? /**
? ? ? ? ?* 請(qǐng)求的接口名
? ? ? ? ?*/
? ? ? ? private String interfaceName;

? ? ? ? public UserRequest(String ip, String userName, String interfaceName) {
? ? ? ? ? ? this.ip = ip;
? ? ? ? ? ? this.userName = userName;
? ? ? ? ? ? this.interfaceName = interfaceName;
? ? ? ? }

? ? ? ? public String getIp() {return ip;}

? ? ? ? public String getUserName() { return userName;}

? ? ? ? public String getInterfaceName() {return interfaceName;}
? ? }
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論

宜川县| 布拖县| 巩留县| 连平县| 久治县| 宜川县| 白河县| 黄山市| 望城县| 萨嘎县| 澎湖县| 沁源县| 内江市| 沭阳县| 三原县| 南岸区| 福鼎市| 安仁县| 枣阳市| 静乐县| 石景山区| 伊通| 丹棱县| 瑞安市| 亚东县| 尼勒克县| 永顺县| 吉木乃县| 桐城市| 枣庄市| 岳普湖县| 社会| 荥阳市| 习水县| 吉首市| 蕉岭县| 宜阳县| 南通市| 临猗县| 邮箱| 宁武县|