es使用经验

1,165 阅读3分钟

基础概念

重要的基础配置

es用root用户启动会报错,建议给es创建单独的用户

es默认network.host绑定是的本地回环localhost,这时候他默认你是用来测试的。不会启动bootstrap checks。但是当绑定的不是localhost时,会进行bootstrap checks,例如会检查虚拟内存有没有给够等等。如果配置没给够,会启动失败。不过日志中会说明那些配置没给够。参考官方文档:important-settingssystem-config

GC不用关心,不用专门去调。而且jvm heap这块最多不要超过32G。我在生产上配置为31G。其实es使用的是大量的page cache,jvm heap的大小需要按需调整,不是越大越好,越大反而增加了GC的负担。

jdk配置

es包里带有一个官方测试过的open-jdk,在$ES_HOME/bin/elasticsearch-env中能看到选择jdk的地方。

# now set the path to java
if [ ! -z "$JAVA_HOME" ]; then
  JAVA="$JAVA_HOME/bin/java"
else
  if [ "$(uname -s)" = "Darwin" ]; then
    # OSX has a different structure
    JAVA="$ES_HOME/jdk/Contents/Home/bin/java"
  else
    JAVA="$ES_HOME/jdk/bin/java"
  fi
fi

可以看到,如果操作系统里配置了java环境,会用操作系统里配置的。但是我们这里想用es包里面的。那么把这些都注释掉,留下这么一行就行

JAVA="$ES_HOME/jdk/Contents/Home/bin/java"

mapping

官方文档

mapping规定了每个字段是什么数据类型,是否能分词(我们的业务不涉及),是否可搜索(我们的业务不涉及)

动态mapping

例如文本类型:在es中有text类型和keyword类型。 text涉及分词【不能聚合】,目前业务使用es做数据分析,所以字符类型的数据均应设置成keyword【可以聚合】。

通过动态mapping可以 将字符类型的 统一配置成keyword 还有些场景,例如我们想把int_xxx这种字段统一配置成int类型。 即int开头的字段名,在es中存为int。同理还有long_xxx。

template索引模板

template索引模板 对应极客时间ES视频 18-21节

每有一个新的业务时,创建索引必须好好设计索引模板。我接触到的索引模板中主要包含两部分,settings&mapping。附上一个demo:

# 通过kibana访问
GET _template/xxx-log
# 返回结果如下
{
  "xxx-log" : {
    "order" : 0,
    # 模板就是一个模子,这些索引都能适用这个模板。所以是通配符。
    "index_patterns" : [
      "log-*"
    ],
    "settings" : {
      # 这里能够设置生命周期(我们都是用kibana可视化设置生命周期的),分片数量,副本数量。
      "index" : {
        "lifecycle" : {
          "name" : "ilm-log"
        },
        "number_of_shards" : "1"
      }
    },
    "mappings" : {
      # 这里是动态模板,把所有文本类型的数据直接认为是keyword类型。因为我们的业务不涉及分词
      "dynamic_templates" : [
        {
          "strings_as_keywords" : {
            "mapping" : {
              "type" : "keyword"
            },
            "match_mapping_type" : "string"
          }
        }
      ],
      "properties" : {
        "resp_time" : {
          "type" : "integer"
        },
        "sequence" : {
          "type" : "long"
        },
        "terminalNo" : {
          "type" : "long"
        },
        # short占内存小,能省则省,因为是大数据。
        "province" : {
          "type" : "short"
        },
        "errCode" : {
          "type" : "long"
        },
        "ip" : {
          "type" : "ip"
        },
        # 时间类型的字段,需要和logstash洗出来的时间格式匹配,主要是后面要带时区
        "snap_time" : {
          "format" : [
            "yyyy-MM-dd HH:mm:ss:SSSZ"
          ],
          "type" : "date"
        },
        "index_date" : {
          "type" : "date"
        },
        "logId" : {
          "type" : "long"
        },
        "id" : {
          "type" : "integer"
        },
        "attr" : {
          "type" : "long"
        }
      }
    },
    # 别名 在复杂业务时好处多多。目前我们没有用到过。
    "aliases" : { }
  }
}

调优

根据经验,大的开源项目官方文档中都有详细的调优说明。es调优官方文档

es集群刚开始上线半个月后,频繁的出现fgc,发现fielddata占用了很多内存,并且不会被回收。由于用户频繁的对元数据_id进行排序操作,_idtext类型,对这种类型进行排序或者聚合就会导致出现这种情况。通过学习ES断路器相关知识,对fielddata阈值进行调整,限制为30%。

配置如下,需要重启集群才行。

indices.fielddata.cache.size: "30%"

如何查看fielddata使用情况。官方文档

用户访问控制

当v7.1时,简单的用户访问控制功能免费了。官方也出了文章以及视频。

官方blog

中文社区出的视频

es如何进行监控

通过kibana中monitor页面可以进行非常详细的底层指标观测。

如何进行预警:因为es提供了丰富的cat api

目前做的监控预警比较简单,当集群的状态不是green时就发送邮件,检测频率为每分钟调用一次cat api (GET _cat/health)。

生产问题解决

  • 当磁盘使用大小超过85%时,会停止写入。这时候咱们去清理一些磁盘空间,当磁盘空间释放后,还必须手动执行
PUT _settings
{
	"index": {
		"blocks": {
			"read_only_allow_delete": "false"
		}
	}
}
  • 极客时间上有专题讲解:65-74【阮一鸣ES课程】 这里面大部分咱们的生产环境都解决过,部分压测相关的没有做过。可以留意。

配置

es中的配置有的在线可以修改通过api,但是有些需要修改配置文件,滚动重启集群才可以。

配置分级别,有临时的,有永久的。需要注意,尽量不要使用cerebro去改配置。

滚动升级&滚动重启

背景:我们部署方式都是tar包。

集群重启 滚动升级

滚动升级和重启最重要的是防止产生大量的IO。

es的升级不可逆,安排充分的时间进行升级操作,不要升了一半,剩下一般等明天再生。

官方建议

从数据节点开始升级,数据节点升级完成后再升级主节点。高版本的节点可以加入低版本的集群,反过来则不可以。要遵循这个规则。

Disable shard allocation.

这台节点都要下线进行升级了,默认一分钟后就会飘数据。不禁用会造成IO泛洪操作。

PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.enable": "primaries"
  }
}

通过下面的请求来验证,确认修改成功了。

GET _cluster/settings

如果开始发生分片的漂移了怎么取消?

这其实是分片的分布问题。官方文档,其中用过的是cancel取消分片的分配。

cancel Cancel allocation of a shard (or recovery). Accepts index and shard for index name and shard number, and node for the node to cancel the shard allocation on. This can be used to force resynchronization of existing replicas from the primary shard by cancelling them and allowing them to be reinitialized through the standard recovery process. By default only replica shard allocations can be cancelled. If it is necessary to cancel the allocation of a primary shard then the allow_primary flag must also be included in the request.

Stop non-essential indexing and perform a synced flush. (Optional)

滚动升级的时候有数据一直往里写入也是可以的,不过执行这个api会加速之后的恢复过程。具体描述参考官方文档

POST _flush/synced

这个api涉及的官方文档,里面提到v7.6之后被标记deprecate

Shut down a single node.

停掉进程。不要kill -9 kill即可,观察日志看是否优雅停掉。

重点:准备要升级的包

包里的config,data,logs等相关配置需要留意。

其实就是把旧包里的配置挪到新版本的对应位置。

Start the upgraded node.

启动新版本的程序。

Reenable shard allocation.

恢复shard分配策略

PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.enable": null
  }
}

通过下面的请求来验证,确认恢复成功了。

GET _cluster/settings

Wait for the node to recover.

最后一步:可以在cerebro中观察是否集群健康状态为绿色

循环上述所有步骤,数据节点升级完成后再升级master节点

如图所示,主shard分配到了高版本的节点,此时是不会把副本落在低版本的节点上。

从7.2.0升7.6.1遇到的问题

deprecated日志出现

[WARN ][o.e.d.t.TransportInfo    ] [node4] transport.publish_address was printed as [ip:port] instead of [hostname/ip:port]. This format is deprecated and will change to [hostname/ip:port] in a future version. Use -Des.transport.cname_in_publish_address=true to enforce non-deprecated formatting.

解决方案:加jvm参数。

# 在$ES_HOME/bin/elasticsearch这个脚本中添加
-Des.transport.cname_in_publish_address=true \

es启动输出大段内容

尚未有解决方案。github讨论说是一个bug。

regular expression has redundant nested repeat operator * /(?:(?:\[(?<TIMESTAMP_ISO8601:elasticsearch.server.timestamp>(?:(?>\d\d){1,2})-(?:(?:0?[1-9]|1[0-2]))-(?:(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9]))[T ](?:(?:2[0123]|[01][0-9])):?(?:(?:[0-5][0-9]))(?::?(?:(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?)))?(?:(?:Z|[+-](?:(?:2[0123]|[01]?[0-9]))(?::?(?:(?:[0-5][0-9])))))?)\]\[(?<LOGLEVEL:log.level>([Aa]lert|ALERT|[Tt]race|TRACE|[Dd]ebug|DEBUG|[Nn]otice|NOTICE|[Ii]nfo|INFO|[Ww]arn?(?:ing)?|WARN?(?:ING)?|[Ee]rr?(?:or)?|ERR?(?:OR)?|[Cc]rit?(?:ical)?|CRIT?(?:ICAL)?|[Ff]atal|FATAL|[Ss]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?))(?:\s*)?\]\[(?<DATA:elasticsearch.component>.*?)(?:\s*)\]((?:\s*))?(\[(?<DATA:elasticsearch.node.name>.*?)\])?((?:\s*))?)(?:\[gc\]\[(?<NUMBER:elasticsearch.server.gc.overhead_seq>(?:(?:(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+))))))\] overhead, spent \[(?<NUMBER:elasticsearch.server.gc.collection_duration.time:float>(?:(?:(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+))))))(?<DATA:elasticsearch.server.gc.collection_duration.unit>.*?)\] collecting in the last \[(?<NUMBER:elasticsearch.server.gc.observation_duration.time:float>(?:(?:(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+))))))(?<DATA:elasticsearch.server.gc.observation_duration.unit>.*?)\]))|(?:(?:\[(?<TIMESTAMP_ISO8601:elasticsearch.server.timestamp>(?:(?>\d\d){1,2})-(?:(?:0?[1-9]|1[0-2]))-(?:(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9]))[T ](?:(?:2[0123]|[01][0-9])):?(?:(?:[0-5][0-9]))(?::?(?:(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?)))?(?:(?:Z|[+-](?:(?:2[0123]|[01]?[0-9]))(?::?(?:(?:[0-5][0-9])))))?)\]\[(?<LOGLEVEL:log.level>([Aa]lert|ALERT|[Tt]race|TRACE|[Dd]ebug|DEBUG|[Nn]otice|NOTICE|[Ii]nfo|INFO|[Ww]arn?(?:ing)?|WARN?(?:ING)?|[Ee]rr?(?:or)?|ERR?(?:OR)?|[Cc]rit?(?:ical)?|CRIT?(?:ICAL)?|[Ff]atal|FATAL|[Ss]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?))(?:\s*)?\]\[(?<DATA:elasticsearch.component>.*?)(?:\s*)\]((?:\s*))?(\[(?<DATA:elasticsearch.node.name>.*?)\])?((?:\s*))?)(?:\[gc\]\[young\]\[(?<NUMBER:elasticsearch.server.gc.young.one>(?:(?:(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+))))))\]\[(?<NUMBER:elasticsearch.server.gc.young.two>(?:(?:(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+))))))\](?:\s*)(?<GREEDYMULTILINE:message>(.|
)*)))|(?:(?:\[(?<TIMESTAMP_ISO8601:elasticsearch.server.timestamp>(?:(?>\d\d){1,2})-(?:(?:0?[1-9]|1[0-2]))-(?:(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9]))[T ](?:(?:2[0123]|[01][0-9])):?(?:(?:[0-5][0-9]))(?::?(?:(?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?)))?(?:(?:Z|[+-](?:(?:2[0123]|[01]?[0-9]))(?::?(?:(?:[0-5][0-9])))))?)\]\[(?<LOGLEVEL:log.level>([Aa]lert|ALERT|[Tt]race|TRACE|[Dd]ebug|DEBUG|[Nn]otice|NOTICE|[Ii]nfo|INFO|[Ww]arn?(?:ing)?|WARN?(?:ING)?|[Ee]rr?(?:or)?|ERR?(?:OR)?|[Cc]rit?(?:ical)?|CRIT?(?:ICAL)?|[Ff]atal|FATAL|[Ss]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?))(?:\s*)?\]\[(?<DATA:elasticsearch.component>.*?)(?:\s*)\]((?:\s*))?(\[(?<DATA:elasticsearch.node.name>.*?)\])?((?:\s*))?)(?:\s*)((\[(?<INDEXNAME:elasticsearch.index.name>[a-zA-Z0-9_.-]*)\]|\[(?<INDEXNAME:elasticsearch.index.name>[a-zA-Z0-9_.-]*)\/(?<DATA:elasticsearch.index.id>.*?)\]))?(?:\s*)(?<GREEDYMULTILINE:message>(.|
)*))/