愚見の使用の最適化Elasticsearch

Elasticsearchは、多くの場合、ログ解析ツールとして保存され、多くの場合、エンタープライズアプリケーションで使用されています。Elasticsearchは強力な検索、分析を提供し、バックエンド技術はすでに、スタックの不可欠な部分です。

ElasticsearchのメンテナンスElastciSearchクラスタは、いくつかのチューニングと分析を行ったとき、無理がある場合、その議論を歓迎し、純粋に謙虚な意見を書かれています。私が使用しElasticsearchバージョンが5.xのでした

データを照会し、データを挿入するために多数の要求をElasticsearch、あなたはファイルハンドルの多数を必要とする、CentOSのシステムのデフォルト1024のファイルハンドル。あなたは、接続を拒否するオペレーティングシステムは、データが失われる可能性があることを意味していることを意味し、ファイルハンドルの不足している場合、これは、悲惨です

それはお受けできません。Elasticsearch発射顧客のログを参照するには、次のコマンドを使用します。

ulimitの-a

表示結果:

コアファイルサイズ(ブロック、-c)0 
データSEGサイズ(キロバイト、-d)無制限の
スケジューリング優先度(-e)0 
ファイルサイズ(ブロック、-f)無制限の
ペンディング信号(-i)127673 
最大ロックされたメモリ(キロバイト、 - L)無制限の
最大メモリサイズ(バイト、-m)無制限の
オープンファイル(-n)1024 
管のサイズ(512バイト、-p)8つの
POSIXメッセージキュー(バイト、-q)819200 
リアルタイム優先順位(-r)0 
スタックサイズ(キロバイト、-s)8192 
CPU時間(秒、-t)無制限の
最大ユーザ・プロセス(-u)2056474 
仮想メモリ(キロバイト、-v)無制限の
ファイルロック(-x)無制限

ファイルハンドル数(開いているファイル)の上に1024年に、要求ElasticSearchの多数が、この数は処理するのに十分でない場合には、それが655360に変更することができます。

一時的な変更はすぐに有効にするには、次のコマンドを実行することができますが、マシンが失敗した後に再起動します。

655360 -nのulimit

常設、/etc/security/limits.confを変更し、あなたを有効にするには、マシンを再起動する必要があります。

u_es  -  NOFILE 655360

ユーザーが開始するElasticSearch上記構成u_esは、ユーザは、655360にElasticSearchファイルハンドルが設けられています。

JVMパラメータ最適化

ElasticsearchはJVM上で実行されている、JVMのチューニングは、そのパラメータがそうすることが重要です。最も一般的なチューニングは、Javaのメモリを割り当てることです。JVMのメモリ・モデルであり、以下、各ブロックの具体的な役割は、それが本明細書に記載されていません。

愚見の使用の最適化Elasticsearch


どのくらいに古いものと新しい世代のメモリ割り当ての割合は?

JVMメモリは古いものと新しい世代のに分かれています。

  • 新生代(またはエデン)

  • スペースのオブジェクト割り当ての新しいインスタンス。スペースの新しい世代は、一般的に100メガバイト、500メガバイトで、通常は非常に小さいです。新世代は、2つの存続スペースが含まれています。

  • 古いオブジェクト・ストレージ・スペース。これらのオブジェクトは、長期保存であることが予想と長期間にわたって維持されます。古い世代は、通常、新しい世代よりもはるかに大きいです。

新世代、旧世代ガーベジコレクションのフェーズは、「世界を停止」になります。この間、JVMが実行を停止し、到達可能性解析をオブジェクトにするために、死んだオブジェクトを収集。時間内にこの段階を停止し、それが起こっているだろう。リクエストは、フラグメンテーションが割り当てられていない、のpingが応答されていない、提供されていません。全世界が本当に停止しました。

新世代のために、それは大したことではないのです。それは少しスペースGCはすぐに実行されることを意味します。しかし、古い世代ははるかに大きく、そして遅いGCは、1秒でも15秒のポーズを意味するかもしれないがある - サーバソフトウェアのために、これは容認できません。

一般的に、我々は多くのメモリ、それは新しいものと古いための方法だということに割り当てますか?彼らの比率はどのくらいですか?

1より適切である:一般的には、古い年の割合とメモリの新世代は2です。3G、割り当て1Gの新世代を割り当てるなど、ヒープメモリは、古い時代の残りの部分を与えました。ElasticSearceプロファイルでjvm.options設定ファイル:

-Xms3g //初期化ヒープサイズの設定
-Xmx3g //設定する最大メモリヒープ
-Xmn1g //メモリの新世代を設定します。

Elasticesearchをどのくらいのメモリを割り当てるには?

在使用Elasticesearch的时候,我们对装Elasticesearch的机器进行了升级,从最小的8G内存升级到了16G内存,然后到目前的32G内存。一台机器装一个Elasticesearch节点,我们应该怎么分配机器的内存呢?

官方给出了解决方案,把一半(少于)的内存分配给Luence,另外的内存分配给ElasticSearch.

内存对于 Elasticsearch 来说绝对是重要的,它可以被许多内存数据结构使用来提供更快的操作。但是说到这里, 还有另外一个内存消耗大户 非堆内存 (off-heap):Lucene。

Lucene 被设计为可以利用操作系统底层机制来缓存内存数据结构。Lucene 的段是分别存储到单个文件中的。因为段是不可变的,这些文件也都不会变化,这是对缓存友好的,同时操作系统也会把这些段文件缓存起来,以便更快的访问。

Lucene 的性能取决于和操作系统的相互作用。如果你把所有的内存都分配给 Elasticsearch 的堆内存,那将不会有剩余的内存交给 Lucene。这将严重地影响全文检索的性能。

标准的建议是把 50% 的可用内存作为 Elasticsearch 的堆内存,保留剩下的 50%。当然它也不会被浪费,Lucene 会很乐意利用起余下的内存。

我们实际的解决办法是将机器的一半分给Elasticesearch的堆,栈内存、方法区、常量池、非堆内存占用另外一半。

分配给堆最大内存应该小于 32766 mb(~31.99 gb)

JVM 在内存小于 32 GB 的时候会采用一个内存对象指针压缩技术。

对于 32 位的系统,意味着堆内存大小最大为 4 GB。对于 64 位的系统, 可以使用更大的内存,但是 64 位的指针意味着更大的浪费,因为你的指针本身大了。更糟糕的是, 更大的指针在主内存和各级缓存(例如 LLC,L1 等)之间移动数据的时候,会占用更多的带宽。

Java 使用一个叫作 内存指针压缩(compressed oops)的技术来解决这个问题。它的指针不再表示对象在内存中的精确位置,而是表示 偏移量 。这意味着 32 位的指针可以引用 40 亿个 对象 , 而不是 40 亿个字节。最终, 也就是说堆内存增长到 32 GB 的物理内存,也可以用 32 位的指针表示。

一旦你越过那个神奇的 ~32 GB 的边界,指针就会切回普通对象的指针。每个对象的指针都变长了,就会使用更多的 CPU 内存带宽,也就是说你实际上失去了更多的内存。事实上,当内存到达 40–50 GB 的时候,有效内存才相当于使用内存对象指针压缩技术时候的 32 GB 内存。

这段描述的意思就是说:即便你有足够的内存,也尽量不要 超过 32 GB。因为它浪费了内存,降低了 CPU 的性能,还要让 GC 应对大内存。

关掉swap

内存交换 到磁盘对服务器性能来说是 致命 的。

如果内存交换到磁盘上,一个 100 微秒的操作可能变成 10 毫秒。再想想那么多 10 微秒的操作时延累加起来。不难看出 swapping 对于性能是多么可怕。

用以下命令关掉swap:

sudo swapoff -a


不要碰以下的配置

所有的调整就是为了优化,但是这些调整,你真的不需要理会它。因为它们经常会被乱用,从而造成系统的不稳定或者糟糕的性能,甚至两者都有可能。

线程池配置

许多人 喜欢 调整线程池。无论什么原因,人们都对增加线程数无法抵抗。索引太多了?增加线程!搜索太多了?增加线程!节点空闲率低于 95%?增加线程!

Elasticsearch 默认的线程设置已经是很合理的了。对于所有的线程池(除了 搜索 ),线程个数是根据 CPU 核心数设置的。如果你有 8 个核,你可以同时运行的只有 8 个线程,只分配 8 个线程给任何特定的线程池是有道理的。

搜索线程池设置的大一点,配置为 int(( 核心数 * 3 )/ 2 )+ 1 。

垃圾回收器

Elasticsearch 默认的垃圾回收器( GC )是 CMS。这个垃圾回收器可以和应用并行处理,以便它可以最小化停顿。然而,它有两个 stop-the-world 阶段,处理大内存也有点吃力。

尽管有这些缺点,它还是目前对于像 Elasticsearch 这样低延迟需求软件的最佳垃圾回收器。官方建议使用 CMS。

合理设置最小主节点

minimum_master_nodes 设置及其重要,为了防止集群脑裂,这个参数应该设置为法定个数就是 ( master 候选节点个数 / 2) + 1。

分片均匀,磁盘优化,剔除掉高负载的Master竞选?

笔者在实际生产环境中遇到了有一个节点的负载是其他节点的几倍,从虚拟机监控上看,所有的节点的qps是差不多的。机器的配置是一样的,为什么负载会有如此大的差距?

  • 首先,我们怀疑数据分配不均匀,我们排查了下,没有这种现象。

  • 然后,我们监控到了高负载的节点磁盘IO非常的高,经常达到100%,我们怀疑是那个虚拟机磁盘性能不行。但是我们当时没有更好的磁盘。

  • 我们找到了一个适中的解决办法是将这台高负载的节点剔除Master竞选,即将elasticsearch.yml文件中的node.master改为false然后重启,负载下降了一些。

数据存储天数的优化

存储天数的优化,这个需要根据实际的业务来,下面是删除过期数据的脚本,该脚本来源于https://stackoverflow.com/questions/33430055/removing-old-indices-in-elasticsearch#answer-39746705 ;

#!/bin/bash
searchIndex=logstash-monitor
elastic_url=logging.core.k94.kvk.nl
elastic_port=9200
date2stamp () {
 date --utc --date "$1" +%s
}
dateDiff (){
 case $1 in
 -s) sec=1; shift;;
 -m) sec=60; shift;;
 -h) sec=3600; shift;;
 -d) sec=86400; shift;;
 *) sec=86400;;
 esac
 dte1=$(date2stamp $1)
 dte2=$(date2stamp $2)
 diffSec=$((dte2-dte1))
 if ((diffSec < 0)); then abs=-1; else abs=1; fi
 echo $((diffSec/sec*abs))
}
for index in $(curl -s "${elastic_url}:${elastic_port}/_cat/indices?v" | grep -E " ${searchIndex}-20[0-9][0-9]\.[0-1][0-9]\.[0-3][0-9]" | awk '{ print $3 }'); do
 date=$(echo ${index: -10} | sed 's/\./-/g')
 cond=$(date +%Y-%m-%d)
 diff=$(dateDiff -d $date $cond)
 echo -n "${index} (${diff})"
 if [ $diff -gt 1 ]; then
 echo " / DELETE"
 # curl -XDELETE "${elastic_url}:${elastic_port}/${index}?pretty"
 else
 echo ""
 fi
done

然后使用crontab每天定时执行一次这个脚本。

集群分片设置

ES一旦创建好索引后,就无法调整分片的设置,而在ES中,一个分片实际上对应一个lucene 索引,而lucene索引的读写会占用很多的系统资源,因此,分片数不能设置过大;所以,在创建索引时,合理配置分片数是非常重要的。一般来说,我们遵循一些原则:

  1. 控制每个分片占用的硬盘容量不超过ES的最大JVM的堆空间设置(一般设置不超过32G,参加上文的JVM设置原则),因此,如果索引的总容量在500G左右,那分片大小在16个左右即可;当然,最好同时考虑原则2。

  2. 考虑一下node数量,一般一个节点有时候就是一台物理机,如果分片数过多,大大超过了节点数,很可能会导致一个节点上存在多个分片,一旦该节点故障,即使保持了1个以上的副本,同样有可能会导致数据丢失,集群无法恢复。所以, 一般都设置分片数不超过节点数的3倍。


索引优化

1.修改index_buffer_size 的设置,可以设置成百分数,也可设置成具体的大小,大小可根据集群的规模做不同的设置测试。

indices.memory.index_buffer_size:10%(默认)
indices.memory.min_index_buffer_size:48mb(默认)
indices.memory.max_index_buffer_size
  1. _id字段的使用,应尽可能避免自定义_id, 以避免针对ID的版本管理;建议使用ES的默认ID生成策略或使用数字类型ID做为主键。

  2. _all字段及_source字段的使用,应该注意场景和需要,_all字段包含了所有的索引字段,方便做全文检索,如果无此需求,可以禁用;_source存储了原始的document内容,如果没有获取原始文档数据的需求,可通过设置includes、excludes 属性来定义放入_source的字段。

  3. 合理的配置使用index属性,analyzed 和not_analyzed,根据业务需求来控制字段是否分词或不分词。只有 groupby需求的字段,配置时就设置成not_analyzed, 以提高查询或聚类的效率。

查询优化

  • 查询优化,调整filter过滤顺序


如果把过滤效果不明显的条件放在了前面,导致查询出大量不需要的数据,导致查询变慢。

把过滤效果明显的条件提前,按照过滤效果把过滤条件排序

  • 索引时间精度优化


研究Filter的工作原理可以看出,它每次工作都是遍历整个索引的,所以时间粒度越大,对比越快,搜索时间越短,在不影响功能的情况下,时间精度越低越好,有时甚至牺牲一点精度也值得,当然最好的情况是根本不作时间限制。

es重新刷索引,增加冗余的时间字段,精确到天。带有时间范围的查询使用该字段进行查询

  • 查询Fetch Source优化


业务查询语句获取的数据集比较大,并且从source中获取了非必须的字段,导致查询较慢。

举例:只需要从es中查询id这一个字段,却把所有字段查询了出来

  • 预索引数据


利用索引查询数据是最优的方式。例如,如果所有的文档都有 price 字段,并且大多数查询都在一个固定的范围列表中运行范围聚合,那么可以通过将 index 预索引到 index 和使用 terms 聚合来更快地实现聚合。

例如,像下面这样:

PUT index/type/1
{
 "designation": "spoon",
 "price": 13
}

像这样的查询:

GET index/_search
{
 "aggs": {
 "price_ranges": {
 "range": {
 "field": "price",
 "ranges": [
 { "to": 10 },
 { "from": 10, "to": 100 },
 { "from": 100 }
 ]
 }
 }
 }
}

文档在索引的时候要使用 price_range ,应该被映射为关键词:

PUT index
{
 "mappings": {
 "type": {
 "properties": {
 "price_range": {
 "type": "keyword"
 }
 }
 }
 }
}
PUT index/type/1
{
 "designation": "spoon",
 "price": 13,
 "price_range": "10-100"
}

然后这个请求就直接聚合新字段,而不是在 price 字段运行范围查询:

GET index/_search
{
 "aggs": {
 "price_ranges": {
 "terms": {
 "field": "price_range"
 }
 }
 }
}

总结

总的来说,ElasticSearch的优化,优化可以从以下方面的考虑:

  • ハードウェアの最適化:配布マシン、マシン構成、マシンのメモリ、マシンのCPU、ネットワークマシン、マシンのディスクパフォ​​ーマンス

  • オペレーティングシステム設定の最適化:ファイルハンドルを最適化し、スワップ閉じ

  • ElasticSearch合理的なディストリビューションノード、選挙マスターのための合理的なディストリビューションノード

  • ElasticSearchストレージの最適化、コピーの数、インデックス数、フラグメント数

  • ElasticSearchの使用の最適化、最適化インデックス、クエリの最適化

 最後に、JVMをカバーする、ロック、並行性の高い、反射、春の原理、マイクロサービス、飼育係、データベース、データ構造など、インタビューブック「.PDFを終えたJavaのコア知識を共有」

困っている友達は、探検、Javaのアーキテクチャ技術交換Qグループ328993819共有に追加することができ、


おすすめ

転載: blog.51cto.com/14528283/2435440