20

golang实现流量控制操作

 4 years ago
source link: https://studygolang.com/articles/26383
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

** 文章转自go语言中文文档 http://www.topgoer.com **

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

目录:

-videos

--ce.html

-limiter.go

-main.go

main.go文件代码:

package main

import (
	"log"
	"net/http"
	"text/template"
	"time"

	"github.com/julienschmidt/httprouter"
)

type middleWareHandler struct {
	r *httprouter.Router
	l *ConnLimiter
}

//NewMiddleWareHandler ...
func NewMiddleWareHandler(r *httprouter.Router, cc int) http.Handler {
	m := middleWareHandler{}
	m.r = r
	m.l = NewConnLimiter(cc)
	return m
}

func (m middleWareHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if !m.l.GetConn() {
		defer func() { recover() }()
		log.Panicln("Too many requests")
		return
	}
	m.r.ServeHTTP(w, r)
	defer m.l.ReleaseConn()
}

//RegisterHandlers ...
func RegisterHandlers() *httprouter.Router {
	router := httprouter.New()
	router.GET("/ce", ce)
	return router
}

func ce(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	//为了演示效果这块设置了等待
	time.Sleep(time.Second * 100)
	t, _ := template.ParseFiles("./videos/ce.html")
	t.Execute(w, nil)
}

func main() {
	r := RegisterHandlers()
	//里面的参数2为设置的最大流量
	mh := NewMiddleWareHandler(r, 2)
	http.ListenAndServe(":9000", mh)
}

limiter.go文件代码

package main

import (
	"log"
)

//ConnLimiter 定义一个结构体
type ConnLimiter struct {
	concurrentConn int
	bucket         chan int
}

//NewConnLimiter ...
func NewConnLimiter(cc int) *ConnLimiter {
	return &ConnLimiter{
		concurrentConn: cc,
		bucket:         make(chan int, cc),
	}
}

//GetConn 获取通道里面的值
func (cl *ConnLimiter) GetConn() bool {
	if len(cl.bucket) >= cl.concurrentConn {
		log.Printf("Reached the rate limitation.")
		return false
	}

	cl.bucket <- 1
	return true
}

//ReleaseConn 释放通道里面的值
func (cl *ConnLimiter) ReleaseConn() {
	c := <-cl.bucket
	log.Printf("New connction coming: %d", c)
}

videos/ce.html文件代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    欢迎访问www.5lmh.com
</body>
</html>

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK