Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Permintaan berbilang benang sedang berjalan dan tidak mendapat RPS tinggi

Permintaan berbilang benang sedang berjalan dan tidak mendapat RPS tinggi

WBOY
WBOYke hadapan
2024-02-09 16:48:10981semak imbas

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()
}

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()
}

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()
...

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,
}

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!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam