ES使用规范

一、基础规范

Elasticsearch适用场景

(1).待检索数据类型复杂:

如需要查询的数据有结构化数据(关系型数据库等)、半结构化数据(网页、XML等)、非结构化数据(日志、图片、图像等)等,而Elasticsearch则可以对以上数据类型进行清洗、分词、建立倒排索引等一系列操作(建立索引),然后提供全文检索(查询)的能力。

(2).检索条件多样化(如涉及模糊查询),常规查询无法满足:

全文检索(查询)可以包括简单的词和短语,或者词或短语的多种形式。

(3). 站内搜索、垂直搜索

电商网站的商品搜索可以说是站内搜索,和垂直搜索有交集。让用户通过搜索关键词就能直达目标内容

集群初始化阶段

(1)、 建议单个分片最大容量30GB-50GB。 根据索引预计承载的最大数据容量和单个分片容量确定主分片个数。 为了提升数据可靠性,合理设置副本分片个数。如:三节点的集群,业务请求若为query请求,且每次都要请求每个分片,则建议一般不要超过12个分片,单节点拥有分片不建议超过3个。

(2)、将最小堆大小(Xms)和最大堆大小(Xmx)设置为彼此相等防止内存抖动

(3)、给ES的内存配置不是越大越好,建议不能超过32GB,不同jdk版本最大边界值是不同的,对于32位小于32G JVM才采用内存对象指针压缩技术,不然对象指针需要占用很大的内存; 一旦你越过那个神奇的30-32G的边界,指针就会切回普通对象的指针,意味着就算给ES100G的内存,ES仍然最多使用30-32G的内存;

(4)、预留一半的内存给lucene假如设备的内存是64G , 那就要预留出32G的内存给Lucene,Lucene的设计目的是把底层OS里的数据缓存到内存中。Lucene的段是分别存储到单个文件中的,这些文件都是不会变化的,所以很利于缓存,同时操作系统也会把这些段文件缓存起来,以便更快的访问。建议是把50%的内存给elasticsearch,剩下的50%也不会没有用处的,Lucene会很快吞噬剩下的这部分内存

(5)、ES节点需配置禁用swap。swap内存空间出现不足的情况操作系统将物理空间划分出来一部分当做内存空间使用。这将大大降低机器的性能

(6)、系统参数配置:用户打开最大文件数65535、以及线程数至少为4096、开辟虚拟内存262144

(7)、锁定内存,防止进行内存的交换使用swapping。bootstrap.memory_lock : true

(8)、es的垃圾回收器设置成G1

(9)、安装IK。ES中采用标准分词器进行分词,这种方式并不适用于中文网站,因此需要修改ES对中文友好分词

二、开发规范

1.避免超大的document

我们不考虑引擎层的限制,超大的document在实际生产环境中是很不好的。超大document会耗费更多的网络资源,内存资源和磁盘资源,甚至对那些不要求获取_source的请求,也是一样,因为es需要从_source中提取_id字段,对于超大document这个获取_id字段的过程的资源开销也是很大的。而将这种超大document写入es也会使用大量的内存,占用内存空间的大小甚至会是documdent本身大小的数倍。近似匹配的搜索,比如phrase query,以及高亮显示,对超大document的资源开销会更大,因为这些操作的性能开销直接跟document的大小成正比。

2.避免稀疏的数据

(1).避免将没有任何关联性的数据写入同一个索引

我们必须避免将结构完全不一样的数据写入同一个索引中,因为结构完全不一样的数据,field是完全不一样的,会导致index数据非常稀疏。最好将这种数据写入不同的索引中,如果这种索引数据量比较少,那么可以考虑给其很少的primary shard,比如1个,避免资源浪费。

(2).对document的结构进行规范化/标准化

对不同类型的document进行标准化。例如:如果所有的document都有一个时间戳field,不过有的叫做timestamp,有的叫做creation_date,那么可以将不同document的这个field重命名为相同的字段,尽量让documment的结构相同。有的document有一个字段,叫做goods_type,但是有的document没有这个字段,此时可以对没有这个字段的document,补充一个goods_type给一个默认值,比如default

(3).避免使用多个types存储不一样结构的document

很多人会很喜欢在一个index中放很多个types来存储不同类型的数据。但是其实不是这样的,最好不要这么干,如果你在一个index中有多个type,但是这些type的数据结构不太一样,那么这些type实际上底层都是写到这个索引中的,还是会导致稀疏性。如果多个type的结构不太一样,最好放入不同的索引中,不要写入一个索引中。(针对于ES7之前的版本)
在ES7.X版本中去掉type就是为了提高ES处理数据的效率

(4).对稀疏的field禁用norms和doc_values

对于不参与评分以及不排序的字段禁止norms和doc_values字段,因为这两个字段的存储机制类似,都是每个field有一个全量的存储,对存储浪费很大。如果一个field不需要考虑其相关度分数,那么可以禁用norms,如果不需要对一个field进行排序或者聚合,那么可以禁用doc_values字段。

3.index索引命名规范

(1). 力求简洁明义

能够一眼看出来这索引是用来存什么数据的。最好是能以产品线名词来英文命名索引。且名字加后缀_v1,方便后续因为主分片数调整或者调整某字段类型等原因需要reindex。或按照日期来进行命名Rollver index

(2). 受文件系统的限制。

仅可能为小写字母,不能下划线开头。索引名称作为磁盘上的目录名称,这些名称必须符合不同操作系统的约定。需遵守下列规则:
1>. 不能包括 , /, *, ?, “, <, >, |, 空格, 逗号, #

2>. 7.0版本之前可以使用冒号:,但不建议使用并在7.0版本之后不再支持

3>. 不能以这些字符 -, _, + 开头

4>. 不能包括 ‘.’

5>. 长度不能超过 255 个字符

(3). 对字段命名规范

不能完全使用空格。但用于对象类型,’.’不能解析到有效路径。同样这个命名也是不容许的,因为以点号结尾会造成混淆。所以’.’不能使用。

(4). 不用默认配置和动态mapping、数据用途(类型、分词、存储、排序)弄清

需要根据业务的实际场景来进行mapping,mapping 需严格模式(dynamic:strict)

(5). 建议开发可根据实际业务需求进行索引设置

1>. 找到translog flush 的最优配置 。调整index.translog.sync_interval和index.translog.flush_threshold_size设置(注:此选项需要根据业务场景来确定。系统可以接受一定几率的数据丢失)。

2>. 动态调整index.refresh_interval以满足业务需求。如果实时性要求不高,可以调大刷新频率(默认是1s,可以调到30s甚至更大)。

3>. 如不是业务需要,尽量不要指定映射为“nested”类型。

4>. 禁用 _all 字段。_all可以在搜索的时候不指定特定字段,从所有字段中检索.如果你不需要这个特性,可以禁用 _all。

5>. 对字段不分词或者不索引, 字段的index 属性设置为:not_analyzed或者 no 可以节省很多运算,降低 CPU 占用。尤其是 binary 类型,默认情况下占用 CPU 非常高,而这种类型根本不需要进行分词做索引。

三、操作规范

搜索结果不要返回过大的结果集

es是一个搜索引擎,所以如果用这个搜索引擎对大量的数据进行搜索,并且返回搜索结果中排在最前面的少数结果,是非常合适的。然而,如果要做成类似数据库的东西,每次都进行大批量的查询,是很不合适的。如果真的要做大批量结果的查询,记得考虑用scroll api。

运维过程,按照节点上磁盘的种类进行数据的冷热分离。如:业务数据索引放到SSD磁盘,备份数据放到HDD磁盘