Elasticsearch 在贝壳搜索的部署实践
1. 引言
Elasticsearch(简称 ES) 是一个基于 Lucene 的搜索引擎,使用 java 语言进行开发,RESTful web 接口进行交互,不同语言很容易开箱即用。同时 ES 完整生态中包含了 elasticsearch、logstash、kibana(3 个组合简称 ELK)、Beats、APM 等多个组件。ES 的简单快捷部署、成熟的生态、稳定的服务为搜索引擎与日志分析带来了极大的便利。在贝壳搜索架构的技术迭代中,也从 Solr Cloud 迁移到了 ES 上。
2.Elasitcsearch 基本概念
在介绍安装与部署之前先了解一下 ES 的基本概念。
-
Cluster(集群)
-
集群是由一个或者多个 node 组成,进行跨节点的数据存储于查询功能。
-
Node(节点)
-
是集群组成部分,每个节点都可提供对集群的查询和搜索功能。
-
每个节点由唯一的名字进行标识,默认情况下使用 UUID,node 通过集群名称与集群地址加入集群。
-
node 可扮演 master、data、ingest、tribe 等不同的角色,不同的角色可以同时存在。例如一个 node 节点作为 master 角色的同时也可以为 data 角色。
-
Index(索引)
-
是文本集合,类似与 mysql 中的表。
-
存在 mapping 对索引字段结构、查询分词类型、写入分词类型等属性进行定义。
-
通过 settings 对索引进行备份、分片、最大查询数目、分词器、refresh 等进行设置。
-
Document(文本)
-
是集群中的最基本的存储信息,每个 document 存在唯一的 ID。
-
每个文本以 json 格式进行存储。
-
Shard(分片)
-
每个 index 由多个 shard 组成,每个 shard 是一个单独的 Lucene 索引,用来存储真正的文本数据,每个 shard 最多存储 2,147,483,519(Integer.MAX_VALUE - 128) 个 document。
-
查询与写入的时候可通过 routing 字段进行路由到不同的分片上。
-
replica(备份)
-
每个 shard 会存在主分片与备份分片,为保证高可用,同一个 shard 无论主备分片,不会存储在同一个 node 节点上。
3.Elasticsearch 部署实践
安装部署一个完整的高可用集群主要有以下几个步骤。
-
官方下载、解压
-
修改配置
-
加密传输
-
数据备份
-
集群监控
-
性能测试
1. 官方下载
当前最新版本 6.5,官方下载地址见 [1],下载后有 30 天试用版。试用版中支持账号密码、报警、Machine Learning、以及最新扩集群备份等特性。试用期结束后,转为基础版,影响较大的是账号密码验证、报警等功能不再支持。
2. 修改配置
修改配置主要有三部分配置:linux 系统配置、elasticsearch.yml 配置、jvm.options 配置。
2.1 修改 linux 配置 (需要 root 权限)
- 修改 linux 服务器文件句柄打开数目限制。
通过使用命令 ulimit-n65536
或者修改 /etc/security/limits.conf
文件,在文件中添加 user-nofile65536
来修改操作系统对文件句柄的限制。
- 调高线程数目限制。
ES 中使用的线程池为不同的操作,高并发下可能需要创建大量的线程,因此官方建议至少调高到 4096。通过修改 /etc/security/limits.conf
文件,在文件中添加 user-nproc4096
。
- 修改虚拟内存限制。
ES 默认使用 mmapfs 目录来存储其索引。mmap 计数的默认操作系统限制可能太低,这可能导致内存不足异常,在 /etc/sysctl.conf 文件,添加 vm.max_map_count=262144
,并执行 sysctl-p
使配置生效。
- 禁用文件系统缓存 swap。
因为这可能使得 JVM 的堆甚至正在执行的文件被交换到磁盘上,通过 sudo swapoff-a
命令进行关闭交互区。或者在 /etc/sysctl.conf
文件,添加 vm.swappiness=1
, 减少内核交换的倾向,同时仍然允许在紧急条件下使用系统交换。
包含但不限于以上 linux 配置修改,修改之后,ES 即可以成功启动。
2.2 修改 elasticsearch.yml 文件
修改位于下载目录中 config 下的 elasticsearch.yml 文件,以下配置文件与生产环境配置文件有出入,附带注释,供参考。
1. `# ---------------------------------- Cluster -----------------------------------`
2. `#`
3. `# Use a descriptive name for your cluster:`
4. `# 集群名称`
5. `cluster.name: cluster-test`
6. `# ------------------------------------ Node ------------------------------------`
7. `# Use a descriptive name for the node:`
8. `# 节点名称`
9. `node.name: node-name`
10. `# 为该节点设置角色,如上介绍,一个节点可同时为多个角色,如果都为false,则为协调节点`
11. `node.master: true`
12. `node.data: true`
13. `node.ingest: false`
14. `# ----------------------------------- Paths ------------------------------------`
15. `#`
16. `# Path to directory where to store the data (separate multiple locations by comma):`
17. `# 数据存储路径`
18. `path.data: /home/work/data/elasticsearch/data`
19. `#`
20. `# Path to log files:`
21. `# 日志存储路径,包含执行日志与慢查询等日志,慢查询可通过修改log4j2.properties文件来设置`
22. `path.logs: /home/work/data/elasticsearch/logs`
23. `#`
24. `# ----------------------------------- Memory -----------------------------------`
25. `#`
26. `# Lock the memory on startup:`
27. `#启动的时候是否 锁定内存与弃用系统过滤器`
28. `bootstrap.memory_lock: true`
29. `bootstrap.system_call_filter: false`
30. `#`
31. `#`
32. `# ---------------------------------- Network -----------------------------------`
33. `#`
34. `# Set the bind address to a specific IP (IPv4 or IPv6):`
35. `#发布地址`
36. `network.host: 127.0.0.1`
37. `#`
38. `# Set a custom port for HTTP:`
39. `#`
40. `#jmxport:7300`
41. `提供的http端口`
42. `http.port: 8300`
43. `用来不同Node节点之间进行tcp交互的端口`
44. `transport:`
45. ` tcp:`
46. ` port: 8309`
47. ` compress: true`
48. ` connect_timeout: 30s`
50. `http.cors.enabled: true`
51. `http.cors.allow-origin: "*"`
52. `http.cors.allow-headers: Authorization,Content-Type`
53. `# 用到docker的时候,因为dockerIP与宿主机IP不同,端口也可能不同,因此需要指定发布地址与端口`
54. `http.publish_host: 10.26.9.44`
55. `http.publish_port: 8309`
56. `#`
57. `# For more information, consult the network module documentation.`
58. `#`
59. `# --------------------------------- Discovery ----------------------------------`
60. `#`
61. `# Pass an initial list of hosts to perform discovery when new node is started:`
62. `# The default list of hosts is ["127.0.0.1", "[::1]"]`
63. `# 服务发现所配置的node节点`
64. `discovery.zen.ping.unicast.hosts: ["192.168.0.1:9201","192.168.0.2:9201","192.168.0.3:9201"]`
65. `#℡`
66. `# Prevent the "split brain" by configuring the majority of nodes (total number of master-eligible nodes / 2 + 1):`
67. `# 至少2个节点存活`
68. `discovery.zen.minimum_master_nodes: 2`
70. `#ping 选主节点超时`
71. `discovery.zen.ping_timeout: 5s`
72. `#ping 其它节点的超时时间`
73. `discovery.zen.fd.ping_timeout: 30s`
74. `discovery.zen.fd.ping_retries: 6`
75. `discovery.zen.fd.ping_interval: 10s`
76. `#如果没有主节点 阻塞写操作`
77. `discovery.zen.no_master_block: write`
78. `#`
79. `# For more information, consult the zen discovery module documentation.`
81. `#增加查询与写入的队列长度`
82. `thread_pool:`
83. ` search:`
84. ` queue_size: 2048`
85. ` index:`
86. ` queue_size: 1024`
87. `# ---------------------------------- Various -----------------------------------`
88. `#`
89. `# Require explicit names when deleting indices:`
90. `#是否可以自动创建索引以及模糊匹配进行删除修改等操作,如果需要打开则设置为true`
91. `action.destructive_requires_name: false`
92. `+.*,-*意思是可以自动创建以 .开头的索引`
93. `action.auto_create_index: +.*,-*`
95. `# 最大限制bool查询的条数`
96. `indices.query.bool.max_clause_count: 4096`
98. `相同shard,不能分布在同一个IP机器上,如果一台机器上部署多个节点,使用该配置增加安全性`
99. `cluster:`
100. ` routing:`
101. ` allocation:`
102. ` same_shard.host: true`
103. `# ---------------------------------- x-pack ----------------------------------`
104. `# x-pack相关配置以及机密连接证书配置`
105. `# 打开账号密码认证,6.X之后需要使用加密传输才能进行账号密码认证`
106. `# 创建CA证书`
107. `xpack.security.enabled: true`
108. `xpack.security.transport.ssl.enabled: true`
109. `xpack.ssl.verification_mode: certificate`
110. `xpack.security.transport.ssl.verification_mode: certificate`
111. `xpack.security.transport.ssl.keystore.path: certs/elastic-certificates.p12`
112. `xpack.security.transport.ssl.truststore.path: certs/elastic-certificates.p12`
113. `xpack.ml.enabled: false`
114. `node.ml: false`
115. `xpack.security.audit.enabled: true`
116. `xpack.monitoring.exporters.my_local:`
117. ` type: local`
118. ` use_ingest: false`
2.3 修改文件 jvm.options
ES 使用 java 语言开发,那不可避免的就是使用了 JVM。该文件在下载目录的 config 下,包含了 ES 的 JVM 配置,介绍以下几个关键参数与调优建议。
- -Xms 与 -Xmx设置 JVM 堆大小,建议设置小于 32G,并且不要超过服务器内存大小 50%。
如果 JVM 堆小于 32 GB,采用一个内存对象指针压缩技术,这可以大大降低内存的使用:每个指针 4 字节而不是 8 字节。Lucene 能很好利用文件系统的缓存,它是通过系统内核管理的。如果没有足够的文件系统缓存空间,性能会受到影响。 此外,专用于堆的内存越多意味着其他所有使用 doc values 的字段内存越少。
- -XX:+UseG1GC
建议使用使用 G1 收集器。-XX:MaxGCPauseMillis=200、-XX:G1HeapRegionSize=32M、-XX:InitiatingHeapOccupancyPercent=70 等配置;具体参数含义可见 oracle 官网 [2] 介绍。对于搜索引擎来说,秒级别的 stop the world 是不可容忍的,通过配置最长暂停时间设置目标值 200ms,来减少回收停顿时间。
- -XX:+HeapDumpOnOutOfMemoryError
当 ES 发生 OOM 异常的时候, 可以保存堆内存数据到设置的固定目录,可用来分析 ES 节点异常原因。
其他一些常规 JVM 配置,可根据配置文件中介绍修改,不再在这里介绍。
至此,修改完以上介绍的配置之后,可直接启动了。启动后,白金版功能特性有一个月的试用期。
3. 加密传输
ES 从 6.0 开始,如果需要使用 X-pack 安全功能,要求 SSL/TLS 加密传输。通过以下步骤进行加密传入:
- xpack.security.enabled 设置为 true。
刚下载的使用的是试用版的 license,则默认的该值为 false,需要在 elasticsearch.yml 配置文件中设置为 true。
- 为集群生成安全证书。
使用 elasticsearch-certutil ca
命令,生成一个默认名称为 elastic-stack-ca.p12
的文件,在生成改文件的时候,会提示输入一个保护该证书的密码。构建集群则需要将该证书拷贝到其他机器上
- 为集群中的每个节点生成私钥、安全证书。
使用 bin/elasticsearch-certutil cert--ca elastic-stack-ca.p12
命令生成一个默认名称为 elastic-certificates.p12
文件,包含了节点证书、节点秘钥,CA 证书。如果想根据每个节点 hostname 查实, bin/elasticsearch-certutil cert
可通过使用 –name,–dns,–ip 等参数生成不同的证书。如果不使用,则可共用相同证书,直接将该文件拷贝到其他机器上。在生成该文件的时候,同时会输入一个保护该证书的密码。拷贝到其他集群上使用该证书的时候,需要输入该密码
- 增加证书相关配置
1. ` xpack.security.enabled: true //开启安全认证`
2. ` xpack.security.transport.ssl.enabled: true //使用加密传输`
3. ` xpack.ssl.verification_mode: certificate //只通过证书认证,如果有需要,可更加严格的进行机器认证`
4. ` xpack.security.transport.ssl.verification_mode: certificate`
5. ` xpack.security.transport.ssl.keystore.path: certs/elastic-certificates.p12 //指定证书所在路径`
6. ` xpack.security.transport.ssl.truststore.path: certs/elastic-certificates.p12`
- 添加证书到秘钥库
使用 bin/elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password
与 bin/elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password
命令,将秘钥添加到 ES 的秘钥库中
4. 数据备份
为了增加集群的稳定性与数据安全性,每天对索引数据进行快照备份。现在 ES 提供了 S3、Hadoop、谷歌云等多种备份到共享存储上的插件,由于公司内部大数据集群比较完善,因此采用将快照数据备份到 HDFS 上。
4.1Hadoop HDFS 插件安装
使用 bin/elasticsearch-plugin install repository-hdfs
命令安装该插件
4.2 连接 Hadoop 集群
为每个 ES 节点安装玩插件之后,需要为节点所在的机器确认能与 Hadoop 客户端进行连接。如果集群中一个节点在启动的时候,未与 Hadoop 连接通,则需要将该节点移除,或者重启该节点。公司内部 Hadoop 使用了 kerberos 作为安全认证,需要使用 keytab,获取到 keytab 之后,在 config 目录下创建 repository-hdfs 目录,将 keytab 名称改为 krb5.keytab,然后使用 keytab 验证是否能连接通 Hadoop 集群
4.3 配置仓库
与 Hadoop 联通后,创建仓库。在创建仓库的时候,应该执行在 HDFS 下的路径,快照数据存储在该路径下。同时也应该对写入与恢复速度进行限制,防止在进行快照备份与恢复的情况下,将网络 IO 打满,影响正常业务的使用。
1. `PUT _snapshot/hdfs_repository`
2. `{`
3. ` "type": "hdfs",`
4. ` "settings": {`
5. ` "uri": "hdfs://nn-cluster",`
6. ` "path": "/user/search/elasticsearch/repositories"`
7. ` "compress":"true",`
8. ` "max_restore_bytes_per_sec":"300mb",`
9. ` "max_snapshot_bytes_per_sec":"100mb", `
10. ` "security.principal": "search/_HOST@HADOOP.COM",`
11. ` }`
12. `}`
4.4 将集群上的数据,选择性的备份
在备份集群上数据的时候,可能会进行选择性的备份数据,可通过模糊匹配的方式进行索引的批量选取
1. put _snapshot/hdfs_repository/snapshot_1
2. `{`
3. ` "indices":"+白名单索引,-黑名单索引"`
4. `}`
4.5 从集群上恢复数据
可以选择性的从仓库中恢复索引,如果未指定,则将该快照下的所有索引恢复到当前集群中。
POST _snapshot/仓库名称/快照名称/_restore
{
"indices":"索引名称"
}
4.6 意义
通过每天在业务低峰期将 ES 集群中的重要索引数据定时备份到 HDFS 上,可以增加数据的安全性,如果多个集群共用相同的 HDFS 目录,则可进行跨集群恢复。例如将 A 集群中的数据快照备份到仓库中,B 集群同样可以使用该快照,恢复到 B 集群中。当一个集群出现故障的时候,可快速在另一个集群中,将数据恢复到备份的时间点。再结合我们引入 docker 部署 ES 集群,可分钟级部署一个新集群,使用快照恢复数据。在一个集群完全不可用的情况下,分钟级就可重建一个相同的集群提供服务。
同时如果有数据回溯需求或者开发、测试、线上等不同环境跨集群拷贝索引等需求,也可使用快照进行拷贝。
5. 集群监控
5.1 性能监控
性能监控包含主要的三大资源:磁盘、CPU、内存
5.1.1 通过 kibana 监控
安装 kibana,安装后,每个 Node 节点的 CPU、内存、QPS、查询队列、segment 数目等信息都可在界面中看到。
如下图所示
5.1.2 通过 grafana 监控报警
kibana 虽然对每个节点都有详细的监控,但是无法在一个界面中展现出整个集群的状态,而且 kibana 的报警机制并不完善。通过 grafana 读取 ES 中内置索引 .monitoring-es-6-*
数据,索引中包含了对整个集群的监控信息。可对整个集群甚至多个集群的状态进行监控与报警。在 grafana 中配置阈值,超过阈值时候讲报警信息发送到指定 API 进行微信、短信、邮件等报警处理。
5.2 慢查询监控
对搜索引擎来说,查询所花费的时间是至关重要的,因此对于每个索引可设置慢查询阈值,目前线上设置的为 100ms,超过 100ms 时候会打印出所有的慢查询请求,随着集群 cluster 数目与节点 node 数目增多,对于慢查询的监控也是非常有必要的。通过使用 rsyslog+kafka+logstash+Elasticsearch+Grafana 对慢查询日志进行统计收集后进行监控报警
至此,一个完整的高可用集群搭建完毕!!!
6. 性能测试
集群搭建好,选择多少 Node 节点合适呢,不同的 Node 扮演什么角色呢。通过对搭建好的 ES 集群进行压力测试,来根据业务规模,预估 ES 集群。因为 ES 检索会存在缓存,所以不适合使用 apacheAB 进行压力测试,需要模拟线上真实请求进行测试。以下压测为线上一个集群部署服务之前进行的测试,与线上使用的多个集群中可能存在出入供参考:
6.1 集群规模
ES 集群: 3 台 master+6 台 data
index 索引: 500 万左右 Document,1 个 shard,5 个 replica
客户端: 使用 6 台直接连接 ES 的搜索客户端
6.2 压力测试
复制贝壳找房线上搜索请求,结论如下:
请求总数 | 408 错误 | 错误率 | QPS | 响应时间 |
---|---|---|---|---|
1200000 次 | 60 条 | 0.005% | 5402.36 | 18.21ms |
成功率统计速率监控
6.3 小结
对集群进行更高压力测试,超时错误增多,响应时间也同比上升。为保证搜索时效性,并且 20ms 以内将数据返回与集群的稳定性,因此选择了资源与效果的权衡,使用当前 3+6 节点提供 5000QPS 线上搜索。当然不同的集群也要根据应用场景的不同,进行集群规模与参数的一些调整,例如日志集群多用于写可适当调整写入队列等参数。
在线上使用的时候,客户端可以使用 sniffer[3] 与集群中每个节点获得连接,采用轮询的方式与集群进行数据交互,既可以防止配置中只连接的某几个节点而导致压力过大,又可以动态的添加节点后直接与新增节点获得连接。
4. 高可用集群架构
4.1 跨机房部署
为了保证数据的安全性与集群容错性,采用冷备跨集群部署。通过 index 模块,双写到不同机房的 ES 集群,保持主备集群都可用,对外提供搜索服务,正常情况下,同一机房读取模块使用当前机房的集群提供服务,一旦当前机房网络出现问题,则降级切换到远程其他机房。有跨机房备份之后,大大提高了集群的安全性与可用性。
4.2 业务隔离
虽然一个 ES 集群能够很容的动态扩展,但是大量业务使用同一个集群带来的风险是比较高的,因此建议采用多集群部署,进行业务隔离,避免业务之间的相互干扰,提高稳定性。
4.3 容器化部署
使用 Docker 容器化部署 ES 节点,既可充分利用机器资源,也进行 CPU、内存、磁盘、网络等资源隔离,避免不同集群之间相互干扰。
5. 总结
elasticsearch 是一个快速迭代的开源组件,迭代更新非常迅速,很方便用于搜索引擎和日志分析。本文主要介绍了一个高可用集群完整的安装部署实践,在使用的过程中如何对集群进行配置、监控、测试、数据备份,以及最后介绍我们的高可用架构,使用 docker 容器支持多个机房进行主备,K8s 编排快速创建集群。希望本文对于计划使用 Elasticsearch 的维护者可以带来一些有用的信息。
6. 参考文献
[1]. https://www.elastic.co/downloads/elasticsearch
[2]. https://www.oracle.com/technetwork/cn/articles/java/g1gc-1984535-zhs.html
[3]. https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/sniffer.html
时间:2019-03-10 19:32 来源: 转发量:次
声明:本站部分作品是由网友自主投稿和发布、编辑整理上传,对此类作品本站仅提供交流平台,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,不为其版权负责。如果您发现网站上有侵犯您的知识产权的作品,请与我们取得联系,我们会及时修改或删除。
相关文章:
相关推荐:
网友评论: