rate.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. package limit
  2. import (
  3. "gd_auth_check/common.in/config"
  4. "sync"
  5. "time"
  6. )
  7. const (
  8. releaseInterval = time.Second
  9. )
  10. type Limiter struct {
  11. mu sync.Mutex
  12. // 总容量
  13. burst int
  14. // 已使用数
  15. used int
  16. // 已使用的令牌
  17. usedToken map[string]int64
  18. // 时间轮,用以自动清理令牌
  19. tiker *time.Ticker
  20. }
  21. func NewLimiter(burst int) *Limiter {
  22. return &Limiter{
  23. burst: burst,
  24. usedToken: make(map[string]int64),
  25. }
  26. }
  27. func (lim *Limiter) Allow() (bool, string) {
  28. ok, tokenArr := lim.reserveN(1)
  29. if ok {
  30. return ok, tokenArr[0]
  31. }
  32. return ok, ""
  33. }
  34. func (lim *Limiter) AllowN(n int) (bool, []string) {
  35. return lim.reserveN(n)
  36. }
  37. func (lim *Limiter) reserveN(n int) (bool, []string) {
  38. lim.mu.Lock()
  39. defer lim.mu.Unlock()
  40. tokenArr := make([]string, 0, n)
  41. if lim.burst-lim.used-n >= 0 {
  42. lim.used += n
  43. for i := 0; i < n; i++ {
  44. // 生成令牌
  45. token := getToken(fromMem)
  46. tokenArr = append(tokenArr, token)
  47. // 存储令牌
  48. lim.usedToken[token] = time.Now().Unix()
  49. }
  50. go lim.ticker()
  51. return true, tokenArr
  52. }
  53. return false, nil
  54. }
  55. func (lim *Limiter) releaseToken(token string) {
  56. lim.mu.Lock()
  57. defer lim.mu.Unlock()
  58. delete(lim.usedToken, token)
  59. lim.used--
  60. }
  61. func (lim *Limiter) ticker() {
  62. if lim.tiker == nil {
  63. lim.tiker = time.NewTicker(releaseInterval)
  64. }
  65. defer func() {
  66. lim.tiker.Stop()
  67. }()
  68. if len(lim.usedToken) == 0 {
  69. return
  70. }
  71. interval, _ := config.Conf.RateLimit.RescueTickerTime.Int64()
  72. for range lim.tiker.C {
  73. if len(lim.usedToken) == 0 {
  74. break
  75. }
  76. ts := time.Now().Unix()
  77. for k, v := range lim.usedToken {
  78. // 超过3秒的则直接释放
  79. if ts-v > interval {
  80. delete(lim.usedToken, k)
  81. lim.used--
  82. }
  83. }
  84. // 全部释放完
  85. if lim.used == 0 {
  86. break
  87. }
  88. }
  89. }