- [x] I have searched the 
[issues](https://github.com/apache/incubator-dubbo/issues) of this repository 
and believe that this is not a duplicate.
- [x] I have checked the 
[FAQ](https://github.com/apache/incubator-dubbo/blob/master/FAQ.md) of this 
repository and believe that this is not a duplicate.

### Environment

* Dubbo version: 2.6.3

### Step to reproduce this issue

1. 配置限流过滤器;
2. 运行时修改系统时间;
3. 时间差范围内的正常请求全部被拒;

### 原因描述

过滤器[org.apache.dubbo.rpc.filter.TpsLimitFilter](https://github.com/apache/incubator-dubbo/blob/master/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/TpsLimitFilter.java)
 通过调用 
[org.apache.dubbo.rpc.filter.tps.StatItem](https://github.com/apache/incubator-dubbo/blob/master/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java)实现TPS限流。类org.apache.dubbo.rpc.filter.tps.StatItem实现了令牌桶算法,

https://github.com/apache/incubator-dubbo/blob/f720ccb965d490e6cc328af8d3e9820cb6eaf8f7/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java#L41-L56

上面的实现通过原子计数器token来记录可用令牌数量,在能取到令牌的情况下,每次调用对令牌数的自减。令牌桶重置(重新设置为最大值)的条件:**_当前系统时间  
> 上次重置令牌的时间  + 时间间隔_**。

该实现对系统时间具有依赖性:
以`rate`=5000,`interval`=1000ms(即限流5000TPS),实际访问量为1000TPS为例,应用原来的时钟与标准时间同步,在系统运行过程中系统时钟发生了变化(可能因为应用服务器同步了错误的NTP服务导致):
 
- 
当系统时钟比标准时间慢(假设慢15分钟),则从差错时间点开始,当前系统时间重新变回到了15分钟前,而上次令牌重置时间并不会马上发生变化,导致`lastResetTime
 - now = 15min`,此时条件`now > lastResetTime + interval` 
在接下来的15分钟之内不再不满足。意味着5000个令牌在1000TPS的实际访问量情况下5秒钟即被用完。后续的14分钟55秒的时间段内,所有的请求由于触发了限流的条件全部被拒,直到这个时间之后满足令牌桶重置的条件,才能恢复业务。

- 
当系统时间比标准时间快(假设快15分钟),由于此时满足令牌桶重置的条件,限流可以正常工作。但是,在系统时间恢复至标准时间时,lastResetTime会比标准时间提前约15分钟,这时同样会导致系统时间恢复的15分钟后续的请求全部被拒绝,直到15钟后满足令牌通重置的条件。

### Expected Result

在运行时系统时间发生变化,限流仍能正常发挥作用。

### Actual Result

运行过程中系统时间发生变化,导致限流不能正确执行,后续请求在相差的时间长度范围,请求全部被拒绝。


[ Full content available at: 
https://github.com/apache/incubator-dubbo/issues/2345 ]
This message was relayed via gitbox.apache.org for [email protected]

Reply via email to