Go语言实战 : API服务器 (3) 服务器雏形 | 小册免费学

144 阅读2分钟

简单API服务器功能

实现外部请求对API 服务器健康检查和状态查询,返回响应结果

1.API服务器的状态监测的内部函数

通过对外提供的API接口,调用内部的函数,可以获取到

  1. 当前服务器的健康状况
  2. 服务器硬盘
  3. CPU
  4. 内存使用量 以内存状态检测的内部函数为例
func RAMCheck(c *gin.Context) {
	u, _ := mem.VirtualMemory()

        //获取当前内存占用量
	usedMB := int(u.Used) / MB
	usedGB := int(u.Used) / GB
	totalMB := int(u.Total) / MB
	totalGB := int(u.Total) / GB
	usedPercent := int(u.UsedPercent)

	status := http.StatusOK
	text := "OK"

        //根据当前内存状态,返回健康信息
	if usedPercent >= 95 {
		status = http.StatusInternalServerError
		text = "CRITICAL"
	} else if usedPercent >= 90 {
		status = http.StatusTooManyRequests
		text = "WARNING"
	}

	message := fmt.Sprintf("%s - Free space: %dMB (%dGB) / %dMB (%dGB) | Used: %d%%", text, usedMB, usedGB, totalMB, totalGB, usedPercent)
	c.String(status, "\n"+message)
}

2.加载API服务器的状态监测的路由

该代码块定义了一个叫 sd 的分组,在该分组下注册了 /health、/disk、/cpu、/ram HTTP 路径,分别路由到 sd.HealthCheck、sd.DiskCheck、sd.CPUCheck、sd.RAMCheck 函数。

该分组主要用于响应外部的请求的API接口,用户通过API接口去调用相应的内置的函数,从而获取到API服务器健康状况、服务器硬盘、CPU 和内存使用量的这些信息

// Load loads the middlewares, routes, handlers.
func Load(g *gin.Engine, mw ...gin.HandlerFunc) *gin.Engine {
	// Middlewares.
        //设置响应头
	g.Use(gin.Recovery())
	g.Use(middleware.NoCache)
	g.Use(middleware.Options)
	g.Use(middleware.Secure)
	g.Use(mw...)
	// 404 Handler.
        //404设置
	g.NoRoute(func(c *gin.Context) {
		c.String(http.StatusNotFound, "The incorrect API route.")
	})


	// The health check handlers
	svcd := g.Group("/sd")
	{
		svcd.GET("/health", sd.HealthCheck)
		svcd.GET("/disk", sd.DiskCheck)
		svcd.GET("/cpu", sd.CPUCheck)
		svcd.GET("/ram", sd.RAMCheck)
	}

	return g
}

3.程序入口

程序入口先进行路由的加载,随后在 apiserver 中也添加自检程序。

自检程序的工作是:在启动 HTTP 端口前 go 一个 pingServer 协程,启动 HTTP 端口后,该协程不断地 ping /sd/health 路径,如果失败次数超过一定次数,说明服务器的健康状态为异常,则终止 HTTP 服务器进程。通过自检可以最大程度地保证启动后的 API 服务器处于健康状态。

func main() {
	// Create the Gin engine.
	g := gin.New()

	middlewares := []gin.HandlerFunc{}

	// Routes.
	router.Load(
		// Cores.
		g,

		// Middlwares.
		middlewares...,
	)

	// Ping the server to make sure the router is working.
	go func() {
		if err := pingServer(); err != nil {
			log.Fatal("The router has no response, or it might took too long to start up.", err)
		}
		log.Print("The router has been deployed successfully.")
	}()

	log.Printf("Start to listening the incoming requests on http address: %s", ":8080")
	log.Printf(http.ListenAndServe(":8080", g).Error())
}

// pingServer pings the http server to make sure the router is working.
func pingServer() error {
	for i := 0; i < 2; i++ {
		// Ping the server by sending a GET request to `/health`.
		resp, err := http.Get("http://127.0.0.1:8080" + "/sd/health")
		if err == nil && resp.StatusCode == 200 {
			return nil
		}

		// Sleep for a second to continue the next ping.
		log.Print("Waiting for the router, retry in 1 second.")
		time.Sleep(time.Second)
	}
	return errors.New("Cannot connect to the router.")
}