话题 (elasicsearch) 已与当前话题合并
elasticsearch

elasticsearch

在搜索数量不大于10000时,有必要用searchAfter吗?

Elasticsearchrochy 回复了问题 • 2 人关注 • 1 个回复 • 38 次浏览 • 2 小时前 • 来自相关话题

给ES 9200 端口配置域名无效

Elasticsearchjuin 回复了问题 • 4 人关注 • 5 个回复 • 135 次浏览 • 1 天前 • 来自相关话题

ES的jvm内存不足会有怎样的错误?

Elasticsearchtiantianle 回复了问题 • 4 人关注 • 3 个回复 • 175 次浏览 • 5 天前 • 来自相关话题

ES重索引(reindex)时如何不停止写入服务(业务存在少量物理删除文档操作)?

Elasticsearchfanmo3yuan 回复了问题 • 13 人关注 • 7 个回复 • 1996 次浏览 • 5 天前 • 来自相关话题

_cat/indices API查询得到的docs.count数量和实际查询的数量对不上,差不多正好1倍的关系。这个docs.count包含了副本吗?

Elasticsearchzqc0512 回复了问题 • 3 人关注 • 2 个回复 • 161 次浏览 • 5 天前 • 来自相关话题

es能否9200端口监听在127.0.0.1 9300端口监听到0.0.0.0这样配置?

Elasticsearchmedcl 回复了问题 • 4 人关注 • 3 个回复 • 99 次浏览 • 5 天前 • 来自相关话题

es 偶发查询缓慢

Elasticsearchzqc0512 回复了问题 • 8 人关注 • 12 个回复 • 421 次浏览 • 5 天前 • 来自相关话题

es统计相关问题

Elasticsearchrochy 回复了问题 • 3 人关注 • 1 个回复 • 84 次浏览 • 6 天前 • 来自相关话题

ik+pinyin 实现搜索建议时

Elasticsearchrochy 回复了问题 • 3 人关注 • 1 个回复 • 116 次浏览 • 6 天前 • 来自相关话题

elasticsearch是否可以关闭查询缓存?

Elasticsearchrochy 回复了问题 • 2 人关注 • 1 个回复 • 105 次浏览 • 2019-02-13 17:46 • 来自相关话题

elasticsearch能否支持中文拼音纠错?

Elasticsearchrochy 回复了问题 • 3 人关注 • 1 个回复 • 2881 次浏览 • 2019-02-13 17:43 • 来自相关话题

filter查询不到数据,字段值一样,mapping也没有发现什么不一样。

Elasticsearchrochy 回复了问题 • 2 人关注 • 2 个回复 • 113 次浏览 • 2019-02-13 15:57 • 来自相关话题

elasticsearch集群高写入的问题?

Elasticsearchtaoyantu 回复了问题 • 5 人关注 • 3 个回复 • 389 次浏览 • 2019-02-11 17:08 • 来自相关话题

Elastic日报 第529期 (2019-02-03)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 585 次浏览 • 2019-02-03 10:20 • 来自相关话题

1.在Elasticsearch数据库上公开2400万个信用和抵押记录。 http://t.cn/EtdTYAs 2.使用Elasticsearch构建长期安全运营平台。 http://t.cn/EtdHXAV 3.(自备梯子)飞行汽车比您想象的更接近现实。 http://t.cn/EtdQtfV 编辑:至尊宝 归档:https://elasticsearch.cn/article/6356 订阅:https://tinyletter.com/elastic-daily
1.在Elasticsearch数据库上公开2400万个信用和抵押记录。 http://t.cn/EtdTYAs 2.使用Elasticsearch构建长期安全运营平台。 http://t.cn/EtdHXAV 3.(自备梯子)飞行汽车比您想象的更接近现实。 http://t.cn/EtdQtfV 编辑:至尊宝 归档:https://elasticsearch.cn/article/6356 订阅:https://tinyletter.com/elastic-daily

es查询问题。

Elasticsearchmedcl 回复了问题 • 2 人关注 • 1 个回复 • 520 次浏览 • 2019-01-31 16:21 • 来自相关话题

在搜索数量不大于10000时,有必要用searchAfter吗?

回复

Elasticsearchrochy 回复了问题 • 2 人关注 • 1 个回复 • 38 次浏览 • 2 小时前 • 来自相关话题

给ES 9200 端口配置域名无效

回复

Elasticsearchjuin 回复了问题 • 4 人关注 • 5 个回复 • 135 次浏览 • 1 天前 • 来自相关话题

ES的jvm内存不足会有怎样的错误?

回复

Elasticsearchtiantianle 回复了问题 • 4 人关注 • 3 个回复 • 175 次浏览 • 5 天前 • 来自相关话题

ES重索引(reindex)时如何不停止写入服务(业务存在少量物理删除文档操作)?

回复

Elasticsearchfanmo3yuan 回复了问题 • 13 人关注 • 7 个回复 • 1996 次浏览 • 5 天前 • 来自相关话题

es能否9200端口监听在127.0.0.1 9300端口监听到0.0.0.0这样配置?

回复

Elasticsearchmedcl 回复了问题 • 4 人关注 • 3 个回复 • 99 次浏览 • 5 天前 • 来自相关话题

es 偶发查询缓慢

回复

Elasticsearchzqc0512 回复了问题 • 8 人关注 • 12 个回复 • 421 次浏览 • 5 天前 • 来自相关话题

es统计相关问题

回复

Elasticsearchrochy 回复了问题 • 3 人关注 • 1 个回复 • 84 次浏览 • 6 天前 • 来自相关话题

ik+pinyin 实现搜索建议时

回复

Elasticsearchrochy 回复了问题 • 3 人关注 • 1 个回复 • 116 次浏览 • 6 天前 • 来自相关话题

elasticsearch是否可以关闭查询缓存?

回复

Elasticsearchrochy 回复了问题 • 2 人关注 • 1 个回复 • 105 次浏览 • 2019-02-13 17:46 • 来自相关话题

elasticsearch能否支持中文拼音纠错?

回复

Elasticsearchrochy 回复了问题 • 3 人关注 • 1 个回复 • 2881 次浏览 • 2019-02-13 17:43 • 来自相关话题

filter查询不到数据,字段值一样,mapping也没有发现什么不一样。

回复

Elasticsearchrochy 回复了问题 • 2 人关注 • 2 个回复 • 113 次浏览 • 2019-02-13 15:57 • 来自相关话题

elasticsearch集群高写入的问题?

回复

Elasticsearchtaoyantu 回复了问题 • 5 人关注 • 3 个回复 • 389 次浏览 • 2019-02-11 17:08 • 来自相关话题

es查询问题。

回复

Elasticsearchmedcl 回复了问题 • 2 人关注 • 1 个回复 • 520 次浏览 • 2019-01-31 16:21 • 来自相关话题

询问一个Elasticsearch关于ansj的分词问题

回复

Elasticsearchrochy 回复了问题 • 3 人关注 • 3 个回复 • 224 次浏览 • 2019-01-30 10:10 • 来自相关话题

Elastic日报 第529期 (2019-02-03)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 585 次浏览 • 2019-02-03 10:20 • 来自相关话题

1.在Elasticsearch数据库上公开2400万个信用和抵押记录。 http://t.cn/EtdTYAs 2.使用Elasticsearch构建长期安全运营平台。 http://t.cn/EtdHXAV 3.(自备梯子)飞行汽车比您想象的更接近现实。 http://t.cn/EtdQtfV 编辑:至尊宝 归档:https://elasticsearch.cn/article/6356 订阅:https://tinyletter.com/elastic-daily
1.在Elasticsearch数据库上公开2400万个信用和抵押记录。 http://t.cn/EtdTYAs 2.使用Elasticsearch构建长期安全运营平台。 http://t.cn/EtdHXAV 3.(自备梯子)飞行汽车比您想象的更接近现实。 http://t.cn/EtdQtfV 编辑:至尊宝 归档:https://elasticsearch.cn/article/6356 订阅:https://tinyletter.com/elastic-daily

Hive 与 ElasticSearch 的数据交互

Elasticsearchrochy 发表了文章 • 0 个评论 • 321 次浏览 • 2019-01-27 14:52 • 来自相关话题

本文将详细介绍利用 ES 与 Hive 直接的数据交互;通过 Hive 外部表的方式,可以快速将 ES 索引数据映射到 Hive 中,使用易于上手的 Hive SQL 实现对数据的进一步加工。

一、开发环境

1、组件版本

  • CDH 集群版本:6.0.1
  • ES 版本:6.5.1
  • Hive 版本:2.1.1
  • ES-Hadoop 版本:6.5.1

2、Hive 简介

Hive 在 Hadoop 生态系统中扮演着数据仓库的角色,借助 Hive 可以方便地进行数据汇总、即席查询以及分析存储在 Hadoop 文件系统中的大型数据集。

Hive 通过类 SQL 语言(HSQL)对 Hadoop 上的数据进行抽象,这样用户可以通过 SQL 语句对数据进行定义、组织、操作和分析;在 Hive 中,数据集是通过表(定义了数据类型相关信息)进行定义的,用户可以通过内置运算符或用户自定义函数(UDF)对数据进行加载、查询和转换。

3、Hive 安装 ES-Hadoop

官方推荐的安装方式:

使用 add jar

add jar /path/elasticsearch-hadoop.jar

使用 hive.aux.jars.path

$ bin/hive --auxpath=/path/elasticsearch-hadoop.jar

修改配置(hive-site.xml)

<property>
  <name>hive.aux.jars.path</name>
  <value>/path/elasticsearch-hadoop.jar</value>
  <description>A comma separated list (with no spaces) of the jar files</description>
</property>

CDH6.X 推荐的安装方法

elasticsearch-hadoop.jar 复制到 Hive 的 auxlib 目录中,然后重启 Hive 即可。

cp elasticsearch-hadoop.jar /opt/cloudera/parcels/CDH/lib/hive/auxlib/

二、Hive 与 ElasticSearch 的数据交互

1、数据类型对照表

请务必注意,ES 中的类型是 index/_mapping 中对应的数据类型,非 _source 里面数据的类型。

Hive type Elasticsearch type
void null
boolean boolean
tinyint byte
smallint short
int int
bigint long
double double
float float
string string
binary binary
timestamp date
struct map
map map
array array
union not supported (yet)
decimal string
date date
varchar string
char string

2、建立 Hive 外部表

CREATE EXTERNAL TABLE default.surface(
    water_type STRING,
    water_level STRING,
    monitor_time TIMESTAMP,
    sitecode STRING,
    p492 DOUBLE,
    p311 DOUBLE,
    status STRING
)
STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler'
TBLPROPERTIES(
    'es.resource'='ods_data_day_surface*/doc',
    'es.query'='?q=status:001'
    'es.nodes'='sky-01','es.port'='9200',
    'es.net.http.auth.user'='sky',
    'es.net.http.auth.pass'='jointsky',
    'es.date.format'='yyyy-MM-dd HH:mm:ss',
    'es.ser.reader.value.class'='com.jointsky.bigdata.hive.EsValueReader'
    'es.mapping.names'='waterType:water_type,monitortime:monitor_time'
);

3、配置项说明

es.resource

es.resource 用于设置 ES 资源的位置,默认该配置项同时设置了读和写的索引,当然也可以分别设置读写索引名称:

  • es.resource.read:设置读取位置;
  • es.resource.write:设置写入位置。

es.query

es.query 设置查询过滤条件,目前支持 uri queryquery dslexternal resource 三种设置方式。

# uri (or parameter) query
es.query = ?q=costinl

# query dsl
es.query = { "query" : { "term" : { "user" : "costinl" } } }

# external resource
es.query = org/mypackage/myquery.json

es.mapping.names

es.mapping.names 用于设置 Hive 与 ES 的字段映射关系,如果不设置,则默认字段名不发生变化(即为 data type 区域定义的字段名);此外该部分还用于定义 Hive 到 ES 的数据映射类型。

'es.mapping.names' = 'date:@timestamp , url:url_123 ')

其他通用字段的说明请参考文章:使用 ES-Hadoop 将 Spark Streaming 流数据写入 ES

4、自定义日期类型解析

目前将 ES 的 date 类型映射到 Hive 的 TIMESTAMP 类型时,ES-Hadoop 组件只能识别时间戳格式或者标准的 XSD 格式的日期字符串:

@Override
protected Object parseDate(Long value, boolean richDate) {
    return (richDate ? new TimestampWritable(new Timestamp(value)) : processLong(value));
}

@Override
protected Object parseDate(String value, boolean richDate) {
    return (richDate ? new TimestampWritable(new Timestamp(DatatypeConverter.parseDateTime(value).getTimeInMillis())) : parseString(value));
}

关于 XSD(XML Schema Date/Time Datatypes)可用参考文章:https://www.w3schools.com/xml/schema_dtypes_date.asp

为了兼容自定义的日期格式,需要编写自定义的日期读取类:


import org.apache.hadoop.hive.serde2.io.TimestampWritable;
import org.elasticsearch.hadoop.cfg.Settings;
import org.elasticsearch.hadoop.hive.HiveValueReader;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;

public class EsValueReader extends HiveValueReader {
    private String dateFormat;
    private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private static final String DEFAULT_DATE_FORMAT_MIN = "yyyy-MM-dd HH:mm";
    private static final String DEFAULT_DATE_FORMAT_HOUR = "yyyy-MM-dd HH";
    private static final String DEFAULT_DATE_FORMAT_DAY = "yyyy-MM-dd";

    @Override
    public void setSettings(Settings settings) {
        super.setSettings(settings);
        dateFormat = settings.getProperty("es.date.format");
    }

    @Override
    protected Object parseDate(String value, boolean richDate) {
        if (value != null && value.trim().length() > 0 && DEFAULT_DATE_FORMAT.equalsIgnoreCase(dateFormat)) {
            if (richDate){
                if (value.length() == 16){
                    return new TimestampWritable(new Timestamp(parseDate(value, DEFAULT_DATE_FORMAT_MIN).getTime()));
                }
                if (value.length() == 13){
                    return new TimestampWritable(new Timestamp(parseDate(value, DEFAULT_DATE_FORMAT_HOUR).getTime()));
                }
                if (value.length() == 10){
                    return new TimestampWritable(new Timestamp(parseDate(value, DEFAULT_DATE_FORMAT_DAY).getTime()));
                }
                return new TimestampWritable(new Timestamp(parseDate(value, DEFAULT_DATE_FORMAT).getTime()));
            }
            return parseString(value);
        }
        return super.parseDate(value, richDate);
    }

    /**
     * 解析日期,根據指定的格式進行解析.<br>
     * 如果解析錯誤,則返回null
     * @param stringDate 日期字串
     * @param format 日期格式
     * @return 日期型別
     */
    private static Date parseDate(String stringDate, String format) {
        if (stringDate == null) {
            return null;
        }
        try {
            return parseDate(stringDate, new String[] { format });
        } catch (ParseException e) {
            return null;
        }
    }

    public static Date parseDate(String str, String... parsePatterns) throws ParseException {
        return parseDateWithLeniency(str, parsePatterns, true);
    }

    private static Date parseDateWithLeniency(
            String str, String[] parsePatterns, boolean lenient) throws ParseException {
        if (str == null || parsePatterns == null) {
            throw new IllegalArgumentException("Date and Patterns must not be null");
        }

        SimpleDateFormat parser = new SimpleDateFormat();
        parser.setLenient(lenient);
        ParsePosition pos = new ParsePosition(0);
        for (String parsePattern : parsePatterns) {
            String pattern = parsePattern;
            if (parsePattern.endsWith("ZZ")) {
                pattern = pattern.substring(0, pattern.length() - 1);
            }
            parser.applyPattern(pattern);
            pos.setIndex(0);
            String str2 = str;
            if (parsePattern.endsWith("ZZ")) {
                str2 = str.replaceAll("([-+][0-9][0-9]):([0-9][0-9])$", "$1$2");
            }
            Date date = parser.parse(str2, pos);
            if (date != null && pos.getIndex() == str2.length()) {
                return date;
            }
        }
        throw new ParseException("Unable to parse the date: " + str, -1);
    }
}

上述代码的 Maven 依赖

<dependencies>
    <dependency>
        <groupId>org.apache.hive</groupId>
        <artifactId>hive-exec</artifactId>
        <version>2.1.1</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch-hadoop</artifactId>
        <version>6.5.4</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

自定义日期解析包的部署

代码编写完成后,将代码进行打包,然后将打包好的 jar 包放置到 Hive 的 auxlib 目录中,然后重启 Hive 即可;该步骤与 ES-Hadoop 的安装步骤一样。

在编写 Spark 程序从 Hive 中读取数据的时候,需要添加对该包的依赖以及对 ES-Hadoop 的依赖。

三、总结

经过上述的步骤,Hive 与 ES 的映射已经不成问题,如果想从 ES 中导出数据,可用借助 HSQL insert into table XXX select * from XXXXX; 的方式从 ES 中读取数据写入到 HDFS;当然通过更为复杂的 HSQL 可以将数据进行处理,并将数据重新写入到 ES 或者存储到 HDFS。

充分利用 ES 的查询、过滤和聚合,可以很好的去服务数据标准化、数据清洗、数据分布情况等 ETL 流程。


Any Code,Code Any!

扫码关注『AnyCode』,编程路上,一起前行。

Elastic日报 第522期 (2019-01-27)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 171 次浏览 • 2019-01-27 10:35 • 来自相关话题

1.在现有Elasticsearch集群中添加或删除节点。 http://t.cn/EtUHo2i 2.运行400+节点Elasticsearch集群。 http://t.cn/EtUHqmF 3.(自备梯子)亚马逊变得比你意识到的更强大。 http://t.cn/EtUHBLe 编辑:至尊宝 归档:https://elasticsearch.cn/article/6348 订阅:https://tinyletter.com/elastic-daily
1.在现有Elasticsearch集群中添加或删除节点。 http://t.cn/EtUHo2i 2.运行400+节点Elasticsearch集群。 http://t.cn/EtUHqmF 3.(自备梯子)亚马逊变得比你意识到的更强大。 http://t.cn/EtUHBLe 编辑:至尊宝 归档:https://elasticsearch.cn/article/6348 订阅:https://tinyletter.com/elastic-daily

自研基于StanfordNLP的ES分词插件

ElasticsearchGod_lockin 发表了文章 • 5 个评论 • 245 次浏览 • 2019-01-22 19:32 • 来自相关话题

为ES构建Stanford NLP分词插件

Stanford NLP?

Stanford分词器是斯坦福大学NLP团队维护的一个开源分词器,支持了包括中文、英文…的语言,而且除了分词之外,它还支持了包括词性分析、情感分析…的各种功能。\ 这俩是这个project的项目主页

Why Stanford core NLP?

  市面上确实会有很多很有名的开源分词器,比如IK、Jieba,还有一些其他团队和公司提供的开源/商用的分词器,他们各有优劣。但是在各种分词器上比较了一大堆的分词case之后,我们发现Stanford NLP似乎是最适合我们当前需求的一个,因为我们不仅仅需要分词,还需要一些包括情感分析之类在内的更多的一些功能。

我们公司是做金融数据的搜索推荐的,在对比了各家分词器之后我们老板觉得Stanford NLP的效果最好,但是作为算法出身的人,他实现了一套非常重的分词、排序、搜索的服务。

在对比如研报、财报之类的信息进行搜索的时候确实会比较有效,但是在对经济类的新闻进行搜索的时候就会显得十分的笨重。

基于这个背景,我开始试图在ES里面引入老板推崇的Stanford 分词器来适应他的搜索、分词的需要,同时也能够不通过他那个笨重的分词排序服务来对我们系统中大量的经济、金融类的新闻进行分词、索引,并提供和他自己分词效果类似的分词和检索服务。

Why this project

我在包括百度、某谷姓404网站、GitHub以及国内的中文社区(Elastic中文社区)在内的各种地方搜过也问过了,但是似乎没有一个直接开箱可用的分词插件。所以,我只剩一条路了,就是搭建一个自己的插件来引用这个分词器。

How

对ES来说,插件主要分为两个部分:

  1. 让ES可以看到的部分(class extends Plugin)
  2. 自己行使职能的部分(functional part)

plugin

  1. 为了让ES可以加载我们的plugin,我们需要先继承Plugin类,然后我们这个是个分词器插件,所以还要实现AnalysisPlugin类
  2. 看过ES源码或者其他分词器源码的同学应该会知道,分词器插件需要实现两个方法,一个用来提供tokenizer,一个是analyzer分别对应分词器中的这俩。
    • 重写Map<String, AnalysisModule.AnalysisProvider<TokenizerFactory>>是为了可以提供搜索用分词器
    • 重写Map<String, AnalysisModule.AnalysisProvider<AnalyzerProvider<? extends Analyzer>>>是为了可以提供索引用分词器
  3. 在这个分词器里面我们主要是依靠Tokenizer来实现分词的

functional class

分词器,特别是Tokenizer主要是靠重写三个方法来实现分词的

  1. incrementToken:用来确定每一个词元,输出每一个单词(字)以及它的位置、长度等
  2. reset:用来重制分词结果
  3. end:用来告诉ES,这段文本的分词已经结束了

所以我们主要需要重写的就是这仨方法,当然了,为了能让分词器正确的使用,我们还需要添加一些分词器的配置和初始化的内容,具体代码不写了可以参考我的git,主要讲两个坑:

  1. ES是通过配置文件里的路径来寻找对应的插件类
  2. 然后通过配置文件里的key和刚才提到的代码里的key来寻找对应的分词器,所以这俩地方不要写错了 #plugin-descriptor.properties: classname=org.elasticsearch.plugin.analysis.AnalysisSDPlugin #plugin-descriptor.properties: name=stanford-core-nlp
  3. 在开发过程中由于有java-security的存在,所以需要通过AccessController来调用和加载我们需要的外部jar包

odds and ends

  1. Stanford分词器里面包含了很多功能,目前我使用了分词的部分
  2. 分词器自带词典文件,不过如果要做词典的修改可能需要解包,修改,再重新打包
  3. 我现在hardcode了一大堆的标点符号在里面,后面可能会去优化一下部分逻辑
  4. 待完成的功能还有其他功能包括情感分析之类的

also see

GitHub 地址

Elastic日报 第515期 (2019-01-20)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 196 次浏览 • 2019-01-20 08:26 • 来自相关话题

1.Java应用日志导入ELK。 http://t.cn/E5GiA1T 2.使用Tokens分发Cassandra数据。 http://t.cn/E5GIOd5 3.(自备梯子)为什么如此难以让计算机像人一样说话? http://t.cn/EqFOf04 编辑:至尊宝 归档:https://elasticsearch.cn/article/6337 订阅:https://tinyletter.com/elastic-daily
1.Java应用日志导入ELK。 http://t.cn/E5GiA1T 2.使用Tokens分发Cassandra数据。 http://t.cn/E5GIOd5 3.(自备梯子)为什么如此难以让计算机像人一样说话? http://t.cn/EqFOf04 编辑:至尊宝 归档:https://elasticsearch.cn/article/6337 订阅:https://tinyletter.com/elastic-daily

Elastic日报 第508期 (2019-01-13)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 230 次浏览 • 2019-01-13 10:43 • 来自相关话题

1.创建DSL。 http://t.cn/EqcmScm 2.使用ANTLR从GSA迁移到Elasticsearch。 http://t.cn/Eqc3j1w 3.(自备梯子)将定义2019年的技术。 http://t.cn/EqUQ61i 编辑:至尊宝 归档:https://elasticsearch.cn/article/6329 订阅:https://tinyletter.com/elastic-daily
1.创建DSL。 http://t.cn/EqcmScm 2.使用ANTLR从GSA迁移到Elasticsearch。 http://t.cn/Eqc3j1w 3.(自备梯子)将定义2019年的技术。 http://t.cn/EqUQ61i 编辑:至尊宝 归档:https://elasticsearch.cn/article/6329 订阅:https://tinyletter.com/elastic-daily

Elastic日报 第501期 (2019-01-06)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 230 次浏览 • 2019-01-06 08:51 • 来自相关话题

1.Elasticsearch查询与Spring Data。 http://t.cn/EGM5RCs 2.Spring Data Elasticsearch介绍。 http://t.cn/EAE698A 3.(自备梯子)区块链是互联网失败的提示。 http://t.cn/EbmQ42J 编辑:至尊宝 归档:https://elasticsearch.cn/article/6319 订阅:https://tinyletter.com/elastic-daily
1.Elasticsearch查询与Spring Data。 http://t.cn/EGM5RCs 2.Spring Data Elasticsearch介绍。 http://t.cn/EAE698A 3.(自备梯子)区块链是互联网失败的提示。 http://t.cn/EbmQ42J 编辑:至尊宝 归档:https://elasticsearch.cn/article/6319 订阅:https://tinyletter.com/elastic-daily

Elastic日报 第494期 (2018-12-30)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 218 次浏览 • 2018-12-30 09:58 • 来自相关话题

1.使用ElasticSearch进行全文检索。 http://t.cn/Eb9Ahhr 2.使用Flink和Kafka构建数据管道。 http://t.cn/Eb92onY 3.(自备梯子)Jupyter Notebook 扩展。 http://t.cn/EyD8Ao5 编辑:至尊宝 归档:https://elasticsearch.cn/article/6312 订阅:https://tinyletter.com/elastic-daily
1.使用ElasticSearch进行全文检索。 http://t.cn/Eb9Ahhr 2.使用Flink和Kafka构建数据管道。 http://t.cn/Eb92onY 3.(自备梯子)Jupyter Notebook 扩展。 http://t.cn/EyD8Ao5 编辑:至尊宝 归档:https://elasticsearch.cn/article/6312 订阅:https://tinyletter.com/elastic-daily

Elastic日报 第487期 (2018-12-23)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 193 次浏览 • 2018-12-23 10:03 • 来自相关话题

1.使用Elasticsearch进行简单标记。 http://t.cn/E4pK0fk 2.Java中的Elasticsearch指南。 http://t.cn/E4pXPl4 3.(自备梯子)智能家居技术仍然不够智能。 http://t.cn/E4CNtpJ 编辑:至尊宝 归档:https://elasticsearch.cn/article/6218 订阅:https://tinyletter.com/elastic-daily
1.使用Elasticsearch进行简单标记。 http://t.cn/E4pK0fk 2.Java中的Elasticsearch指南。 http://t.cn/E4pXPl4 3.(自备梯子)智能家居技术仍然不够智能。 http://t.cn/E4CNtpJ 编辑:至尊宝 归档:https://elasticsearch.cn/article/6218 订阅:https://tinyletter.com/elastic-daily

Day 20 - Elastic性能实战指南

Adventlaoyang360 发表了文章 • 10 个评论 • 644 次浏览 • 2018-12-20 09:14 • 来自相关话题

让Elasticsearch飞起来!——性能优化实践干货

0、题记

Elasticsearch性能优化的最终目的:用户体验。 关于爽的定义——著名产品人梁宁曾经说过“人在满足时候的状态叫做愉悦,人不被满足就会难受,就会开始寻求。如果这个人在寻求中,能立刻得到即时满足,这种感觉就是爽!”。 Elasticsearch的爽点就是:快、准、全! 关于Elasticsearch性能优化,阿里、腾讯、京东、携程、滴滴、58等都有过很多深入的实践总结,都是非常好的参考。本文换一个思路,基于Elasticsearch的爽点,进行性能优化相关探讨。

1、集群规划优化实践

1.1 基于目标数据量规划集群

在业务初期,经常被问到的问题,要几个节点的集群,内存、CPU要多大,要不要SSD? 最主要的考虑点是:你的目标存储数据量是多大?可以针对目标数据量反推节点多少。

1.2 要留出容量Buffer

注意:Elasticsearch有三个警戒水位线,磁盘使用率达到85%、90%、95%。 不同警戒水位线会有不同的应急处理策略。 这点,磁盘容量选型中要规划在内。控制在85%之下是合理的。 当然,也可以通过配置做调整。

1.3 ES集群各节点尽量不要和其他业务功能复用一台机器。

除非内存非常大。 举例:普通服务器,安装了ES+Mysql+redis,业务数据量大了之后,势必会出现内存不足等问题。

1.4 磁盘尽量选择SSD

Elasticsearch官方文档肯定推荐SSD,考虑到成本的原因。需要结合业务场景, 如果业务对写入、检索速率有较高的速率要求,建议使用SSD磁盘。 阿里的业务场景,SSD磁盘比机械硬盘的速率提升了5倍。 但要因业务场景而异。

1.5 内存配置要合理

官方建议:堆内存的大小是官方建议是:Min(32GB,机器内存大小/2)。 Medcl和wood大叔都有明确说过,不必要设置32/31GB那么大,建议:热数据设置:26GB,冷数据:31GB。 总体内存大小没有具体要求,但肯定是内容越大,检索性能越好。 经验值供参考:每天200GB+增量数据的业务场景,服务器至少要64GB内存。 除了JVM之外的预留内存要充足,否则也会经常OOM。

1.6 CPU核数不要太小

CPU核数是和ESThread pool关联的。和写入、检索性能都有关联。 建议:16核+

1.7 超大量级的业务场景,可以考虑跨集群检索

除非业务量级非常大,例如:滴滴、携程的PB+的业务场景,否则基本不太需要跨集群检索。

1.8 集群节点个数无需奇数

ES内部维护集群通信,不是基于zookeeper的分发部署机制,所以,无需奇数。 但是discovery.zen.minimum_master_nodes的值要设置为:候选主节点的个数/2+1,才能有效避免脑裂。

1.9 节点类型优化分配

集群节点数:<=3,建议:所有节点的master:true, data:true。既是主节点也是路由节点。 集群节点数:>3, 根据业务场景需要,建议:逐步独立出Master节点和协调/路由节点。

1.10 建议冷热数据分离

热数据存储SSD和普通历史数据存储机械磁盘,物理上提高检索效率。

2、索引优化实践

Mysql等关系型数据库要分库、分表。Elasticserach的话也要做好充分的考虑。

2.1 设置多少个索引?

建议根据业务场景进行存储。 不同通道类型的数据要分索引存储。举例:知乎采集信息存储到知乎索引;APP采集信息存储到APP索引。

2.2 设置多少分片?

建议根据数据量衡量。 经验值:建议每个分片大小不要超过30GB

2.3 分片数设置?

建议根据集群节点的个数规模,分片个数建议>=集群节点的个数。 5节点的集群,5个分片就比较合理。 注意:除非reindex操作,分片数是不可以修改的。

2.4副本数设置?

除非你对系统的健壮性有异常高的要求,比如:银行系统。可以考虑2个副本以上。 否则,1个副本足够。 注意:副本数是可以通过配置随时修改的。

2.5不要再在一个索引下创建多个type

即便你是5.X版本,考虑到未来版本升级等后续的可扩展性。 建议:一个索引对应一个type。6.x默认对应_doc,5.x你就直接对应type统一为doc。

2.6 按照日期规划索引

随着业务量的增加,单一索引和数据量激增给的矛盾凸显。 按照日期规划索引是必然选择。 好处1:可以实现历史数据秒删。很对历史索引delete即可。注意:一个索引的话需要借助delete_by_query+force_merge操作,慢且删除不彻底。 好处2:便于冷热数据分开管理,检索最近几天的数据,直接物理上指定对应日期的索引,速度快的一逼! 操作参考:模板使用+rollover API使用

2.7 务必使用别名

ES不像mysql方面的更改索引名称。使用别名就是一个相对灵活的选择。

3、数据模型优化实践

3.1 不要使用默认的Mapping

默认Mapping的字段类型是系统自动识别的。其中:string类型默认分成:text和keyword两种类型。如果你的业务中不需要分词、检索,仅需要精确匹配,仅设置为keyword即可。 根据业务需要选择合适的类型,有利于节省空间和提升精度,如:浮点型的选择。

3.2 Mapping各字段的选型流程

11.png

3.3 选择合理的分词器

常见的开源中文分词器包括:ik分词器、ansj分词器、hanlp分词器、结巴分词器、海量分词器、“ElasticSearch最全分词器比较及使用方法” 搜索可查看对比效果。 如果选择ik,建议使用ik_max_word。因为:粗粒度的分词结果基本包含细粒度ik_smart的结果。

3.4 date、long、还是keyword

根据业务需要,如果需要基于时间轴做分析,必须date类型; 如果仅需要秒级返回,建议使用keyword

4、数据写入优化实践

4.1 要不要秒级响应?

Elasticsearch近实时的本质是:最快1s写入的数据可以被查询到。 如果refresh_interval设置为1s,势必会产生大量的segment,检索性能会受到影响。 所以,非实时的场景可以调大,设置为30s,甚至-1。

4.2 减少副本,提升写入性能。

写入前,副本数设置为0, 写入后,副本数设置为原来值。

4.3 能批量就不单条写入

批量接口为bulk,批量的大小要结合队列的大小,而队列大小和线程池大小、机器的cpu核数。

4.4 禁用swap

在Linux系统上,通过运行以下命令临时禁用交换:

sudo swapoff -a

5、检索聚合优化实战

5.1 禁用 wildcard模糊匹配

数据量级达到TB+甚至更高之后,wildcard在多字段组合的情况下很容易出现卡死,甚至导致集群节点崩溃宕机的情况。 后果不堪设想。 替代方案: 方案一:针对精确度要求高的方案:两套分词器结合,standard和ik结合,使用match_phrase检索。 方案二:针对精确度要求不高的替代方案:建议ik分词,通过match_phrase和slop结合查询。

5.2极小的概率使用match匹配

中文match匹配显然结果是不准确的。很大的业务场景会使用短语匹配“match_phrase"。 match_phrase结合合理的分词词典、词库,会使得搜索结果精确度更高,避免噪音数据。

5.3 结合业务场景,大量使用filter过滤器

对于不需要使用计算相关度评分的场景,无疑filter缓存机制会使得检索更快。 举例:过滤某邮编号码。

5.3控制返回字段和结果

和mysql查询一样,业务开发中,select * 操作几乎是不必须的。 同理,ES中,_source 返回全部字段也是非必须的。 要通过_source 控制字段的返回,只返回业务相关的字段。 网页正文content,网页快照html_content类似字段的批量返回,可能就是业务上的设计缺陷。 显然,摘要字段应该提前写入,而不是查询content后再截取处理。

5.4 分页深度查询和遍历

分页查询使用:from+size; 遍历使用:scroll; 并行遍历使用:scroll+slice。 斟酌集合业务选型使用。

5.5 聚合Size的合理设置

聚合结果是不精确的。除非你设置size为2的32次幂-1,否则聚合的结果是取每个分片的Top size元素后综合排序后的值。 实际业务场景要求精确反馈结果的要注意。 尽量不要获取全量聚合结果——从业务层面取TopN聚合结果值是非常合理的。因为的确排序靠后的结果值意义不大。

5.6 聚合分页合理实现

聚合结果展示的时,势必面临聚合后分页的问题,而ES官方基于性能原因不支持聚合后分页。 如果需要聚合后分页,需要自开发实现。包含但不限于: 方案一:每次取聚合结果,拿到内存中分页返回。 方案二:scroll结合scroll after集合redis实现。

6、业务优化

让Elasticsearch做它擅长的事情,很显然,它更擅长基于倒排索引进行搜索。 业务层面,用户想最快速度看到自己想要的结果,中间的“字段处理、格式化、标准化”等一堆操作,用户是不关注的。 为了让Elasticsearch更高效的检索,建议: 1)要做足“前戏” 字段抽取、倾向性分析、分类/聚类、相关性判定放在写入ES之前的ETL阶段进行; 2)“睡服”产品经理 产品经理基于各种奇葩业务场景可能会提各种无理需求。 作为技术人员,要“通知以情晓之以理”,给产品经理讲解明白搜索引擎的原理、Elasticsearch的原理,哪些能做,哪些真的“臣妾做不到”。

7、小结

实际业务开发中,公司一般要求又想马儿不吃草,又想马儿飞快跑。 对于Elasticsearch开发也是,硬件资源不足(cpu、内存、磁盘都爆满)几乎没有办法提升性能的。 除了检索聚合,让Elasticsearch做N多相关、不相干的工作,然后得出结论“Elastic也就那样慢,没有想像的快”。 你脑海中是否也有类似的场景浮现呢? 提供相对NB的硬件资源、做好前期的各种准备工作、让Elasticsearch轻装上阵,相信你的Elasticsearch也会飞起来!

来日我们再相会......

推荐阅读: 1、阿里:https://elasticsearch.cn/article/6171 2、滴滴:http://t.cn/EUNLkNU 3、腾讯:http://t.cn/E4y9ylL 4、携程:https://elasticsearch.cn/article/6205 5、社区:https://elasticsearch.cn/article/6202 6、社区:https://elasticsearch.cn/article/708 7、社区:https://elasticsearch.cn/article/6202

33.jpg

Elasticsearch基础、进阶、实战第一公众号

Day 16 - Elasticsearch性能调优

Advent白衬衣 发表了文章 • 2 个评论 • 1300 次浏览 • 2018-12-16 20:10 • 来自相关话题

因为总是看到很多同学在说elasticsearch性能不够好,集群不够稳定,询问关于elasticsearch的调优,但是每次都是一个个点的单独讲,很多时候都是case by case的解答,今天简单梳理下日常的elasticsearch使用调优,以下仅为自己日常经验之谈,如有疏漏,还请大家帮忙指正。

一、配置文件调优

elasticsearch.yml

内存锁定

bootstrap.memory_lock:true 锁定堆内存;

zen.discovery

ES是一个P2P类型的分布式系统,使用gossip协议,集群的任意请求都可以发送到集群的任一节点,然后es内部会找到需要转发的节点,并且与之进行通信。 在es1.x的版本,es默认是开启组播,启动es之后,可以快速将局域网内集群名称,默认端口的相同实例加入到一个大的集群,后续再es2.x之后,都调整成了单播,避免安全问题和网络风暴; 单播discovery.zen.ping.unicast.hosts,建议写入集群内所有的节点及端口,如果新实例加入集群,新实例只需要写入当前集群的实例,即可自动加入到当前集群,之后再处理原实例的配置即可,新实例加入集群,不需要重启原有实例; 节点zen相关配置: discovery.zen.ping_timeout:判断master选举过程中,发现其他node存活的超时设置,主要影响选举的耗时,参数仅在加入或者选举 master 主节点的时候才起作用 discovery.zen.join_timeout:节点确定加入到集群中,向主节点发送加入请求的超时时间,默认为3s discovery.zen.minimum_master_nodes:参与master选举的最小节点数,当集群能够被选为master的节点数量小于最小数量时,集群将无法正常选举。

故障检测( fault detection )

两种情况下回进行故障检测,第一种是由master向集群的所有其他节点发起ping,验证节点是否处于活动状态;第二种是:集群每个节点向master发起ping,判断master是否存活,是否需要发起选举。 故障检测需要配置以下设置使用 形如: discovery.zen.fd.ping_interval 节点被ping的频率,默认为1s。 discovery.zen.fd.ping_timeout 等待ping响应的时间,默认为 30s,运行的集群中,master 检测所有节点,以及节点检测 master 是否正常。 discovery.zen.fd.ping_retries ping失败/超时多少导致节点被视为失败,默认为3。

https://www.elastic.co/guide/en/elasticsearch/reference/6.x/modules-discovery-zen.html

队列数量

不建议盲目加大es的队列数量,如果是偶发的因为数据突增,导致队列阻塞,加大队列size可以使用内存来缓存数据,如果是持续性的数据阻塞在队列,加大队列size除了加大内存占用,并不能有效提高数据写入速率,反而可能加大es宕机时候,在内存中可能丢失的上数据量。 哪些情况下,加大队列size呢?GET /_cat/thread_pool,观察api中返回的queue和rejected,如果确实存在队列拒绝或者是持续的queue,可以酌情调整队列size。

https://www.elastic.co/guide/en/elasticsearch/reference/6.x/modules-threadpool.html

内存使用

设置indices的内存熔断相关参数,根据实际情况进行调整,防止写入或查询压力过高导致OOM, indices.breaker.total.limit: 50%,集群级别的断路器,默认为jvm堆的70%; indices.breaker.request.limit: 10%,单个request的断路器限制,默认为jvm堆的60%; indices.breaker.fielddata.limit: 10%,fielddata breaker限制,默认为jvm堆的60%。

https://www.elastic.co/guide/en/elasticsearch/reference/6.x/circuit-breaker.html

根据实际情况调整查询占用cache,避免查询cache占用过多的jvm内存,参数为静态的,需要在每个数据节点配置。 indices.queries.cache.size: 5%,控制过滤器缓存的内存大小,默认为10%。接受百分比值,5%或者精确值,例如512mb。

https://www.elastic.co/guide/en/elasticsearch/reference/6.x/query-cache.html

创建shard

如果集群规模较大,可以阻止新建shard时扫描集群内全部shard的元数据,提升shard分配速度。 cluster.routing.allocation.disk.include_relocations: false,默认为true。

https://www.elastic.co/guide/en/elasticsearch/reference/6.x/disk-allocator.html

二、系统层面调优

jdk版本

当前根据官方建议,选择匹配的jdk版本;

jdk内存配置

首先,-Xms和-Xmx设置为相同的值,避免在运行过程中再进行内存分配,同时,如果系统内存小于64G,建议设置略小于机器内存的一半,剩余留给系统使用。 同时,jvm heap建议不要超过32G(不同jdk版本具体的值会略有不同),否则jvm会因为内存指针压缩导致内存浪费,详见: https://www.elastic.co/guide/cn/elasticsearch/guide/current/heap-sizing.html

交换分区

关闭交换分区,防止内存发生交换导致性能下降(部分情况下,宁死勿慢) swapoff -a

文件句柄

Lucene 使用了 大量的 文件。 同时,Elasticsearch 在节点和 HTTP 客户端之间进行通信也使用了大量的套接字,所有这一切都需要足够的文件描述符,默认情况下,linux默认运行单个进程打开1024个文件句柄,这显然是不够的,故需要加大文件句柄数 ulimit -n 65536

https://www.elastic.co/guide/en/elasticsearch/reference/6.5/setting-system-settings.html

mmap

Elasticsearch 对各种文件混合使用了 NioFs( 注:非阻塞文件系统)和 MMapFs ( 注:内存映射文件系统)。请确保你配置的最大映射数量,以便有足够的虚拟内存可用于 mmapped 文件。这可以暂时设置: sysctl -w vm.max_map_count=262144 或者你可以在 /etc/sysctl.conf 通过修改 vm.max_map_count 永久设置它。

https://www.elastic.co/guide/cn/elasticsearch/guide/current/_file_descriptors_and_mmap.html

磁盘

如果你正在使用 SSDs,确保你的系统 I/O 调度程序是配置正确的。 当你向硬盘写数据,I/O 调度程序决定何时把数据实际发送到硬盘。 大多数默认 nix 发行版下的调度程序都叫做 cfq(完全公平队列)。但它是为旋转介质优化的: 机械硬盘的固有特性意味着它写入数据到基于物理布局的硬盘会更高效。 这对 SSD 来说是低效的,尽管这里没有涉及到机械硬盘。但是,deadline 或者 noop 应该被使用。deadline 调度程序基于写入等待时间进行优化, noop 只是一个简单的 FIFO 队列。 echo noop > /sys/block/sd/queue/scheduler

磁盘挂载

mount -o noatime,data=writeback,barrier=0,nobh /dev/sd* /esdata* 其中,noatime,禁止记录访问时间戳;data=writeback,不记录journal;barrier=0,因为关闭了journal,所以同步关闭barrier; nobh,关闭buffer_head,防止内核影响数据IO

磁盘其他注意事项

使用 RAID 0。条带化 RAID 会提高磁盘I/O,代价显然就是当一块硬盘故障时整个就故障了,不要使用镜像或者奇偶校验 RAID 因为副本已经提供了这个功能。 另外,使用多块硬盘,并允许 Elasticsearch 通过多个 path.data 目录配置把数据条带化分配到它们上面。 不要使用远程挂载的存储,比如 NFS 或者 SMB/CIFS。这个引入的延迟对性能来说完全是背道而驰的。

三、elasticsearch使用方式调优

当elasticsearch本身的配置没有明显的问题之后,发现es使用还是非常慢,这个时候,就需要我们去定位es本身的问题了,首先祭出定位问题的第一个命令:

hot_threads

GET /_nodes/hot_threads&interval=30s

抓取30s的节点上占用资源的热线程,并通过排查占用资源最多的TOP线程来判断对应的资源消耗是否正常,一般情况下,bulk,search类的线程占用资源都可能是业务造成的,但是如果是merge线程占用了大量的资源,就应该考虑是不是创建index或者刷磁盘间隔太小,批量写入size太小造成的。

https://www.elastic.co/guide/en/elasticsearch/reference/6.x/cluster-nodes-hot-threads.html

pending_tasks

GET /_cluster/pending_tasks

有一些任务只能由主节点去处理,比如创建一个新的 索引或者在集群中移动分片,由于一个集群中只能有一个主节点,所以只有这一master节点可以处理集群级别的元数据变动。在99.9999%的时间里,这不会有什么问题,元数据变动的队列基本上保持为零。在一些罕见的集群里,元数据变动的次数比主节点能处理的还快,这会导致等待中的操作会累积成队列。这个时候可以通过pending_tasks api分析当前什么操作阻塞了es的队列,比如,集群异常时,会有大量的shard在recovery,如果集群在大量创建新字段,会出现大量的put_mappings的操作,所以正常情况下,需要禁用动态mapping。

https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-pending.html

字段存储

当前es主要有doc_values,fielddata,storefield三种类型,大部分情况下,并不需要三种类型都存储,可根据实际场景进行调整: 当前用得最多的就是doc_values,列存储,对于不需要进行分词的字段,都可以开启doc_values来进行存储(且只保留keyword字段),节约内存,当然,开启doc_values会对查询性能有一定的影响,但是,这个性能损耗是比较小的,而且是值得的;

fielddata构建和管理 100% 在内存中,常驻于 JVM 内存堆,所以可用于快速查询,但是这也意味着它本质上是不可扩展的,有很多边缘情况下要提防,如果对于字段没有分析需求,可以关闭fielddata;

storefield主要用于_source字段,默认情况下,数据在写入es的时候,es会将doc数据存储为_source字段,查询时可以通过_source字段快速获取doc的原始结构,如果没有update,reindex等需求,可以将_source字段disable;

_all,ES在6.x以前的版本,默认将写入的字段拼接成一个大的字符串,并对该字段进行分词,用于支持整个doc的全文检索,在知道doc字段名称的情况下,建议关闭掉该字段,节约存储空间,也避免不带字段key的全文检索;

norms:搜索时进行评分,日志场景一般不需要评分,建议关闭;

tranlog

Elasticsearch 2.0之后为了保证不丢数据,每次 index、bulk、delete、update 完成的时候,一定触发刷新 translog 到磁盘上,才给请求返回 200 OK。这个改变在提高数据安全性的同时当然也降低了一点性能。 如果你不在意这点可能性,还是希望性能优先,可以在 index template 里设置如下参数:

{
    "index.translog.durability": "async"
}

index.translog.sync_interval:对于一些大容量的偶尔丢失几秒数据问题也并不严重的集群,使用异步的 fsync 还是比较有益的。比如,写入的数据被缓存到内存中,再每5秒执行一次 fsync ,默认为5s。小于的值100ms是不允许的。 index.translog.flush_threshold_size:translog存储尚未安全保存在Lucene中的所有操作。虽然这些操作可用于读取,但如果要关闭并且必须恢复,则需要重新编制索引。此设置控制这些操作的最大总大小,以防止恢复时间过长。达到设置的最大size后,将发生刷新,生成新的Lucene提交点,默认为512mb。

refresh_interval

执行刷新操作的频率,这会使索引的最近更改对搜索可见,默认为1s,可以设置-1为禁用刷新,对于写入速率要求较高的场景,可以适当的加大对应的时长,减小磁盘io和segment的生成;

禁止动态mapping

动态mapping的坏处: 1.造成集群元数据一直变更,导致集群不稳定; 2.可能造成数据类型与实际类型不一致; 3.对于一些异常字段或者是扫描类的字段,也会频繁的修改mapping,导致业务不可控。 动态mapping配置的可选值及含义如下: true:支持动态扩展,新增数据有新的字段属性时,自动添加对于的mapping,数据写入成功 false:不支持动态扩展,新增数据有新的字段属性时,直接忽略,数据写入成功 strict:不支持动态扩展,新增数据有新的字段时,报错,数据写入失败

批量写入

批量请求显然会大大提升写入速率,且这个速率是可以量化的,官方建议每次批量的数据物理字节数5-15MB是一个比较不错的起点,注意这里说的是物理字节数大小。文档计数对批量大小来说不是一个好指标。比如说,如果你每次批量索引 1000 个文档,记住下面的事实: 1000 个 1 KB 大小的文档加起来是 1 MB 大。 1000 个 100 KB 大小的文档加起来是 100 MB 大。 这可是完完全全不一样的批量大小了。批量请求需要在协调节点上加载进内存,所以批量请求的物理大小比文档计数重要得多。 从 5–15 MB 开始测试批量请求大小,缓慢增加这个数字,直到你看不到性能提升为止。然后开始增加你的批量写入的并发度(多线程等等办法)。 用iostat 、 top 和 ps 等工具监控你的节点,观察资源什么时候达到瓶颈。如果你开始收到 EsRejectedExecutionException ,你的集群没办法再继续了:至少有一种资源到瓶颈了。或者减少并发数,或者提供更多的受限资源(比如从机械磁盘换成 SSD),或者添加更多节点。

索引和shard

es的索引,shard都会有对应的元数据,且因为es的元数据都是保存在master节点,且元数据的更新是要hang住集群向所有节点同步的,当es的新建字段或者新建索引的时候,都会要获取集群元数据,并对元数据进行变更及同步,此时会影响集群的响应,所以需要关注集群的index和shard数量,建议如下: 1.使用shrink和rollover api,相对生成合适的数据shard数; 2.根据数据量级及对应的性能需求,选择创建index的名称,形如:按月生成索引:test-YYYYMM,按天生成索引:test-YYYYMMDD; 3.控制单个shard的size,正常情况下,日志场景,建议单个shard不大于50GB,线上业务场景,建议单个shard不超过20GB;

segment merge

段合并的计算量庞大, 而且还要吃掉大量磁盘 I/O。合并在后台定期操作,因为他们可能要很长时间才能完成,尤其是比较大的段。这个通常来说都没问题,因为大规模段合并的概率是很小的。 如果发现merge占用了大量的资源,可以设置: index.merge.scheduler.max_thread_count: 1 特别是机械磁盘在并发 I/O 支持方面比较差,所以我们需要降低每个索引并发访问磁盘的线程数。这个设置允许 max_thread_count + 2 个线程同时进行磁盘操作,也就是设置为 1 允许三个线程。 对于 SSD,你可以忽略这个设置,默认是 Math.min(3, Runtime.getRuntime().availableProcessors() / 2) ,对 SSD 来说运行的很好。 业务低峰期通过force_merge强制合并segment,降低segment的数量,减小内存消耗; 关闭冷索引,业务需要的时候再进行开启,如果一直不使用的索引,可以定期删除,或者备份到hadoop集群;

自动生成_id

当写入端使用特定的id将数据写入es时,es会去检查对应的index下是否存在相同的id,这个操作会随着文档数量的增加而消耗越来越大,所以如果业务上没有强需求,建议使用es自动生成的id,加快写入速率。

routing

对于数据量较大的业务查询场景,es侧一般会创建多个shard,并将shard分配到集群中的多个实例来分摊压力,正常情况下,一个查询会遍历查询所有的shard,然后将查询到的结果进行merge之后,再返回给查询端。此时,写入的时候设置routing,可以避免每次查询都遍历全量shard,而是查询的时候也指定对应的routingkey,这种情况下,es会只去查询对应的shard,可以大幅度降低合并数据和调度全量shard的开销。

使用alias

生产提供服务的索引,切记使用别名提供服务,而不是直接暴露索引名称,避免后续因为业务变更或者索引数据需要reindex等情况造成业务中断。

避免宽表

在索引中定义太多字段是一种可能导致映射爆炸的情况,这可能导致内存不足错误和难以恢复的情况,这个问题可能比预期更常见,index.mapping.total_fields.limit ,默认值是1000

避免稀疏索引

因为索引稀疏之后,对应的相邻文档id的delta值会很大,lucene基于文档id做delta编码压缩导致压缩率降低,从而导致索引文件增大,同时,es的keyword,数组类型采用doc_values结构,每个文档都会占用一定的空间,即使字段是空值,所以稀疏索引会造成磁盘size增大,导致查询和写入效率降低。

Elastic日报 第480期 (2018-12-16)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 223 次浏览 • 2018-12-16 10:13 • 来自相关话题

1.Elasticsearch Ingest Node 与Logstash性能对比。 http://t.cn/EUQQ0EQ 2.方法:如何将rsyslog与Kafka和Logstash集成。 http://t.cn/EUQ8Lyy 3.(自备梯子)iPhone的黄金时代即将结束。 http://t.cn/EUQ86dB 编辑:至尊宝 归档:https://elasticsearch.cn/article/6201 订阅:https://tinyletter.com/elastic-daily 
1.Elasticsearch Ingest Node 与Logstash性能对比。 http://t.cn/EUQQ0EQ 2.方法:如何将rsyslog与Kafka和Logstash集成。 http://t.cn/EUQ8Lyy 3.(自备梯子)iPhone的黄金时代即将结束。 http://t.cn/EUQ86dB 编辑:至尊宝 归档:https://elasticsearch.cn/article/6201 订阅:https://tinyletter.com/elastic-daily 

Day 14 - 订单中心基于elasticsearch 的解决方案

Elasticsearchblogsit 发表了文章 • 1 个评论 • 814 次浏览 • 2018-12-14 15:24 • 来自相关话题

       ElasticSearch分布式搜索储存集群的引入,主要是为了解决订单数据的存储与搜索的问题。 项目背景:       15年去哪儿网酒店日均订单量达到30w+,随着多平台订单的聚合日均订单能达到100w左右。原来采用的热表分库方式,即将最近6个月的订单的放置在一张表中,将历史订单放在在history表中。history表存储全量的数据,当用户查询的下单时间跨度超过6个月即查询历史订单表,此分表方式热表的数据量为4000w左右,当时能解决的问题。但是显然不能满足携程艺龙订单接入的需求。如果继续按照热表方式,数据量将超过1亿条。全量数据表保存2年的可能就超过4亿的数据量。所以寻找有效途径解决此问题迫在眉睫。由于对这预计4亿的数据量还需按照预定日期、入住日期、离店日期、订单号、联系人姓名、电话、酒店名称、订单状态……等多个条件查询。所以简单按照某一个维度进行分表操作没有意义。ElasticSearch分布式搜索储存集群的引入,就是为了解决订单数据的存储与搜索的问题。 具体解决方案: 1、系统性能         对订单模型进行抽象和分类,将常用搜索字段和基础属性字段剥离DB做分库分表。存储订单详情,ElasticSearch存储搜素字段。订单复杂查询直接走ElasticSearch。如下图:
elasticsearch1.png
       通用数据存储模型
elasticsearch2.png
关键字段     ■ 业务核心字段,用于查询过滤 系统字段     ■ version 避免高并发操作导致数据覆盖 大字段     ■ order_data订单详情数据(JSON)     ■ 可灵活需要索引的字段返回的字段
    2、系统可用性      系统可用性保障:双机房高可用如下图。        
elasticsearch3.png
     数据可用性保障:             一、异步多写保证数据一致性。                  二、数据补充机制:   1、每天凌晨task扫描数据库热表数据与es数据版本进行比较。   2、将第三方推送过来数据中的,订单号即时插入订单同步队列表中。如果数据模型解析转换、持久化成功。删除队列中订单号。同时设置1分钟一次的task 扫描队列表。   3、推送第三方的数据也采用同样的方式。保证给第三方数据的准确性。
elasticsearch4.png
3、系统伸缩性       elasticSearch中索引设置了8个分片,目前Es单个索引的文档达到到1.4亿,合计达到2亿条数据占磁盘大小64G,集群机器磁盘容量240G。
     

Day 12 - Elasticsearch日志场景最佳实践

Adventginger 发表了文章 • 0 个评论 • 942 次浏览 • 2018-12-12 16:35 • 来自相关话题

1. 背景

Elasticsearch可广泛应用于日志分析、全文检索、结构化数据分析等多种场景,大幅度降低维护多套专用系统的成本,在开源社区非常受欢迎。然而Elasticsearch为满足多种不同的使用场景,底层组合使用了多种数据结构,部分数据结构对具体的用户使用场景可能是冗余的,从而导致默认情况下无法达到性能和成本最优化。 幸运的是,Elasticsearch提供非常灵活的模板配置能力,用户可以按需进行优化。多数情况下,用户结合使用场景进行优化后,Elasticsearch的性能都会有数倍的提升,成本也对应有倍数级别的下降。本文主要介绍不同日志使用场景下的调优经验。

2. 日志处理基本流程

日志处理的基本流程包含:日志采集 -> 数据清洗 -> 存储 -> 可视化分析。Elastic Stack提供完整的日志解决方案,帮助用户完成对日志处理全链路的管理,推荐大家使用。每个流程的处理如下:

  • 日志采集:从业务所在的机器上,较实时的采集日志传递给下游。常用开源组件如Beats、Logstash、Fluentd等。
  • 数据清洗:利用正则解析等机制,完成日志从文本数据到结构化数据的转换。用户可使用Logstash 或 Elasticsearch Ingest模块等完成数据清洗。
  • 存储:使用Elasticsearch对数据进行持久存储,并提供全文搜索和分析能力。
  • 可视化分析:通过图形界面,完成对日志的搜索分析,常用的开源组件如Kibana、Grafana。

使用Elastic Stack处理日志的详细过程,用户可参考官方文章Getting started with the Elastic Stack,这里不展开介绍。

3. 日志场景调优

       对于Elasticsearch的通用调优,之前分享的文章Elasticsearch调优实践,详细介绍了Elasticsearch在性能、稳定性方面的调优经验。而对于日志场景,不同的场景使用方式差别较大,这里主要介绍常见使用方式下,性能和成本的优化思路。

3.1 基础场景

对于多数简单日志使用场景,用户一般只要求存储原始日志,并提供按关键字搜索日志记录的能力。对于此类场景,用户可跳过数据清洗阶段,并参考如下方式进行优化:

  • 建议打开最优压缩,一般可降低40%存储。
  • 设置原始日志字段(message)为text,去除keyword类型子字段,提供全文搜索能力,降低存储。
  • 关闭_all索引,前面已通过message提供全文搜索能力。
  • 对于其他字符串字段,统一设置为keyword类型,避免默认情况下字符串字段同时存储text、keyword两种类型的数据。
  • 使用开源组件(如Beats)上报数据时会包含较多辅助信息,用户可通过修改组件配置文件进行裁剪。

这样去除message的keyword子字段、_all等冗余信息后,再加上最优压缩,可以保证数据相对精简。下面给出这类场景的常用模板,供用户参考:

{
    "order": 5,
    "template": "my_log_*",
    "settings": {
        "translog.durability": "async",
        "translog.sync_interval": "5s",
        "index.refresh_interval": "30s",
        "index.codec": "best_compression"    # 最优压缩
    },
    "mappings": {
        "_default_": {
            "_all": {                        # 关闭_all索引
                "enabled": false
            },
            "dynamic_templates": [
                {
                    "log": {                 # 原始日志字段,分词建立索引
                        "match": "message",
                        "mapping": {
                            "type": "text"
                        }
                    }
                },
                {
                    "strings": {             # 其他字符串字段,统一设置为keyword类型
                        "match_mapping_type": "string",
                        "mapping": {
                            "type": "keyword"
                        }
                    }
                }
            ]
        }
    }
}

3.2 精准搜索场景

对于部分用户,普通的全文检索并不能满足需求,希望精准搜索日志中的某部分,例如每条日志中包含程序运行时多个阶段的耗时数据,对具体一个阶段的耗时进行搜索就比较麻烦。对于此类场景,用户可基于基础场景,进行如下调整:

  • 清洗过程中,可仅解析出需要精准搜索的部分作为独立字段,用于精准搜索。
  • 对于精准搜索字段,如果无排序/聚合需求,可以关闭doc_values;对于字符串,一般使用keyword,可按需考虑使用text。

下面给出这类场景的常用模板,供用户参考:

{
    "order": 5,
    "template": "my_log_*",
    "settings": {
        "translog.durability": "async",
        "translog.sync_interval": "5s",
        "index.refresh_interval": "30s",
        "index.codec": "best_compression"    # 最优压缩
    },
    "mappings": {
        "_default_": {
            "_all": {                        # 关闭_all索引
                "enabled": false
            },
            "dynamic_templates": [
                {
                    "log": {                 # 原始日志字段,分词建立索引
                        "match": "message",
                        "mapping": {
                            "type": "text"
                        }
                    }
                },
                {
                    "precise_fieldx": {       # 精准搜索字段
                        "match": "fieldx",
                        "mapping": {
                            "type": "keyword",
                            "doc_values": false
                        }
                    }
                },
                {
                    "strings": {             # 其他字符串字段,统一设置为keyword类型
                        "match_mapping_type": "string",
                        "mapping": {
                            "type": "keyword"
                        }
                    }
                }
            ]
        }
    }
}

3.3 统计分析场景

对于某些场景,日志包含的主要是程序运行时输出的统计信息,用户通常会完全解析日志进行精确查询、统计分析,而是否保存原始日志关系不大。对于此类场景,用户可进行如下调整:

  • 清洗过程中,解析出所有需要的数据作为独立字段;原始日志非必要时,建议去除。
  • 如果有强需求保留原始日志,可以设置该字段enabled属性为false,只存储不索引。
  • 多数字段保持默认即可,会自动建立索引、打开doc_values,可用于查询、排序、聚合。
  • 对部分无排序/聚合需求、开销高的字段,可以关闭doc_values。

下面给出这类场景的常用模板,供用户参考:

{
    "order": 5,
    "template": "my_log_*",
    "settings": {
        "translog.durability": "async",
        "translog.sync_interval": "5s",
        "index.refresh_interval": "30s",
        "index.codec": "best_compression"    # 最优压缩
    },
    "mappings": {
        "_default_": {
            "_all": {                        # 关闭_all索引
                "enabled": false
            },
            "dynamic_templates": [
                {
                    "log": {                 # 原始日志字段,关闭索引
                        "match": "message",
                        "mapping": {
                            "enabled": false
                        }
                    }
                },
                {
                    "index_only_fieldx": {   # 仅索引的字段,无排序/聚合需求
                        "match": "fieldx",
                        "mapping": {
                            "type": "keyword",
                            "doc_values": false
                        }
                    }
                },
                {
                    "strings": {             # 其他字符串字段,统一设置为keyword类型
                        "match_mapping_type": "string",
                        "mapping": {
                            "type": "keyword"
                        }
                    }
                }
            ]
        }
    }
}

ES 5.1及之后的版本,支持关键字查询时自动选择目标字段,用户没有必要再使用原始日志字段提供不指定字段进行查询的能力。

4. 小结

日志的使用方式比较灵活,本文结合常见的客户使用方式,从整体上对性能、成本进行优化。用户也可结合自身业务场景,参考文章Elasticsearch调优实践进行更细致的优化。

Day 10 - Elasticsearch 分片恢复并发数过大引发的bug分析

Adventhowardhuang 发表了文章 • 4 个评论 • 866 次浏览 • 2018-12-10 11:43 • 来自相关话题

       大家好,今天为大家分享一次 ES 的填坑经验。主要是关于集群恢复过程中,分片恢复并发数调整过大导致集群 hang 死的问题。

场景描述

       废话不多说,先来描述场景。某日,腾讯云线上某 ES 集群,15个节点,2700+ 索引,15000+ 分片,数十 TB 数据。由于机器故障,某个节点被重启,此时集群有大量的 unassigned 分片,集群处于 yellow 状态。为了加快集群恢复的速度,手动调整分片恢复并发数,原本想将默认值为2的 node_concurrent_recoveries 调整为10,结果手一抖多加了一个0,设定了如下参数:

curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
    "persistent": {
        "cluster.routing.allocation.node_concurrent_recoveries": 100,
        "indices.recovery.max_bytes_per_sec": "40mb"
    }
}
'

       设定之后,观察集群 unassigned 分片,一开始下降的速度很快。大约几分钟后,数量维持在一个固定值不变了,然后,然后就没有然后了,集群所有节点 generic 线程池卡死,虽然已存在的索引读写没问题,但是新建索引以及所有涉及 generic 线程池的操作全部卡住。立马修改分片恢复并发数到10,通过管控平台一把重启了全部节点,约15分钟后集群恢复正常。接下来会先介绍一些基本的概念,然后再重现这个问题并做详细分析。

基本概念

ES 线程池(thread pool)

ES 中每个节点有多种线程池,各有用途。重要的有:

  • generic :通用线程池,后台的 node discovery,上述的分片恢复(node recovery)等等一些通用后台的操作都会用到该线程池。该线程池线程数量默认为配置的处理器数量(processors)* 4,最小128,最大512。
  • index :index/delete 等索引操作会用到该线程池,包括自动创建索引等。默认线程数量为配置的处理器数量,默认队列大小:200.
  • search :查询请求处理线程池。默认线程数量:int((# of available_processors * 3) / 2) + 1,默认队列大小:1000.
  • get :get 请求处理线程池。默认线程数量为配置的处理器数量,默认队列大小:1000.
  • write :单个文档的 index/delete/update 以及 bulk 请求处理线程。默认线程数量为配置的处理器数量,默认队列大小:200,在写多的日志场景我们一般会将队列调大。 还有其它线程池,例如备份回档(snapshot)、analyze、refresh 等,这里就不一一介绍了。详细可参考官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-threadpool.html

集群恢复之分片恢复

       我们知道 ES 集群状态分为三种,green、yellow、red。green 状态表示所有分片包括主副本均正常被分配;yellow 状态表示所有主分片已分配,但是有部分副本分片未分配;red 表示有部分主分片未分配。 一般当集群中某个节点因故障失联或者重启之后,如果集群索引有副本的场景,集群将进入分片恢复阶段(recovery)。此时一般是 master 节点发起更新集群元数据任务,分片的分配策略由 master 决定,具体分配策略可以参考腾讯云+社区的这篇文章了解细节:https://cloud.tencent.com/developer/article/1334743 。各节点收到集群元数据更新请求,检查分片状态并触发分片恢复流程,根据分片数据所在的位置,有多种恢复的方式,主要有以下几种:

  • EXISTING_STORE : 数据在节点本地存在,从本地节点恢复。
  • PEER :本地数据不可用或不存在,从远端节点(源分片,一般是主分片)恢复。
  • SNAPSHOT : 数据从备份仓库恢复。
  • LOCAL_SHARDS : 分片合并(shrink)场景,从本地别的分片恢复。

PEER 场景分片恢复并发数主要由如下参数控制:

  • cluster.routing.allocation.node_concurrent_incoming_recoveries:节点上最大接受的分片恢复并发数。一般指分片从其它节点恢复至本节点。
  • cluster.routing.allocation.node_concurrent_outgoing_recoveries :节点上最大发送的分片恢复并发数。一般指分片从本节点恢复至其它节点。
  • cluster.routing.allocation.node_concurrent_recoveries :该参数同时设置上述接受发送分片恢复并发数为相同的值。 详细参数可参考官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/shards-allocation.html

       集群卡住的主要原因就是从远端节点恢复(PEER Recovery)的并发数过多,导致 generic 线程池被用完。涉及目标节点(target)和源节点(source)的恢复交互流程,后面分析问题时我们再来详细讨论。

问题复现与剖析

       为了便于描述,我用 ES 6.4.3版本重新搭建了一个三节点的集群。单节点 1 core,2GB memory。新建了300个 index, 单个 index 5个分片一个副本,共 3000 个 shard。每个 index 插入大约100条数据。 先设定分片恢复并发数,为了夸张一点,我直接调整到200,如下所示:

curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
    "persistent": {
        "cluster.routing.allocation.node_concurrent_recoveries": 200 // 设定分片恢复并发数
    }
}
'

  接下来停掉某节点,模拟机器挂掉场景。几分钟后,观察集群分片恢复数量,卡在固定数值不再变化:

分片恢复统计信息.png

  通过 allocation explain 查看分片分配状态,未分配的原因是受到最大恢复并发数的限制:

分片恢复限制.png
  观察线程池的数量,generic 线程池打满128.

线程池统计.png

此时查询或写入已有索引不受影响,但是新建索引这种涉及到 generic 线程池的操作都会卡住。 通过堆栈分析,128 个 generic 线程全部卡在 PEER recovery 阶段。

堆栈分析.png
         现象有了,我们来分析一下这种场景,远程分片恢复(PEER Recovery)流程为什么会导致集群卡住。

       当集群中有分片的状态发生变更时,master 节点会发起集群元数据更新(cluster state update)请求给所有节点。其它节点收到该请求后,感知到分片状态的变更,启动分片恢复流程。部分分片需要从其它节点恢复,代码层面,涉及分片分配的目标节点(target)和源节点(source)的交互流程如下:

远端恢复时序分析.png
 

       6.x 版本之后引入了 seqNo,恢复会涉及到 seqNo+translog,这也是6.x提升恢复速度的一大改进。我们重点关注流程中第 2、4、5、7、10、12 步骤中的远程调用,他们的作用分别是:

  • 第2步:分片分配的目标节点向源节点(一般是主分片)发起分片恢复请求,携带起始 seqNo 和 syncId。
  • 第4步:发送数据文件信息,告知目标节点待接收的文件清单。
  • 第5步:发送 diff 数据文件给目标节点。
  • 第7步:源节点发送 prepare translog 请求给目标节点,等目标节点打开 shard level 引擎,准备接受 translog。
  • 第10步:源节点发送指定范围的 translog 快照给目标节点。
  • 第12步:结束恢复流程。

       我们可以看到除第5步发送数据文件外,多次远程交互 submitRequest 都会调用 txGet,这个调用底层用的是基于 AQS 改造过的 sync 对象,是一个同步调用。 如果一端 generic 线程池被这些请求打满,发出的请求等待对端返回,而发出的这些请求由于对端 generic 线程池同样的原因被打满,只能 pending 在队列中,这样两边的线程池都满了而且相互等待对端队列中的线程返回,就出现了分布式死锁现象。

问题处理

       为了避免改动太大带来不确定的 side effect,针对腾讯云 ES 集群我们目前先在 rest 层拒掉了并发数超过一定值的参数设定请求并提醒用户。与此同时,我们向官方提交了 issue:https://github.com/elastic/elasticsearch/issues/36195 进行跟踪。

总结

       本文旨在描述集群恢复过程出现的集群卡死场景,避免更多的 ES 用户踩坑,没有对整体分片恢复做详细的分析,大家想了解详细的分片恢复流程可以参考腾讯云+社区 Elasticsearch 专栏相关的文章:https://cloud.tencent.com/developer/column/2428

完结,谢谢!