5.0 起所有设置在生效前都要校验:节点级和默认索引级设置在启动时校验,动态设置在更新前校验,且每个设置必须是"已注册"的。同时一批老设置被改名或删除:索引级设置不能再在节点级配置、
name换成node.name、节点属性必须放node.attr.命名空间、node.client删除、带netty中缀的设置换成transport同义项。本文对照 v5.6.16 源码,把"未知设置""节点级索引设置"两种启动失败的报错原文和处理办法写出来。
说明
来源和边界先交代:本文的依据出自 v5.6.16 标签下的官方文件(settings.asciidoc、AbstractScopedSettings.java、Plugin.java),文中引用的原文均来自这些文件。我没有启动集群、也没有跑测试,示例取自官方示例;哪些是文档写明、哪些是我的推断,正文里逐处标注。

图 1:官方文件 settings.asciidoc(v5.6.16 标签)。来源:GitHub elastic/elasticsearch v5.6.16 settings.asciidoc
校验变严
5.0 迁移文档 Settings 一节(migrate_5_0/settings.asciidoc 第 4–13 行)开头:
From Elasticsearch 5.0 on all settings are validated before they are applied. Node level and default index level settings are validated on node startup, dynamic cluster and index setting are validated before they are updated/added to the cluster state.
Every setting must be a known setting. All settings must have been registered with the node or transport client they are used with.
按这段说法,以前没有这层校验,拼错的设置名不会让节点起不来。5.0 起,未注册的设置会让节点启动失败。源码里报错的位置是 AbstractScopedSettings.validate 第 268–296 行,消息格式是:
unknown setting [xxx] did you mean [yyy]?
unknown setting [xxx] please check that any required plugins are installed, or check the breaking changes documentation for removed settings
前一种是和已注册设置的编辑距离超过 0.7 时给出的拼写建议,后一种是找不到相近项时的兜底提示。看到第二种,先查是下面几节就是这张对照表,不是被删除或改名的老设置。
对插件作者,迁移文档要求自定义设置在插件加载时注册。5.6.16 里的入口是 Plugin#getSettings(),返回要注册的 Setting 列表;文档里写的 SettingsModule#registerSettings 是 5.0 发布时的说法,写新插件按 getSettings() 来。SettingsModule 的注释也说明,没有注册的设置不可用,指定了就会在启动时被节点拒绝。

图 2:官方文件 AbstractScopedSettings.java(v5.6.16 标签)。来源:GitHub elastic/elasticsearch v5.6.16 AbstractScopedSettings.java
升级要先过启动校验,而不是先看功能
这类改动没有"部分生效",要么校验通过,要么节点起不来。所以我的判断是:升级 5.x 最先要做的,是用目标版本把现有 elasticsearch.yml 校验一遍,功能变化可以往后放。在灰度节点上先起一个,把所有未知设置的报错一次看完,再滚动升级其余节点,比一个节点一个节点地试省事。

图 3:官方文件 templates.asciidoc(v5.6.16 标签)。来源:GitHub elastic/elasticsearch v5.6.16 templates.asciidoc
升级前怎么把未知设置找出来
难点是找出配置里有哪些设置已经不认识。可以先把配置文件里实际写了的设置列出来:
grep -v '^\s*#' $ES_PATH_CONF/elasticsearch.yml | grep -v '^\s*$'
然后拿目标版本起一个灰度节点(哪怕只在容器里起一下再停),让它自己报。报错一次只显示一个未知设置,改一个再起一次,直到启动成功。重点看这几类:
- 拼写错误的设置:报
unknown setting [..] did you mean [..]?,最容易改; - 已经改名或删除的设置:按迁移表逐个改,下面几节列了;
- 索引级设置写在节点级:是另一条报错,见下一节,不是"未知设置"。
我的默认做法是在 CI 里加一步配置校验:每次升级前,把 elasticsearch.yml 拿去新版本里启动一次。5.0 之后每次升级都可以这么做,比靠人记着省事。
索引级设置不能再写在节点级
官方原文(第 15–22 行):
In previous versions Elasticsearch allowed to specify index level setting as defaults on the node level, inside the
elasticsearch.yamlfile or even via command-line parameters. From Elasticsearch 5.0 on only selected settings like for instanceindex.codeccan be set on the node level. All other settings must be set on each individual index. To set default values on every index, index templates should be used instead.
源码在 SettingsModule 第 82–132 行:节点设置里凡是以 index. 开头、又不是集群级注册设置的,会先打一段 WARN 日志,再抛 IllegalArgumentException:
node settings must not contain any index level settings
WARN 日志里的说明是:5.x 起索引级设置不能写在节点配置、系统属性或命令行参数里;要升级已有索引,用 /${index}/_settings 更新;如果设置不都是动态的,要先关闭索引;以后新建的索引用索引模板设默认值。
所以这类报错的处理动作是:把设置搬到索引模板里(新索引)并用 _settings 更新现有索引,不是简单删掉,否则默认值就丢了。5.x 的模板用 template 字段匹配索引名(templates 文档开头示例),不是 index_patterns(那是后续大版本的写法):
PUT _template/defaults
{
"template": "*",
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
}
}
模板只在索引创建时生效,改模板不影响已有索引。
节点相关设置的改名与删除
对应迁移文档第 24–48 行:
| 旧 | 新/状态 |
|---|---|
name |
改为 node.name;-Dname=xxx 不再支持 |
node.add_id_to_custom_path |
改名 add_lock_id_to_custom_path |
node.name 默认值 |
改为节点 ID 的前 7 个字符(节点 ID 是随机 UUID) |
node.mode、node.local |
删除;本地模式用 transport.type: local,关 HTTP 用 http.enabled: false |
node.client |
删除;配了它的节点无法启动 |
节点属性 node.xxx |
必须放 node.attr. 命名空间(node.master、node.data、node.ingest 例外) |
node.name 默认值的变化要看 2.4.6 的实现:InternalSettingsPreparer 第 177–190 行在没设置 node.name 时调用 randomNodeName,从 names.txt 里随机取一个名字。所以 2.x 默认的是一个随机的名字,不是主机名;5.0 起改成节点 ID 的前 7 位。无论哪个版本,默认名都不能对应到具体机器。如果日志、监控、告警里需要靠节点名找机器,显式配置,官方配置文档里的示例就是(configuration.asciidoc 第 62 行):
node.name: ${
HOSTNAME}
node.client 删除之后,"客户端节点"这个打包角色没有了。迁移文档要求每个角色单独设置,只做协调的节点写成:
node.master: false
node.data: false
node.ingest: false
文档原文说的是"各个角色要用已有的 node.master、node.data、node.ingest 分别设置"。是否要关掉 ingest,取决于这个节点是否还要承担 ingest 任务,上面是纯协调节点的写法。
老的配置模板里可能还留着 node.client,升级前 grep 一遍比等启动失败快:
grep -rn 'node.client' $ES_PATH_CONF
节点属性命名空间
分配过滤(allocation filtering)、forced awareness、节点分组用到的属性,都要带 node.attr. 前缀:
# 2.x
node.rack: r1
# 5.0
node.attr.rack: r1
源码里 Node.NODE_ATTRIBUTES 是一个 group setting,前缀是 node.attr.;DiscoveryNode 从这里读属性。旧的 node.rack 在 5.0 里没有注册,按上文的校验会在启动时被拒绝,不是静默失效。迁移时仍然要验证一次属性读到了没有:
curl -s 'localhost:9200/_cat/nodeattrs?v'
这个 cat 接口在 5.6.16 里存在(RestNodeAttrsAction),列出每个节点的属性。分配过滤规则(如 index.routing.allocation.require.rack)里引用的属性名,要和 node.attr. 之后的名字一致。
传输层设置去掉 netty 中缀
All settings with a
nettyinfix have been replaced by their already existingtransportsynonyms. For instancetransport.netty.bind_hostis no longer supported and should be replaced by the superseding settingtransport.bind_host.
transport.netty.bind_host 这类带 netty 的写法,改成已经存在的同义设置 transport.bind_host。做全局替换前先确认目标名在 5.x 里存在,不是所有带 netty 的设置都有同义项;哪些没有,以启动时的 unknown setting 提示为准。
同一页里还有几处会让节点起不来的删除
迁移文档同一页还列出这些,没有在本文逐项展开,升级前一并 grep:
gateway.format删除,默认用smile(第 50–53 行);security.manager.enabled删除,要加权限只能改本地 Java 安全策略(第 62–66 行);network.host等设置里的_non_loopback_值删除,改用_local_,_site_这类地址范围或明确的接口、地址(第 68–73 行);- 线程池设置前缀
threadpool改成thread_pool,线程池类型不能再改,suggest线程池删除(第 79–108 行); discovery.zen.initial_ping_timeout、discovery.zen.ping.timeout删除,只保留discovery.zen.ping_timeout(第 116–122 行);index.analysis.analyzer.default_index不再支持,改用index.analysis.analyzer.default(第 110–114 行)。
升级前的检查清单
- 把
elasticsearch.yml逐行过一遍,拼错或已删除的设置先清掉,5.0 会拒绝启动; - 节点级写的索引默认设置迁移到索引模板,已有索引用
_settings更新; name改node.name,node.add_id_to_custom_path改add_lock_id_to_custom_path;- 自定义节点属性加
node.attr.前缀,并确认分配过滤规则仍生效; - 用
node.client: true的节点改成显式的角色设置; - 所有
transport.netty.*改成transport.*; - 自带插件按
Plugin#getSettings()注册设置,第三方插件确认有 5.x 版本; - 同一页其余的删除项(见上节)过一遍。
写在最后
设置校验从严带来的变化是:配置错误从"悄悄没生效"变成"启动就失败"。这是按迁移文档"5.0 起所有设置都要校验"的说法得出的理解。代价是升级时会一次性遇到积累下来的问题,好处是以后配置里的拼写错误会在启动时暴露。
做法上,先用灰度节点把报错一次跑完,再滚动升级;同时把配置里没人知道为什么存在的旧项清掉,之后每次升级的配置校验也会轻松些。
参考
本文对照 Elasticsearch
v5.6.16标签的官方文档核对,引文逐字取自原文。撰写时未启动集群、未运行测试。