@
ES的优势在倒排索引的设计,以及单节点PB级数据存储;所以有搜索全文或大数据需求,可以考虑使用ES。
https://blog.csdn.net/weixin_39576751/article/details/112272464
存储索引文件的一个文件系统且它支持很多类型,主要职责是对数据的持久化以及整个集群重启后可以通过gateway重新恢复数据
支持的格式有:本地Local FileSystem、分布式Shared FileSystem(做snapshot的时候会用到)、Hadoop的文件系统HDFS、Amazon(亚马逊)的S3。
ES是基于Lucene的,一个分片就是一个lucene。 Lucene是做检索的,但是他是一个单机的搜索引擎,ES底层使用Lucene需要在每个节点上都运行Lucene进行响应的索引,查询及更新所以需要支持业务层的分布式
River常见的插件有RabbitMQ River、Twitter River,例如可以通过一些自定义的脚本将传统的数据库(mysql)等数据源通过格式化转换后直接同步到es集群里,这个river大部分是自己写的,写出来的东西质量参差不齐,将这些东西集成到es中会引发很多内部bug,严重影响了es的正常应用,所以在es2.0之后考虑将其去掉。
Elasticsearch是基于P2P的系统,它首先通过广播的机制寻找存在的节点,然后再通过多播协议来进行节点间的通信,同时也支持点对点的交互
ES支持多种通信接口,Thrift、Memcached以及Http,默认的是http,JMX就是java的一个远程监控管理框架
ES暴露给我们的访问接口,官方推荐的方案就是Restful接口,直接发送http请求,方便后续使用nginx做代理、分发包括可能后续会做权限的管理,通过http很容易做这方面的管理。如果使用java客户端它是直接调用api,在做负载均衡以及权限管理还是不太好做
查看集群统计信息(对大集群非常有用),可以查看jvm、os等信息,进行调优或监控很有帮助,具体参数解释查看:https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-stats.html
GET _cluster/stats
{
"_nodes" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"cluster_uuid": "YjAvIhsCQ9CbjWZb2qJw3Q",
"cluster_name": "elasticsearch",
"timestamp": 1459427693515,
"status": "green",
"indices": {
"count": 1,
"shards": {
"total": 5,
"primaries": 5,
"replication": 0,
"index": {
"shards": {
"min": 5,
"max": 5,
"avg": 5
},
"primaries": {
"min": 5,
"max": 5,
"avg": 5
},
"replication": {
"min": 0,
"max": 0,
"avg": 0
}
}
},
"docs": {
"count": 10,
"deleted": 0
},
"store": {
"size": "16.2kb",
"size_in_bytes": 16684,
"total_data_set_size": "16.2kb",
"total_data_set_size_in_bytes": 16684,
"reserved": "0b",
"reserved_in_bytes": 0
},
"fielddata": {
"memory_size": "0b",
"memory_size_in_bytes": 0,
"evictions": 0
},
"query_cache": {
"memory_size": "0b",
"memory_size_in_bytes": 0,
"total_count": 0,
"hit_count": 0,
"miss_count": 0,
"cache_size": 0,
"cache_count": 0,
"evictions": 0
},
"completion": {
"size": "0b",
"size_in_bytes": 0
},
"segments": {
"count": 4,
"memory": "8.6kb",
"memory_in_bytes": 8898,
"terms_memory": "6.3kb",
"terms_memory_in_bytes": 6522,
"stored_fields_memory": "1.2kb",
"stored_fields_memory_in_bytes": 1248,
"term_vectors_memory": "0b",
"term_vectors_memory_in_bytes": 0,
"norms_memory": "384b",
"norms_memory_in_bytes": 384,
"points_memory" : "0b",
"points_memory_in_bytes" : 0,
"doc_values_memory": "744b",
"doc_values_memory_in_bytes": 744,
"index_writer_memory": "0b",
"index_writer_memory_in_bytes": 0,
"version_map_memory": "0b",
"version_map_memory_in_bytes": 0,
"fixed_bit_set": "0b",
"fixed_bit_set_memory_in_bytes": 0,
"max_unsafe_auto_id_timestamp" : -9223372036854775808,
"file_sizes": {}
},
"mappings": {
"field_types": [],
"runtime_field_types": []
},
"analysis": {
"char_filter_types": [],
"tokenizer_types": [],
"filter_types": [],
"analyzer_types": [],
"built_in_char_filters": [],
"built_in_tokenizers": [],
"built_in_filters": [],
"built_in_analyzers": []
},
"versions": [
{
"version": "8.0.0",
"index_count": 1,
"primary_shard_count": 1,
"total_primary_size": "7.4kb",
"total_primary_bytes": 7632
}
]
},
"nodes": {
"count": {
"total": 1,
"data": 1,
"coordinating_only": 0,
"master": 1,
"ingest": 1,
"voting_only": 0
},
"versions": [
"7.14.0"
],
"os": {
"available_processors": 8,
"allocated_processors": 8,
"names": [
{
"name": "Mac OS X",
"count": 1
}
],
"pretty_names": [
{
"pretty_name": "Mac OS X",
"count": 1
}
],
"architectures": [
{
"arch": "x86_64",
"count": 1
}
],
"mem" : {
"total" : "16gb",
"total_in_bytes" : 17179869184,
"free" : "78.1mb",
"free_in_bytes" : 81960960,
"used" : "15.9gb",
"used_in_bytes" : 17097908224,
"free_percent" : 0,
"used_percent" : 100
}
},
"process": {
"cpu": {
"percent": 9
},
"open_file_descriptors": {
"min": 268,
"max": 268,
"avg": 268
}
},
"jvm": {
"max_uptime": "13.7s",
"max_uptime_in_millis": 13737,
"versions": [
{
"version": "12",
"vm_name": "OpenJDK 64-Bit Server VM",
"vm_version": "12+33",
"vm_vendor": "Oracle Corporation",
"bundled_jdk": true,
"using_bundled_jdk": true,
"count": 1
}
],
"mem": {
"heap_used": "57.5mb",
"heap_used_in_bytes": 60312664,
"heap_max": "989.8mb",
"heap_max_in_bytes": 1037959168
},
"threads": 90
},
"fs": {
"total": "200.6gb",
"total_in_bytes": 215429193728,
"free": "32.6gb",
"free_in_bytes": 35064553472,
"available": "32.4gb",
"available_in_bytes": 34802409472
},
"plugins": [
{
"name": "analysis-icu",
"version": "7.14.0",
"description": "The ICU Analysis plugin integrates Lucene ICU module into elasticsearch, adding ICU relates analysis components.",
"classname": "org.elasticsearch.plugin.analysis.icu.AnalysisICUPlugin",
"has_native_controller": false
},
...
],
"ingest": {
"number_of_pipelines" : 1,
"processor_stats": {
...
}
},
"network_types": {
...
},
"discovery_types": {
...
},
"packaging_types": [
{
...
}
]
}
}
查看集群状态,可以更细到索引层面,查看具体哪个索引导致集群状态Red等。
GET _cluster/health?level=indices
GET _cluster/health?level=shards
https://www.elastic.co/guide/cn/elasticsearch/guide/current/_cluster_health.html
es集群最大节点建议200。过多节点会产生什么问题?
对于每个 Elasticsearch 索引,映射和状态的相关信息都存储在集群状态中。这些信息存储在内存中,以便快速访问。因此,如果集群中的索引和分片数量过多,这会导致集群状态过大,如果映射较大的话,尤为如此。这会导致更新变慢,因为所有更新都需要通过单线程完成,从而在将变更分发到整个集群之前确保一致性
集群状态会加载到每个节点(包括主节点)上的堆内存中,而且堆内存大小与索引数量以及单个索引和分片中的字段数成正比关系,所以还需要同时监测主节点上的堆内存使用量并确保其大小适宜,这一点很重要。
GET /_nodes/stats # 同上集群
索引相当于数据库中Database。每个索引又由一个或多个分片组成。每个分片都是一个 Lucene 索引实例,您可以将其视作一个独立的搜索引擎,它能够对 Elasticsearch 集群中的数据子集进行索引并处理相关查询。
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields
一个索引默认1000分片(参数:cluster.max_shards_per_node)。
人们通常将 50GB 作为分片上限,而且这一限值在各种用例中都已得到验证
这里有一个很好的经验法则:确保对于节点上已配置的每个 GB,将分片数量保持在 20 以下。如果某个节点拥有 30GB 的堆内存,那其最多可有 600 个分片,但是在此限值范围内,您设置的分片数量越少,效果就越好。一般而言,这可以帮助集群保持良好的运行状态。
GET /_cat/shards
https://www.elastic.co/cn/blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster
GET /_cat/segments?v
index shard prirep ip segment generation docs.count docs.deleted size size.memory committed searchable version compound
test 0 p 127.0.0.1 _0 0 1 0 3kb 2042 false true 8.0.0 true
test1 0 p 127.0.0.1 _0 0 1 0 3kb 2042 false true 8.0.0 true
GET _segments # 可查看每个段信息
已提交索引段是指那些已经执行过提交命令的段,意味着在磁盘已经持久化,且是只读的
一个文档是一个可被索引的基础信息单元。存储的数据是文档,一条数据对应一篇文档,类似mysql数据库中的一行数据
一个文档中对应的多个列,类似mysql数据库中一行有多列。字段包括词项和词项对应的value值
词项是索引的最小单位,一般可以把词项当作词
查询token:https://www.elastic.co/guide/en/elasticsearch/reference/1.6/docs-termvectors.html#_term_information
GET /_analyze?
{
"analyzer": "standard",
"text": "orJ2t4r8Rlgz-988Y947mMas5zuU"
}
返回:
{
"tokens": [
{
"token": "orj2t4r8rlgz",
"start_offset": 0,
"end_offset": 12,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "988y947mmas5zuu",
"start_offset": 13,
"end_offset": 28,
"type": "<ALPHANUM>",
"position": 1
}
]
}
可以理解为mysql或者solr中对应的schema,只不过这里的mapping增加了动态识别功能
允许集群系统存储数据总量超过单机容量
默认5分片是标准用法。
如果有一个有限且明确的数据集——可以只使用一个分片。
如果没有,最理想分片数应该依赖于节点的数量:
节点最大数 = 分片数 *(副本数 + 1)
节点最大数该如何确定?
解决访问压力过大时,单机无法处理所有请求,应对增长的并发查询。
缺点:各分片副本占用额外的存储空间,主分片及副本之间数据拷贝也存在时间开销。
单集群最多节点200
单节点最多600分片,es默认每个节点最多1000分片
确保对于节点上已配置的每个 GB,将分片数量保持在 20 以下。如果某个节点拥有 30GB 的堆内存,那其最多可有 600 个分片,但是在此限值范围内,您设置的分片数量越少,效果就越好
单分片大小控制在50GB
最后根据自己要存储的数据量,进行压测。再根据压测数据,对索引设置分片大小。
创建一定量数据后,可:
GET _cluster/stats # 查看集群状态(os、jvm、indices、nodes等信息)
GET /_nodes/stats # 同上集群
GET /_cat/shards # 查看索引分片
GET /_cat/segments # 查看segments
Elasticsearch Server(Elasticsearch caches)
https://elastic.blog.csdn.net/article/details/108970774
https://www.elastic.co/guide/cn/elasticsearch/guide/current/_deep_dive_on_doc_values.html
Elasticsearch 中的 Doc Values 常被应用到以下场景:
Doc Values 是在索引时与 倒排索引 同时生成。也就是说 Doc Values 和 倒排索引 一样,基于 Segement 生成并且是不可变的。同时 Doc Values 和 倒排索引 一样序列化到磁盘,这样对性能和扩展性有很大帮助。
因为文档值被序列化到磁盘,我们可以依靠操作系统的帮助来快速访问。
当 工作集(working set) 远小于节点的可用内存,系统会自动将所有的文档值保存在内存中,使得其读写十分高速;
当其远大于可用内存,操作系统会自动把 Doc Values 加载到系统的页缓存中,从而避免了 jvm 堆内存溢出异常
Doc Values 默认对所有字段启用,除了 analyzed strings。也就是说所有的数字、地理坐标、日期、IP 和不分析( not_analyzed )字符类型都会默认开启。
analyzed strings 暂时还不能使用 Doc Values。文本经过分析流程生成很多 Token,使得 Doc Values 不能高效运行
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"session_id": {
"type": "string",
"index": "not_analyzed",
"doc_values": false
}
}
}
}
}
列存储优势:
因为基于列存储,所以每一列本身就相当于索引。所以在做一些需要索引的操作时,就不需要额外的数据结构来为此列创建合适的索引。
利于压缩有两个原因。一来你会发现大部分列数据基数其实是重复的,二来相同的列数据类型一致,这样利于数据结构填充的优化和压缩,而且对于数字列这种数据类型可以采取更多有利的算法去压缩存储。
https://blog.csdn.net/dc_726/article/details/41143175
文本字段存储在倒排索引中,数字字段和地理字段存储在BKD树中。
数据类型 | 数据结构 |
---|---|
text/keyword | 倒排索引 |
数字/地理位置 | BKD树 |
https://nereuschen.github.io/2015/09/16/ElasticSearch内存使用分析/
https://blog.csdn.net/jiao_fuyou/article/details/50509941
由于集群状态会加载到每个节点(包括主节点)上的堆内存中,而且堆内存大小与索引数量以及单个索引和分片中的字段数成正比关系,所以还需要同时监测主节点上的堆内存使用量并确保其大小适宜,这一点很重要。
每个分片都有一部分数据需要保存在内存中,这部分数据也会占用堆内存空间。这包括存储分片级别以及段级别信息的数据结构,因为只有这样才能确定数据在磁盘上的存储位置。这些数据结构的大小并不固定,不同用例之间会有很大的差别
为了能够在单个节点上存储尽可能多的数据,下面两点至关重要:管理堆内存使用量;尽可能减少开销。节点的堆内存空间越多,其能处理的数据和分片就越多。
(https://www.elastic.co/cn/blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster)
https://www.elastic.co/cn/blog/significantly-decrease-your-elasticsearch-heap-memory-usage
https://blog.csdn.net/qq_42046105/article/details/91488572?ops_request_misc=%7B%22request%5Fid%22%3A%22162900587816780264061739%22%2C%22scm%22%3A%2220140713.130102334.pc%5Fblog.%22%7D&request_id=162900587816780264061739&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_v29-3-91488572.pc_v2_rank_blog_default&utm_term=elasticsearch&spm=1018.2226.3001.4450
https://www.elastic.co/guide/cn/elasticsearch/guide/current/_finding_exact_values.html#_internal_filter_operation
https://www.elastic.co/guide/cn/elasticsearch/guide/current/filter-caching.html
https://blog.csdn.net/jiao_fuyou/article/details/50509941
https://segmentfault.com/a/1190000040238635?utm_source=sf-similar-article
Query Cache也称为Filter Cache,顾名思义它的作用就是对一个查询中包含的过滤器执行结果进行缓存。
比如我们常用的term,terms,range过滤器都会在满足某种条件后被缓存,注意,这里的bool过滤器是不会被缓存的,但bool过滤器包含的子query clause会被缓存
(5.1.1版本term被取消了)
https://blog.csdn.net/chennanymy/article/details/52403594
https://segmentfault.com/a/1190000040238635?utm_source=sf-similar-article
term 查询在倒排索引中查找 XHDK-A-1293-#fJ3 然后获取包含该 term 的所有文档。本例中,只有文档 1 满足我们要求。
过滤器会创建一个 bitset (一个包含 0 和 1 的数组),它描述了哪个文档会包含该 term 。匹配文档的标志位是 1 。本例中,bitset 的值为 [1,0,0,0] 。在内部,它表示成一个 "roaring bitmap",可以同时对稀疏或密集的集合进行高效编码。
一旦为每个查询生成了 bitsets ,Elasticsearch 就会循环迭代 bitsets 从而找到满足所有过滤条件的匹配文档的集合。执行顺序是启发式的,但一般来说先迭代稀疏的 bitset (因为它可以排除掉大量的文档)。
Elasticsearch 能够缓存非评分查询从而获取更快的访问,但是它也会不太聪明地缓存一些使用极少的东西。非评分计算因为倒排索引已经足够快了,所以我们只想缓存那些我们 知道 在将来会被再次使用的查询,以避免资源的浪费。
为了实现以上设想,Elasticsearch 会为每个索引跟踪保留查询使用的历史状态。如果查询在最近的 256 次查询中会被用到,那么它就会被缓存到内存中。当 bitset 被缓存后,缓存会在那些低于 10,000 个文档(或少于 3% 的总索引数)的段(segment)中被忽略。这些小的段即将会消失,所以为它们分配缓存是一种浪费。
https://www.elastic.co/guide/cn/elasticsearch/guide/current/filter-caching.html
全称是 Shard Request Cache,即分片级请求缓存。当对一个或多个索引发送搜索请求时,搜索请求首先会发送到ES集群中的某个节点,称之为协调节点;协调节点会把该搜索请求分发给其他节点并在相应分片上执行搜索操作,我们把分片上的执行结果称为“本地结果集”,之后,分片再将执行结果返回给协调节点;协调节点获得所有分片的本地结果集之后,合并成最终的结果并返回给客户端。
Request Cache 在每个分片上缓存了本地结果集,这使得频繁使用的搜索请求几乎立即返回结果。默认情况下只会缓存查询中参数 size=0 的搜索请求的结果,因此将不会缓存hits,但会缓存 hits.total,aggregations(聚合) 和 suggestions。所以,request cache 分片请求缓存非常适合日志用例场景,在这种情况下,数据不会在旧索引上更新,并且可以将常规聚合保留在高速缓存中以供重用。
https://blog.csdn.net/a745233700/article/details/118055871
从历史上看,fielddata 是 所有 字段的默认设置。但是 Elasticsearch 已迁移到 doc values 以减少 OOM 的几率(ES2.0)。分析的字符串是仍然使用 fielddata 的最后一块阵地。 最终目标是建立一个序列化的数据结构类似于 doc values ,可以处理高维度的分析字符串,逐步淘汰 fielddata。
fielddata 需要与 request 断路器共享堆内存、索引缓冲内存和过滤器缓存
可配置:indices.fielddata.cache.size
GET /_nodes/stats/indices/fielddata
在启用字段数据之前,请考虑为什么将文本字段用于聚合、排序或在脚本中使用。启用 fielddata 通常没有任何意义,因为它非常耗费内存资源。仅仅是做全文搜索的应用,就不需要启用fielddata。
https://blog.csdn.net/laoyang360/article/details/108970774
https://www.elastic.co/guide/cn/elasticsearch/guide/current/aggregations-and-analysis.html
Elasticsearch Server(Elasticsearch caches)
参考:
https://www.elastic.co/guide/cn/elasticsearch/guide/current/_talking_to_elasticsearch.html
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-create-index.html
Indexing Buffer是用来缓存新数据,当其满了或者refresh/flush interval到了,就会以segment file的形式写入到磁盘。 这个参数的默认值是10% heap size。根据经验,这个默认值也能够很好的工作,应对很大的索引吞吐量。 但有些用户认为这个buffer越大吞吐量越高,因此见过有用户将其设置为40%的。到了极端的情况,写入速度很高的时候,40%都被占用,导致OOM。
ES被设计成每个node都可以响应用户的api请求,因此每个node的内存里都包含有一份集群状态的拷贝。这个cluster state包含诸如集群有多少个node,多少个index,每个index的mapping是什么?有少shard,每个shard的分配情况等等 (ES有各类stats api获取这类数据)。 在一个规模很大的集群,这个状态信息可能会非常大的,耗用的内存空间就不可忽视了。并且在ES2.0之前的版本,state的更新是由master node做完以后全量散播到其他结点的。 频繁的状态更新都有可能给heap带来压力。 在超大规模集群的情况下,可以考虑分集群并通过tribe node连接做到对用户api的透明,这样可以保证每个集群里的state信息不会膨胀得过大。
ES是分布式搜索引擎,搜索和聚合计算除了在各个data node并行计算以外,还需要将结果返回给汇总节点进行汇总和排序后再返回。无论是搜索,还是聚合,如果返回结果的size设置过大,都会给heap造成很大的压力,特别是数据汇聚节点。超大的size多数情况下都是用户用例不对,比如本来是想计算cardinality,却用了terms aggregation + size:0这样的方式; 对大结果集做深度分页;一次性拉取全量数据等等。
Java 使用一个叫作 内存指针压缩(compressed oops)的技术来解决这个问题。 它的指针不再表示对象在内存中的精确位置,而是表示 偏移量 。这意味着 32 位的指针可以引用 40 亿个 对象 , 而不是 40 亿个字节。最终, 也就是说堆内存增长到 32 GB 的物理内存,也可以用 32 位的指针表示。
一旦你越过那个神奇的 ~32 GB 的边界,指针就会切回普通对象的指针。 每个对象的指针都变长了,就会使用更多的 CPU 内存带宽,也就是说你实际上失去了更多的内存。事实上,当内存到达 40–50 GB 的时候,有效内存才相当于使用内存对象指针压缩技术时候的 32 GB 内存。
这段描述的意思就是说:即便你有足够的内存,也尽量不要 超过 32 GB。因为它浪费了内存,降低了 CPU 的性能,还要让 GC 应对大内存。
( 大内存的机器、及swapping)
https://www.elastic.co/guide/cn/elasticsearch/guide/current/heap-sizing.html
https://www.elastic.co/guide/cn/elasticsearch/guide/current/distrib-write.html
倒排索引写过程
https://www.elastic.co/guide/cn/elasticsearch/guide/current/translog.html
所有的查询都或多或少的会进行相关度计算,但不是所有的查询都会有分析阶段,文本查询可以分为两个部分:
??1. 基于词项的查询,如 term 或 fuzzy 这样的查询是没有分析阶段的。他们对单个词项进行操作。
??2. 基于全文的查询,比如match, 它们会先了解字段映射的信息,判断字段是否被分词,是否是日期还是数字等, 再根据映射信息,构建要查询的词项列表,根据列表进行查询。
https://www.jianshu.com/p/6d55b24fb9ab
https://www.elastic.co/guide/cn/elasticsearch/guide/current/dynamic-indices.html
增加或者减少机器时候会自动均衡
主节点的主要职责是和集群操作相关的内容,如创建或删除索引,跟踪哪些节点是群集的一部分,并决定哪些分片分配给相关的节点。稳定的主节点对集群的健康是非常重要的
https://www.elastic.co/guide/en/elasticsearch/reference/7.9/modules-node.html
Zen是Elasticsearch默认发现机制。Zen发现默认使用多播来发现其他节点。有时多播由于各种原因而失效,或在一个大型集群多播发现产生大量不必要流量Zen也可使用单播方式。
discovery.zen.minimum_master_nodes = 候选主节点(集群节点数)/ 2 + 1
https://zhuanlan.zhihu.com/p/34858035
master选举当然是由master-eligible节点发起,当一个master-eligible节点发现满足以下条件时发起选举:
总结一句话,即当一个节点发现包括自己在内的多数派的master-eligible节点认为集群没有master时,就可以发起master选举。
假如集群中有3个master-eligible node,分别为Node_A、 Node_B、 Node_C, 选举优先级也分别为Node_A、Node_B、Node_C。三个node都认为当前没有master,于是都各自发起选举,选举结果都为Node_A(因为选举时按照优先级排序,如上文所述)。于是Node_A开始等join(选票),Node_B、Node_C都向Node_A发送join,当Node_A接收到一次join时,加上它自己的一票,就获得了两票了(超过半数),于是Node_A成为Master。此时cluster_state(集群状态)中包含两个节点,当Node_A再收到另一个节点的join时,cluster_state包含全部三个节点。
https://zhuanlan.zhihu.com/p/334348919
脑裂问题可能有以下几个原因造成:
如何避免脑裂:我们可以基于上述原因,做出优化措施:
https://www.jianshu.com/p/a65c9c62db4a
https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-cluster.html
通过阈值判定,将在不同的node上的shard转移来平衡集群中每台node的shard数。发生在节点增减、修改replica的配置的时候。
关闭allocation以后,rebalance过程也会被禁止。
https://www.elastic.co/guide/cn/elasticsearch/guide/current/_scale_horizontally.html
https://cloud.tencent.com/developer/article/1825511?from=article.detail.1529651
https://help.aliyun.com/document_detail/170095.html
nested 的可能的性能问题不容小觑。
nested本质:每个嵌套对象都被索引为一个单独的Lucene文档。如果我们为包含100个用户对象的单个文档建立索引,则将创建101个Lucene文档。
nested 较 父子文档不同之处:
https://www.elastic.co/guide/cn/elasticsearch/guide/current/_queries_and_filters.html
从 Elasticsearch 2.0 开始,过滤(filters)已经从技术上被排除了,同时所有的查询(queries)拥有变成不评分查询的能力。
然而,为了明确和简单,我们用 "filter" 这个词表示不评分、只过滤情况下的查询。你可以把 "filter" 、 "filtering query" 和 "non-scoring query" 这几个词视为相同的。
相似的,如果单独地不加任何修饰词地使用 "query" 这个词,我们指的是 "scoring query" 。
过滤查询(Filtering queries)只是简单的检查包含或者排除,这就使得计算起来非常快。考虑到至少有一个过滤查询(filtering query)的结果是 “稀少的”(很少匹配的文档),并且经常使用不评分查询(non-scoring queries),结果会被缓存到内存中以便快速读取,所以有各种各样的手段来优化查询结果。
相反,评分查询(scoring queries)不仅仅要找出匹配的文档,还要计算每个匹配文档的相关性,计算相关性使得它们比不评分查询费力的多。同时,查询结果并不缓存。
https://www.elastic.co/guide/cn/elasticsearch/guide/current/relevance-intro.html
https://www.elastic.co/guide/cn/elasticsearch/guide/current/controlling-relevance.html
https://www.elastic.co/guide/cn/elasticsearch/guide/current/scoring-theory.html
检索词频率:检索词在该字段出现的频率?出现频率越高,相关性也越高。 字段中出现过 5 次要比只出现过 1 次的相关性高。
反向文档频率:每个检索词在索引中出现的频率?频率越高,相关性越低。检索词出现在多数文档中会比出现在少数文档中的权重更低。
字段长度准则:字段的长度是多少?长度越长,相关性越低。 检索词出现在一个短的 title 要比同样的词出现在一个长的 content 字段权重更大
https://en.wikipedia.org/wiki/Okapi_BM25
https://en.wikipedia.org/wiki/Tf–idf
https://www.elastic.co/guide/en/elasticsearch/reference/current/similarity.html
https://www.jianshu.com/p/70d1c3045c11
如果有条件,尽可能使用SSD硬盘, 不错的CPU。ES的厉害之处在于ES本身的分布式架构以及lucene的特性。IO的提升,会极大改进ES的速度和性能。
初期规划,设置合适的分片数,集群节点数。
使用alias:生产提供服务的索引,切记使用别名提供服务,而不是直接暴露索引名称,避免后续因为业务变更或者索引数据需要reindex等情况造成业务中断。
冷热数据隔离(如日志数据)
避免宽表
在索引中定义太多字段是一种可能导致映射爆炸的情况,这可能导致内存不足错误和难以恢复的情况,这个问题可能比预期更常见,index.mapping.total_fields.limit ,默认值是1000
避免稀疏索引
因为索引稀疏之后,对应的相邻文档id的delta值会很大,lucene基于文档id做delta编码压缩导致压缩率降低,从而导致索引文件增大,同时,es的keyword,数组类型采用doc_values结构,每个文档都会占用一定的空间,即使字段是空值,所以稀疏索引会造成磁盘size增大,导致查询和写入效率降低。
作者:架构文摘
链接:https://juejin.cn/post/6868081322779230216
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
系统层面的调优主要是内存的设定与避免交换内存。
综合来说,可以考虑以下几个方面来提升写索引的性能:
https://cloud.tencent.com/developer/article/1436787
translog flush间隔调整
在默认设置下,translog的持久化策略为每个请求都flush,这个是影响es写入速度的最大因素,如果可以接受一定概率的数据丢失,可以将刷盘设置为周期性或者到一定大小再刷盘。
索引刷新间隔refresh_interval
默认索引的refresh_interval为1秒,这意味着数据写入1秒后就可以搜索到,每次索引的refresh会产生一个新的Lucene段,这会导致频繁的segment merge行为,如果不需要这么高的搜索实时性,应该降低索引refresh周期。
使用bulk请求
批量写比一个索引请求只写单个文档的效率高得多。
自动生成doc ID
写入文档时如果外部指定了id,则es会先尝试读取原来的doc版本号,以判断是否要更新,这会涉及一次读磁盘的操作,通过自动生成doc id可以避免。
减少副本的数量
ES 为了保证集群的可用性,提供了 Replicas(副本)支持,然而每个副本也会执行分析、索引及可能的合并过程,所以 Replicas 的数量会严重影响写索引的效率。
当写索引时,需要把写入的数据都同步到副本节点,副本节点越多,写索引的效率就越慢。
如果我们需要大批量进行写入操作,可以先禁止 Replica 复制,设置 index.number_of_replicas: 0 关闭副本。在写入完成后,Replica 修改回正常的状态。
随着数据量的变化,段的数量会越来越多,消耗的多文件句柄数及 CPU 就越多,查询效率就会下降。
由于 Lucene 段合并的计算量庞大,会消耗大量的 I/O,所以 ES 默认采用较保守的策略,让后台定期进行段合并,如下所述:
索引写入效率下降:当段合并的速度落后于索引写入的速度时,ES 会把索引的线程数量减少到 1。
这样可以避免出现堆积的段数量爆发,同时在日志中打印出“now throttling indexing”INFO 级别的“警告”信息。
提升段合并速度:ES 默认对段合并的速度是 20m/s,如果使用了 SSD,我们可以通过以下的命令将这个合并的速度增加到 100m/s。
PUT /_cluster/settings
{
"persistent" : {
"indices.store.throttle.max_bytes_per_sec" : "100mb"
}
}
不需要评分时,使用过滤查询,减少评分过程
文档模型
文档应该合理建模,特别是应该避免join操作,嵌套(nested)会使查询慢几倍,父子关系可能使查询慢数百倍。
优化日期搜索
在使用日期范围检索时,使用now的查询通常不能缓存,因为匹配到的范围一直在变化,我们可以将日期四舍五入到分钟,甚至可以将时间分为一个大的可缓存部分和一个小的不可缓存部分。
避免大结果集和深翻
定期删除
由于在 Lucene 中段具有不变性,每次进行删除操作后不会立即从硬盘中进行实际的删除,而是产生一个 .del 文件记录删除动作。
随着删除操作的增长,.del 文件会越来也多。当我们进行查询操作的时候,被删除的数据还会参与检索中,然后根据 .del 文件进行过滤。.del 文件越多,查询过滤过程越长,进而影响查询的效率。
当机器空闲时,我们可以通过如下命令删除文件,来提升查询的效率
https://cloud.tencent.com/developer/article/1436787
https://cloud.tencent.com/developer/article/1436787
https://www.jianshu.com/p/472963f7a3f4
https://www.jianshu.com/p/883325b7bbda?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
https://zhuanlan.zhihu.com/p/43437056
原文:https://www.cnblogs.com/caozibiao/p/15177147.html