本次分享主要包含两个方面的实战经验:索引性能和查询性能。php
一. 索引性能(Index Performance)html
首先要考虑的是,索引性能是否有必要作优化?前端
索引速度提升与否?主要是看瓶颈在什么地方,如果 Read DB(产生DOC)的速度比较慢,那瓶颈不在 ElasticSearch 时,优化就没那么大的动力。实际上 Elasticsearch 的索引速度仍是很是快的。java
咱们有一次遇到 Elasticsearch 升级后索引速度很慢,查下来是新版 IK 分词的问题,修改分词插件后获得解决。node
若是须要优化,应该如何优化?mysql
SSD 是经济压力能承受状况下的不二选择。减小碎片也能够提升索引速度,天天进行优化仍是颇有必要的。在初次索引的时候,把 replica 设置为 0,也能提升索引速度。web
bulk 是否是必定须要呢?redis
如果 Elasticsearch 普通索引已经致使高企的 LA,IO 压力已经见顶,这时候 bulk 也没法提供帮助,SSD 应该是很好的选择。sql
在 create doc 速度能跟上的时候,bulk 是能够提升速度的。docker
记得 threadpool.index.queue_size ++,否则会出现索引时队列不够用的状况。
indices.memory.index_buffer_size:10% 这个参数能够进行适当调整。
调整以下参数也能够提升索引速度:index.translog.flush_threshold_ops:50000 和 refresh_interval。
二. 查询性能(Query Perofrmance)
王道是什么?routing,routing,仍是 routing。
咱们为了提升查询速度,减小慢查询,结合本身的业务实践,使用多个集群,每一个集群使用不一样的 routing。好比,用户是一个routing维度。
在实践中,这个routing 很是重要。
咱们碰到一种状况,想把此维度的查询(即用户查询)引到非用户routing 的集群,结果集群彻底顶不住!
在大型的本地分类网站中,城市、类目也是一个不错的维度。咱们使用这种维度进行各类搭配。而后在前端分析查询,把各个不一样查询分别引入合适的集群。这样作之后,每一个集群只须要不多的机器,并且保持很小的 CPU Usage 和 LA。从而查询速度够快,慢查询几乎消灭。
分合?
分别(索引和routing)查询和合并(索引和routing)查询,即此分合的意思。
索引愈来愈大,单个 shard 也很巨大,查询速度也愈来愈慢。这时候,是选择分索引仍是更多的shards?
在实践过程当中,更多的 shards 会带来额外的索引压力,即 IO 压力。
咱们选择了分索引。好比按照每一个大分类一个索引,或者主要的大城市一个索引。而后将他们进行合并查询。如:http://cluster1:9200/shanghai,beijing/_search?routing=fang,自动将查询中城市属性且值为上海或北京的查询,且是房类目的,引入集群 cluster1,而且routing等于fang。
http://cluster1:9200/other/_search?routing=jinan,linyi。小城市的索引,咱们使用城市作 routing,如本例中同时查询济南和临沂城市。
http://cluster1:9200/_all/_search,所有城市查询。
再如: http://cluster2:9200/fang,che/_search?routing=shanghai_qiche,shanghai_zufang,beijing_qiche,beijing_zufang。查询上海和北京在小分类汽车、整租的信息,那咱们进行如上合并查询。并将其引入集群 cluster2。
使用更多的 shards?
除了有 IO 压力,并且不能进行所有城市或所有类目查询,由于彻底顶不住。
Elastic 官方文档建议:一个 Node 最好不要多于三个 shards。
如果 "more shards”,除了增长更多的机器,是没办法作到这一点的。
分索引,虽然一个 Node 总的shards 仍是挺多的,可是一个索引能够保持3个之内的shards。
咱们使用分索引时,全量查询是能够顶住的,虽然压力有点儿高。
索引愈来愈大,资源使用也愈来愈多。如果要进行更细的集群分配,大索引使用的资源成倍增长。
有什么办法能减少索引?显然,建立 doc 时,把不须要的 field 去掉是一个办法;可是,这须要对业务很是熟悉。
有啥立竿见影的办法?
根据咱们信息的特色,内容(field:description)占了索引的一大半,那咱们就不把 description 索引进 ES,doc 小了一倍,集群也小了一倍,所用的资源(Memory, HD or SSD, Host, snapshot存储,还有时间)大大节省,查询速度天然也更快。
那要查 description 怎么办?
上面的实例中,咱们能够把查询引入不一样集群,天然咱们也能够把 description 查询引入一个非实时(也能够实时)集群,这主要是咱们业务特色决定的,由于description查询所占比例很是小,使得咱们能够这样作。
被哪些查询搞过?第一位是 Range 查询,这货的性能真不敢恭维。在最热的查询中,如果有这货,确定是很是痛苦的,网页变慢,查询速度变慢,集群 LA 高企,严重的时候会致使集群 shard 自动下线。因此,建议在最热的查询中避免使用 Range 查询。
Facet 查询,在后续版本这个被 aggregations 替代,咱们大多数时候让它在后端进行运算。
三. 其余
1)线程池
线程池咱们默认使用 fixed,使用 cached 有可能控制很差。主要是比较大的分片 relocation时,会致使分片自动下线,集群可能处于危险状态。在集群高压时,如果 cached ,分片也可能自动下线。自 1.4 版本后,咱们就一直 fixed,至于新版是否还存在这个问题,就没再试验了。
两个缘由:一是 routing王道带来的改善,使得集群一直低压运行;二是使用fixed 后,已经极少遇到自动下线shard了。
咱们前面说过,user 是一个很是好的维度。这个维度很重要,routing 效果很是明显。其余维度,须要根据业务特色,进行组合。
因此咱们的集群一直是低压运行,就不多再去关注新版本的 使用 cached 配置问题。
hreadpool.search.queue_size 这个配置是很重要的,通常默认是够用了,能够尝试提升。
2)优化
天天优化是有好处的,能够大大改善查询性能。max_num_segments 建议配置为1。虽然优化时间会变长,可是在高峰期前能完成的话,会对查询性能有很大好处。
3) JVM GC的选择:选择 G1仍是 CMS?
应该大多数人仍是选择了 CMS,咱们使用的经验是 G1 和 CMS 比较接近;但和 CMS 相比,仍是有一点距离,至少在咱们使用经验中是如此。
JVM 32G 现象?
128G内存的机器配置一个 JVM,而后是巨大的 heapsize (如64G)?
仍是配多个 JVM instance,较小的 heapsize(如32G)?
个人建议是后者。实际使用中,后者也能帮助咱们节省很多资源,并提供不错的性能。具体请参阅 “Don’t Cross 32 GB!" (https://www.elastic.co/guide/en/elasticsearch/guide/current/heap-sizing.html#compressed_oops)
跨 32G 时,有一个现象,使用更多的内存,好比 40G,效果还不如31G!
这篇文档值得你们仔细阅读。
JVM 还有一个配置 bootstrap.mlockall: true,比较重要。这是让 JVM 启动的时候就 锁定 heap 内存。
有没有用过 较小的 heapsize,加上SSD?我据说有人使用过,效果还不错,固然,咱们本身还没试过。
4)插件工具
推荐 kopf,是一个挺不错的工具,更新及时,功能完备,可让你忘掉不少 API :)。
索引,查询,和一些重要的配置,是今天分享的重点。
Q&A
Q1:您建议生产环境JVM采用什么样的参数设置?FULL GC频率和时间如何?
CMS 标准配置。
ES_HEAP_NEWSIZE=?G
JAVA_OPTS="$JAVA_OPTS -XX:+UseCondCardMark"
JAVA_OPTS="$JAVA_OPTS -XX:CMSWaitDuration=250"
JAVA_OPTS="$JAVA_OPTS -XX:+UseParNewGC"
JAVA_OPTS="$JAVA_OPTS -XX:+UseConcMarkSweepGC"
JAVA_OPTS="$JAVA_OPTS -XX:CMSInitiatingOccupancyFraction=75"
JAVA_OPTS="$JAVA_OPTS -XX:+UseCMSInitiatingOccupancyOnly"
Full GC 不多去care 它了。咱们使用 Elasticsearch 在JVM上花的时间不多。
Q2:生产环境服务器如何配置性价比较高?单机CPU核数、主频?内存容量?磁盘容量?
内存大一些,CPU 多核是必要的,JVM 和 Elasticsearch 会充分使用内存和多核的。 关于内存容量的问题,不少是 JVM Tunning 的问题。 磁盘容量没啥要求。
Q3: 分组统计(Facet 查询或 aggregations )大多数时候让它在后端进行运算,怎么实现?应用若是须要实时进行统计并且并发量较大,如何优化?
由于咱们是网站系统,因此对于 Facet 请求,引导到后端慢慢计算,前端初始的时候可能没数据,可是此后就会有了。
若是是精确要求的话,那就只能从 提升 facet 查询性能去下手,好比 routing、filter、cache、更多的内存...
Q4:存进Elasticsearch的数据,timestamp是UTC时间,Elasticsearch集群会在UTC 0点,也就是北京时间早上8点自动执行优化?如何改参数设置这个时间?
咱们没有使用Elasticsearch的自动优化设置。本身控制优化时间。
Q5:个人Java程序,log4j2 Flume appender,而后机器上的Flume agent ,直接Elasticsearch 的sink avro到 es节点上,多少个agent 连在单个Elasticsearch节点比较合适 ?
ElasticSearch自己是一个分布式计算集群,因此,请求平均分配到每一个 node 便可。
Q6:我代码里直接用 Java API 生成Flume appender 格式,Flume agent 里interceptor去拆分几个字段,这样是否是太累了?比较推荐的作法是否是仍是各业务点本身控制字段,调用Elasticsearch API 生成索引内容?
业务点本身控制生成的文档吧?若是须要产生不一样routing,而且分了索引,这些实际上是业务相关的。routing和不一样索引,都是根据业务状况哪些查询比较集中而进行处理的。
Q7:您见过或管理过的生产环境的Elasticsearch数据量多大?
咱们使用 Elasticsearch 进行某些业务处理,数据量过亿。
Q8:SSD性能提高多少?
SSD 对索引帮助很是大,效果当当的,提升几十倍应该是没问题。不过,咱们没有试过彻底使用SSD顶查询,而是使用内存,内存性价比仍是不错的。
Q9:咱们如今有256个shard,用uid作routing,全部查询都是走routing。每一个shard有30多G,每次扩容很慢,有什么建议?
能够考虑使用分合查询吗? 或者使用更多的维度? 256个 shard 确实比较难以控制。可是若是是分索引和查询,比more shards(256) 效果应该会好很多。
Q10:Elasticsearch排序等聚合类的操做须要用到fielddata,查询时很慢。新版本中doc values聚合查询操做性能提高很大,大家有没有用过?
Facet 查询须要更大的内存,更多的 CPU 资源。能够考虑routing、filter、cache等多种方式提升性能。
Aggs 未来是要替换 Facet,建议尽快替换原来的facet API。
Q11:Elasticsearch配置bootstrap.mlockall,咱们在使用中发现会致使启动很慢,由于Elasticsearch要获取到足够的内存才开始启动。
启动慢是能够接受的,启动慢的缘由也许是内存没有有效释放过,好比文件 cached了。 内存充足的状况下,启动速度仍是蛮快的,能够接受。 JVM 和 Lucene 都须要内存,通常是JVM 50%, 剩下的50% 文件cached 为Lucene 使用。
Q12:优化是一个开销比较大的操做,天天优化的时候是否会致使查询不可用?如何优化这块?
优化是开销很大的。不会致使查询不可用。优化是值得的,大量的碎片会致使查询性能大大下降。 若是很是 care 查询,能够考虑多个集群。在优化时,查询 skip 这个集群就能够。
Q13:Elasticsearch适合作到10亿级数据查询,天天千万级的数据实时写入或更新吗?
10亿是能够作到的,若是文档轻量,10亿所占的资源还不是不少。
ELK 使用 Elasticsearch ,进行日志处理天天千万是小case吧?
不过咱们除了使用 ELK 进行日志处理,还进行业务处理,10亿级快速查询是能够作到,不过,须要作一些工做,好比索引和shards的分分合合:)
Q14:Elasticsearch相比Solr有什么优点吗?
咱们当年使用 Solr 的时候,Elasticsearch 刚出来。他们都是基于 Lucene的。 Elasticsearch 相对于 solr ,省事是一个优势。并且如今 Elasticsearch 相关的应用软件也愈来愈多。Solr 和 Lucene 集成度很高,更新版本是和Lucene一块儿的,这是个优势。
不少年没用 Solr了,毕竟那时候数据量还不大,因此折腾的就少了,主要仍是折腾 JVM。因此,就再也不过多的比较了。
Q15:分词用的什么组件?Elasticsearch自带的吗?
咱们使用 IK 分词,不过其余分词也不错。IK分词更新仍是很及时的。并且它能够远程更新词典。:)
Q16: reindex有没有好的方法?
reindex 这个和 Lucene 有关,它的 update 就是 delete+ add。
Q17:以上面的两个例子为例 : 是存储多份一样的数据么?
是两个集群。第一个集群使用大城市分索引,不过,还有大部分小城市合并一个索引。大城市仍是用类目进行routing,小城市合并的索引就使用城市进行routing 。
第二个集群,大类分得索引,好比fang、che,房屋和车辆和其余类目在一个集群上,他们使用 city+二级类目作routing。
Q18:集群部署有没有使用 Docker ? 咱们使用的时候 ,同一个服务器 节点之间的互相发现没有问题 ,可是跨机器的时候须要强制指定network.publish_host 和discovery.zen.ping.unicast.hosts 才能解决集群互相发现问题。
咱们使用puppet进行部署。暂没使用 Docker。 强制指定network.publish_host 和discovery.zen.ping.unicast.hosts 才能解决集群,跨IP段的时候是有这个须要。
Q19:您建议采用什么样的数据总线架构来保证业务数据按routing写入多个Elasticsearch集群,怎么保证多集群Elasticsearch中的数据与数据库中数据的一致性?
咱们之前使用 PHP在web代码中进行索引和分析 query,而后引导到不一样集群。 如今咱们开发了一套Go rest系统——4sea,使用 Redis + elastic 以综合提升性能。
索引时,更新db的同时,提交一个文档 ID 通知4sea 进行更新,而后根据配置更新到不一样集群。
数据提交到查询时,就是分析 query 并引导到不一样集群。
这套 4sea 系统,有机会的能够考虑开源,不算很复杂的。
Q20: 能介绍一下Elasticsearch的集群rebanlance、段合并相关的原理和经验吗?
“段”合并?,咱们是根据业务特色,产生几个不同的集群,主要仍是 routing 不同。
shards 比较平均很重要的,因此选择routing 维度是难点,选择城市的话,大城市所在分片会很是大,此时能够考虑 分索引,几个大城市几个索引,而后小城市合并一个索引。
若是 shards 大小分布平均的话,就不关心如何 allocation 了。
Q21:关于集群rebalance,其实就是cluster.routing.allocation配置下的那些rebalance相关的设置,好比allow_rebalance/cluster_concurrent_rebalance/node_initial_primaries_recoveries,推荐怎么配置?
分片多的状况下,这个才是须要的吧。
分片比较少时,allow_rebalance disable,而后手动也能够接受的。
分片多,通常状况会自动平衡。咱们对主从不太关心。只是若是一台机器多个 JVM instance (多个 Elasticsearch node)的话,咱们写了个脚原本避免同一shard 在一台机器上。
cluster_concurrent_rebalance 在恢复的时候根据状况修改。正常状况下,再改为默认就行了。
node_initial_primaries_recoveries,在保证集群低压的状况下,不怎么care。
kopf 上面有好多这种配置,你能够多试试。
Q22:合并查询是异步请求仍是同步请求?作缓存吗?
合并查询是 Elasticsearch 自带 API。
Q23:用httpurlconnection请求的时候,会发现返回请求很耗时,通常怎么处理?
尽量减小慢查询吧?咱们不少工做就是想办法如何减小慢查询,routing和分分合合,就是这个目的。
Q24:生产环境单个节点存储多少G数据?
有大的,有小的。小的也几十G了。不过根据咱们本身的业务特色,某些集群就去掉了全文索引。惟一的全文索引,使用基本的routing(比较平衡的routing,好比user。城市的话,就作不到平衡了,由于大城市数据不少),而后作了 快照,反正是增量快照,1小时甚至更短期均可以考虑!!!去掉全文索引的其余业务集群,就小多了。