go-elasticsearch/v8调用报错“read: connection reset by peer”
我在本地通过Docker部署了ElasticSearch,并使用ES的官方Golang SDK来调用ES,写入一些数据。
ES版本等相关信息:
- ES with Docker: V8.11.0
- SDK: go-elasticsearch/v8
新建客户端和插入的方法代码如下:
func NewClientV8(ctx context.Context) *elasticsearch.Client {
cert, err := ioutil.ReadFile("http_ca.crt")
if err != nil {
log.Fatalf("Failed to load certificate: %v", err)
}
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM(cert)
cfg := elasticsearch.Config{
Addresses: []string{
"https://localhost:9200",
},
Username: "elastic",
Password: "bghCDHWKJknLrkr+8ZMF",
Transport: &http.Transport{
MaxIdleConnsPerHost: 20,
TLSClientConfig: &tls.Config{
RootCAs: certPool,
},
},
}
es, err := elasticsearch.NewClient(cfg)
if err != nil {
log.Fatalf("Error creating the client: %s", err)
return es
}
res, err := es.Info()
if err != nil {
log.Fatalf("Error getting response: %s", err)
}
defer res.Body.Close()
log.Println(res)
return es
}
func (*ES8) Bulk(ctx context.Context, docs []BulkRequest) error {
bulkRequestBody := strings.Builder{}
for _, doc := range docs {
metaData := fmt.Sprintf(`{ "index" : { "_index" : "%s", "_id" : "%s" } }%s`, index, doc.Id, "\n")
docData, err := json.Marshal(doc.Doc)
if err != nil {
log.Printf("Error marshaling document: %v", err)
continue
}
bulkRequestBody.WriteString(metaData)
bulkRequestBody.Write(docData)
bulkRequestBody.WriteString("\n")
}
// Send the bulk request
req := esapi.BulkRequest{
Index: index,
Body: strings.NewReader(bulkRequestBody.String()),
Refresh: "true",
Pretty: true,
}
res, err := req.Do(context.Background(), es)
if err != nil {
log.Fatalf("Error performing bulk request: %s", err)
return err
}
defer res.Body.Close()
// if res.IsError() {
// log.Printf("Error[%s]: %s", res.Status(), res.String())
// } else {
// log.Println("Bulk insert successful", res.String())
// }
return nil
}
我写了一个循环,每次插入100条数据分批插入数据,总数据量50w条。
程序一开始运行良好,但当插入一些数据之后,程序报错:
Error performing bulk request: read tcp 127.0.0.1:50989->127.0.0.1:9200: read: connection reset by peer
问题定位
出现了这个错误,我第一反应就是连接数过多,那么可能是连接不复用。
我重启了ES集群,并且使用下面命令netstat -an | grep "127.0.0.1.9200" | wc -l来查看连接数量。
不出所料,连接数在程序运行的过程中一直增加:
我找了很多资料,包括更改ES集群的配置、修改client的最大连接数配置等,都没有解决问题。
我甚至还去go-elasticsearch的github上提了issue:github.com/elastic/go-…
解决问题
最终,我找到了一个类似问题的issue:github.com/elastic/go-…
在Golang的http内置库中,有这么一段话:
It is the caller's responsibility to close Body. The default HTTP client's Transport may not reuse HTTP/1.x "keep-alive" TCP connections if the Body is not read to completion and closed.
回顾我自己的代码,我没有读response的body,这可能是导致连接无法复用的原因。
我修改了代码,新的代码如下:
func (*ES8) Bulk(ctx context.Context, docs []BulkRequest) error {
bulkRequestBody := strings.Builder{}
for _, doc := range docs {
metaData := fmt.Sprintf(`{ "index" : { "_index" : "%s", "_id" : "%s" } }%s`, index, doc.Id, "\n")
docData, err := json.Marshal(doc.Doc)
if err != nil {
log.Printf("Error marshaling document: %v", err)
continue
}
bulkRequestBody.WriteString(metaData)
bulkRequestBody.Write(docData)
bulkRequestBody.WriteString("\n")
}
// Send the bulk request
req := esapi.BulkRequest{
Index: index,
Body: strings.NewReader(bulkRequestBody.String()),
Refresh: "true",
Pretty: true,
}
res, err := req.Do(context.Background(), es)
if err != nil {
log.Fatalf("Error performing bulk request: %s", err)
return err
}
defer res.Body.Close()
res.String() // 新加的
}
再重新跑程序,问题解决!连接数维持在一个很低的数量。
写在最后
如果不需要用到http的response body,建议使用如下的写法:
io.Copy(ioutil.Discard, resp.Body)