Heim  >  Artikel  >  Backend-Entwicklung  >  Warum wird die Spanner-Abfrage mit ReadOnlyTransaction in Golang Goroutine allmählich langsamer?

Warum wird die Spanner-Abfrage mit ReadOnlyTransaction in Golang Goroutine allmählich langsamer?

WBOY
WBOYnach vorne
2024-02-08 21:00:121026Durchsuche

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

Frageninhalt

Ich versuche, etwa 10.000 Zeilen aus einer Tabelle abzufragen. Nach dem Ausprobieren beteiligt limit offset 的各种其他选项并且没有找到所需的成功之后,我尝试在每个 goroutine 中查询单行。思路是每行只需要 ~5ms 来查询和获取,但是一批 10k 会接管 20s.

Unten ist eine vereinfachte Version des Codes dargestellt:

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

Die Ergebnisse werden wie folgt verfolgt:

{"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"}

Startet gut und wie erwartet, aber die Abfragezeiten nehmen immer mehr zu.

MaxSessionsMinSessions 对于 spannerClient100 Man könnte sich also vorstellen, dass es nach 100 zu einer leichten Verlangsamung kommt, aber das ist nicht der Fall.

Bitte lesen Sie hier:

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

Nicht iterative Abfragen (ReadRowusw.) liefern mir die gleichen Ergebnisse.

Die Verwendung von tx := spannerClient.Single() außerhalb einer for-Schleife führt zu ähnlichen Ergebnissen.

Frage:

  1. Bedeutet das, dass die Goroutine trotz der Ausführung von spannerClient.Single() innerhalb der Goroutine immer noch versucht, dieselbe Sitzung/Transaktion zu verwenden?
  2. Wie kann der obige Inhalt geändert werden, um dieses Problem zu lösen?

Richtige Antwort


TLDR: Die standardmäßige maximale Sitzungspoolgröße beträgt 400, was bedeutet, dass Sie nie mehr als 400 Abfragen parallel ausführen können. Um diese Parallelität zu erreichen, müssen Sie die Größe des Sitzungspools erhöhen.

Zuallererst: Ich glaube nicht, dass das parallele Senden von 10.000 Abfragen, sodass jede Abfrage eine Zeile liest, nicht die effizienteste Lösung für Ihr Problem ist. Wenn Sie zum Filtern keine anderen Kriterien als die Mitarbeiter-IDs verwenden können und diese IDs überall verstreut sind, ist die Erstellung der Abfrage im Formular immer noch effizienter

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

Ein vollständiges Beispiel finden Sie in diesem Kommentar: https:///github.com/googleapis/google-cloud-go/issues/858#issuecomment-550982307

Zurück zu Ihrer konkreten Frage:

  1. Sie messen nicht wirklich die Zeit, die zum Ausführen der Abfrage benötigt wird. Das ist etwas verwirrend, aber die Zeile it := tx.Query(gCtx, stmt2) führt die Abfrage nicht aus, sondern bereitet sie lediglich auf die Ausführung vor. Wird ausgeführt, wenn row, err := it.Next() zum ersten Mal aufgerufen wird. Dies können Sie auch an den erfassten Ausführungszeiten erkennen. Die erste Anweisung scheint innerhalb von 30 Mikrosekunden ausgeführt zu werden, was unmöglich ist. it := tx.Query(gCtx, stmt2) 行确实执行查询,它只是准备执行查询。第一次调用 row, err := it.Next()
  2. Das bedeutet, dass etwas auf Ihrem Client Ihren Fortschritt einschränkt. In diesem Fall bin ich mir ziemlich sicher, dass es die maximale Größe Ihres Sitzungspools ist. Die standardmäßige maximale Sitzungspoolgröße beträgt 400. Dadurch können bis zu 400 Abfragen parallel ausgeführt werden. Die zunehmende Wartezeit, die Sie sehen, ist darauf zurückzuführen, dass die Goroutine in eine Warteschlange gestellt wird, in der sie darauf wartet, dass die Sitzung verfügbar wird. Goroutinen am Ende der Warteschlange warten länger.

Das obige ist der detaillierte Inhalt vonWarum wird die Spanner-Abfrage mit ReadOnlyTransaction in Golang Goroutine allmählich langsamer?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen