实践四:GO控制访问流量

519 阅读2分钟

前言

在实际的工程中,经常会遇到访问请求流量达到服务器,服务器需要处理的任务比较复杂(比如,加载镜像,启动任务等)。但是,如果等服务端处理完成后,会导致Http连接超时,从而造成访问失败。因此,我们常用的一种办法是先返回给客户端需要的反馈数据,然后异步处理比较耗时的过程,之后再推送处理结果或者更新数据库等相应的状态。

实验

在web开发中,Go的应用也比较广泛,比较常用的有Beego,GIN,Lris,Echo等,本次实验我们采用GIN来实现,其他的实现方式也不会相差太多。

代码

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"strconv"
	"time"
	pm "web/pg_manager"
)

var mydb pm.MyDB
var ChanPool chan byte

func init() {
	ChanPool = make(chan byte, 2)
	mydb.New(20)
}
func main() {

	defer mydb.Close()

	r := gin.Default()
	v1 := r.Group("/v1.0/")

	v1.GET("/images", getImages)

	r.Run(":9051")
}
func getImages(c *gin.Context) {

	select {
	case ChanPool <- '1':
		sql := "select row_to_json(t.*) from (select * from imagetab where user_id=17) t"
		results := mydb.ReadMany(sql)
		go loop() //模拟耗时
		c.JSON(200, results)
	default:
		c.JSON(500, "服务器负载严重,请稍后再试...")
	}
}
func loop() {
	for i := 0; i < 10; i++ {
		time.Sleep(time.Second)
		fmt.Println(i)
	}
	<-pm.ChanPool
}
  • 代码实现的功能:获取image列表,但是在获取时,模拟一个耗时比较长的操作。设置的chan大小为2,可以连续处理2个http请求,如果超过2个,会返回一个状态为500,并且反馈信息为”服务器负载严重,请稍后再试...“
  • 使用chan来记录耗时请求的访问的次数
  • 如果耗时操作完成,则从chan中释放一个数据,其他的请求就可以进来
  • 如果chan中的数据达到了2个,之后在插入到chan中的数据会阻塞,此时从执行select中的default

模拟

$ for i in $(seq 1 3); do curl http://localhost:9051/v1.0/images;done
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100     4  100     4    0     0    125      0 --:--:-- --:--:-- --:--:--   125null
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100     4  100     4    0     0     86      0 --:--:-- --:--:-- --:--:--    86null
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    42  100    42    0     0    531      0 --:--:-- --:--:-- --:--:--   531"服务器负载严重,请稍后再试..."

前面两次可以访问成功,第三次的时候访问失败