限流,單機,分布式限流


總結:解決網站的高訪問量,有三大利器,緩存,降級,限流,我這里講解一下 常用的幾種限流手段。

          單機 ,有型號量,令牌通,漏桶,

          分布式,可以考慮從網關,redis ngnix, 阿里 Sentinel 等手段解決 。話不多說代碼如下:

      1.單機:

        1.1 型號量

    // 線程池

ExecutorService exec = Executors.newCachedThreadPool();
// 只能5個線程同時訪問
final Semaphore semp = new Semaphore(5);

@Override
public void limit() {
// 模擬20個客戶端訪問
for (int index = 0; index < 20; index++) {
final int NO = index;
Runnable run = new Runnable() {
public void run() {
try {
// 獲取許可 一直阻塞
semp.acquire();
// semp.tryAcquire(1, TimeUnit.MINUTES); //這個嘗試 多長時間獲取 到
//處理業務
log.info("Accessing: " + NO);
Thread.sleep((long) (Math.random() * 10000));
log.info("存在多少有效" + semp.availablePermits());
} catch (InterruptedException e) {
log.info("error:{}",e);
} finally {
// 訪問完后,釋放
semp.release();
}
}
};
exec.execute(run);
}
// 退出線程池
//exec.shutdown();
}


1.2 guava
ExecutorService exec = Executors.newCachedThreadPool();// 線程池
final RateLimiter limit = RateLimiter.create(2);//1s只能有10個

@Override
public void limit() {
// 模擬20個客戶端訪問
for (int index = 0; index < 20; index++) {
final int NO = index;
Runnable run = new Runnable() {
public void run() {
try {
// 獲取許可
limit.acquire();
//處理業務
log.info("Accessing: " + NO);
Thread.sleep((long) (Math.random() * 10000));
} catch (InterruptedException e) {
log.info("error:{}", e);
}
}
};
exec.submit(run);
}
}

2.0 分布式版本
  2.1  redis-spring-data
@Autowired
private RedisTemplate redisTemplate;
ExecutorService exec = Executors.newCachedThreadPool();// 線程池
@Override
public void limit() {
//這里我用 包名+類名+方法
String key = "com.example.demo.limit.redis.ResdisLimitServiceImpl.limit";

RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
for (int i = 0; i < 100; i++) {
final int no = i;
exec.submit(new Runnable() {
@Override
public void run() {
if (counter.incrementAndGet() > 10) {
//拒絕請求
log.info("拒絕請求{}", no);
}
try {
//處理請求
log.info("處理請求{}", no);
} finally {
counter.decrementAndGet();
}
try {
Thread.sleep((long) (Math.random() * 10000));
} catch (InterruptedException e) {

}
}
});
}
}
2.2 redission 版本

@Autowired
private RedissonClient redisson;

ExecutorService exec = Executors.newCachedThreadPool();// 線程池

@Override
public void limit() {
RSemaphore semaphore = redisson.getSemaphore("semaphore");
semaphore.trySetPermits(10);
log.info("有效:{}",semaphore.availablePermits());
for (int i = 0; i <100 ; i++) {
final int no = i;
exec.submit(new Runnable() {
@Override
public void run() {
try {
if(semaphore.tryAcquire(1, TimeUnit.SECONDS)){
try {
log.info("處理業務{}",no);
Thread.sleep((long) (Math.random() * 10000));
}finally {
semaphore.release(1);
}
}else {
log.info("拒絕業務{}",no);
}
} catch (InterruptedException e) {
log.error("error:{}",e);
}
}
});
}
}

3.0 基於注解 redis開發 限流 使用方便

使用如下:

@Limit(key = "test", period = 100, count = 10)
@PostMapping("dept/update")
public ResponseResult updateDept(String name, Boolean leader, Integer id
, Double age, BigDecimal price, ResponseResultCode em){

return ResponseResultFactory.success("添加成功");
}
jmeter 測試如下 具體實現 參考我的代碼庫





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM