Golang中读写Cloud Firestore时遇到高延迟(>500ms)问题如何解决
Golang中读写Cloud Firestore时遇到高延迟(>500ms)问题如何解决 我的 Firestore 集合包含少于 100 个文档,我正在使用 firestore-go-SDK 来建立连接。以下是我用来查询 Firestore 的代码。
func connectFirestore() {
ctx := context.Background()
// 设置您的 Google Cloud Platform 项目 ID。
projectID := <Project-ID>
client, err := firestore.NewClient(ctx, projectID)
if err != nil {
log.Println("Failed to create client: " + err.Error())
}
defer client.Close()
startTime := time.Now()
iter := client.Collection("User").Documents(ctx)
for {
_, err := iter.Next()
if err == iterator.Done {
break
} else if err != nil {
log.Println("Error in iterator ", err)
break
}
}
endTime := time.Now()
log.Println("Latency of DB call ", endTime.Sub(startTime))
}
当我尝试使用 Node.js 应用程序访问同一个集合时,我得到的延迟小于 10 毫秒。NodeJS 代码如下:
async function firebaseGetData() {
const db = new Firestore({
projectId: <Project-ID>,
keyFilename: <Project-Key-File>,
});
firebaseGetData(db)
var startTime = Date.now()
const snapshot = await db.collection('User').get();
var startTime = Date.now()
snapshot.forEach((doc) => {
console.log(doc.id, '=>', doc.data());
var endTime = Date.now()
var latency = endTime - startTime
console.log("Latency " + latency)
});
}
更多关于Golang中读写Cloud Firestore时遇到高延迟(>500ms)问题如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang中读写Cloud Firestore时遇到高延迟(>500ms)问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Golang中处理Firestore高延迟问题,通常与连接池、上下文配置和批量获取方式有关。以下是优化方案:
func connectFirestoreOptimized() {
// 使用带超时的上下文,避免无限期等待
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
projectID := <Project-ID>
// 配置客户端选项,启用连接池
client, err := firestore.NewClient(ctx, projectID, option.WithGRPCConnectionPool(10))
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer client.Close()
startTime := time.Now()
// 使用GetAll一次性获取所有文档,而不是迭代器
docs, err := client.Collection("User").Documents(ctx).GetAll()
if err != nil {
log.Fatalf("Failed to get documents: %v", err)
}
endTime := time.Now()
log.Printf("Latency of DB call: %v, Documents fetched: %d",
endTime.Sub(startTime), len(docs))
}
// 另一种优化方案:使用带重试的查询
func connectFirestoreWithRetry() {
ctx := context.Background()
projectID := <Project-ID>
// 配置重试策略
retryPolicy := []gax.CallOption{
gax.WithRetry(func() gax.Retryer {
return gax.OnCodes([]codes.Code{
codes.DeadlineExceeded,
codes.Unavailable,
}, gax.Backoff{
Initial: 100 * time.Millisecond,
Max: 2000 * time.Millisecond,
Multiplier: 1.5,
})
}),
}
client, err := firestore.NewClient(ctx, projectID,
option.WithGRPCDialOption(grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(1024*1024*5))),
)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer client.Close()
startTime := time.Now()
// 使用带重试的查询
iter := client.Collection("User").Documents(ctx)
iter = firestore.NewDocumentIterator(iter, retryPolicy...)
var count int
for {
_, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Printf("Error in iterator: %v", err)
break
}
count++
}
endTime := time.Now()
log.Printf("Latency with retry: %v, Documents: %d",
endTime.Sub(startTime), count)
}
// 使用批量读取优化小数据集
func batchReadFirestore() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
client, err := firestore.NewClient(ctx, <Project-ID>)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer client.Close()
startTime := time.Now()
// 预取所有文档ID(如果已知)
// 然后使用批量读取
collectionRef := client.Collection("User")
// 如果文档ID已知,可以直接批量获取
// docRefs := []*firestore.DocumentRef{...}
// docs, err := client.GetAll(ctx, docRefs)
// 对于未知文档,使用查询优化
query := collectionRef.Limit(100).OrderBy(firestore.DocumentID)
docs, err := query.Documents(ctx).GetAll()
if err != nil {
log.Fatalf("Failed to batch read: %v", err)
}
endTime := time.Now()
log.Printf("Batch read latency: %v, Documents: %d",
endTime.Sub(startTime), len(docs))
}
关键优化点:
- 使用
WithTimeout上下文避免无限等待 - 配置
WithGRPCConnectionPool启用连接池 - 使用
GetAll()替代迭代器减少RPC调用次数 - 对于小数据集,一次性获取比迭代更高效
- 考虑添加重试机制处理临时网络问题
Node.js SDK可能默认启用了某些优化,而Go SDK需要显式配置。

