欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

互联网高并发限流方案分析

程序员文章站 2022-06-11 09:26:52
...
单进程限流:
1、令牌桶算法
  令牌桶算法是以一定的速率往桶内放入令牌,业务服务从桶内获取到令牌才能进行业务操作,获取不到令牌,则拒绝服务。
2、漏桶算法
  漏桶算法是固定的速率从桶内拿令牌,不固定的速率往桶内放令牌,当桶满了,则拒绝服务。

实现方式:
 
   <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>25.1-jre</version>
    </dependency>
  

 
   import java.util.Random;
import java.util.concurrent.TimeUnit;

import org.redisson.Redisson;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.google.common.util.concurrent.RateLimiter;
import com.gupao.jwt.JwtTokenUtils;
import com.gupao.jwt.PassToken;
import com.gupao.model.User;
import com.gupao.redis.RedisCacheManager;
import com.gupao.redis.RedissionManager;
import com.gupao.service.UserService;

@Controller
public class UserController extends BaseController {
	
	@Autowired
	RedisCacheManager redisCacheManager;
	
	@Autowired
	RedissionManager redissionManager;
	
	@Autowired
	RedissonClient redissonClient;
	
	@Autowired
	UserService userService;
	//令牌桶算法                                                                              1:每秒新增的令牌数
	RateLimiter tokenLimiter=RateLimiter.create(1);
	
	//漏桶算法                                                                                 1:每秒新增的令牌数 500:从冷启动速率到平均速率的间隔时间,也可以叫作预热时间                                   
	RateLimiter leakyLimiter=RateLimiter.create(1, 500, TimeUnit.MILLISECONDS);
	
	
	
	
	/**
	 * 令牌桶限流方案一:获取不到令牌,直接走降级
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/tokenBucket")
	@ResponseBody
//	@UserLoginToken
	@PassToken
	public String tokenBucket() throws Exception {
		long start=System.currentTimeMillis();
		try {
//		    double limiter=rateLimiter.acquire();
//		    System.out.println("获取token时间:"+limiter);
//			boolean flag=rateLimiter.tryAcquire();
			//如果500毫秒内获取不到令牌,直接走降级
			boolean flag=tokenLimiter.tryAcquire(500, TimeUnit.MILLISECONDS);
			if(!flag) {
				System.out.println("服务器太忙了!");
				return "服务器太忙了!";
			}
			Random random=new Random();
			Integer id=random.nextInt(10000);
			User user=new User(id, "admin"+id, "admin"+id);
			boolean result=userService.addUser(user);
			if(result) {
				System.out.println("新增用户成功:"+user.toString());
				return user.toString();
			}else {
				System.out.println("新增用户失败");
				return "新增用户失败";
			}
		} catch (Exception e) {
			System.out.println("异常"+e);
			return "500";
		}finally {
			long end=System.currentTimeMillis();
			System.out.println("耗时:"+(end-start));
		}
	}
	
	/**
	 * 令牌桶限流方案二:如果获取不到令牌,就一直等待
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/tokenBucket1")
	@ResponseBody
//	@UserLoginToken
	@PassToken
	public String tokenBucket1() throws Exception {
		long start=System.currentTimeMillis();
		try {
			//如果获取不到令牌 就一直等待
		    double limiter=tokenLimiter.acquire();
		    System.out.println("获取token时间:"+limiter);
//			boolean flag=rateLimiter.tryAcquire();
//			if(!flag) {
//				System.out.println("服务器太忙了!");
//				return "服务器太忙了!";
//			}
			Random random=new Random();
			Integer id=random.nextInt(10000);
			User user=new User(id, "admin"+id, "admin"+id);
			boolean result=userService.addUser(user);
			if(result) {
				System.out.println("新增用户成功:"+user.toString());
				return user.toString();
			}else {
				System.out.println("新增用户失败");
				return "新增用户失败";
			}
		} catch (Exception e) {
			System.out.println("异常"+e);
			return "500";
		}finally {
			long end=System.currentTimeMillis();
			System.out.println("耗时:"+(end-start));
		}
	}
	
	/**
	 * 漏桶限流方案一:如果获取不到令牌,直接走降级
	 * @return
	 */
	@RequestMapping("/leakyBucket1")
	@ResponseBody
//	@UserLoginToken
	@PassToken
	public String leakyBucket1() {
		long start=System.currentTimeMillis();
		try {
//		    double limiter=rateLimiter.acquire();
//		    System.out.println("获取token时间:"+limiter);
//			boolean flag=rateLimiter.tryAcquire();
			boolean flag=leakyLimiter.tryAcquire(500, TimeUnit.MILLISECONDS);
			if(!flag) {
				System.out.println("服务器太忙了!");
				return "服务器太忙了!";
			}
			Random random=new Random();
			Integer id=random.nextInt(10000);
			User user=new User(id, "admin"+id, "admin"+id);
			boolean result=userService.addUser(user);
			if(result) {
				System.out.println("新增用户成功:"+user.toString());
				return user.toString();
			}else {
				System.out.println("新增用户失败");
				return "新增用户失败";
			}
		} catch (Exception e) {
			System.out.println("异常"+e);
			return "500";
		}finally {
			long end=System.currentTimeMillis();
			System.out.println("耗时:"+(end-start));
		}
	}
	
	/**
	 * 漏桶限流方案二:如果获取不到令牌,就一直等待
	 * @return
	 */
	@RequestMapping("/leakyBucket")
	@ResponseBody
//	@UserLoginToken
	@PassToken
	public String leakyBucket() {
		long start=System.currentTimeMillis();
		try {
		    double limiter=leakyLimiter.acquire();
		    System.out.println("获取token时间:"+limiter);
//			boolean flag=rateLimiter.tryAcquire();
//			if(!flag) {
//				System.out.println("服务器太忙了!");
//				return "服务器太忙了!";
//			}
			Random random=new Random();
			Integer id=random.nextInt(10000);
			User user=new User(id, "admin"+id, "admin"+id);
			boolean result=userService.addUser(user);
			if(result) {
				System.out.println("新增用户成功:"+user.toString());
				return user.toString();
			}else {
				System.out.println("新增用户失败");
				return "新增用户失败";
			}
		} catch (Exception e) {
			System.out.println("异常"+e);
			return "500";
		}finally {
			long end=System.currentTimeMillis();
			System.out.println("耗时:"+(end-start));
		}
	}
	
	/**
	 * 分布式限流方案二:如果获取不到令牌,就一直等待
	 * @return
	 */
	@RequestMapping("/redissionLimit")
	@ResponseBody
//	@UserLoginToken
	@PassToken
	public String redissionLimit() {
		long start=System.currentTimeMillis();
		try {
			RRateLimiter redisLimiter=redissionManager.getRRateLimiter("userLimiter");
			redisLimiter.trySetRate(RateType.PER_CLIENT, 1, 1, RateIntervalUnit.SECONDS);
			redisLimiter.acquire();
//			System.out.println("获取token时间:"+limiter);
			
//			boolean flag=rateLimiter.tryAcquire();
//			if(!flag) {
//				System.out.println("服务器太忙了!");
//				return "服务器太忙了!";
//			}
			Random random=new Random();
			Integer id=random.nextInt(10000);
			User user=new User(id, "admin"+id, "admin"+id);
			boolean result=userService.addUser(user);
			if(result) {
				System.out.println("新增用户成功:"+user.toString());
				return user.toString();
			}else {
				System.out.println("新增用户失败");
				return "新增用户失败";
			}
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("异常"+e);
			return "500";
		}finally {
			long end=System.currentTimeMillis();
			System.out.println("耗时:"+(end-start));
		}
	}
	
	/**
	 * 分布式限流方案一:如果获取不到令牌,直接走降级
	 * @return
	 */
	@RequestMapping("/redissionLimit1")
	@ResponseBody
//	@UserLoginToken
	@PassToken
	public String redissionLimit1() {
		long start=System.currentTimeMillis();
		try {
//			Config config = new Config();
//			config.useSingleServer().setAddress("redis://192.168.126.11:6379");
//			RedissonClient redissionLimiter = Redisson.create(config);
//			RRateLimiter redisLimiter=redissionLimiter.getRateLimiter("test");
//			redisLimiter.trySetRate(RateType.PER_CLIENT, 1, 1, RateIntervalUnit.SECONDS);
			RRateLimiter redisLimiter=redissionManager.getRRateLimiter("userLimiter");
			redisLimiter.trySetRate(RateType.PER_CLIENT, 1, 1, RateIntervalUnit.SECONDS);
			boolean flag=redisLimiter.tryAcquire(500, TimeUnit.MILLISECONDS);
			if(!flag) {
				System.out.println("服务器太忙了!");
				return "服务器太忙了!";
			}
			Random random=new Random();
			Integer id=random.nextInt(10000);
			User user=new User(id, "admin"+id, "admin"+id);
			boolean result=userService.addUser(user);
			if(result) {
				System.out.println("新增用户成功:"+user.toString());
				return user.toString();
			}else {
				System.out.println("新增用户失败");
				return "新增用户失败";
			}
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("异常"+e);
			return "500";
		}finally {
			long end=System.currentTimeMillis();
			System.out.println("耗时:"+(end-start));
		}
	}
 
  





分布式限流:

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


		<dependency>
			<groupId>org.redisson</groupId>
			<artifactId>redisson</artifactId>
			<version>3.10.5</version>
		</dependency>


<bean id="fstCodec" class="org.redisson.codec.FstCodec" />

	<redisson:client id="redissonClient" threads="0"
		netty-threads="0" codec-ref="fstCodec"  >
		<redisson:single-server
			idle-connection-timeout="10000" ping-timeout="1000" connect-timeout="10000"
			timeout="3000" retry-attempts="3" retry-interval="1500"
			subscriptions-per-connection="5" client-name="none"
			address="redis://192.168.126.11:6379"
			subscription-connection-minimum-idle-size="1"
			subscription-connection-pool-size="50" connection-minimum-idle-size="10"
			connection-pool-size="64" database="0" />
	</redisson:client>


import org.redisson.api.RRateLimiter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class RedissionManager {
	
	@Autowired
	private RedissonClient redissonClient;

//	public void setRedissonClient(RedissonClient redissonClient) {
//		this.redissonClient = redissonClient;
//	}

	public RRateLimiter getRRateLimiter(String key) {
		return redissonClient.getRateLimiter(key);
	}
}