golang网络框架,Golang 框架

本文目录一览:

iris 真的是最快的Golang 路由框架吗

对各种Go http路由框架的比较, Iris明显胜出,它的性能远远超过其它Golang http路由框架。

但是,在真实的环境中,Iris真的就是最快的Golang http路由框架吗?

Benchmark测试分析

在那篇文章中我使用的是Julien Schmidt的 测试代码,他模拟了静态路由、Github API、Goolge+ API、Parse API的各种情况,因为这些API是知名网站的开放的API,看起来测试挺真实可靠的。

但是,这个测试存在着一个严重的问题,就是Handler的业务逻辑非常的简单,各个框架的handler类似,比如Iris的Handler的实现:

funcirisHandler(_ *iris.Context) {}funcirisHandlerWrite(c *iris.Context) { io.WriteString(c.ResponseWriter, c.Param(“name”))}funcirisHandlerTest(c *iris.Context) { io.WriteString(c.ResponseWriter, c.Request.RequestURI)}

几乎没有任何的业务逻辑,最多是往Response中写入一个字符串。

这和生产环境中的情况严重不符!

实际的产品肯定会有一些业务的处理,比如参数的校验,数据的计算,本地文件的读取、远程服务的调用、缓存的读取、数据库的读取和写入等,有些操作可能花费的时间很多,一两个毫秒就可以搞定,有的却很耗时,可能需要几十毫秒,比如:

从一个网络连接中读取数据 写数据到硬盘中 调用其它服务,等待服务结果的返回 ……

这才是我们常用的case,而不是一个简单的写字符串。

因此那个测试框架的Handler还应该加入时间花费的情况。

模拟真实的Handler的情况

我们模拟一下真实的情况,看看Iris框架和Golang内置的Http路由框架的性能如何。

首先使用Iris实现一个Http Server:

packagemainimport(“os””strconv””time””github.com/kataras/iris”)funcmain() { api := iris.New() api.Get(“/rest/hello”,func(c *iris.Context) { sleepTime, _ := strconv.Atoi(os.Args[1])ifsleepTime 0{ time.Sleep(time.Duration(sleepTime) * time.Millisecond) } c.Text(“Hello world”) }) api.Listen(“:8080”)}

我们可以传递给它一个时间花费的参数sleepTime,模拟这个Handler在处理业务时要花费的时间,它会让处理这个Handler的暂停sleepTime毫秒,如果为0,则不需要暂停,这种情况类似上面的测试。

然后我们使用Go内置的路由功能实现一个Http Server:

packagemainimport(“log””net/http””os””strconv””time”)// There are some golang RESTful libraries and mux libraries but i use the simplest to test.funcmain() { http.HandleFunc(“/rest/hello”,func(w http.ResponseWriter, r *http.Request) { sleepTime, _ := strconv.Atoi(os.Args[1])ifsleepTime 0{ time.Sleep(time.Duration(sleepTime) * time.Millisecond) } w.Write([]byte(“Hello world”)) }) err := http.ListenAndServe(“:8080”,nil)iferr !=nil{ log.Fatal(“ListenAndServe: “, err) }}

编译两个程序进行测试。

1、首先进行业务逻辑时间花费为0的测试

运行程序 iris 0,然后执行 wrk -t16 -c100 -d30s 进行并发100,持续30秒的测试。

iris的吞吐率为46155 requests/second。

运行程序 gomux 0,然后执行 wrk -t16 -c100 -d30s 进行并发100,持续30秒的测试。

Go内置的路由程序的吞吐率为55944 requests/second。

两者的吞吐量差别不大,iris略差一点

2、然后进行业务逻辑时间花费为10的测试

运行程序 iris 10,然后执行 wrk -t16 -c100 -d30s 进行并发100,持续30秒的测试。

iris的吞吐率为97 requests/second。

运行程序 gomux 10,然后执行 wrk -t16 -c100 -d30s 进行并发100,持续30秒的测试。

Go内置的路由程序的吞吐率为9294 requests/second。

3、最后进行业务逻辑时间花费为1000的测试

这次模拟一个极端的情况,业务处理很慢,处理一个业务需要1秒的时间。

运行程序 iris 1000,然后执行 wrk -t16 -c100 -d30s 进行并发100,持续30秒的测试。

iris的吞吐率为1 requests/second。

运行程序 gomux 1000,然后执行 wrk -t16 -c100 -d30s 进行并发100,持续30秒的测试。

Go内置的路由程序的吞吐率为95 requests/second。

可以看到,如果加上业务逻辑的处理时间,Go内置的路由功能要远远好于Iris, 甚至可以说Iris的路由根本无法应用的有业务逻辑的产品中,随着业务逻辑的时间耗费加大,iris的吞吐量急剧下降。

而对于Go的内置路由来说,业务逻辑的时间耗费加大,单个client会等待更长的时间,但是并发量大的网站来说,吞吐率不会下降太多。

比如我们用1000的并发量测试 gomux 10和 gomux 1000。

gomux 10: 吞吐率为47664 gomux 1000: 吞吐率为979

这才是Http网站真实的情况,因为我们要应付的网站的并发量,网站应该支持同时有尽可能多的用户访问,即使单个用户得到返回页面需要上百毫秒也可以接受。

而Iris在业务逻辑的处理时间增大的情况下,无法支持大的吞吐率,即使在并发量很大的情况下(比如1000),吞吐率也很低。

深入了解Go http server的实现

Go http server实现的是每个request对应一个goroutine (goroutine per request), 考虑到Http Keep-Alive的情况,更准确的说是每个连接对应一个goroutine(goroutine per connection)。

因为goroutine是非常轻量级的,不会像Java那样 Thread per request会导致服务器资源不足,无法创建很多的Thread, Golang可以创建足够多的goroutine,所以goroutine per request的方式在Golang中没有问题。而且这还有一个好处,因为request是在一个goroutine中处理的,不必考虑对同一个Request/Response并发读写的问题。

如何查看Handler是在哪一个goroutine中执行的呢?我们需要实现一个函数来获取goroutine的Id:

funcgoID()int{varbuf[64]byte n := runtime.Stack(buf[:], false) idField := strings.Fields(strings.TrimPrefix(string(buf[:n]),”goroutine “))[0] id, err := strconv.Atoi(idField)iferr !=nil{panic(fmt.Sprintf(“cannot get goroutine id: %v”, err)) }returnid}

然后在handler中打印出当前的goroutine id:

func(c *iris.Context) { fmt.Println(goID()) ……}

func(w http.ResponseWriter, r *http.Request) { fmt.Println(goID()) ……}

启动 gomux 0,然后运行 ab -c 5 -n 5 测试一下,apache的ab命令使用5个并发并且每个并发两个请求访问服务器。

可以看到服务器的输出:

因为没有指定 -k参数,每个client发送两个请求会创建两个连接。

你可以加上 -k参数,可以看出会有重复的goroutine id出现,表明同一个持久连接会使用同一个goroutine处理。

以上是通过实验验证我们的理论,下面是代码分析。

net/http/server.go的 第2146行 go c.serve()表明,对于一个http连接,会启动一个goroutine:

func(srv *Server) Serve(l net.Listener) error {deferl.Close()iffn := testHookServerServe; fn !=nil{ fn(srv, l) }vartempDelay time.Duration// how long to sleep on accept failureiferr := srv.setupHTTP2(); err !=nil{returnerr }for{ rw, e := l.Accept() …… tempDelay =0 c := srv.newConn(rw) c.setState(c.rwc, StateNew) // before Serve can returngoc.serve() }}

而这个 c.serve方法会从连接中 读取request交由handler处理:

func(c *conn) serve() { ……for{ w, err := c.readRequest() …… req := w.req serverHandler{c.server}.ServeHTTP(w, w.req)ifc.hijacked() {return } w.finishRequest()if!w.shouldReuseConnection() {ifw.requestBodyLimitHit || w.closedRequestBodyEarly() { c.closeWriteAndWait() }return } c.setState(c.rwc, StateIdle) }}

而 ServeHTTP的实现如下,如果没有配置handler或者路由器,则使用缺省的 DefaultServeMux。

func(sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { handler := sh.srv.Handlerifhandler ==nil{ handler = DefaultServeMux }ifreq.RequestURI ==”*” req.Method ==”OPTIONS”{ handler = globalOptionsHandler{} } handler.ServeHTTP(rw, req)}

可以看出这里并没有新开goroutine,而是在同一个connection对应的goroutine中执行的。如果试用Keep-Alive,还是在这个connection对应的goroutine中执行。

正如注释中所说的那样:

// HTTP cannot have multiple simultaneous active requests.[*] // Until the server replies to this request, it can’t read another, // so we might as well run the handler in this goroutine. // [*] Not strictly true: HTTP pipelining. We could let them all process // in parallel even if their responses need to be serialized. serverHandler{c.server}.ServeHTTP(w, w.req)

因此业务逻辑的时间花费会影响单个goroutine的执行时间,并且反映到客户的浏览器是是延迟时间latency增大了,如果并发量足够多,影响的是系统中的goroutine的数量以及它们的调度,吞吐率不会剧烈影响。

Iris的分析

如果你使用Iris查看每个Handler是使用哪一个goroutine执行的,会发现每个连接也会用不同的goroutine执行,可是性能差在哪儿呢?

或者说,是什么原因导致Iris的性能急剧下降呢?

Iris服务器的监听和为连接启动一个goroutine没有什么明显不同,重要的不同在与Router处理Request的逻辑。

原因在于Iris为了提供性能,缓存了context,对于相同的请求url和method,它会从缓存中使用相同的context。

func(r *MemoryRouter) ServeHTTP(res http.ResponseWriter, req *http.Request) {ifctx := r.cache.GetItem(req.Method, req.URL.Path); ctx !=nil{ ctx.Redo(res, req)return } ctx := r.getStation().pool.Get().(*Context) ctx.Reset(res, req)ifr.processRequest(ctx) {//if something found and served then add it’s clone to the cache r.cache.AddItem(req.Method, req.URL.Path, ctx.Clone()) } r.getStation().pool.Put(ctx)}

由于并发量较大的时候,多个client的请求都会进入到上面的 ServeHTTP方法中,导致相同的请求会进入下面的逻辑:

ifctx := r.cache.GetItem(req.Method, req.URL.Path); ctx !=nil{ ctx.Redo(res, req)return}

ctx.Redo(res, req)导致不断循环,直到每个请求处理完毕,将context放回到池子中。

所以对于Iris来说,并发量大的情况下,对于相同的请求(req.URL.Path和Method相同)会进入排队的状态,导致性能低下。

golang 有哪些比较稳定的 web 开发框架

第一个:Beego框架

Beego框架是astaxie的GOWeb开发的开源框架。Beego框架最大的特点是由八个大的基础模块组成,八大基础模块的特点是可以根据自己的需要进行引入,模块相互独立,模块之间耦合性低。

相应的Beego的缺点就是全部使用时比较臃肿,通过bee工具来构建项目时,直接生成项目目录和耦合关系,从而会导致在项目开发过程中受制性较大。

第二个:Gin框架

Gin是一个GOlang的微框架,封装比较优雅,API友好,源码注释比较明确,已经发布了1.0版本;具有快速灵活、容错方便等特点,其实对于golang而言,web框架的依赖远比Python、Java更小。

目前在很多使用golang的中小型公司中进行业务开发,使用Gin框架的很多,大家如果想使用golang进行熟练Web开发,可以多关注一下这个框架。

第三个:Iris框架

Iris框架在其官方网站上被描述为GO开发中最快的Web框架,并给出了多框架和多语言之前的性能对比。目前在github上,Iris框架已经收获了14433个star和1493个fork,可见是非常受欢迎的。

在实际开发中,Iris框架与Gin框架的学习曲线几乎相同,所以掌握了Gin就可以轻松掌握Iris框架。

第四个:Echo框架

也是golang的微型Web框架,其具备快速HTTP路由器、支持扩展中间件,同时还支持静态文件服务、Websocket以及支持制定绑定函数,制定相应渲染函数,并允许使用任意的HTML模版引擎。

GoLang — Gin框架

• 何为框架:

框架一直是敏捷开发中的利器,能让开发者很快的上手并做出应用,甚至有的时候,脱离了框架,一些开发者都不会写程序了。成长总不会一蹴而就,从写出程序获取成就感,再到精通框架,快速构造应用,当这些方面都得心应手的时候,可以尝试改造一些框架,或是自己创造一个。

Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,已经发布了1.0版本。具有快速灵活,容错方便等特点。其实对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的net/http足够简单,性能也非常不错。框架更像是一些常用函数或者工具的集合。借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范。

(1)首先需要安装,安装比较简单,使用go get即可

go get github.com/gin-gonic/gin

如果安装失败,直接去Github clone下来,放置到对应的目录即可。

(2)代码中使用:

下面是一个使用Gin的简单例子:

package main

import (

“github.com/gin-gonic/gin”

)

func main() {

router := gin.Default()

router.GET(“/ping”, func(c *gin.Context) {

c.JSON(200, gin.H{

“message”: “pong”,

})

})

router.Run(“:8080”) // listen and serve on 0.0.0.0:8080

}

简单几行代码,就能实现一个web服务。使用gin的Default方法创建一个路由handler。然后通过HTTP方法绑定路由规则和路由函数。不同于net/http库的路由函数,gin进行了封装,把request和response都封装到gin.Context的上下文环境。最后是启动路由的Run方法监听端口。麻雀虽小,五脏俱全。当然,除了GET方法,gin也支持POST,PUT,DELETE,OPTION等常用的restful方法。

Gin可以很方便的支持各种HTTP请求方法以及返回各种类型的数据,详情可以前往查看。

2.1 匹配参数

我们可以使用Gin框架快速的匹配参数,如下代码所示:

冒号:加上一个参数名组成路由参数。可以使用c.Param的方法读取其值。当然这个值是字串string。诸如/user/rsj217,和/user/hello都可以匹配,而/user/和/user/rsj217/不会被匹配。

浏览器输入以下测试:

返回结果为:

其中c.String是gin.Context下提供的方法,用来返回字符串。

其中c.Json是gin.Context下提供的方法,用来返回Json。

下面我们使用以下gin提供的Group函数,方便的为不同的API进行分类。

我们创建了一个gin的默认路由,并为其分配了一个组 v1,监听hello请求并将其路由到视图函数HelloPage,最后绑定到 0.0.0.0:8000

C.JSON是Gin实现的返回json数据的内置方法,包含了2个参数,状态码和返回的内容。http.StatusOK代表返回状态码为200,正文为{“message”: “welcome”}。

注:Gin还包含更多的返回方法如c.String, c.HTML, c.XML等,请自行了解。可以方便的返回HTML数据

我们在之前的组v1路由下新定义一个路由:

下面我们访问

可以看到,通过c.Param(“key”)方法,Gin成功捕获了url请求路径中的参数。同理,gin也可以捕获常规参数,如下代码所示:

在浏览器输入以下代码:

通过c.Query(“key”)可以成功接收到url参数,c.DefaultQuery在参数不存在的情况下,会由其默认值代替。

我们还可以为Gin定义一些默认路由:

这时候,我们访问一个不存在的页面:

返回如下所示:

下面我们测试在Gin里面使用Post

在测试端输入:

附带发送的数据,测试即可。记住需要使用POST方法.

继续修改,将PostHandler的函数修改如下

测试工具输入:

发送的内容输入:

返回结果如下:

备注:此处需要指定Content-Type为application/x-www-form-urlencoded,否则识别不出来。

一定要选择对应的PUT或者DELETE方法。

Gin框架快速的创建路由

能够方便的创建分组

支持url正则表达式

支持参数查找(c.Param c.Query c.PostForm)

请求方法精准匹配

支持404处理

快速的返回给客户端数据,常用的c.String c.JSON c.Data

golang反射框架Fx

Fx是一个golang版本的依赖注入框架,它使得golang通过可重用、可组合的模块化来构建golang应用程序变得非常容易,可直接在项目中添加以下内容即可体验Fx效果。

Fx是通过使用依赖注入的方式替换了全局通过手动方式来连接不同函数调用的复杂度,也不同于其他的依赖注入方式,Fx能够像普通golang函数去使用,而不需要通过使用struct标签或内嵌特定类型。这样使得Fx能够在很多go的包中很好的使用。

接下来会提供一些Fx的简单demo,并说明其中的一些定义。

1、一般步骤

大致的使用步骤就如下。下面会给出一些完整的demo

2、简单demo

将io.reader与具体实现类关联起来

输出:

3、使用struct参数

前面的使用方式一旦需要进行注入的类型过多,可以通过struct参数方式来解决

输出

如果通过Provide提供构造函数是生成相同类型会有什么问题?换句话也就是相同类型拥有多个值呢?

下面两种方式就是来解决这样的问题。

4、使用struct参数+Name标签

在Fx未使用Name或Group标签时不允许存在多个相同类型的构造函数,一旦存在会触发panic。

输出

上面通过Name标签即可完成在Fx容器注入相同类型

5、使用struct参数+Group标签

使用group标签同样也能完成上面的功能

输出

基本上Fx简单应用在上面的例子也做了简单讲解

1、Annotated(位于annotated.go文件) 主要用于采用annotated的方式,提供Provide注入类型

源码中Name和Group两个字段与前面提到的Name标签和Group标签是一样的,只能选其一使用

2、App(位于app.go文件) 提供注入对象具体的容器、LiftCycle、容器的启动及停止、类型变量及实现类注入和两者映射等操作

至于Provide和Populate的源码相对比较简单易懂在这里不在描述

具体源码

3、Extract(位于extract.go文件)

主要用于在application启动初始化过程通过依赖注入的方式将容器中的变量值来填充给定的struct,其中target必须是指向struct的指针,并且只能填充可导出的字段(golang只能通过反射修改可导出并且可寻址的字段),Extract将被Populate代替。 具体源码

4、其他

诸如Populate是用来替换Extract的,而LiftCycle和inout.go涉及内容比较多后续会单独提供专属文件说明。

在Fx中提供的构造函数都是惰性调用,可以通过invocations在application启动来完成一些必要的初始化工作:fx.Invoke(function); 通过也可以按需自定义实现LiftCycle的Hook对应的OnStart和OnStop用来完成手动启动容器和关闭,来满足一些自己实际的业务需求。

Fx框架源码解析

主要包括app.go、lifecycle.go、annotated.go、populate.go、inout.go、shutdown.go、extract.go(可以忽略,了解populate.go)以及辅助的internal中的fxlog、fxreflect、lifecycle

golang性能测试框架k6源码分析

k6是新兴的性能测试框架,比肩jmeter,另外测试脚本使用js,更加适合自动化的架构。

k6启动的框架是使用golang的cli标准框架cobra,入口函数

进入cobra框架后,我们直接查看getRunCmd,这个是命令run的入口,主要工作都是从这里开始。

重点关注初始化Runner,这个是通过js脚本,使用goja库解析后,生成的实际执行单元。

进入js目录,查看Runner的结构,runner.go

Runner有一些配置属性,另外还有方法,方法用lib.Runner的接口进行规范。

Runner有一个NewVU方法,里面定义了连接参数,实现api测试

返回主函数,在初始化完成Runner后,启动调度器,以及做结果收集

最终封装成一个engine

启动测试

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/238235.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-12 12:10
下一篇 2024-12-12 12:10

相关推荐

  • Ojlat:一款快速开发Web应用程序的框架

    Ojlat是一款用于快速开发Web应用程序的框架。它的主要特点是高效、易用、可扩展且功能齐全。通过Ojlat,开发人员可以轻松地构建出高质量的Web应用程序。本文将从多个方面对Oj…

    编程 2025-04-29
  • Zlios——一个多功能的开发框架

    你是否在开发过程中常常遇到同样的问题,需要不断去寻找解决方案?你是否想要一个多功能、易于使用的开发框架来解决这些问题?那么,Zlios就是你需要的框架。 一、简介 Zlios是一个…

    编程 2025-04-29
  • 使用Golang调用Python

    在现代软件开发中,多种编程语言的协作是相当普遍的。其中一种使用场景是Golang调用Python,这使得在使用Python库的同时,可以利用Golang的高性能和强大并发能力。这篇…

    编程 2025-04-29
  • agavi开发框架

    Agavi是一个基于MVC模式的Web应用程序开发框架,以REST和面向资源的设计为核心思想。本文章将从Agavi的概念、优点、使用方法和实例等方面进行详细介绍。 一、概念 Aga…

    编程 2025-04-29
  • Python unittest框架用法介绍

    Python unittest框架是Python自带的一种测试框架,可以用来编写并运行测试用例。在本文中,我们将从以下几个方面详细介绍Python unittest框架的使用方法和…

    编程 2025-04-29
  • com.alipay.sofa.bolt框架

    com.alipay.sofa.bolt框架是一款高性能、轻量级、可扩展的RPC框架。其广泛被应用于阿里集团内部服务以及阿里云上的服务。该框架通过NIO支持高并发,同时还内置了多种…

    编程 2025-04-29
  • 使用Netzob进行网络协议分析

    Netzob是一款开源的网络协议分析工具。它提供了一套完整的协议分析框架,可以支持多种数据格式的解析和可视化,方便用户对协议数据进行分析和定制。本文将从多个方面对Netzob进行详…

    编程 2025-04-29
  • 使用Golang创建黑色背景图片的方法

    本文将从多个方面介绍使用Golang创建黑色背景图片的方法。 一、安装必要的代码库和工具 在开始创建黑色背景图片之前,我们需要先安装必要的代码库和工具: go get -u git…

    编程 2025-04-29
  • 微软发布的网络操作系统

    微软发布的网络操作系统指的是Windows Server操作系统及其相关产品,它们被广泛应用于企业级云计算、数据库管理、虚拟化、网络安全等领域。下面将从多个方面对微软发布的网络操作…

    编程 2025-04-28
  • Django框架:从简介到项目实战

    本文将从Django的介绍,以及如何搭建Django环境开始,逐步深入到Django模型、视图、模板、表单,最后通过一个小型项目实战,进行综合性的应用,让读者获得更深入的学习。 一…

    编程 2025-04-28

发表回复

登录后才能评论