Это 25-й день моего участия в августовском испытании обновлений. Узнайте подробности события:Испытание августовского обновления
Если ❤️моя статья оказалась полезной, ставьте лайк и подписывайтесь. Это самый большой стимул для меня продолжать техническое творчество.Больше предыдущих статей в моей личной колонке
Значение ограничения тока системы и реализации кода Golang
Значение ограничения тока
Три мощных инструмента для систем с высокой степенью параллелизма: кэширование, понижение версии и ограничение тока.
- Кэш: улучшите скорость доступа к системе и увеличьте вычислительную мощность, а также увеличьте кеш для соответствующих служб.
- Понижение уровня: когда нагрузка на сервер резко возрастает, понизьте его в соответствии с бизнес-стратегией, чтобы высвободить ресурсы службы для обеспечения нормального ведения бизнеса.
- Текущее ограничение: благодаря одновременному ограничению скорости можно добиться отказа в обслуживании, постановки в очередь, ожидания, перехода на более раннюю версию и другой обработки.
Время/скорость ограничения тока дырявого ведра
- rate.NewLimiter(limit,burst)
- limit указывает количество токенов, генерируемых в секунду, и максимальное количество токенов, хранящихся в пакете
- Разрешить определить, можно ли в данный момент получить токен
- Wait блокирует и ждет, пока не будет получен токен
- Резерв возвращает время ожидания, после чего переходит к получению токена
отслеживание исходного кода по времени/скорости
- Рассчитать разницу во времени между последним запросом и текущим запросом
- Количество токенов, сгенерированных за разницу во времени расчета + количество старых токенов
- Если токен отрицательный, рассчитайте время ожидания
- Если токен положительный, после запроса token-1
Добавьте крылья к прокси-серверу шлюза
package middleware
import (
"fmt"
"golang.org/x/time/rate"
)
func RateLimiter() func(c *SliceRouterContext) {
l := rate.NewLimiter(1, 2)
return func(c *SliceRouterContext) {
if !l.Allow() {
c.Rw.Write([]byte(fmt.Sprintf("rate limit:%v,%v", l.Limit(), l.Burst())))
c.Abort()
return
}
c.Next()
}
}
Доступ к промежуточному ПО
package main
import (
"github.com/e421083458/gateway_demo/proxy/middleware"
"github.com/e421083458/gateway_demo/proxy/proxy"
"log"
"net/http"
"net/url"
)
var addr = "127.0.0.1:2002"
// 熔断方案
func main() {
coreFunc := func(c *middleware.SliceRouterContext) http.Handler {
rs1 := "http://127.0.0.1:2003/base"
url1, err1 := url.Parse(rs1)
if err1 != nil {
log.Println(err1)
}
rs2 := "http://127.0.0.1:2004/base"
url2, err2 := url.Parse(rs2)
if err2 != nil {
log.Println(err2)
}
urls := []*url.URL{url1, url2}
return proxy.NewMultipleHostsReverseProxy(c, urls)
}
log.Println("Starting httpserver at " + addr)
sliceRouter := middleware.NewSliceRouter()
sliceRouter.Group("/").Use(middleware.RateLimiter())
routerHandler := middleware.NewSliceRouterHandler(coreFunc, sliceRouter)
log.Fatal(http.ListenAndServe(addr, routerHandler))
}
контрольная работа
$ curl '127.0.0.1:2002/abo'
http://127.0.0.1:2004/base/abo
RemoteAddr=127.0.0.1:62366,X-Forwarded-For=127.0.0.1,X-Real-Ip=
headers =map[Accept:[*/*] Accept-Encoding:[gzip] User-Agent:[curl/7.69.1] X-Forwarded-For:[127.0.0.1]]
Administrator@DESKTOP-U15QB8I MINGW64 /d/Dev/workplace/golang/gateway_v1/pratise/proxy/limiter/rate_limiter (master)
$ curl '127.0.0.1:2002/abo'
rate limit:1,2
Administrator@DESKTOP-U15QB8I MINGW64 /d/Dev/workplace/golang/gateway_v1/pratise/proxy/limiter/rate_limiter (master)
$ curl '127.0.0.1:2002/abo'
http://127.0.0.1:2004/base/abo
RemoteAddr=127.0.0.1:62366,X-Forwarded-For=127.0.0.1,X-Real-Ip=
headers =map[Accept:[*/*] Accept-Encoding:[gzip] User-Agent:[curl/7.69.1] X-Forwarded-For:[127.0.0.1]]
Administrator@DESKTOP-U15QB8I MINGW64 /d/Dev/workplace/golang/gateway_v1/pratise/proxy/limiter/rate_limiter (master)
$ curl '127.0.0.1:2002/abo'
rate limit:1,2