• null
    2019-08-09
    re:为什么令牌是从令牌桶中出的,那么 next 就无需增加一个 interval?

    next 变量的意思是下一个令牌的生成时间,可以理解为当前线程请求的令牌的生成时刻,如第一张图所示:线程 T1 的令牌的生成时刻是第三秒。

    线程 T 请求时,存在三种场景:
    1. 桶里有剩余令牌。
    2. 刚创建令牌,线程同时请求。
    3. 桶里无剩余令牌。

    场景 2 可以想象成线程请求的同时令牌刚好生成,没来得及放入桶内就被线程 T 拿走了。因此将场景 2 和场景 3 合并成一种情况,那就是桶里没令牌。即线程请求时,桶里可分为有令牌和没令牌。

    “桶里没令牌”,线程 T 需要等待;需要等待则意味着 now(线程 T 请求时刻) 小于等于 next(线程 T 所需的令牌的生成时刻)。这里可以想象一下线程 T 在苦苦等待令牌生成的场景,只要线程 T 等待那么久之后,就会被放行。放行这一刻令牌同时生成,立马被线程拿走,令牌没放入桶里。对应到代码就是 resync 方法没有进入 if 语句内。

    “桶里有令牌”,线程 T 不需要等待。说明线程 T 对应的令牌已经早早生成,已在桶内。代码就是:now > next(请求时刻大于对应令牌的生成时刻)。因此在分配令牌给线程之前,需要计算线程 T 迟到了多久,迟到的这段时间,有多少个令牌生成¹;然后放入桶内,满了则丢弃²;未来的线程的令牌在这个时刻已经生成放入桶内³(即 resync 方法的逻辑)。线程无需等待,所以不需要增加一个 interval 了。

    角标分别对应 resync 方法内的代码:
    ¹: long newPermits=(now-next)/interval;
    ²: storedPermits=min(maxPermits,
            storedPermits + newPermits);
    ³: next = now;
    展开

    作者回复: 👍条理清晰

     2
     9
  • 花儿少年
    2019-06-18
    很精髓的就是reserve方法,我来试着稍微解释一下
    首先肯定是计算令牌桶里面的令牌数量
    然后取令牌桶中的令牌数量storedPermits 与当前的需要的令牌数量 1 做比较,大于等于 1,说明令牌桶至少有一个令牌,此时下一令牌的获取是不需要等待的,表现为 next 不需要变化;而当令牌桶中的令牌没有了即storedPermits等于 0 时,next 就会变化为下一个令牌的获取时间,注意 nr 的值变化

    作者回复: 👍

     3
     8
  • the geek
    2019-06-04
    老师,当b>1时的reserve方法写的有问题吧,long at = next;不应该是第一行,而应该在// 重新计算下一令牌产生时间
        next = next + nr*interval;
    这行代码之后吧
     1
     4
  • 辣椒
    2019-06-04
    // 令牌净需求:首先减掉令牌桶中的令牌
                long nr = 1 - fb;
                // 重新计算下一令牌产生时间
                next = next + nr*interval;
                // 重新计算令牌桶中的令牌
                this.storedPermits -= fb;

    老师这儿没有看懂,能不能解释一下?
    展开
     9
     4
  • zsh0103
    2019-05-26
    老师好,问个问题。文中代码b=3,r=1/s时,如果在next之后同时来了3个请求,应该时都可以获得令牌的对吧。就是说这3个请求都可以执行。那岂不是违背了r=1/s的限制吗。

    作者回复: 按照令牌桶算法是这样的,所以b不能搞得太大

    
     3
  • 梦倚栏杆
    2019-12-13
    有个疑问:高并发情况下单独一个线程维护一个队列放令牌,性能上扛不住,那么获取令牌时每次加锁去计算性能就可以抗的主?是根据什么依据来判断性能的呢?

    作者回复: 高并发场景下,CPU忙碌,大概率会出现就绪的线程被积压,对于定时放令牌的线程,其定时器会被大概率的延迟

    
     2
  • 又双叒叕是一年啊
    2019-05-30
    long interval = 1000_000_000;
    这是什么写法
     1
     2
  • 范瑞
    2020-01-05
    老师,经过单元测试后,个人感觉 resync 方法有bug。resync 的功能仅仅是将时间转换为令牌的操作,并更新下一次产生令牌的时间。不消耗令牌。
    resync 方法中 //新产生的令牌数
    long newPermits = (now - next) / interval; 这一步中,假如 now - next 为 1.9 秒,interval 为1秒,那么除法后,会将 0.9 秒丢弃,长期这种操作,会导致错误越来越多。我这边做了一个补偿操作:
    long diff = (now - next) % interval;
     // 将下一个令牌发放时间重置为当前时间
    next = now - diff;

    单元测试在 https://github.com/1996fanrui/fanrui-learning/blob/755cb85bfc84981ba3a0309cc4fee91035e7ee25/module-juc/src/test/java/com/dream/juc/ratelimiter/RateLimiterTest.java

    虽然课程早就结束了,但还是非常期待老师的反馈。
    展开
     1
     1
  • 刘鸿博
    2019-08-26
    newPermits, storePermits, fb, nr 都应该是double, 而不是long.

    作者回复: 示例代码只是为了更容易理解,实际应用还是要参考guava的实现

     1
     1
  • speedy9
    2019-06-11
    老师,前一个桶大小为1的代码是不是写错了,// 返回线程需要等待的时间 应该是return Math.max(at-now,0)吧
     1
     1
  • Darren
    2019-05-26
    老师,请教一下,限流器和信号量为什么感觉一样的,那为什么2个还都存在?是因为业务场景不同吗?请老师解惑下

    作者回复: 限流器不需要释放操作,信号量没办法控制带时间范围的限流,只能用于非常简单的场景

     1
     1
  • 爱吃回锅肉的瘦子
    2019-05-26
    老师,有没什么资料推荐关于guava预热功能呢?主要网上资料太繁杂,不知道要如何甄别哪些是比较经典的

    作者回复: 能把为什么用的是那个积分函数,而不是用其他积分函数讲清楚的,应该是比较好的。最好是看guava的代码注视,写的非常详细。

    
     1
  • 锦
    2019-05-25
    很精彩!老师应该去讲数据结构与算法:)

    作者回复: 何必难为自己呢,不讲了😄

     1
     1
  • 高源
    2019-05-25
    还有就是老师我问一下因为我不是在互联网公司工作接触高并发场景少,我又喜欢学习研究提高自己,是不是得多看多练,实战

    作者回复: 最好还是找个互联网企业,有些问题只有在很高的并发压力下才会爆发。不过技术没有互联网之分,只要基础牢,成长会很快。多看基础性的东西,一定带着问题去看。

    
     1
  • 卖火柴的托儿索
    2020-01-09
    老师,请问您用的是什么画图工具?

    作者回复: PPT😂

    
    
  • 赤城
    2019-11-07
    令牌桶原理:
          从令牌桶中获取令牌,如果令牌数量大于1,则直接获取,如果令牌桶中已经没有令牌,则等待时间加一个间隔时间,同时令牌桶中新增一批令牌(数量为每秒限流数)。
    令牌桶实现:
          通过acquire获取令牌时,将当前时间传递到方法中,返回一个获取令牌时间,如果时间与当前时间相同,说明令牌时从令牌桶中直接获取的,如果返回一个大于当前时间的值,则等待一段时间(返回值-当前时间)。
           在获取令牌时间时,具体实现代码很优秀,先赞一个!如果当前时间大于上次令牌时间,则将上次令牌时间设置为当前时间,同时令牌桶中根据限流率添加一批令牌,要保证令牌总数不大于最大值。然后再从令牌桶中取一个令牌返回。
    展开
    
    
  • 18518471028
    2019-10-17
    容量为1的 synchronized long reserve(long now) 这个方法中的 Math.max(at,0)没有意义,at一直大于0
    
    
  • 静海
    2019-09-18
    老师,请教下接收rocketmq消息,能否采用限流器Guava RateLimiter进行限流? 要怎么做?

    作者回复: 没这么做过,应该是做不了的

     1
    
  • 一个慢慢爬行的普通人
    2019-09-16
    老师,我刚刚应该是想错了,线程池任务提交频繁是不是导致线程池存储任务队列不断扩大,从而可能会导致系统不稳定,但是这方面线程池也可以用有界队列来控制,所以不太清楚是什么能够导致系统不稳定

    作者回复: 一个例子是,恶意攻击导致正常的请求被拒绝。一般来讲系统到达极限后会出各种意料之外的问题

    
    
  • 韩大
    2019-08-16
    guava的ratelimit好像是阻塞的,而不是抛弃请求,这样会不会导致用户响应时间过长的问题?

    作者回复: 会,限流主要是保护后端不死,慢总比死了好

    
    
我们在线,来聊聊吧