Permintaan berbilang benang sedang berjalan dan tidak mendapat RPS tinggi

WBOY
Lepaskan: 2024-02-09 16:48:10
ke hadapan
957 orang telah melayarinya

go 中的多线程请求并且没有获得高 RPS

editor php Xigua menyedari bahawa apabila menggunakan bahasa Go untuk membuat permintaan berbilang benang, kadangkala ia tidak mungkin untuk mendapatkan kelajuan permintaan sesaat (RPS) yang tinggi. Walaupun bahasa Go sangat baik dalam pemprosesan serentak, dalam beberapa kes, permintaan berbilang benang tidak begitu cekap. Ini mungkin disebabkan kependaman rangkaian, persaingan sumber, dsb. Dalam artikel ini, kami akan meneroka masalah ini dan menyediakan beberapa penyelesaian yang mungkin untuk meningkatkan RPS permintaan berbilang benang dalam bahasa Go.

Kandungan soalan

Saya cuba menulis klien berbilang benang untuk menguji pelayan saya. Apabila saya menggunakan 2 goroutine, semuanya baik-baik saja, saya mendapat 50k rps dan beban cpu saya normal, tetapi apabila saya mencipta lebih daripada 2 goroutine, rps turun kepada 3k tetapi beban cpu saya melebihi. Walaupun apabila saya menjalankan kod klien beberapa kali (seperti menjalankan kod yang sama pada 3 konsol pada masa yang sama) saya mendapat lebih rps seperti 80k rps.

Ini kod pelanggan saya

package main

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

func main() {
    requesturl := fmt.sprintf("http://localhost:%d/home", 3333)
    var wg sync.waitgroup
    wg.add(4)
    req, err := http.newrequest(http.methodget, requesturl, nil)
    if err != nil {
        fmt.printf("client: could not create request: %s\n", err)
        os.exit(1)
    }
    for i := 0; i < 4; i++ {
        go func() {
            defer wg.done()
            client := http.client{
                timeout: 30 * time.second,
            }
            for {
                client.do(req)
            }
        }()
    }
    wg.wait()
}
Salin selepas log masuk

Ini kod sebelah pelayan saya

package main

import (
    "errors"
    "fmt"
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
    "log"
    "net/http"
    "os"
    "sync"
)

// log handling
func openlogfile(path string) (*os.file, error) {
    logfile, err := os.openfile(path, os.o_wronly|os.o_append|os.o_create, 0644)
    if err != nil {
        return nil, err
    }
    return logfile, nil
}

// variables of counter in metric
var okstatuscounter = prometheus.newcounter(
    prometheus.counteropts{
        name: "ok_request_count",
        help: "number of 200",
    },
)

func listener(serverlog *log.logger) http.handlerfunc {
    return func(w http.responsewriter, r *http.request) {
        //metric 
        okstatuscounter.inc()
        
        w.writeheader(http.statusok)
    }
}

func main() {
    //metric
    prometheus.mustregister(okstatuscounter)

    //log handling
    filesimpleserverlog, err := openlogfile("simpleserver/simpleserverlog.log")
    if err != nil {
        log.fatal(err)
    }
    serverlog := log.new(filesimpleserverlog, "[simple server]", log.lstdflags|log.lshortfile|log.lmicroseconds)

    var wg sync.waitgroup
    wg.add(1)

    //server:
    go func() {
        defer wg.done()
        mux := http.newservemux()
        mux.handlefunc("/home", listener(serverlog))
        mux.handle("/metrics", promhttp.handler())
        server := http.server{
            addr:    fmt.sprintf(":%d", 3333),
            handler: mux,
        }
        if err := server.listenandserve(); err != nil {
            if !errors.is(err, http.errserverclosed) {
                serverlog.printf("error running http server: %s\n", err)
            }
        }
    }()
    wg.wait()
}
Salin selepas log masuk

Pada mulanya saya fikir go mungkin menggunakan satu port untuk semua sambungan pelanggan, tetapi apabila saya menyemaknya dengan netstat ia menggunakan berbilang port. Saya cuba mencari tetapi tidak menemui jawapan yang sesuai

Saya cuba sync.mutex:

var mu sync.Mutex
...
for i := 0; i < 1000; i++ {
        go func() {
            defer wg.Done()
            client := http.Client{
                //Timeout: 30 * time.Second,
            }
            for {
                mu.Lock()
                _, err := client.Do(req)
                if err != nil {
                    clientLog.Printf("client: error making http request: %s\n", err)
                    os.Exit(1)
                }
                mu.Unlock()
            }
        }()
    }
    wg.Wait()
...
Salin selepas log masuk

Dengan perubahan di atas, saya mendapat 13k rps dan beban cpu saya ok, tetapi ia tidak mencukupi

Penyelesaian

Memandangkan anda hanya menghantar permintaan kepada satu hos, nilai lalai pengangkutan http tidak akan berfungsi untuk awak. Adalah lebih baik untuk menetapkan parameter secara manual mengikut situasi anda:

t := http.DefaultTransport.(*http.Transport).Clone()
t.MaxIdleConns = 100
t.MaxConnsPerHost = 100
t.MaxIdleConnsPerHost = 100
    
httpClient = &http.Client{
  Timeout:   10 * time.Second,
  Transport: t,
}
Salin selepas log masuk

Untuk maklumat lanjut boleh baca di sini.

Atas ialah kandungan terperinci Permintaan berbilang benang sedang berjalan dan tidak mendapat RPS tinggi. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:stackoverflow.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!