Elasticsearch & Logstash -- 一些经验总结

本文作为一些实践经验的总结,未必是最佳实践,欢迎大家交流。


ES集群环境:

节点配置:  8核CPU, 48GB内存, 4*2TB磁盘JBOD

节点数量:9

操作系统:CentOS 6.4 Final

JDK 1.7.0_45

ES版本:1.2.1

1.  通过管线化的思路增加索引速度

如果要保证准实时性,索引速度必须得到保证。为此进行了多种尝试。包括增加ES_HEAPSIZE到16GB,禁用 _all字段,设置所有字段值为not_analyzed。在采取这些措施之后,进行的测试中其索引速度仍不过3000/s,与预期差距较大,部署模式是:


测试程序发送数据 -> Redis消息队列 -> Logstash -> Elasticsearch集群


在测试进行时做了一些观察,发现在整个过程中Redis队列中是有大量的数据积压的。这里有两种可能,一是消费者处理能力不足;二是Redis队列本身就是瓶颈。为此,在这个基础之上又加入一个Logstash实例来对接到那一个Redis队列上,发现索引速度甚至还不如之前,由此可断定瓶颈应该就在Redis消息队列上。


Redis消息队列一个进程只能利用一个CPU核心,如果有大量的读写同时发生,那么势必会发生抢占CPU资源的现象。这也在测试过程中得到了体现:如果测试发送程序将数据全部发送到Redis队列中后,每秒的索引量会有一个明显的提升。


为了解决Redis队列的瓶颈问题,使用多管线机制,来增加整个系统的吞吐量,为此,我们同时部署了多个Redis实例,和对应数量的Logstash实例:


测试程序发送数据 -> Redis消息队列1 -> Logstash-> Elasticsearch集群

测试程序发送数据 -> Redis消息队列2 -> Logstash2 -> Elasticsearch集群

测试程序发送数据 -> Redis消息队列3 -> Logstash3 -> Elasticsearch集群

...

通过多次尝试,发现随着管线数量的增加,索引速度也会有相应提高,最终我们使用了5条管线,将索引速度稳定在了1.2W~1.5W/s,这个已经可以满足我们目前的需求了。


采用管线机制的好处是,扩展性是显而易见的。


2. 聚合过程中通过script机制进行数据类型转换

其实这更多是一个设计问题,而且这里的数据类型转换方案,在数据量较大的时候,并不具有可用性,对于几千万的数据的类型转换大概需要几十秒。这里提一下,主要还是为了说明ES里还是可以进行数据类型转换的~

{
    "size": 0,
    "query": {
        "filtered": {
            "filter": {
                "regexp": {
                    "who": "[0-9]+" 
                }
            }
        }
    },
    "aggs": {
        "max_who": {
            "max": {
                "script": "Double.parseDouble(_source.who)" 
            }
        }
    }
}

以上的script部分使用的是默认的支持语言mvel脚本,它还支持Python,Javascript等脚本语言,不过都需要单独安装,并且需要在所有的节点上都安装对应的语言插件。

在ES 1.3版本使用,默认支持的语言已经成为Groovy了,这点需要了解一下。还是要再次提醒一下,对于大量的数据,从我们的测试来看,这个数据类型转换的过程还是很慢的。


3. 使用terms过滤器,同时找到多个确切值

比如,我们想过滤出价格为20或者30的所有的文档,我们可以这样写:

        GET /my_store/products/_search
        {
            "query" : {
                "filtered" : {
                    "filter" : {
                        "terms" : { #1
                            "price" : [20, 30]
                        }
                    }
                }
            }
        }

等价于SQL的:

SELECT * 

FROM products

WHERE price IN (20, 30);

采用这种方式,要比使用多个bool过滤器的组合要简单许多。


4. 日期直方图(date_histogram)聚合的补零操作

有这样一种场景,我们要看一年中的某一指标,在每个月的变化情况。这时,如果其中的几个月没有数据记录,那么这几个月的结果就不会在聚合结果中显示。为了显示上的完整性,前端的应用程序可以对返回的数据做一下处理,但是,date_histogram已经内置了这样的补零操作,非常方便使用:

            curl -XGET 'localhost:9200/cars/transactions/_search?search_type=count&pretty=true' -d '
            {
                "aggs": {
                    "sales": {
                        "date_histogram": {
                            "field": "sold",
                            "interval": "month",
                            "format": "yyyy-MM-dd",
                            "min_doc_count": 0, 
                            "extended_bounds": { 
                                "min": "2014-01-01",
                                "max": "2014-12-31"
                            }
                        }
                    }
                }
            }'

以上的查询会返回,2014年每个月的汽车销售量的分布,其中为了显示完整性而设置的参数有两个:

min_doc_count: 即使这个月中没有任何的销售记录(也就是0),也将其包含在聚合结果中,值为0即可

extended_bounds: 显示日期的范围强制扩展到2014年一整年的

这样,得出来的结果对于图表显示来说就非常友好了。


5. 索引时日期格式的自动识别

在索引数据时, ES会自动尝试识别日期类型,默认情况下,ES会将yyyy-MM-ddTHH:mm:ssZ格式的数据视作日期类型,并以日期类型存储,像是"2014-08-01T03:27:33.730Z"这样的串会被识别成日期格式,而类似“2014-08-01 12:00:00”这样的串,只会被识别成字符串。这也是需要注意的一点。


以上就是到目前为止,使用ES过程中总结的一些经验,可能给出的方案并非最佳,如有更好方案,欢迎大家进一步的交流。

你可能感兴趣的:(elasticsearch)