Loggly服务底层的很多核心功能都使用了ElasticSearch作为搜索引擎。就像Jon Gifford(译者注:Loggly博客作者之一)在他近期关于“ElasticSearch vs Solr”的文章中所述,日志管理在搜索技术方面产生一些粗暴的需求,坚持下来以后,它必须能够:
在超大规模数据集上可靠地进行准实时索引 - 在我们的案例中,每秒有超过100,000个日志事件与此同时,在该索引上可靠高效地处理超大量的搜索请求
当时我们正在构建Gen2日志管理服务,想保证使用的所有ElasticSearch配置信息,可以获得最优的索引和搜索性能。悲剧的是,我们发现想在ElasticSearch文档里找到这样的信息非常困难,因为它们不只在一个地方。本文总结了我们的学习经验,可作为一个配置属性的参考检查单(checklist)用于优化你自己应用中的ES。
小贴士1:规划索引、分片 以及集群增长情况
ES使得创建大量索引和超大量分片非常地容易,但更重要的是理解每个索引和分片都是一笔开销。如果拥有太多的索引或分片,单单是管理负荷就会影响到ES集群的性能,潜在地也会影响到可用性方面。这里我们专注于管理负荷,但运行大量的索引/分片依然会非常显著地影响到索引和检索性能。
我们发现影响管理负荷的最大因素是集群状态数据的大小,因为它包含了集群中每个索引的所有mapping数据。我们曾经一度有单个集群拥有超过900MB的集群状态数据。该集群虽然在运行但并不可用。
让我们通过一些数据来了解到底发生了什么 。。。。。。
假如有一个索引包含50k的mapping数据(我们当时是有700个字段)。如果每小时生成一个索引,那么每天将增加24 x 50k的集群状态数据,或者1.2MB。如果需要在系统中保留一年的数据,那么集群状态数据将高达438MB(以及8670个索引,43800个分片)。如果与每天一个索引(18.25MB,365个索引,1825个分片)作比较,会看到每小时的索引策略将会是一个完全不同的境况。
幸运的是,一旦系统中有一些真实数据的话,实际上非常容易做这些预测。我们应当能够看到集群必须处理多少状态数据和多少索引/分片。在上到生产环境之前真的应该演练一下,以便防止凌晨3:00收到集群挂掉的电话告警。
在配置方面,我们完全可以控制系统中有多少索引(以及有多少分片),这将让我们远离危险地带。
小贴士2:在配置前了解集群的拓扑结构
Loggly通过独立的master节点和data节点来运行ES。这里不讨论太多的部署细节(请留意后续博文),但为了做出正确的配置选择,需要先确定部署的拓扑结构。
另外,我们为索引和搜索使用单独的ES client节点。这将减轻data节点的一些负载,更重要的是,这样我们的管道就可以和本地客户端通信,从而与集群的其他节点通信。
可通过设置以下两个属性的值为true或false来创建ES的data节点和master节点:
Master node: node.master:true node.data:false Data node: node.master:false node.data:true Client node: node.master:false node.data:false以上是相对容易的部分,现在来看一些值得关注的ES高级属性。对大多数部署场景来说默认设置已经足够了,但如果你的ES使用情况和我们在log管理中遇到的一样难搞,你将会从下文的建议中受益良多。
小贴士3: 内存设置
Linux把它的物理RAM分成多个内存块,称之为分页。内存交换(swapping)是这样一个过程,它把内存分页复制到预先设定的叫做交换区的硬盘空间上,以此释放内存分页。物理内存和交换区加起来的大小就是虚拟内存的可用额度。
内存交换有个缺点,跟内存比起来硬盘非常慢。内存的读写速度以纳秒来计算,而硬盘是以毫秒来计算,所以访问硬盘比访问内存要慢几万倍。交换次数越多,进程就越慢,所以应该不惜一切代价避免内存交换的发生。
ES的mlockall属性允许ES节点不交换内存。(注意只有Linux/Unix系统可设置。)这个属性可以在yaml文件中设置:
bootstrap.mlockall: true在5.x版本中,已经改成了bootstrap.memory_lock: true.
mlockall默认设置成false,即ES节点允许内存交换。一旦把这个值加到属性文件中,需要重启ES节点才可生效。可通过以下方式来确定该值是否设置正确:
curl :9200/_nodes/process?pretty如果你正在设置这个属性,请使用-DXmx选项或ES_HEAP_SIZE属性来确保ES节点分配了足够的内存。
小贴士4:discovery.zen属性控制ElasticSearch的发现协议
Elasticsearch默认使用服务发现(Zen discovery)作为集群节点间发现和通信的机制。Azure、EC2和GCE也有使用其他的发现机制。服务发现由discovery.zen.*开头的一系列属性控制。
在0.x和1.x版本中同时支持单播和多播,且默认是多播。所以要在这些版本的ES中使用单播,需要设置属性discovery.zen.ping.multicast.enabled为false。
从2.0开始往后服务发现就仅支持单播了。