分布式限流的一次坑

之前在一篇文章中提到過,因為業務的集群限流需求,在每次請求都需要拿到當前的日期,不過精確到天即可。上次給出的解決方案是,因為Calendar的性能問題,選擇更加直接粗暴的方式,就是下面這個。

分佈式限流的一次坑

通過當前的時間戳(毫秒級別),除以一天的毫秒數,得到的結果就是從1970 到今天經歷過的天數。

最近業務在使用限流功能時,需要限制接口每天調用1w次。

不過,在限流實現中,第一個版本的實現邏輯是這樣的,如果第一個請求是早上8點過來的,那麼會在redis創建一個對應的key,並設置24小時過期,所以從今天早上8點到明天早上8點,只能調用1w次,多餘的就拒絕。但是有個問題,每天限制的時間段可能是不一樣的。

業務提出了新需求:必須按照0點到第二天0的時間段進行限制。

對於這個需求,我表示會心一笑,上述的粗暴方案不是正好滿足麼,三下五除二,就給加上了這個功能。

分佈式限流的一次坑

如果業務配置的限流週期是天,那麼就在原始id上再加上當前的天數當前redis的key,那麼每天的key都是不一樣的,新的一天,都會有一個新的key,如此的美好。

業務使用改進後的版本上線了2天,甩過來一個監控頁面,開始diss我們了,為什麼昨天觸發了限流,今天凌晨2點多還在限流。看著埋點數據,發現這個鍋是甩不掉了,只能開始翻代碼,無果。

後來通過redis的埋點數據,發現凌晨2點多操作的redis key還是帶著昨天的天數。這個就很奇怪了?明明已經第二天2點了,怎麼還是昨天的天數,這時候我已經開始懷疑服務器的時間是不是有問題,鬼使神差的讓業務同學去驗證,結果肯定是被打臉了。

排查了很久,才把關注點放在了 System.currentTimeMillis()這個方法的返回值上,其實返回的時間戳是從1970開始到現在格林威治時間的時間戳,而北京時間比格林威治整整快了8個小時。

所以真相是,通過暴力方案返回的天數,在北京時間早上8點之前都算是之前一天,過了8點,才算是新的一天,才會使用新的redis key進行計數,感覺自己埋下的坑,有下面這麼大!

分佈式限流的一次坑

繼續修復,繼續發版,下次在使用這種暴力方案時,考慮一下時區問題。


分享到:


相關文章: