1. 流量控

利用go channel实现限流量控制,原理:设置一个缓冲通道,设置访问中间键,当用户请求连接时判断channel里面长度是不是大于设定的缓冲值,如果没有就存入一个值进入channel,如果大于缓冲值,channel自动阻塞。当用户请求结束的时候,取出channel里面的值。

如果想限制用户HTTP请求进行速率限制可以参考 https://github.com/didip/tollbooth 这个中间键

目录:

-videos

—ce.html

-limiter.go

-main.go

main.go文件代码:

  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. "text/template"
  6. "time"
  7. "github.com/julienschmidt/httprouter"
  8. )
  9. type middleWareHandler struct {
  10. r *httprouter.Router
  11. l *ConnLimiter
  12. }
  13. //NewMiddleWareHandler ...
  14. func NewMiddleWareHandler(r *httprouter.Router, cc int) http.Handler {
  15. m := middleWareHandler{}
  16. m.r = r
  17. m.l = NewConnLimiter(cc)
  18. return m
  19. }
  20. func (m middleWareHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  21. if !m.l.GetConn() {
  22. defer func() { recover() }()
  23. log.Panicln("Too many requests")
  24. return
  25. }
  26. m.r.ServeHTTP(w, r)
  27. defer m.l.ReleaseConn()
  28. }
  29. //RegisterHandlers ...
  30. func RegisterHandlers() *httprouter.Router {
  31. router := httprouter.New()
  32. router.GET("/ce", ce)
  33. return router
  34. }
  35. func ce(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
  36. //为了演示效果这块设置了等待
  37. time.Sleep(time.Second * 100)
  38. t, _ := template.ParseFiles("./videos/ce.html")
  39. t.Execute(w, nil)
  40. }
  41. func main() {
  42. r := RegisterHandlers()
  43. //里面的参数2为设置的最大流量
  44. mh := NewMiddleWareHandler(r, 2)
  45. http.ListenAndServe(":9000", mh)
  46. }

limiter.go文件代码

  1. package main
  2. import (
  3. "log"
  4. )
  5. //ConnLimiter 定义一个结构体
  6. type ConnLimiter struct {
  7. concurrentConn int
  8. bucket chan int
  9. }
  10. //NewConnLimiter ...
  11. func NewConnLimiter(cc int) *ConnLimiter {
  12. return &ConnLimiter{
  13. concurrentConn: cc,
  14. bucket: make(chan int, cc),
  15. }
  16. }
  17. //GetConn 获取通道里面的值
  18. func (cl *ConnLimiter) GetConn() bool {
  19. if len(cl.bucket) >= cl.concurrentConn {
  20. log.Printf("Reached the rate limitation.")
  21. return false
  22. }
  23. cl.bucket <- 1
  24. return true
  25. }
  26. //ReleaseConn 释放通道里面的值
  27. func (cl *ConnLimiter) ReleaseConn() {
  28. c := <-cl.bucket
  29. log.Printf("New connction coming: %d", c)
  30. }

videos/ce.html文件代码

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. www.topgoer.com是个不错的go语言中文文档
  11. </body>
  12. </html>