返回顶部
首页 > 资讯 > 后端开发 > GO >Golang中怎么应付百万级请求
  • 159
分享到

Golang中怎么应付百万级请求

2024-04-02 19:04:59 159人浏览 泡泡鱼
摘要

这篇文章给大家介绍golang中怎么应付百万级请求,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。type PayloadCollection struct 

这篇文章给大家介绍golang中怎么应付百万级请求,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

  • type PayloadCollection struct { 

  •     windowsVersion  string    `JSON:"version"` 

  •     Token           string    `json:"token"` 

  •     Payloads        []Payload `json:"data"` 

  •  

  • type Payload struct { 

  •     // [redacted] 

  •  

  • func (p *Payload) UploadToS3() error { 

  •     // the storageFolder method ensures that there are no name collision in 

  •     // case we get same timestamp in the key name 

  •     storage_path := fmt.Sprintf("%v/%v", p.storageFolder, time.Now().UnixNano()) 

  •  

  •     bucket := S3Bucket 

  •  

  •     b := new(bytes.Buffer) 

  •     encodeErr := json.NewEncoder(b).Encode(payload) 

  •     if encodeErr != nil { 

  •         return encodeErr 

  •     } 

  •  

  •     // Everything we post to the S3 bucket should be marked 'private' 

  •     var acl = s3.Private 

  •     var contentType = "application/octet-stream" 

  •  

  •     return bucket.PutReader(storage_path, b, int64(b.Len()), contentType, acl, s3.Options{}) 

  • 幼稚地使用Go runtines

    最开始的时候我们非常天真地实现一个POST的钩子方法如下,只是简单地将每个请求体的上传动作放到Go rutinues中让他们并行执行:

    func payloadHandler(w Http.ResponseWriter, r *http.Request) {      if r.Method != "POST" {         w.WriteHeader(http.StatusMethodNotAllowed)         return     }      // Read the body into a string for json decoding     var content = &PayloadCollection{}     err := json.NewDecoder(io.LimitReader(r.Body, MaxLength)).Decode(&content)     if err != nil {         w.Header().Set("Content-Type", "application/json; charset=UTF-8")         w.WriteHeader(http.StatusBadRequest)         return     }          // Go through each payload and queue items individually to be posted to S3     for _, payload := range content.Payloads {         go payload.UploadToS3()   // <----- DON'T DO THIS     }      w.WriteHeader(http.StatusOK) }

    在中等规模的负载情况下,这种方法对大部分人都是没有问题的,但在应对更大规模的请求量时候,我们很快就招架不住了。当我们把这个版本的代码部署到生产环境以后,我们期待能有大量的请求进来但实际还不能达到百万级别的数量级。我们完全低估了这个系统要处理的流量数。

    但不管怎么说上面的方法都是欠妥的。因为它没有任何方法让我们去控制Go  runtinues启动的数量。所以当我们的系统在面对每分钟百万级POST请求的时候很快就垮掉了。

    再战

    我们需要找到另外的方法。在一开始我们就在讨论如何让我们的请求处理程序的生命周期尽可能地缩短以及上传到S3的操作能在后台或者异步运行。当然,在Ruby on  Rails里面你必须这么做,否则你将会阻塞到所有其他的网络请求处理程序。无论您使用的是美洲狮,独角兽还是过路人(请不要参与JRuby讨论)。然后我们想到使用消息队列这种比较常见的方法来处理来达到我们的目的,例如Resque,  Sidekiq, SQS等等,还有数不清的工具因为实在有太多方法来实现这个功能。

    所以在第二次迭代的时候,我们需要创建一个缓冲队列,我们会将任务放入队列里面然后再一个个地上传到S3上,但由于我们希望达到能够控制这个队列的最大容量的目的,并且我们有足够的RAM来允许我们将请求体储存到内存当中,所以我们认为直接使用了Go提供的channel,然后将我们的请求直接入队到channel中处理就可以了。

    var Queue chan Payload  func init() {    Queue = make(chan Payload, MAX_QUEUE) }  func payloadHandler(w http.ResponseWriter, r *http.Request) {    ...    // Go through each payload and queue items individually to be posted to S3    for _, payload := range content.Payloads {        Queue <- payload    }    ... }

    我们会从channel中获取任务并且执行他们的上传操作

    func StartProcessor() {     for {         select {         case job := <-Queue:             job.payload.UploadToS3()  // <-- STILL NOT GOOD         }     } }

    但说句老实话,我并不知道这是在干嘛。肯定是因为那时已经太晚还有我们已经喝了太多的红牛。

    这个改动并没有让我们的困境得到任何改善,我们将并发任务放到了队列中执行仅仅是看上去好像解决了问题。但是我们的异步程序一次只会上传一个请求体到S3上面,但是我们的请求数此时远远大于我们上传到S3的数量,可想而知我们的缓冲队列很快就到达了他的极限爆满了,然后它阻挡了其他网络请求的入队操作。

    相当于我们仅仅回避了问题,并且让我们的系统的崩溃时间进入了倒数。我们这个缺陷的版本发布以后,整个系统的延迟率在持续性地每分钟在上涨。

    Golang中怎么应付百万级请求

  • var ( 

  •     MaxWorker = os.Getenv("MAX_WORKERS") 

  •     MaxQueue  = os.Getenv("MAX_QUEUE") 

  •  

  • // Job represents the job to be run 

  • type Job struct { 

  •     Payload Payload 

  •  

  • // A buffered channel that we can send work requests on. 

  • var JobQueue chan Job 

  •  

  • // Worker represents the worker that executes the job 

  • type Worker struct { 

  •     WorkerPool  chan chan Job 

  •     JobChannel  chan Job 

  •     quit        chan bool 

  •  

  • func NewWorker(workerPool chan chan Job) Worker { 

  •     return Worker{ 

  •         WorkerPool: workerPool, 

  •         JobChannel: make(chan Job), 

  •         quit:       make(chan bool)} 

  •  

  • // Start method starts the run loop for the worker, listening for a quit channel in 

  • // case we need to stop it 

  • func (w Worker) Start() { 

  •     go func() { 

  •         for { 

  •             // reGISter the current worker into the worker queue. 

  •             w.WorkerPool <- w.JobChannel 

  •  

  •             select { 

  •             case job := <-w.JobChannel: 

  •                 // we have received a work request. 

  •                 if err := job.Payload.UploadToS3(); err != nil { 

  •                     log.Errorf("Error uploading to S3: %s", err.Error()) 

  •                 } 

  •  

  •             case <-w.quit: 

  •                 // we have received a signal to stop 

  •                 return 

  •             } 

  •         } 

  •     }() 

  •  

  • // Stop signals the worker to stop listening for work requests. 

  • func (w Worker) Stop() { 

  •     go func() { 

  •         w.quit <- true 

  •     }() 

  • 接下来修改我们网络请求的钩子函数,负责创建一个Job的结构体的实例然后将其放入JobQueue channel中等待worker来获取执行。

    func payloadHandler(w http.ResponseWriter, r *http.Request) {      if r.Method != "POST" {         w.WriteHeader(http.StatusMethodNotAllowed)         return     }      // Read the body into a string for json decoding     var content = &PayloadCollection{}     err := json.NewDecoder(io.LimitReader(r.Body, MaxLength)).Decode(&content)     if err != nil {         w.Header().Set("Content-Type", "application/json; charset=UTF-8")         w.WriteHeader(http.StatusBadRequest)         return     }      // Go through each payload and queue items individually to be posted to S3     for _, payload := range content.Payloads {          // let's create a job with the payload         work := Job{Payload: payload}          // Push the work onto the queue.         JobQueue <- work     }      w.WriteHeader(http.StatusOK) }

    在我们网络服务初始化的时候创建一个Dispather并且调用Run()创建一个装有一定数量worker的线程池,用来接收和处理来自JobQueue的Job

    dispatcher := NewDispatcher(MaxWorker)  dispatcher.Run()

    下面是我们Dispather的实现

    type Dispatcher struct {     // A pool of workers channels that are registered with the dispatcher     WorkerPool chan chan Job }  func NewDispatcher(maxWorkers int) *Dispatcher {     pool := make(chan chan Job, maxWorkers)     return &Dispatcher{WorkerPool: pool} }  func (d *Dispatcher) Run() {     // starting n number of workers     for i := 0; i < d.maxWorkers; i++ {         worker := NewWorker(d.pool)         worker.Start()     }      go d.dispatch() }  func (d *Dispatcher) dispatch() {     for {         select {         case job := <-JobQueue:             // a job request has been received             go func(job Job) {                 // try to obtain a worker job channel that is available.                 // this will block until a worker is idle                 jobChannel := <-d.WorkerPool                  // dispatch the job to the worker job channel                 jobChannel <- job             }(job)         }     } }

    当我们将这个版本发布到生产环境以后我们的延迟率马上有明显的下降,我们处理请求的能力有一个质的飞跃。

    Golang中怎么应付百万级请求Golang中怎么应付百万级请求Golang中怎么应付百万级请求

关于Golang中怎么应付百万级请求就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

您可能感兴趣的文档:

--结束END--

本文标题: Golang中怎么应付百万级请求

本文链接: https://lsjlt.com/news/71192.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Golang中怎么应付百万级请求
    这篇文章给大家介绍Golang中怎么应付百万级请求,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。type PayloadCollection struct ...
    99+
    2024-04-02
  • Golang中怎么处理每分钟百万请求
    Golang中怎么处理每分钟百万请求,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。传统上,我们会考虑创建一个工作层架构,利用诸如以下的技术栈:SidekiqResqueDela...
    99+
    2023-06-16
  • golang百万并发请求问题怎么解决
    在Go语言中,可以使用goroutine和channel来实现百万并发请求的处理。以下是一种解决方案的示例: 创建一个请求队列,将...
    99+
    2023-10-27
    golang
  • 怎么用Golang处理每分钟100万个请求
    本文小编为大家详细介绍“怎么用Golang处理每分钟100万个请求”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么用Golang处理每分钟100万个请求”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。面临的问题...
    99+
    2023-07-06
  • Plsql怎么导出百万级数据
    在PL/SQL中如果需要导出大量数据,可以使用以下方法之一: 使用PL/SQL Developer等工具进行数据导出:通过PL/...
    99+
    2024-04-09
    Plsql
  • Golang中怎么实现GET请求
    这篇文章主要讲解了“Golang中怎么实现GET请求”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang中怎么实现GET请求”吧!一、Golang中的GET请求在Golang中,我们可...
    99+
    2023-07-05
  • 怎么在mysql中优化百万级数据表的查询
    怎么在mysql中优化百万级数据表的查询?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1.两种查询引擎查询速度(myIsam 引擎 )InnoDB 中不保存表的...
    99+
    2023-06-15
  • 在Golang中怎么进行网络请求
    这篇文章主要介绍“在Golang中怎么进行网络请求”,在日常操作中,相信很多人在在Golang中怎么进行网络请求问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”在Golang中怎么进行网络请求”的疑惑有所帮助!...
    99+
    2023-07-05
  • 怎么用Mysql存储过程造百万级数据
    本文小编为大家详细介绍“怎么用Mysql存储过程造百万级数据”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么用Mysql存储过程造百万级数据”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1.准备工作(1)由于...
    99+
    2023-07-05
  • Go语言中怎么实现每分钟处理100万个请求
    今天就跟大家聊聊有关Go语言中怎么实现每分钟处理100万个请求,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Go语言程序的单纯方法 最初我们采取了一...
    99+
    2024-04-02
  • hbase中put请求响应慢怎么解决
    HBase中put请求响应慢可能由多种原因引起,以下是一些可能的解决方法: 调整HBase集群的性能参数,如增加RegionSer...
    99+
    2024-04-02
  • golang gorm怎么实现get请求查询
    今天小编给大家分享一下golang gorm怎么实现get请求查询的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。案...
    99+
    2023-06-30
  • 百万级MySQL的数据量怎么快速完成数据迁移
    这篇文章主要讲解了“百万级MySQL的数据量怎么快速完成数据迁移”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“百万级MySQL的数据量怎么快速完成数据迁移”...
    99+
    2024-04-02
  • 如何使用golang中的http.Client进行HTTP请求的高级操作
    如何使用golang中的http.Client进行HTTP请求的高级操作引言:在现代开发中,HTTP请求是不可避免的一部分。golang提供了强大的标准库,其中包含了http包。http包提供了http.Client结构体,用于发送HTTP...
    99+
    2023-11-18
    Http请求 Golang httpclient
  • Java应用的Post请求怎么实现
    这篇文章主要介绍“Java应用的Post请求怎么实现”,在日常操作中,相信很多人在Java应用的Post请求怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java应用的Post请求怎么实现”的疑惑有所...
    99+
    2023-06-04
  • Netty4之怎么实现HTTP请求、响应
    本文小编为大家详细介绍“Netty4之怎么实现HTTP请求、响应”,内容详细,步骤清晰,细节处理妥当,希望这篇“Netty4之怎么实现HTTP请求、响应”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1.Netty...
    99+
    2023-07-05
  • golang爬虫colly发送post请求怎么实现
    本文小编为大家详细介绍“golang爬虫colly发送post请求怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“golang爬虫colly发送post请求怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知...
    99+
    2023-07-02
  • Node.js中怎么处理POST请求并获取请求参数
    本篇内容介绍了“Node.js中怎么处理POST请求并获取请求参数”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!接收POST请求在Node....
    99+
    2023-07-05
  • 为什么 post 请求在 gin golang 中不起作用?
    编程网今天将给大家带来《为什么 post 请求在 gin golang 中不起作用?》,感兴趣的朋友请继续看下去吧!以下内容将会涉及到等等知识点,如果你是正在学习Golang或者已经是大佬级别了,都...
    99+
    2024-04-04
  • 使用golang中的http.Get函数发送GET请求并获取响应
    使用golang中的http.Get函数发送GET请求并获取响应在使用golang进行网络编程时,我们经常需要发送HTTP请求并获取到响应结果。golang的标准库中提供了强大且易于使用的http包,其中的Get函数可以帮助我们发送GET请...
    99+
    2023-11-18
    Golang GET请求 httpGet
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作