《Elastic Stack 实战手册》——四、应用实践——4.3 性能优化场景——4.3.2.Elasticsearch 开发人员最佳实践指南(1): https://developer.aliyun.com/article/1225224spm=a2c6h.13148508.setting.14.438f4f0e18NXNE
查询方式(Querying)
下面我收集了一些技巧,你可以在 Elasticsearch 查询时使用它们。
Elasticseach 里面多线程修改如何保证数据准确性?
1、用如下两个参数校验冲突
UT products/_doc/1?if_seq_no=1&if_primary_term=1 { "title":"iphone", "count":100 }
2、用 version 避免冲突
PUT products/_doc/1?version=30000&version_type=external { "title":"iphone", "count":100 }
尝试分割复杂的查询,并行执行提升性能
如果你同时具有过滤器和聚合组件的复杂查询,则在大多数情况下,可以将它们拆分为多个查
询并并行执行它们可以提高查询性能。
也就是说,在第一个查询中,仅使用过滤器获取匹配,然后在第二个查询中,仅获取聚合结果
而无需再获取检索结果,即 size: 0。
了解你的数字类型,防止被优化导致精度损失
许多 JSON 解析器可以进行各种优化,以提供有效的读/写性能。但可能造成了精度的损失,
所以在选型 Jackson json 解析器时:优先使用 BigDecimal 和 BigInteger。
不要使用 Elasticsearch Transport / Node 客户端
TransportClient 可以支持 2.X,5.X 版本,TransportClient 将会在 Elasticsearch 7.X 版本弃
用并在 8.X 版本中完成删除。
官方推荐使用 Java High Level REST Client,它使用 HTTP 请求而不是 Java 序列化请求。
为了安全起见,坚持使用 HTTP 上的 JSON 格式,而不使用 SMILE (二进制格式)。
使用官方的 Elasticsearch High-level REST 客户端
非官方客户端一般更新太慢,几乎无法跟上 Elasticsearch 新版本的特性,如:Jest 客户端近
一年几乎没有更新,只支持到 6.X 版本。
相比之下,官方 REST 客户端仍然是你相对最好的选择。
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/index.html
不要使用 HTTP 缓存来缓存 Elasticsearch 响应结果
由于便利性和低进入门槛,许多人陷入了将 HTTP 缓存(例如 Varnish http://varnish-cache.
org/)置于 Elasticsearch 集群前面的陷阱。使用 HTTP 缓存缺点如下:
在生产环境中使用 Elasticsearch 时,由于各种原因如:弹性扩展、测试和线上环境分离、零
停机升级等,你很有可能最终会拥有多个集群。
1)一旦为每个集群提供专用的 HTTP 缓存,99%的缓存内容是重复的。
2)如果你决定对所有集群使用单个 HTTP 缓存,那么很难以编程方式配置 HTTP 缓存以适应
不断变化的集群状态的需求。
·如何传达集群负载以使缓存平衡流量?
· 如何配置计划内或手动停机时间?
·在维护时段期间,如何使缓存逐渐从一个集群迁移到另一个集群?
这些都是亟待考虑的问题。如上所述,HTTP 缓存很难以编程方式进行实现。当你需要手动删
除一个或多个条目时,它并不总是像 DELETE FROM cache WHERE keys IN (...) 查询那样容
易。还得通过手动实现。
铭毅提示:这一条我实际没有用过,有用过的童鞋可以留言讨论。
使用基于 _doc 排序的 slice scroll 遍历数据
Scrolls 是 Elasticsearch 提供的一种遍历工具,用来扫描整个数据集,以获取大量甚至全量数
据。它在功能上及内部实现上,与 RDBMS 游标非常相似。但是,大多数人在第一次尝试中都没
有用正确。以下是一些基本知识:
· 如果你接触到 scrolls,你可能正在读取大量数据。slicing 很可能会帮助你显著提高读取性
能。
· 使用 _doc 进行排序,读取速度就会提高 20%+,而无需进行其他任何更改。( _doc 是
一个伪字段)
· scrollId 调用之后会有变化。因此,请确保你始终使用最新检索的滚动 scrollId。
· 在 Reindex 的时候使用 slicing 也能提升索引数据迁移效率。
单文档检索 优先使用 GET /index/type/{id} 而非 POST /index/_search
Elasticsearch 使用不同的线程池来处理 GET /index/type/{id}和 POST /index/_search 查
询。
使用 POST /index/_search 与有效载荷 {query: {"match": {"_id": "123"}}}(或类似的东西)
占据搜索专用线程池。
在高负载下,这将同时降低搜索和单个文档的获取性能。
所以,单文档坚持使用:GET /index/type/{id}。
使用 size: 0 和 includes/ excludes 限定字段返回
Elasticsearch 在添加 size: 0 子句前后会带来显著的性能差异。
除非业务需要,才返回必要字段,无需返回的字段通过 includes 和 excludes 控制。
提前做好压力测试,了解系统支持的上限
分享我的个人最佳实践:
·使用应用程序的性能基准( performance benchmarks)测试来估计应用程序能提供支持的
性能负载上限。如基于 esrally 测试。
·避免将线程池与无限制的任务队列一起使用。队列的过度增长会对内存增加压力。
·如果你的应用程序是借助第三方引擎中转或写入数据(例如,从 kafka 队列到 Elasticsear-
ch 集群写入数据),请确保你的生产者对消费者的压力做出反应。也就是说,如果消费者
延迟开始增加,则最好开始降低生产者的速度。
在查询中提供明确的超时
几乎所有的 Elasticsearch API 都允许用户指定超时。
找出并摆脱耗时长的操作,节省相关资源,建立稳定的服务,这将对你的应用程序和 Elastics-
earch 集群都有帮助。
不要使用注入变量的 JSON 模板
永远不要这样做:
{ "query": { "bool": { "filter": [ { "term": { "username": { "value": {{username}} } } }, { "term": { "password": { "password": {{password}} } } }, ] } } }
防止 SQL 注入,只要有人通过恶意 username 和 password 输入,将暴露你的整个数据集,
这只是时间问题。
我建议使用两种安全的方法来生成动态查询:
·使用 Elasticsearch 官方客户端提供的查询模型。(这在 Java 上效果很好。)
· 使用 JSON 库(例如 Jackson)构建 JSON 树并将其序列化为 JSON。
《Elastic Stack 实战手册》——四、应用实践——4.3 性能优化场景——4.3.2.Elasticsearch 开发人员最佳实践指南(3): https://developer.aliyun.com/article/1225221spm=a2c6h.13148508.setting.16.438f4f0e18NXNE