golang-gin-mgo高并发服务器搭建教程

 更新时间:2020年12月17日 15:46:20   作者:wayne_鱼蛋  
这篇文章主要介绍了golang-gin-mgo高并发服务器搭建教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

gin-mgo服务器搭建

该服务器实现简单接收请求并将请求参数封装存储在mongodb数据库中,本文将讲述gin-mgo的使用方法。

项目完整代码地址: https://github.com/wayne-yhp/golang-gin-mgo

gin web框架使用介绍

首先获取gin框架依赖

go get gopkg.in/gin-gonic/gin.v1

func main() {
  server = gin.Default()
  app.server.GET("/do", IndexRouter)//创造一个GET请求的路由地址,并指定处理函数为IndexRouter函数
  app.server.Run(":8080")
}
func IndexRouter(c *gin.Context) {
  if c.Request.Form == nil {   //获取所有请求参数名和值的预处理
    c.Request.ParseMultipartForm(32 << 20)
  }
  params = c.Request.Form   //获取所有参数列表
  fmt.Println(params)     //打印输出参数
  c.String(http.StatusOK,"hello gin")//返回给页面hello gin字符串
  //c.HTML(http.StatusOK, "index.html", nil)   //页面跳转
}

mgo 持久层框架使用介绍

前提条件mongodb环境已经搭建好了,首先安装mgo框架依赖

go get labix.org/v2/mgo

type User struct{
  username string
  pwd string
}
func main() {
  mgo_session, err = mgo.Dial("127.0.0.1") //获取连接对象session
  if err != nil {
    panic(err)
  }
  defer session.Close()    //方法执行完后关闭连接
  mgo_db = oper.mgo_session.DB("test")  //获取数据库对象,数据库名为test
  //如果没有mongodb没有开启权限认证,则跳过这一步
  mgo_db.Login("test1", "test1")  //用户认证,用户名账户和密码都是test1
  mgo_c = oper.mgo_db.C("coll")  //获取数据库某个集合对象
  //插入操作
  mgo_c.insert(&User{
    username: "xxx",
    pwd: "xxx",
  })
}

提高服务器高并发性能讲解(针对文章开头地址中的项目)

该项目主要实现接收请求,解析封装参数,插入数据库的简单操作,这里只涉及插入操作,故不涉及数据缓存的知识,整个服务处于单机下,故不涉及分布式服务架构,集群的知识。

注意以下

1、开启一个协程独自监听访问数量,进行插入操作

2、实现批量插入

3、实现定时插入

4、加锁解决并发资源竞争

开启一个协程独自监听访问数量,进行插入操作

如果将插入操作放在主线程,那么接收http请求和逻辑处理,数据库插入操作都必须要顺序执行,大大降低了插入效率,因此要开启一个协程,独自监听访问数量,进行数据库插入。

实现批量插入

假想一下如果每次有人访问你的数据库你就进行一次插入操作,那么你的数据库将会是一个什么样的情况?我们都知道数据库操作相对服务器其他操作是一件相对很耗时的事情,所以每次访问就操作一次数据库,会大大降低服务器性能,更别说有几千上万的人同时访问你的服务器了。

实现定时插入

在实现了批量插入的基础上,如果没有达到一定的访问量,那么就不会执行插入操作,刚好在两个访问请求中间隔了很长时间,那么前面的请求就会等待很久才会更新到数据库中,为了防止这种情况,我们必须要设定一个时间,定时插入。

加锁解决并发资源竞争

在并发量几千上万的情况下,可能一秒可以执行很多次数据库的插入操作,这个时候很有可能上一个插入还没执行完,第二个就已经执行了,这时候可能出现数据冗余,服务器瘫痪等问题,因此要给批量插入操作加上一个读写锁。

具体实现细节可以去上述地址中查看。

补充:Golang号称高并发,但高并发时性能不高

1.管道chan吞吐极限10,000,000,单次Put,Get耗时大约100ns/op,无论是采用单Go程,还是多Go程并发(并发数:100, 10000, 100000),耗时均没有变化,Go内核这对chan进行优化。

解决之道:

在系统设计时,避免使用管道chan传递主业务数据,避免将业务流程处理流程分割到对个Go程中执行,这样做减少chan传输耗时,和Go程调度耗时,性能会有很大的提升。

案例分析:nsq和nats都是实时消息队列,nsq在客户端端和服务端大量使用chan转发消息,导致性能不佳,只有100,000/s;而nats服务端在分发消息流程中,没有使用chan,只在客户端接收时使用chan,性能可达到1,000,000/s。

2.互斥锁Mutex在单Go程时Lock,Unlock耗时大约20ns/op,但是采用多Go程时,性能急剧下降,并发越大耗时越长,在Go1.5并发数达到1024耗时900ns/op,Go1.6优化到300ns/op,究其原因,是构建在CPU的原子操作之上,抢占过于频繁将导致,消耗大量CPU时钟,进而CPU多核无法并行。

解决之道:

采用分区,将需要互斥保护的数据,分成多个固定分区(建议是2的整数倍,如256),访问时先定位分区(不互斥),这样就可降低多个Go程竞争1个数据分区的概率。

案例分析:Golang的Go程调度模块,在管理大量的Go程,使用的就是数据分区。

3.select异步操作在单管道时耗时120ns/op,但是随着管道数增加,性能线性下降,每增加1个管道增加100ns/op,究其原因,slelect时当chan数超过1后,Go内部是创建一个Go程,有它每1ms轮训的方式检查每个chan是否可用,而不是采用事件触发。

解决之道:

在select中避免使用过多的管道chan分支,或者把无法用到的chan置为nil;解决select超时,避免使用单独的超时管道,应与数据返回管道共享。

案例分析:nsq和nats都是实时消息队列,由于nsq大量使用chan,这就必然导致大量使用select对多chan操作,结果是性能不高。

4.Go调度性能低下,当出现1,000,000Go程时,Go的调度器的性能急剧下降。

解决之道:

避免动态创建Go程,服务端收到数据并处理的流程中,避免使用chan传递业务数据,这样会引起Go程调度。

案例分析:nsq和nats都是实时消息队列,由于nsq大量使用chan,这就必然导致在服务过程中,引起Go调度,结果是性能不高。

5.defer性能不高,每次defer耗时100ns,,在一个func内连续出现多次,性能消耗是100ns*n,累计出来浪费的cpu资源很大的。

解决之道:

除了需要异常捕获时,必须使用defer;其它资源回收类defer,可以判断失败后,使用goto跳转到资源回收的代码区。

6.内存管理器性能低下,申请16字节的内存,单次消耗30ns,64字节单次消耗70ns,随着申请内存尺寸的增长,耗时会迅速增长。加上GC的性能在1.4, 1.5是都不高,直到1.6, 1.7才得到改善。

解决之道:

建议使用pool,单次Put,Get的耗时大约在28ns,在并发情况下可达到18ns,比起每次创建,会节省很多的CPU时钟。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。

相关文章

  • Golang 语言map底层实现原理解析

    Golang 语言map底层实现原理解析

    这篇文章主要介绍了Golang 语言map底层实现原理解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • GO语言基本数据类型总结

    GO语言基本数据类型总结

    这篇文章主要介绍了GO语言基本数据类型,较为详细的总结了GO语言的基本数据类型,对于GO语言的学习有一定的借鉴参考价值,需要的朋友可以参考下
    2014-12-12
  • 利用Golang解析json数据的方法示例

    利用Golang解析json数据的方法示例

    Go提供了原生的JSON库,并且与语言本身有效的集成在了一起。下面这篇文章将给大家介绍关于利用Golang解析json数据的方法,文中给出了详细的示例代码供大家参考学习,需要的朋友们下面跟着小编来一起学习学习吧。
    2017-07-07
  • Go+Kafka实现延迟消息的实现示例

    Go+Kafka实现延迟消息的实现示例

    本文主要介绍了Go+Kafka实现延迟消息的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • 一文带你了解Go语言中函数设计的实践示例

    一文带你了解Go语言中函数设计的实践示例

    良好设计的函数具有清晰的职责和逻辑结构,提供准确的命名和适当的参数控制,下面我们将一一描述函数设计时能够遵循的最佳实践,希望对大家有所帮助
    2023-06-06
  • Go代码检查的推荐工具及使用详解

    Go代码检查的推荐工具及使用详解

    这篇文章主要为大家介绍了Go代码检查的推荐工具及使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • 一文详解golang中的gmp模型

    一文详解golang中的gmp模型

    这篇文章主要介绍了golang中的gmp模型的诞生、概念及调度讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • Golang实现优雅的将struct转换为map

    Golang实现优雅的将struct转换为map

    在项目实践中,有时候我们需要将struct结构体转为map映射表,然后基于map做数据裁剪或操作。那么下面我来介绍下常用的两种转换方式,希望对大家有所帮助
    2023-01-01
  • 一文详解在Go中如何使用Viper来管理配置

    一文详解在Go中如何使用Viper来管理配置

    Viper 是一个功能齐全的 Go 应用程序配置库,支持很多场景。在本文中,我们将深入探讨 Viper 的各种用法和使用场景,以帮助读者更好地了解和使用 Viper 来管理应用程序配置,感兴趣的同学可以参考阅读
    2023-05-05
  • golang 实用库gotable的具体使用

    golang 实用库gotable的具体使用

    使用gotable框架以实现在CLI命令行界面中打印表格。本文就介绍一下golang 实用库gotable的使用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07

最新评论