现象
现场的 ORG 服务使用了 ES 搜索,但是现场的搜索一直不能够正常工作。 现场情况如下:
- ES 版本为 5.5.1, 部署在机器 B 上,采用 Docker 方式部署。
- ORG 服务采用 go 语言开发,驱动是采用的 “gopkg.in/olivere/elastic.v5” 部署在机器A上,搜索数据一直返回空,在 ES 机器上用命令行直接搜索有结果数据。
- TES 服务采用 node.js 开发,也连接 ES ,能够正常工作。
- 机器 A 上 使用 curl es_addr 能够正常显示 ES 集群相关信息。
- ORG 服务于 ES 服务部署在同一台机器上时,可以正常工作。
简单定位和 ORG 使用的 ES 驱动有一定关系。
排查
用 go 语言编写了一个最基本版本的 es 连接测试:
1 | package main |
运行以上命令得到以下信息:
- 通过
elastic.v5
驱动连接 ES 有具体报错:“no Elasticsearch node available” - 通过 http 访问的访问仍然能够正常打印出来 ES 的提示信息
因此问题更加清晰定位到是 elastic.v5
驱动的工作方式与 ES 配合的过程中存在某些问题。通过网上搜索错误,找到问题相关联的 “v5 connect panic: no Elasticsearch node available”,经过与问题的情况分析,部署方式和访问方式上和我们的情况完全一致,因此问题的解决更近一步。更加详细的分析可以参见: Connection Problems 中的 “How to figure out connection problems?” 章节。
分析
当 sniffing 模式被启用(默认启用),Elastic 使用 Nodes Info API 查找群集中的所有节点。 找到这些节点后,它会定期更新内部连接列表。
现在发现的大多数连接问题,都是因为 Elastic 无法调用节点信息API 或无法访问到 Nodes Info API 提供的 IP:Port
组合地址 。 例如,部署在 Docker 容器内有时会返回内部 IP:Port
组合,这些内部 IP:Port
组合只能从Docker 容器中访问,而不能从 ES 集群外部访问; 这种情况下,您需要更改 Elasticsearch 的网络绑定以绑定到外部可访问的网络接口, 关于 ES 部署在 Docker 中相关情况,可以参见 https://github.com/olivere/elastic/wiki/Docker。
以下是 Nodes Info API 通常返回的内容以及 Elastic 用于查找 IP 的节点:集群节点的端口组合(较新版本稍微更改了返回值):
1 | $ curl -s -XGET 'http://127.0.0.1:9200/_nodes/http?pretty=1' |
1 | { |
可以看到 publish_address
字段包含节点的 IP:PORT
。 如果可以 curl 该此地址,则连接不应存在任何问题。
如果已经启用了 sniffing,但是仍然无法连接到 Elasticsearch,请确认您已将 http://
作为URL的一部分。 使用像 localhost:9200
这样的地址如果不能正常工作,则需要 http://localhost:9200
。
解决
Go ES 驱动解决
可以在 ES 初始化的时候,关闭 Sniffing ,设置如下。
1 | func main() { |
ES 配置解决
如果在 Docker 中运行 ES 单机或者集群,需要保证 ES 在 Nodes Info API 中返回的 publish_address
在容器外部能够可以访问。我们可以通过设置 network.publish_host
或 network.host
来解决。ES 中具体配置参见 http章节配置
network.publish_host
设置允许控制节点将在集群内发布的主机,以便其他节点能够连接到它。 当然,这不能是任何本地地址,默认情况下,它将是第一个非环回地址(如果可能)或本地地址。
network.host
设置是一个简单的设置,可以自动将network.bind_host
和network.publish_host
设置为相同的主机值。
例如以下方式:
1 | docker run -d \ |
扩展阅读:
- ES 在Docker 中各种网络情况下配置参见官方 Blog Docker Networking
- 如果采用 Docker-Compose 来使用 ES 可以参考 How to set network.publish_host for elasticsearch.yaml file using docker-compose.yml 和 bitnami/bitnami-docker-elasticsearch
- 另外也可以参考一下 Elasticsearch in docker container cluster
总结
- 在排查的过程中,ORG 服务虽然不能够正常连接 ES,但是在搜索的时候仍然返回了 200 和空结果,而没有提示连接 ES 报错,错误提示不友好导致了问题排查方向的误导,一直任务是索引建立和使用的问题;错误提示很重要!
- ES 默认工作在 sniffing 方式,而驱动库没有任何提示。此外驱动库在 search 使用的 BoolQuery 没有方法打印出来与 http curl 类似 json 方式的语句