MST

星途 面试题库

面试题:Go HTTP客户端性能优化及高并发场景处理

在高并发场景下使用Go的HTTP客户端向大量不同的API端点发送请求,如何优化性能?比如如何复用连接、处理请求队列、控制并发数等。请详细阐述设计思路并给出关键代码示例。
14.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 复用连接
    • Go的http.Client默认已经支持连接池,通过设置合适的Transport来优化连接复用。http.Transport结构体中的MaxIdleConnsMaxIdleConnsPerHost等字段可以控制连接池的行为。MaxIdleConns设置了整个连接池的最大空闲连接数,MaxIdleConnsPerHost设置了每个主机的最大空闲连接数。
  2. 处理请求队列
    • 可以使用Go的通道(channel)来实现请求队列。将需要发送的请求封装成结构体,然后通过通道发送给处理请求的协程。这样可以解耦请求的生成和处理过程。
  3. 控制并发数
    • 使用信号量(sync.Semaphore)或带缓冲的通道来控制并发数。例如,使用带缓冲的通道,通道的缓冲大小就代表了允许的最大并发数。当一个请求要处理时,先尝试向通道发送一个信号(占用一个并发槽位),处理完成后再从通道接收(释放一个并发槽位)。

关键代码示例

package main

import (
    "fmt"
    "net/http"
    "sync"
)

// RequestItem 封装请求
type RequestItem struct {
    url string
    // 可以添加其他请求相关的字段,如请求方法、请求头、请求体等
}

func main() {
    // 初始化请求队列
    requestQueue := make(chan RequestItem, 100)
    // 控制并发数的通道,这里设置最大并发数为10
    semaphore := make(chan struct{}, 10)
    var wg sync.WaitGroup

    // 创建http.Client并设置连接池
    transport := &http.Transport{
        MaxIdleConns:       100,
        MaxIdleConnsPerHost: 10,
    }
    client := &http.Client{Transport: transport}

    // 启动处理请求的协程
    for i := 0; i < cap(semaphore); i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for item := range requestQueue {
                semaphore <- struct{}{}
                resp, err := client.Get(item.url)
                if err != nil {
                    fmt.Printf("请求 %s 出错: %v\n", item.url, err)
                } else {
                    defer resp.Body.Close()
                    fmt.Printf("请求 %s 成功\n", item.url)
                }
                <-semaphore
            }
        }()
    }

    // 模拟添加请求到队列
    requests := []string{
        "http://example.com/api1",
        "http://example.com/api2",
        // 更多API端点
    }
    for _, url := range requests {
        requestQueue <- RequestItem{url: url}
    }
    close(requestQueue)

    wg.Wait()
}

在上述代码中:

  1. 连接复用:通过http.TransportMaxIdleConnsMaxIdleConnsPerHost设置连接池参数,实现连接复用。
  2. 请求队列:使用chan RequestItem作为请求队列,将请求封装在RequestItem结构体中发送到队列。
  3. 控制并发数:使用make(chan struct{}, 10)创建了一个带缓冲的通道semaphore,缓冲大小为10,以此来控制最大并发数为10。每个请求处理前先向通道发送信号,处理完成后再从通道接收信号,确保并发数不超过设定值。