* Elasticsearch
** Elasticsearch 与 Lucene 之间的关系
Lucene 搜索引擎组件,使用java编写的,为了方便使用的搜索组件,主要的功能就
是建立索引然后进行搜索.本身不能直接使用,需要集成到应用中提供搜索服务.或
者说是完成搜索功能.下面介绍下Lucene的基本概念和建立索引与搜索索引基本
流程.
Lucene 的逻辑概念包括: index,segemnts,documents,field,term等.其关联关
系可以简要描述如下:index 表示索引,由一个或多个段组成;segments 表示段,
由一个或多个文档组成;documents 表示文档,由一个或多个域组成;fields 表示
域,由一个或多个词组成,可以理解为文档的属性;terms 表示词,原始字符串由分
词器进行分词后得到.
index -> segments -> documents -> fields -> terms
Lucene 建立索引流程:对于一个对象需要建立索引时,首先确定哪些属性需要建
立索引并进行预处理,然后使用分词器进行分词.根据分词结果建立索引,将数据
写入到指定索引目录.
Lucene 搜索基本流程:在搜索时,需要确定要搜索的描述(哪个属性,值是什么),
然后使用创建索引时相同的预处理和分词器.最后去索引目录中进行搜索操作.
Lucene 搜索过程中,基本都是按照fields进行搜索,所谓的全文搜索,是经过特殊
处理,将全部field按照特定的格式写入到特定的字段上,搜索这个字段来完成全
文搜索.
Elasticsearch 封装Lucene组件,开箱即用的可拓展的搜索引擎.可以通过tcp链
接和http(restful)等方式提供搜索服务,拓展性极强.
Elasticsearch 为了提供可拓展的搜索服务,提出了很多分布式概念.下面结合
Lucene的已有概念,进行简要描述.Elasticsearch 涉及到的具有代表性的概念包
括:cluster, node, indices, shard, doc, mapping, field, term,分别进行简
单描述:
closter 表示集群 一组Elasticsearch实例(node)所组成的集群.可以方便的进
行横向拓展.提供建立索引和搜索索引的能力. node表示集群中的工作节点,提供
服务相关操作.这些都是逻辑上的概念,条件运行一台物理机器上可以启动多个
node.node 的角色有两个,master和data.master 节点需要参与主master的选举,
并且负责参与集群外部请求的响应与分发和结果的汇集与聚合等操作. data 节
点只负责数据的存储与搜索等操作.一个集群当中可以有多个master和data.一个
node可以即是master同时也是data.同时一个节点既可以不是master同时也不是
data. 这样的节点作为一个搜索的负载均衡器.indices 逻辑上的索引结构,有自
己的索引结构定义(mapping),由一个或多个shard组成. shard 索引的具体结构,
对应lucene的index概念.存储建立索引的数据.并提供基本搜索能力.doc表示
documents 与lucene的文档概念相同. mapping 逻辑上表示indices所处理的文
档类型.用于说明doc的属性特征.同一个mapping中可以有多个类型. field 对应
lucene的field的概念,与其基本相同.term 对应lucene的term的概念,与其基本
相同.
Elasticsearch 的建立索引流程与搜索基本流程与lucene相比较,增加了master
节点对请求的处理以及分发到data节点和汇总各个节点请求的过程,其他基本类
似.
** 主节点选举策略
** 分片策略
** 路由规则
** 请求分发规则
** Elasticsearch 性能调优
*** gc策略调优
分配内存高达30或40G,超过CMS gc 设计的最大值,gc效果不是很理想。因此升
级jdk到1.8,采用g1策略。并在此基础上,结合验证服务器运行情况进行验证。
得到一系列gc调优的参数。减少平常简单查询触发full gc的次数,保证一般情
况下能够正常响应。
基本的调优参数如下:(针对64核心,128g机器) 一般的机器建议采用默认方式.
JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC"
JAVA_OPTS="$JAVA_OPTS -XX:MaxGCPauseMillis=500"
JAVA_OPTS="$JAVA_OPTS -XX:InitiatingHeapOccupancyPercent=30"
JAVA_OPTS="$JAVA_OPTS -XX:NewRatio=10"
JAVA_OPTS="$JAVA_OPTS -XX:G1ReservePercent=20"
JAVA_OPTS="$JAVA_OPTS -XX:SurvivorRatio=8"
JAVA_OPTS="$JAVA_OPTS -XX:ConcGCThreads=4"
JAVA_OPTS="$JAVA_OPTS -XX:G1HeapRegionSize=32"
*** elasticsearch 参数调优
在elasticsearch.yml中,修改其配置。
1、指定数据目录,方便磁盘空间的拓展。
path.data: /mnt/extra/hd/esdata
2、指定缓存策略,在一定程度上提高简单查询效率。
indices.cache.filter.size: 20%
indices.cache.query.size: 3%
indices.fielddata.cache.size: 20%
indices.breaker.fielddata.limit: 80%
3、修改段合并策略,保证其段合并不会占用大量资源。
indices.store.throttle.max_bytes_per_sec: 40m
index.merge.policy.max_merged_segment: 15gb
index.merge.scheduler.max_thread_count: 1
4、修改索引触发写磁盘的时间间隔,减少此过程中所产生段的数量。
index.translog.flush_threshold_ops: 100000
index.translog.flush_threshold_size: 512m
5、node 节点意外下线, 间隔多长时间重新分配分片.
index.unassigned.node_left.delayed_timeout: 5m
6、线程池大小设定修改
线程池默认设置为200,现在根据机器cpu核心数量进行适当调整,
threadpool:
index:
type: fixed
size: 4
threadpool:
search:
type: fixed
size: 4
threadpool:
bulk:
type: fixed
size: 4
*** 系统配置修改
改系统限制,对elasticsearch 创建单独的用户,对用户所占用的系统资源进行
修改。去掉不必要的限制(例如:虚拟内存大小等)。禁用这个用户使用 swap
空间。
在配置文件中添加
bootstrap.mlockall: true
修改配置linux 相关系统配置.
1、elasticsearch 用户禁用swap。
需要修改/etc/security/limits.conf的相关内容,使用elasticsearch用户来启动,
添加
elasticsearch - nofile 65000
elasticsearch - memlock unlimited
接下来修改/etc/pam.d/common-session文件,添加如下内容:
session required pam_limits.so
还需要重新登录。
2、取消其他限制
~/.bashrc
添加
ulimit -v unlimited
ulimit -m unlimited
然后 执行source ~/.bashrc
3 修改下系统参数vm.max_map_count的设置为262144
具体做法是在/etc/sysctl.conf中加入
vm.max_map_count = 262144
重新登录生效。
*** 索引方面的优化
精简索引结构,重新设计,提高可用性与可维护性.精简组件, web与hadoop方面直
接使用elasticsearch api,去掉anydrill.使得es可以获得更多的资源.
*** hadoop 中关于elasticsearch 方面的修改
修改其删除策略,原来的删除策略是使用anydrill,调用elasticsearch 的
delete by query api。并在删除结束后,直接调用flush api,触发段合并,这
样会消耗大量服务器资源,引发服务卡死。同时,delete by query api 在其后
续版本中存在内存溢出问题,进行修改,直接使用elasticsearch 来完成删除操
作,使用scroll api +bulk api 实现。优化业务逻辑,减少es数据执行天任务时
修要修改的数据量,提高任务执行效率.
*** 集群
尝试设置一个master node。两个data node,设置两个balancer。尝试三千万数
据全排,然后取最后面几条,data node内存使用变化不大,master node 内存
使用变化不大,排序所需要的内存,都在balancer中。这样可以保证集群较为稳
定,当出现排序操作时,balancer的内容会大幅增长,但是由于jvm容器的隔离,
即使balancer挂掉,其他组件也不会出现问题,这样会提高系统稳定性。
** Elasticsearch 批量请求使用技巧
elasticsearch api 相关说明非常多,这里只针对批量请求处理的api进行简单说
明.涉及到的api包括scroll api 和bulk api.
// 创建scroll request,并获取结果
SearchResponse scrollResp = client.prepareSearch(this.indiceName)
.setSearchType(SearchType.SCAN)
.setScroll(new TimeValue(
ElasticsearchConstValue.CLIENT_SCROLL_TIME_OUT))
.setQuery(query)
.setSize(ElasticsearchConstValue.CLIENT_BULK_SIZE)
.addField("_id").execute().actionGet();
// 创建bulkRequest
BulkRequestBuilder bulkRequest = client.prepareBulk();
BulkResponse bulkResponse = null;
// 循环处理scroll请求的结果.
while (true) {
for (SearchHit hit : scrollResp.getHits().getHits()) {
// 构造批量请求.
bulkRequest.add(client.prepareDelete(this.indiceName,
this.indiceType, hit.getId()));
}
if (scrollResp.getHits().getHits().length != 0) {
// 统一获取批量请求结果并,重新构造请求.
bulkResponse = bulkRequest.execute().actionGet();
if (bulkResponse != null) {
if (bulkResponse.hasFailures()) {
LOG.error("bulk has error: "
+ bulkResponse.buildFailureMessage());
}
}
bulkRequest = client.prepareBulk();
}
scrollResp = client
.prepareSearchScroll(scrollResp.getScrollId())
.setScroll(new TimeValue(
ElasticsearchConstValue.CLIENT_SCROLL_TIME_OUT))
.execute().actionGet();
if (scrollResp.getHits().getHits().length == 0) {
break;
}
}
// 释放elasticsearch 服务器资源
client.prepareClearScroll().addScrollId(scrollResp.getScrollId())
.execute().actionGet();
** 常见问题
*** Elasticsearch 卡死
在执行大量搜索请求时,发现Elasticsearch卡死, 可以考虑将段合并的资源限制
下,然后将线程池的大小限制下. 这样可以保证es不会卡死.
*** Elasticsearch 报直接内存溢出错误
Elasticsearch 如果报 oom direct memory,则需要注意,Elasticsearch 中集成
的netty模块产生的这个问题,这个问题产生的原因是netty的客户端与服务端通
信过程中,如果某一端的处理能力有限,另一端的数据产生量非常大时,在数据产
生端,会爆出oom direct memory错误. 这个问题是可以重现的,而且在
elasticsearch的 1.7.5 以下的版本中都会出现.建议检查数据接收端是什么原
因导致处理能力慢.是否是数据接收端有性能瓶颈.