#google-cloud-spanner
#google-облако-spanner
Вопрос:
Я получаю задержки около 50-100 мс для простых запросов в spanner (обновления или выбор по первичному ключу). Подключение к spanner из того же проекта / региона. Это ожидаемое поведение? Я ожидал гораздо меньших задержек для них.
Комментарии:
1. Не могли бы вы опубликовать пример запроса? Кроме того, каково время запроса в консоли Google.
Ответ №1:
Нет, задержка для простого выбора с использованием первичного ключа должна быть намного ниже.
Я провел быстрый тест на основе информации, предоставленной вами выше, используя следующую простую программу:
package main
import (
"context"
"fmt"
"math/rand"
"time"
"cloud.google.com/go/spanner"
"github.com/montanaflynn/stats"
"google.golang.org/api/iterator"
)
func main() {
fmt.Printf("Simple Spanner benchmarking...n")
source := rand.NewSource(time.Now().UnixNano())
rnd := rand.New(source)
client, err := spanner.NewClient(context.Background(), "projects/my-project/instances/my-instance/databases/my-database")
if err != nil {
fmt.Printf("Client creation failed: %v", err)
return
}
var times stats.Float64Data
for i := 0; i < 25; i {
id := rnd.Int63n(1000) 100000
statement := spanner.NewStatement("SELECT * FROM Singers WHERE SingerId=@id")
statement.Params["id"] = id
start := time.Now()
iter := client.Single().Query(context.Background(), statement)
for {
row, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
fmt.Printf("Query failure: %v", err)
break
}
var fullName string
row.ColumnByName("FullName", amp;fullName)
fmt.Printf("Singer name: %sn", fullName)
elapsed := time.Since(start)
fmt.Printf("Time: %vn", elapsed)
times = append(times, float64(elapsed.Milliseconds()))
}
iter.Stop()
}
median, _ := stats.Median(times)
avg, _ := stats.Mean(times)
p90, _ := stats.Percentile(times, 90)
fmt.Printf("Median: %vn", median)
fmt.Printf("P90: %vn", p90)
fmt.Printf("Avg: %vn", avg)
}
Приложение было выполнено на минимально возможной виртуальной машине Google Cloud Compute Engine, расположенной в том же регионе, что и экземпляр Spanner. Результаты были:
Simple Spanner benchmarking...
Singer name: FirstName LastName 100960
Time: 374.627846ms
Singer name: FirstName LastName 100865
Time: 4.102019ms
Singer name: FirstName LastName 100488
Time: 3.479059ms
...
Singer name: FirstName LastName 100542
Time: 3.986866ms
Singer name: FirstName LastName 100822
Time: 3.978838ms
Singer name: FirstName LastName 100235
Time: 4.511711ms
Singer name: FirstName LastName 100020
Time: 3.476673ms
Singer name: FirstName LastName 100234
Time: 3.191529ms
Singer name: FirstName LastName 100219
Time: 4.451639ms
Median: 3
P90: 4
Avg: 18.44
Таким образом, ваше время выполнения около 50-100 мс звучит как много. Обычное время выполнения в этом (простом) тестовом примере составляет около 3-4 мс для однорядного выбора (за исключением первого запроса, поскольку это также инициализирует резервный пул сеансов).
- Может ли быть так, что ваша таблица имеет первичный ключ, который использует монотонно возрастающее значение? Это может создать горячие точки в индексе поддержки первичного ключа.
- Может быть, вы закрываете и создаете нового клиента между каждым запросом? Это потребовало бы повторной инициализации пула сеансов для каждого нового запроса?
- Используете ли вы одноразовую транзакцию только для чтения для своих запросов? Или вы используете какой-то другой тип транзакции для чтения данных?
Не могли бы вы предоставить некоторые дополнительные сведения о том, как именно вы выполняете запрос (желательно с примером кода)?
- Вы используете клиентскую библиотеку? Если да, то какой? (Java, Node, Go, …?)
- Вы измеряете только самый первый запрос, который выполняете после запуска вашего приложения? Самый первый запрос будет выполняться медленнее, чем последующие запросы, поскольку клиентской библиотеке потребуется сначала создать сеанс, а затем выполнить запрос.
- Вы пишете, что подключаетесь из одного и того же проекта / региона. Означает ли это, что ваш клиентский код выполняется на виртуальной машине Google Cloud или аналогичной ей?
Комментарии:
1. Использование библиотеки golang. Измерение всех запросов (это долго работающее приложение / сервис). Да, он работает на старомодном вычислительном экземпляре.
2. Я получаю более точные данные об этом (более случайные). Похоже, когда я извлекаю жестко закодированный первичный ключ (который никогда не меняется), он должен быть кэширован, и в этом случае задержки колеблются около 20 мс. Это то, что люди обычно видят? Я меняю его на выбор случайных клавиш, чтобы увидеть эффекты без возможного кэширования.
3. Спасибо за подробный ответ! Я пытаюсь выделить хороший пример из рабочего приложения, немного позже опубликую здесь автономный пример. Чтобы ответить на дополнительные вопросы: Я пытался избежать ситуации с горячими точками, но позвольте мне получить конкретный запрос и структуру таблицы. Почти уверен, что этот клиент используется повторно.