1.硬件选择
Elasticsearch的基础是Lucene,所有的“索引”和“文档”数据都存储在磁盘中,配置数据存储在哪块磁盘可通过修改elasticsearch.yml文件;
磁盘在现代服务器上通常都是瓶颈,Elasticsearch重度使用磁盘,磁盘处理的吞吐量越大,节点就越稳定,如下有一些优化磁盘I/O的技巧;
1.1.使用SSD(固态硬盘)。它相比较机械硬盘性能好太多;
1.2.使用RAID 0。条带化RAID会提高磁盘I/O,但是当一块硬盘故障时整个就都故障了,不要使 用镜像或者奇偶校验RAID因为副本已经提供了这个功能;
1.3.使用多块硬盘,并允许Elasticsearch通过多个path.data目录配置把数据条带化分配在它
们上面;
1.4.不要使用远程挂载的存储,比如NFS,或者SMB/CIFS;
2.分片策略
2.1.合理设置分片数
2.1.1.分片数并不是越多越好
1.一个分片底层即为一个Lucene索引,会消耗一定文件句柄、内存、CPU;
2.每一个搜索请求都需要命中索引中的每一个分片,如果每一个分片处于不同的节点还好
(并行且消耗各自节点上的计算资源),但如果多个分片都在同一个节点上竞争使用相同的
资源,会造成ES性能降低;
3.用于计算相关度的词频统计信息是基于分片的,如果有很多分片且这些分片上的数据都
很少会导致很低的相关度;
即:索引创建时指定的分片数创建后是不支持动态修改的;副本数支持动态修改);
2.1.2.分片遵循原则
原则一:控制每个分片占用的磁盘容量不超过ES的最大JVM堆空间设置,一般不超过
32G(例:如果索引的总容量为500G左右,那么分片大小在16个左右即可,当然需
要同时考虑原则二);
原则二:考虑下“节点”数量,一般一个节点有时候就是一台物理机,如果分片数量过多大大
超过了集群节点数会导致一个节点上有多个分片,一旦该节点故障,即使保持了1
个以上副本,同样有可能造成数据丢失,集群无法恢复,所以一般都设置分片数
不超过节点数的3倍;
分片&&副本&&节点数关系:
(节点数 <= (分片*副本数) + 1)
2.2.推迟分片分配
对于节点瞬时中断的问题,默认情况下ES集群会等待一分钟来查看节点是否会重新加入,
如果该中断节点在此时间内重新加入集群,该节点会保持现有的分片数据,不会触发新的分
片分配,这样就可以减少ES自动再平衡可用分片时所带来的极大开销;
delayed_timeout参数,可以延长再平衡的时间。该设置可以全局设置,也可以在
索引级别进行修改;
PUT /_all/_settings
{
"settings":{
"index_unassigned.node_left.delayed_timeout":"5m"
}
}
3.路由选择
当我们查询文档(数据)时,elasticsearch怎么知道数据保存在哪个分片中呢?它其实是通过这个计算公式来确定数据保存在哪个分片中的;
公式:hash(routing)%number_of_primary_shards[即:hash(id)%分片数]
说明:
routing默认是文档的id(ES每条文档记录都会有个默认的ID),也可以采用自定义值比如用户ID
作为文档ID;
实际有两种查询方式
方式一:不带routing查询
在查询时因为不知道要查询的数据在哪个分片上,所以整个步骤分为两步
分发:请求到达协调节点后,协调节点将查询请求分发到每个分片上;
聚合:协调节点搜索到每个分片上的查询结果,将查询结果排序后返回给用户;
因为要搜寻所有分片所有不带routing的查询方式效率较慢;
方式二:带routing查询
查询时通过routing可以直接定位到数据存放的分片位置,直接在计算出来的分片中去查询
数据就好,无需将请求发送至每一个分片上分别去查询,故检索效率高很多;
4.写入数据优化
ES的默认配置是综合了数据可靠性、写入速度、搜索实时性等因素。实际使用时我们可根据项目的需求进行偏向化的设置;
比如针对搜索性能要求不高,但对写入要求高的场景我们需尽可能的选择恰当的优化策略。综合来说可以考虑如下几个方面来提升写索引的性能;
1.加大Translog Flush,目的是降低Iops、Writeblock;
2.增加Index Refresh间隔,目的是减少Segment Merge的次数;
3.调整Bulk线程池和队列(批量数据提交);
4.优化节点间的任务分布;
5.优化Lucene层索引建立,目的是降低CPU及IO;
4.1.批量数据提交
ES提供了Bulk API支持批量操作,当我们有大量写入操作时可以使用Bulk来批量写入;
默认情况下Bulk默认设置批量提交数据不超过100M,数据条数一般是根据文档大小和服务器性能来确定的,我们在测试Bulk最大提交数据量与性能最优时,数据量大小每次可以5M~15M逐渐增加来确定最大Bukl数据大小与写入性能之间的最优点,当写入性能最优时此时设置的Bulk大小就是最合适的时候;
4.2.优化存储设备
ES是一种密集使用磁盘的应用,在“段”合并时会频繁操作磁盘,所以ES对磁盘的要求比较高,当磁盘性能提升后ES集群整体性能也就会大幅提高;
4.3.合理使用合并
Lucene以“段”的形式存储数据,当有新的数据写入索引时Lucene会自动创建一个新的段。随着数量的变化,段的数量会越来越多消耗的文件句柄数及CPU就越多,查询的效率就会降低。由于Lucene段合并的计算量庞大会消耗大量的I/O,所以ES默认采取比较保守的策略,让后台定期进行段合并;
4.4.减少Refresh的次数
ES在新增数据时,采用了延迟写入的策略,默认情况下索引的refresh_interval为1秒。
Lucene将待写入的数据先写入到内存中,超过1秒(默认)会触发一次Refresh,然后Refresh会把内存中的数据刷新到操作系统的文件缓存系统中。如果我们对搜索的实时性要求不高可以将Refresh周期延长,例如30秒。这样可以减少Refresh刷新次数。但这同时意味着需要消耗更多的Heap内存;
4.5.加大Flush设置
Flush的主要目的是把文件缓存系统中的“段”持久化到磁盘,当Translog的数据达到512MB或30分钟时会触发一次Flush;
index.translog.flush_threshold_sise参数的默认值为512MB,我们可对此参数值进行修改;扩大参数值意味着文件缓存系统需要存储更多的数据,所以我们需要为操作系统的文件缓存系统留下足够的空间;
4.6.减少副本的数量
ES为了保证集群可用性,提供了Replicas(副本)支持,然而每个副本也会执行分析,索引及合并的过程,所以Replicas的数量会严重影响写索引的效率;
当写索引时需要把所有的数据都同步到副本节点,副本节点越多写索引的效率就越慢。如果我们需要大批量进行写入操作时可以先禁止Replicas复制,设置index.number_of_replicas:0关闭副本。在写入完成后再将Replicas修改回正常的状态;
5.内存设置
ES安装后默认设置的内存大小为1GB,可在jvm.option文件中对ES的内存进行设置;
-Xms:表示堆的初始化大小
-Xmx:表示可分配的最大内存
确保Xms和Xmx大小是相同的,其目的是为了能够在JVM垃圾回收机制清理完堆内存后,不需要重新分隔计算堆区的大小而浪费资源,可以减轻伸缩堆大小带来的压力;
ES堆内存分配原则:
1.不要超过物理内存的50%;
2.堆内存大小最好不要超过32GB;
6.重要配置项
参数名 | 参数值 | 说明 |
cluster.name | elasticsearch | 集群名称 |
node.name | node-1 | 集群节点名称(同一集群不可重复) |
node.master | true | 该节点是否有资格被选举为Master节点 |
node.data | true | 该节点是否存储索引数据(数据的增删改都是在data节点完成的) |
index.number_of_shards | 1 | 设置索引分片数(默认为1) |
index_number_of_replicas | 1 | 设置索引副本数(默认为1) |
transport.tcp.compress | true | 设置节点间传输数据是否压缩(默认为false) |
discovery.zen.minimum_master _nodes | 1 | 控制选举行为发生的最小集群主节点数;默认值为1,如果使用默认值会有“脑裂”风险。推荐:(集群候选主节点数/2) + 1 |
discovery.zen.ping.timeout | 3s | 设置集群中自动发现其它节点Ping连接超时的时间,默认为3s。在较差的网络环境下可延长时间,防止因误判该节点宕机从而导致分片转移 |