如何实现限流器,请用chan实现一种限流器,也可以不用chan实现

题目来源: 字节跳动

答案:

使用计数器实现请求限流

限流的要求是在指定的时间间隔内,server 最多只能服务指定数量的请求。实现的原理是我们启动一个计数器,每次服务请求会把计数器加一,同时到达指定的时间间隔后会把计数器清零;这个计数器的实现代码如下所示:

  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "net/http"
  6. "sync"
  7. "time"
  8. )
  9. type RequestLimitService struct {
  10. Interval time.Duration
  11. MaxCount int
  12. Lock sync.Mutex
  13. ReqCount int
  14. }
  15. func NewRequestLimitService(interval time.Duration, maxCnt int) *RequestLimitService {
  16. reqLimit := &RequestLimitService{
  17. Interval: interval,
  18. MaxCount: maxCnt,
  19. }
  20. go func() {
  21. ticker := time.NewTicker(interval)
  22. for {
  23. <-ticker.C
  24. reqLimit.Lock.Lock()
  25. fmt.Println("Reset Count...")
  26. reqLimit.ReqCount = 0
  27. reqLimit.Lock.Unlock()
  28. }
  29. }()
  30. return reqLimit
  31. }
  32. func (reqLimit *RequestLimitService) Increase() {
  33. reqLimit.Lock.Lock()
  34. defer reqLimit.Lock.Unlock()
  35. reqLimit.ReqCount += 1
  36. }
  37. func (reqLimit *RequestLimitService) IsAvailable() bool {
  38. reqLimit.Lock.Lock()
  39. defer reqLimit.Lock.Unlock()
  40. return reqLimit.ReqCount < reqLimit.MaxCount
  41. }
  42. var RequestLimit = NewRequestLimitService(10 * time.Second, 5)
  43. func helloHandler(w http.ResponseWriter, r *http.Request) {
  44. if RequestLimit.IsAvailable() {
  45. RequestLimit.Increase()
  46. fmt.Println(RequestLimit.ReqCount)
  47. io.WriteString(w, "Hello world!
  48. ")
  49. } else {
  50. fmt.Println("Reach request limiting!")
  51. io.WriteString(w, "Reach request limit!
  52. ")
  53. }
  54. }
  55. func main() {
  56. fmt.Println("Server Started!")
  57. http.HandleFunc("/", helloHandler)
  58. http.ListenAndServe(":8000", nil)
  59. }