Rumah >pembangunan bahagian belakang >Golang >Mengapa pertanyaan Spanner menggunakan ReadOnlyTransaction dalam golang goroutine secara beransur-ansur menjadi lebih perlahan?

Mengapa pertanyaan Spanner menggunakan ReadOnlyTransaction dalam golang goroutine secara beransur-ansur menjadi lebih perlahan?

WBOY
WBOYke hadapan
2024-02-08 21:00:121074semak imbas

为什么在 golang goroutine 中使用 ReadOnlyTransaction 进行 Spanner 查询会逐渐变慢

Kandungan soalan

Saya cuba menanyakan kira-kira 10,000 baris daripada jadual. Selepas mencuba terlibat limit offset 的各种其他选项并且没有找到所需的成功之后,我尝试在每个 goroutine 中查询单行。思路是每行只需要 ~5ms 来查询和获取,但是一批 10k 会接管 20s.

Ditunjukkan di bawah ialah versi ringkas kod:

func queryEmp(IDs[]string, spannerClient *spanner.Client) (Employee,error){
query := "Select name from Employee Where id = @id"

    g, gCtx := errgroup.WithContext(ctx)
    for _, ID := range IDs {
        id := ID
        g.Go(func() error {
    
            tx := spannerClient.Single() 
            defer tx.Close()

            stmt2 := spanner.NewStatement(query)
            stmt2.Params = map[string]interface{}{
                "ID": id,
            }

            qstart := time.Now()
            it := tx.Query(gCtx, stmt2)
            defer it.Stop()
            logrus.Debugf("%s took %v \n", "query execution.", time.Since(qstart))

            for {
                row, err := it.Next()
                if err == iterator.Done {
                    break
                }
                if err != nil {
                    return err
                }

                var eID string
                if err := row.Column(0, &eID); err != nil {
                    return err
                }

            }

            return nil
        })
    }
    err = g.Wait()
}

Keputusan dikesan seperti berikut:

{"message":"query execution. took 39.677µs \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
{"message":"query execution. took 34.125µs \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
{"message":"query execution. took 26.634µs \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
{"message":"query execution. took 29.303µs \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
...
...
...
{"message":"query execution. took 188.749562ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
{"message":"query execution. took 276.424692ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
{"message":"query execution. took 188.62849ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
{"message":"query execution. took 217.067524ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
{"message":"query execution. took 276.949166ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
...
...
...
{"message":"query execution. took 454.64281ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
{"message":"query execution. took 452.0848ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
{"message":"query execution. took 525.748738ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
{"message":"query execution. took 454.704656ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
{"message":"query execution. took 455.4276ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"}
...
...
...
{"message":"query execution. took 6.767574136s \n","severity":"debug","time":"2023-11-03T20:52:00-04:00"}
{"message":"query execution. took 6.780578444s \n","severity":"debug","time":"2023-11-03T20:52:00-04:00"}
{"message":"query execution. took 6.785085491s \n","severity":"debug","time":"2023-11-03T20:52:00-04:00"}
{"message":"query execution. took 6.779527006s \n","severity":"debug","time":"2023-11-03T20:52:00-04:00"}

Bermula dengan baik dan seperti yang dijangkakan, tetapi masa pertanyaan terus meningkat.

MaxSessionsMinSessions 对于 spannerClient100 Jadi seseorang akan membayangkan ia mungkin melihat sedikit kelembapan selepas 100, tetapi itu tidak berlaku.

Sila baca di sini:

<code>
Sessions can execute only one transaction at a time. Standalone reads, writes, and queries use a transaction internally, and count toward the one transaction limit.
</code>

Pertanyaan tidak berulang (ReadRowdll) memberi saya hasil yang sama.

Menggunakan tx := spannerClient.Single() di luar gelung for akan memberikan hasil yang serupa.

Soalan:

  1. Adakah ini bermakna walaupun melaksanakan spannerClient.Single() di dalam goroutine, goroutine masih cuba menggunakan sesi/transaksi yang sama?
  2. Bagaimana untuk mengubah suai kandungan di atas untuk menyelesaikan masalah ini?

Jawapan betul


TLDR: Saiz kumpulan sesi maksimum lalai ialah 400, bermakna anda tidak boleh menjalankan lebih daripada 400 pertanyaan secara selari. Anda perlu meningkatkan saiz kumpulan sesi untuk mencapai keselarasan ini.

Pertama sekali: Saya tidak fikir menghantar 10,000 pertanyaan secara selari supaya setiap pertanyaan membaca satu baris bukanlah penyelesaian yang paling berkesan untuk masalah anda. Jika tiada apa-apa lagi yang boleh anda lakukan untuk menapis mengikut ID pekerja, dan ID tersebut tersebar di merata tempat, ia akan menjadi lebih cekap untuk membuat pertanyaan dalam bentuk

select * from employees where id in unnest(@ids)

Untuk contoh lengkap, lihat ulasan ini: https:///github.com/googleapis/google-cloud-go/issues/858#issuecomment-550982307

Kembali kepada soalan khusus anda:

  1. Anda sebenarnya tidak mengukur masa yang diperlukan untuk melaksanakan pertanyaan. Ini sedikit mengelirukan, tetapi baris it := tx.Query(gCtx, stmt2) it := tx.Query(gCtx, stmt2) 行确实执行查询,它只是准备执行查询。第一次调用 row, err := it.Next()tidak
  2. melaksanakan pertanyaan, ia hanya menyediakannya untuk dilaksanakan. Dilaksanakan apabila row, err := it.Next() dipanggil buat kali pertama. Anda juga boleh melihat ini dalam masa pelaksanaan yang direkodkan. Pernyataan pertama nampaknya dilaksanakan dalam masa 30 mikrosaat, yang mustahil.
  3. Ini bermakna bahawa sesuatu pada pelanggan anda mengehadkan kemajuan anda, dalam kes ini saya agak pasti saiz maksimum kumpulan sesi anda. Saiz kumpulan sesi maksimum lalai ialah 400. Ini bermakna sehingga 400 pertanyaan boleh dijalankan secara selari. Masa menunggu yang semakin meningkat yang anda lihat adalah kerana goroutine diletakkan dalam baris gilir menunggu menunggu sesi tersedia. Goroutine di penghujung baris gilir akan menunggu lebih lama.
🎜

Atas ialah kandungan terperinci Mengapa pertanyaan Spanner menggunakan ReadOnlyTransaction dalam golang goroutine secara beransur-ansur menjadi lebih perlahan?. 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