The source address
Today’s article involves very little coding content, mainly introduces what needs to be done before a project goes online, beginners can read this article to have a bottom in mind, if necessary, each direction in this article is worth taking the time to in-depth study
Generate interface documentation
github.com/swaggo/swag
Gin Swagger gin Swagger using gin framework
You can refer to the annotation API for writing comments
The first thing is to install
go install github.com/swaggo/swag/cmd/swag@latest
Copy the code
Secondly, we can refer to the documentation to write comments
Take our login interface for example
You can define a special set of structs to represent parameters or you can just use any of the mature structs in your project
package controllers //c.JSON(http.StatusOK, &Response{ //Code: CodeSuccess, //Msg: CodeSuccess.Msg(), //Data: data, //}) type _ResponseLogin struct {Code int64 'json:" Code "' // Service status response Code Message string 'json:" Message "' // Prompt Message Data string 'json:"data"' // token} type _RequestLogin struct {// Username Username string 'json:" Username "' // Password string `json:"password"` }Copy the code
// LoginHandler User login interface // @router/API /v1/login [POST] // @summary login interface // @Accept Application /json // @produce Application /json // @param login body _RequestLogin true "// @success 200 {object} _ResponseLogin func LoginHandler(c *gin.Context) { p := new(models.ParamLogin) if err := c.ShouldBindJSON(p); err ! = nil { zap.L().Error("LoginHandler with invalid param", Zap. Error(err)) // The json format Error is not a validator Error and cannot be translated. So here to do type judgment is incremented, ok: = err. (the validator. ValidationErrors) if! ok { ResponseError(c, CodeInvalidParam) } else { ResponseErrorWithMsg(c, CodeInvalidParam, RemoveTopStruct (errs.translate (trans)))} return} // Business processing token, err := logic.login (p) if err! Zap.l ().error ("login failed", zap.string ("username", p.user name), zap.Error(err)) if errors.Is(err, mysql.WrongPassword) { ResponseError(c, CodeInvalidPassword) } else { ResponseError(c, CodeServerBusy) } return } ResponseSuccess(c, token) }Copy the code
Don’t forget to add some basic instructions to the main function
Once you’ve written it, you can use Swag init to generate the document
The default is generated in this path:
Then go to the file where we generated the route import first
gs "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" _ "go_web_app/docs" // Don't forget to import the docs you generated in the previous stepCopy the code
Then add the corresponding route
R.git ("/swagger/*any", gs.WrapHandler(swaggerFiles.Handler))Copy the code
Then run and take a look:
It’s kind of convenient
It is also important to note that the initial of the struct used in Swagger must be uppercase, otherwise swag will not display the correct parameter
Finally, we can also modify the air configuration to enable it to automatically restart the Web service after the document modification, which is very convenient, but pay attention to the command change
Unit testing
Just create a new xxx_test.go file and run
package controllers import ( "bytes" "encoding/json" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "testing" ) func TestCreatePostHandler(t *testing.T) { gin.SetMode(gin.TestMode) url := "/ API /v1/post" r := gin.Default() r.post (url, CreatePostHandler) w := httptest.newRecorder () body := '{"title":" new ", "Community_id ":2} 'req, _ := http.NewRequest(http.MethodPost, url, bytes.NewReader([]byte(body))) r.ServeHTTP(w, req) assert.Equal(t, 200, W.code) // Determine if the response Contains an unlogged error message assert.Contains(t, w.body.string (), Res := new(Response) err := json.unmarshal (w.body.bytes (), res) if err! = nil { t.Fatalf("json unmarshal failed: %v", err) } assert.Equal(t, res.Code, CodeNoLogin) }Copy the code
The only caveat here is that if you are running on the command line, it is best to run directly under a package, otherwise it will be troublesome because your test code will not reference code from other files.
Pressure test
Here are a few concepts we need to know about stress testing
Response time RT Throughput QPS TPS Number of concurrent connections
These 5 indicators we can search the corresponding meaning of baidu
Apache Bench
Apache out of the pressure measurement tool
wrk
Open source pressure tools, very easy to use, through Lua scripts to write complex scenarios
You can verify our native service
WRK – t8 – c100 – d30s – latency at http://127.0.0.1:8016/api/v1/postlist? pageSize=10
Current limiting
This is easy to understand for Uber. In fact, no matter how big your input is, my output is always the same. It is just like when I was a child getting soy sauce, I inserted a funnel into the mouth of the bottle and the master poured it into the funnel.
But the downside of this is that it might not be appropriate to have a sudden scene, like a 12 o ‘clock seconds kill? The traffic was so high that the funnel blocked most of the requests for a while, and by the time it was time to execute them, the kill was over.
Uber’s funnel limiting algorithm
Token bucket traffic limiting algorithm
This is easy to understand, you design a token bucket, say 1000 cards in it, each request comes in if there is a sign to go straight to the request, no sign to wait.
This is much better than the previous funnel model, not as rough as the funnel algorithm
Token bucket algorithm implementation
Use flow limiting middleware in gin framework
package middleware import ( "github.com/gin-gonic/gin" "github.com/juju/ratelimit" "net/http" "time" ) // RateLimitMiddleware(fillInterval) specifies the number of caps to be added every fillInterval seconds. Use time. Second or 2ns time.Duration, cap int64) func(c *gin.Context) { bucket := ratelimit.NewBucket(fillInterval, Cap) return func(c *gin.Context) {// if bucket.TakeAvailable(1) == 0 {c.tring (http.statusok, "rate limit") c.Abort() return } c.Next() } }Copy the code
Performance statistics
In fact, go language already has a very good performance statistics tool, here we use gin framework, for convenience directly under the gin performance statistics tool is almost the same with minor differences
"github.com/gin-contrib/pprof"
Copy the code
Then add a line of code where we registered the route:
Then start our Web service
Access the following address (the port number is your server)
http://localhost:8016/debug/pprof/
This is just telling you what analysis is provided
Then we can analyze it on the command line
Terminal input:
Go tool pprof http://127.0.0.1:8016/debug/pprof/profile
Then wait 30 seconds (you can try to access your server during this 30 seconds)
After 30s:
Top3 shows the functions that took the longest time during that time
Of course, you can also view it graphically
brew install graphviz
Then type web in the input field and you can see the SVG image directly
You can also use the Go Torch flame diagram.