高可用之限流-03-Semaphore 信号量做限流

打印 上一主题 下一主题

主题 1012|帖子 1012|积分 3036

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
限流系列

开源组件 rate-limit: 限流
高可用之限流-01-入门介绍
高可用之限流-02-如何计划限流框架
高可用之限流-03-Semaphore 信号量做限流
高可用之限流-04-fixed window 固定窗口
高可用之限流-05-slide window 滑动窗口
高可用之限流-06-slide window 滑动窗口 sentinel 源码
高可用之限流-07-token bucket 令牌桶算法
高可用之限流 08-leaky bucket漏桶算法
高可用之限流 09-guava RateLimiter 入门使用简介 & 源码分析
主流的限流方式

现在主要有以下几种限流方式:

  • 信号量
  • 计数器
  • 滑动窗口
  • 漏桶算法
  • 令牌桶算法
  • 分布式限流
信号量

信号量实际上就是限制系统的并发量,来达到限流的目标。
常见的用法是:创建Semaphore,指定permit的数量。
在方法开始时,调用 Semaphore.acquire() 或者 Semaphore.tryAcquire() 来获取permit,并在方法返回前,调用Semaphore.release()来返还permit。
焦点代码实现
  1. public class LimitSemaphore extends LimitAdaptor {
  2.     /**
  3.      * 日志
  4.      *
  5.      * @since 0.0.5
  6.      */
  7.     private static final Log LOG = LogFactory.getLog(LimitSemaphore.class);
  8.     /**
  9.      * 信号量
  10.      *
  11.      * @since 0.0.5
  12.      */
  13.     private final Semaphore semaphore;
  14.     /**
  15.      * 构造器
  16.      *
  17.      * @param context 上下文
  18.      * @since 0.0.5
  19.      */
  20.     public LimitSemaphore(final ILimitContext context) {
  21.         this.semaphore = new Semaphore(context.count());
  22.     }
  23.     @Override
  24.     public synchronized void acquire() {
  25.         try {
  26.             LOG.debug("[Limit] start acquire");
  27.             this.semaphore.acquire(1);
  28.             LOG.debug("[Limit] end acquire");
  29.         } catch (InterruptedException e) {
  30.             Thread.currentThread().interrupt();
  31.             LOG.error("[Limit] semaphore meet ex: ", e);
  32.         }
  33.     }
  34.     @Override
  35.     public void release() {
  36.         LOG.debug("[Limit] start release");
  37.         this.semaphore.release(1);
  38.         LOG.debug("[Limit] end release");
  39.     }
  40. }
复制代码
测试

我们限定每次只有一个线程可以执行焦点方法,如下:
  1. public class LimitSemaphoreTest {
  2.     private static final Log LOG = LogFactory.getLog(LimitSemaphoreTest.class);
  3.     private static final ILimit LIMIT = LimitBs.newInstance(LimitSemaphore.class)
  4.             .count(1)
  5.             .build();
  6.     static class LimitRunnable implements Runnable {
  7.         @Override
  8.         public void run() {
  9.             for(int i = 0; i < 2; i++) {
  10.                 try {
  11.                     LIMIT.acquire();
  12.                     LOG.info("{}-{}", Thread.currentThread().getName(), i);
  13.                     TimeUnit.SECONDS.sleep(1);
  14.                 } catch (InterruptedException e) {
  15.                     e.printStackTrace();
  16.                 } finally {
  17.                     LIMIT.release();
  18.                 }
  19.             }
  20.         }
  21.     }
  22.     public static void main(String[] args) {
  23.         new Thread(new LimitRunnable()).start();
  24.         new Thread(new LimitRunnable()).start();
  25.     }
  26. }
复制代码

  • 日志输出
  1. 13:35:37.501 [Thread-1] INFO  com.github.houbb.rate.limit.test.semaphore.LimitSemaphoreTest - Thread-1-0
  2. 13:35:38.501 [Thread-2] INFO  com.github.houbb.rate.limit.test.semaphore.LimitSemaphoreTest - Thread-2-0
  3. 13:35:39.502 [Thread-1] INFO  com.github.houbb.rate.limit.test.semaphore.LimitSemaphoreTest - Thread-1-1
  4. 13:35:40.503 [Thread-2] INFO  com.github.houbb.rate.limit.test.semaphore.LimitSemaphoreTest - Thread-2-1
复制代码
可以看到每次只有一个线程可以执行方法。
小结

这种方法最为简单,但是存在很多问题。
并入并发量问题,好比控制的力度不够灵活细致等。
后续我们来看下其他的实现方式。
参考资料

限流技术总结

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

罪恶克星

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表