元数据运维
除非绝对必要,否则请避免使用 metadata_failure_recovery
,使用可能会导致元数据截断、元数据丢失以及元数据 Split-brains 的发生。强烈建议谨慎使用此功能,以防止由于不规范的操作程序导致数据不可恢复的损坏。
本文档主要介绍在实际生产环境中,如何对 Doris 的元数据进行管理。包括 FE 节点建议的部署方式、一些常用的操作方法、以及常见错误的解决方法。
在阅读本文当前,请先阅读 Doris 元数据设计文档 了解 Doris 元数据的工作原理。
重要提示
- 当前元数据的设计是无法向后兼容的。即如果新版本有新增的元数据结构变动(可以查看 FE 代码中的
FeMetaVersion.java
文件中是否有新增的 VERSION),那么在升级到新版本后,通常是无法再回滚到旧版本的。所以,在升级 FE 之前,请务必按照 升级文档 中的操作,测试元数据兼容性。
元数据目录结构
我们假设在 fe.conf 中指定的 meta_dir
的路径为 /path/to/doris-meta
。那么一个正常运行中的 Doris 集群,元数据的目录结构应该如下:
/path/to/doris-meta/
|-- bdb/
| |-- 00000000.jdb
| |-- je.config.csv
| |-- je.info.0
| |-- je.info.0.lck
| |-- je.lck
| `-- je.stat.csv
`-- image/
|-- ROLE
|-- VERSION
`-- image.xxxx
-
bdb 目录
我们将 bdbje 作为一个分布式的 kv 系统,存放元数据的 journal。这个 bdb 目录相当于 bdbje 的“数据目录”。
其中
.jdb
后缀的是 bdbje 的数据文件。这些数据文件会随着元数据 journal 的不断增多而越来越多。当 Doris 定期做完 image 后,旧的日志就会被删除。所以正常情况下,这些数据文件的总大小从几 MB 到几 GB 不等(取决于使用 Doris 的方式,如导入频率等)。当数据文件的总大小大于 10GB,则可能需要怀疑是否是因为 image 没有成功,或者分发 image 失败导致的历史 journal 一直无法删除。je.info.0
是 bdbje 的运行日志。这个日志中的时间是 UTC+0 时区的。通过这个日志,也可以查看一些 bdbje 的运行情况。 -
image 目录
image 目录用于存放 Doris 定期生成的元数据镜像文件。通常情况下,你会看到有一个
image.xxxxx
的镜像文件。其中xxxxx
是一个数字。这个数字表示该镜像包含xxxxx
号之前的所有元数据 journal。而这个文件的生成时间(通过ls -al
查看即可)通常就是镜像的生成时间。你也可能会看到一个
image.ckpt
文件。这是一个正在生成的元数据镜像。通过du -sh
命令应该可以看到这个文件大小在不断变大,说明镜像内容正在写入这个文件。当镜像写完后,会自动重名为一个新的image.xxxxx
并替换旧的 image 文件。只有角色为 Master 的 FE 才会主动定期生成 image 文件。每次生成完后,都会推送给其他非 Master 角色的 FE。当确认其他所有 FE 都收到这个 image 后,Master FE 会删除 bdbje 中旧的元数据 journal。所以,如果 image 生成失败,或者 image 推送给其他 FE 失败时,都会导致 bdbje 中的数据不断累积。
ROLE
文件记录了 FE 的类型(FOLLOWER 或 OBSERVER),是一个文本文件。VERSION
文件记录了这个 Doris 集群的 cluster id,以及用于各个节点之间访问认证的 token,也是一个文本文件。ROLE
文件和VERSION
文件只可能同时存在,或同时不存在(如第一次启动时)。
基本操作
启动单节点 FE
单节点 FE 是最基本的一种部署方式。一个完整的 Doris 集群,至少需要一个 FE 节点。当只有一个 FE 节点时,这个节点的类型为 Follower,角色为 Master。
-
第一次启动
-
假设在 fe.conf 中指定的
meta_dir
的路径为/path/to/doris-meta
。 -
确保
/path/to/doris-meta
已存在,权限正确,且目录为空。 -
直接通过
bash bin/start_fe.sh --daemon
即可启动。 -
启动后,你应该可以在 fe.log 中看到如下日志:
- Palo FE starting...
- image does not exist: /path/to/doris-meta/image/image.0
- transfer from INIT to UNKNOWN
- transfer from UNKNOWN to MASTER
- the very first time to open bdb, dbname is 1
- start fencing, epoch number is 1
- finish replay in xxx msec
- QE service start
- thrift server started
以上日志不一定严格按照这个顺序,但基本类似。
-
单节点 FE 的第一次启动通常不会遇到问题。如果你没有看到以上日志,一般来说是没有仔细按照文档步骤操作,请仔细阅读相关 wiki。
-
-
重启
-
直接使用
bash bin/start_fe.sh
可以重新启动已经停止的 FE 节点。 -
重启后,你应该可以在 fe.log 中看到如下日志:
-
Palo FE starting...
-
finished to get cluster id: xxxx, role: FOLLOWER and node name: xxxx
-
如果重启前还没有 image 产生,则会看到:
- image does not exist: /path/to/doris-meta/image/image.0
-
如果重启前有 image 产生,则会看到:
- start load image from /path/to/doris-meta/image/image.xxx. is ckpt: false
- finished load image in xxx ms
-
transfer from INIT to UNKNOWN
-
replayed journal id is xxxx, replay to journal id is yyyy
-
transfer from UNKNOWN to MASTER
-
finish replay in xxx msec
-
master finish replay journal, can write now.
-
begin to generate new image: image.xxxx
-
start save image to /path/to/doris-meta/image/image.ckpt. is ckpt: true
-
finished save image /path/to/doris-meta/image/image.ckpt in xxx ms. checksum is xxxx
-
push image.xxx to other nodes. totally xx nodes, push succeeded xx nodes
-
QE service start
-
thrift server started
以上日志不一定严格按照这个顺序,但基本类似。
-
-
-
常见问题
对于单节点 FE 的部署,启停通常不会遇到什么问题。如果有问题,请先参照相关 wiki,仔细核对你的操作步骤。
添加 FE
添加 FE 流程在 弹性扩缩容 有详细介绍,不再赘述。这里主要说明一些注意事项,以及常见问题。
-
注意事项
- 在添加新的 FE 之前,一定先确保当前的 Master FE 运行正常(连接是否正常,JVM 是否正常,image 生成是否正常,bdbje 数据目录是否过大等等)
- 第一次启动新的 FE,一定确保添加了
--helper
参数指向 Master FE。再次启动时可不用添加--helper
。(如果指定了--helper
,FE 会直接询问 helper 节点自己的角色,如果没有指定,FE 会尝试从doris-meta/image/
目录下的ROLE
和VERSION
文件中获取信息)。 - 第一次启动新的 FE,一定确保这个 FE 的
meta_dir
已经创建、权限正确且为空。 - 启动新的 FE,和执行
ALTER SYSTEM ADD FOLLOWER/OBSERVER
语句在元数据添加 FE,这两个操作的顺序没有先后要求。如果先启动了新的 FE,而没有执行语句,则新的 FE 日志中会一直滚动current node is not added to the group. please add it first.
字样。当执行语句后,则会进入正常流程。 - 请确保前一个 FE 添加成功后,再添加下一个 FE。
- 建议直接连接到 MASTER FE 执行
ALTER SYSTEM ADD FOLLOWER/OBSERVER
语句。
-
常见问题
-
this node is DETACHED
当第一次启动一个待添加的 FE 时,如果 Master FE 上的 doris-meta/bdb 中的数据很大,则可能在待添加的 FE 日志中看到
this node is DETACHED.
字样。这时,bdbje 正在复制数据,你可以看到待添加的 FE 的bdb/
目录正在变大。这个过程通常会在数分钟不等(取决于 bdbje 中的数据量)。之后,fe.log 中可能会有一些 bdbje 相关的错误堆栈信息。如果最终日志中显示QE service start
和thrift server started
,则通常表示启动成功。可以通过 mysql-client 连接这个 FE 尝试操作。如果没有出现这些字样,则可能是 bdbje 复制日志超时等问题。这时,直接再次重启这个 FE,通常即可解决问题。 -
各种原因导致添加失败
-
如果添加的是 OBSERVER,因为 OBSERVER 类型的 FE 不参与元数据的多数写,理论上可以随意启停。因此,对于添加 OBSERVER 失败的情况。可以直接杀死 OBSERVER FE 的进程,清空 OBSERVER 的元数据目录后,重新进行一遍添加流程。
-
如果添加的是 FOLLOWER,因为 FOLLOWER 是参与元数据多数写的。所以有可能 FOLLOWER 已经加入 bdbje 选举组内。如果这时只有两个 FOLLOWER 节点(包括 MASTER),那么停掉一个 FE,可能导致另一个 FE 也因无法进行多数写而退出。此时,我们应该先通过
ALTER SYSTEM DROP FOLLOWER
命令,从元数据中删除新添加的 FOLLOWER 节点,然后再杀死 FOLLOWER 进程,清空元数据,重新进行一遍添加流程。
-
-
删除 FE
通过 ALTER SYSTEM DROP FOLLOWER/OBSERVER
命令即可删除对应类型的 FE。以下有几点注意事项:
-
对于 OBSERVER 类型的 FE,直接 DROP 即可,无风险。
-
对于 FOLLOWER 类型的 FE。首先,应保证在有奇数个 FOLLOWER 的情况下(3 个或以上),开始删除操作。
- 如果删除非 MASTER 角色的 FE,建议连接到 MASTER FE,执行 DROP 命令,再杀死进程即可。
- 如果要删除 MASTER FE,先确认有
奇数个
FOLLOWER FE并且运行正常
。然后先杀死 MASTER FE 的进程。这时会有某一个 FE 被选举为 MASTER。在确认剩下的 FE 运行正常后,连接到新的 MASTER FE,执行 DROP 命令删除之前老的 MASTER FE 即可。
高级操作
FE 元数据恢复模式
元数据恢复模式
使用不当或操作错误容易造成生产环境不可恢复的数据损坏,因此不再提供元数据恢复模式
的操作文档;如果确有需求,请联系 Doris 社区的开发者
FE 类型变更
如果你需要将当前已有的 FOLLOWER/OBSERVER 类型的 FE,变更为 OBSERVER/FOLLOWER 类型,请先按照前面所述的方式删除 FE,再添加对应类型的 FE 即可
FE 迁移
如果你需要将一个 FE 从当前节点迁移到另一个节点,分以下几种情况。
-
非 MASTER 节点的 FOLLOWER,或者 OBSERVER 迁移
直接添加新的 FOLLOWER/OBSERVER 成功后,删除旧的 FOLLOWER/OBSERVER 即可。
-
单节点 MASTER 迁移
如果你是开发者,这可通过
元数据恢复模式
进行操作,如果你是使用者,不建议使用元数据恢复模式
,建议通过重新搭建环境通过 外表的方式转移数据 -
一组 FOLLOWER 从一组节点迁移到另一组新的节点
在新的节点上部署 FE,通过添加 FOLLOWER 的方式先加入新节点。再逐台 DROP 掉旧节点即可。在逐台 DROP 的过程中,MASTER 会自动选择在新的 FOLLOWER 节点上。
更换 FE 端口
FE 目前有以下几个端口
- edit_log_port:bdbje 的通信端口
- http_port:http 端口,也用于推送 image
- rpc_port:FE 的 thrift server port
- query_port:Mysql 连接端口
- arrow_flight_sql_port: Arrow Flight SQL 连接端口
-
edit_log_port
如果需要更换这个端口,如果是多节点可按节点扩缩容的步骤下线旧节点,重新加入修改配置后的新节点;如果是单节点,参见 FE 迁移中"单节点 MASTER 迁移"
-
http_port
所有 FE 的 http_port 必须保持一致。所以如果要修改这个端口,则所有 FE 都需要同时停机修改后并重启。
-
rpc_port
修改配置后,直接重启 FE 即可。Master FE 会通过心跳将新的端口告知 BE。只有 Master FE 的这个端口会被使用。但仍然建议所有 FE 的端口保持一致。
-
query_port
修改配置后,直接重启 FE 即可。这个只影响到 mysql 的连接目标。
-
arrow_flight_sql_port
修改配置后,直接重启 FE 即可。这个只影响到 Arrow Flight SQL 的连接目标。
查看 BDBJE 中的数据 (仅用于调试)
FE 的元数据日志以 Key-Value 的方式存储在 BDBJE 中。某些异常情况下,可能因为元数据错误而无法启动 FE。在这种情况下,Doris 提供一种方式可以帮助用户查询 BDBJE 中存储的数据,以方便进行问题排查。
首先需在 fe.conf 中增加配置:enable_bdbje_debug_mode=true
,之后通过 bash start_fe.sh --daemon
启动 FE。
此时,FE 将进入 debug 模式,仅会启动 http server 和 MySQL server,并打开 BDBJE 实例,但不会进行任何元数据的加载及后续其他启动流程。
这时,我们可以通过访问 FE 的 web 页面,或通过 MySQL 客户端连接到 Doris 后,通过 show proc "/bdbje";
来查看 BDBJE 中存储的数据。
mysql> show proc "/bdbje";
+----------+---------------+---------+
| DbNames | JournalNumber | Comment |
+----------+---------------+---------+
| 110589 | 4273 | |
| epochDB | 4 | |
| metricDB | 430694 | |
+----------+---------------+---------+
第一级目录会展示 BDBJE 中所有的 database 名称,以及每个 database 中的 entry 数量。
mysql> show proc "/bdbje/110589";
+-----------+
| JournalId |
+-----------+
| 1 |
| 2 |
...
| 114858 |
| 114859 |
| 114860 |
| 114861 |
+-----------+
4273 rows in set (0.06 sec)
进入第二级,则会罗列指定 database 下的所有 entry 的 key。
mysql> show proc "/bdbje/110589/114861";
+-----------+--------------+---------------------------------------------+
| JournalId | OpType | Data |
+-----------+--------------+---------------------------------------------+
| 114861 | OP_HEARTBEAT | org.apache.doris.persist.HbPackage@6583d5fb |
+-----------+--------------+---------------------------------------------+
1 row in set (0.05 sec)
第三级则可以展示指定 key 的 value 信息。
最佳实践
FE 的部署推荐,在 安装与部署文档 中有介绍,这里再做一些补充。
-
如果你并不十分了解 FE 元数据的运行逻辑,或者没有足够 FE 元数据的运维经验,我们强烈建议在实际使用中,只部署一个 FOLLOWER 类型的 FE 作为 MASTER,其余 FE 都是 OBSERVER,这样可以减少很多复杂的运维问题! 不用过于担心 MASTER 单点故障导致无法进行元数据写操作。首先,如果你配置合理,FE 作为 java 进程很难挂掉。其次,如果 MASTER 磁盘损坏(概率非常低),我们也可以用 OBSERVER 上的元数据,通过
元数据恢复模式
的方式手动恢复。 -
FE 进程的 JVM 一定要保证足够的内存。我们强烈建议 FE 的 JVM 内存至少在 10GB 以上,推荐 32GB 至 64GB。并且部署监控来监控 JVM 的内存使用情况。因为如果 FE 出现 OOM,可能导致元数据写入失败,造成一些无法恢复的故障!
-
FE 所在节点要有足够的磁盘空间,以防止元数据过大导致磁盘空间不足。同时 FE 日志也会占用十几 G 的磁盘空间。
其他常见问题
-
fe.log 中一直滚动
meta out of date. current time: xxx, synchronized time: xxx, has log: xxx, fe type: xxx
这个通常是因为 FE 无法选举出 Master。比如配置了 3 个 FOLLOWER,但是只启动了一个 FOLLOWER,则这个 FOLLOWER 会出现这个问题。通常,只要同时重新启动所有 FOLLOWER 就可以了。如果启动起来后,仍然没有解决问题,那么可能需要进一步排查是否有其他未知问题。
-
Clock delta: xxxx ms. between Feeder: xxxx and this Replica exceeds max permissible delta: xxxx ms.
bdbje 要求各个节点之间的时钟误差不能超过一定阈值。如果超过,节点会异常退出。我们默认设置的阈值为 5000 ms,由 FE 的参数
max_bdbje_clock_delta_ms
控制,可以酌情修改。但我们建议使用 ntp 等时钟同步方式保证 Doris 集群各主机的时钟同步。 -
image/
目录下的镜像文件很久没有更新Master FE 会默认每 50000 条元数据 journal,生成一个镜像文件。在一个频繁使用的集群中,通常每隔半天到几天的时间,就会生成一个新的 image 文件。如果你发现 image 文件已经很久没有更新了(比如超过一个星期),则可以顺序的按照如下方法,查看具体原因:
-
在 Master FE 的 fe.log 中搜索
memory is not enough to do checkpoint. Committed memory xxxx Bytes, used memory xxxx Bytes.
字样。如果找到,则说明当前 FE 的 JVM 内存不足以用于生成镜像(通常我们需要预留一半的 FE 内存用于 image 的生成)。那么需要增加 JVM 的内存并重启 FE 后,再观察。每次 Master FE 重启后,都会直接生成一个新的 image。也可用这种重启方式,主动地生成新的 image。注意,如果是多 FOLLOWER 部署,那么当你重启当前 Master FE 后,另一个 FOLLOWER FE 会变成 MASTER,则后续的 image 生成会由新的 Master 负责。因此,你可能需要修改所有 FOLLOWER FE 的 JVM 内存配置。 -
在 Master FE 的 fe.log 中搜索
begin to generate new image: image.xxxx
。如果找到,则说明开始生成 image 了。检查这个线程的后续日志,如果出现checkpoint finished save image.xxxx
,则说明 image 写入成功。如果出现Exception when generate new image file
,则生成失败,需要查看具体的错误信息。
-
-
bdb/
目录的大小非常大,达到几个 G 或更多如果在排除无法生成新的 image 的错误后,bdb 目录在一段时间内依然很大。则可能是因为 Master FE 推送 image 不成功。可以在 Master FE 的 fe.log 中搜索
push image.xxxx to other nodes. totally xx nodes, push succeeded yy nodes
。如果 yy 比 xx 小,则说明有的 FE 没有被推送成功。可以在 fe.log 中查看到具体的错误Exception when pushing image file. url = xxx
。同时,你也可以在 FE 的配置文件中添加配置:
edit_log_roll_num=xxxx
。该参数设定了每多少条元数据 journal,做一次 image。默认是 50000。可以适当改小这个数字,使得 image 更加频繁,从而加速删除旧的 journal。 -
FOLLOWER FE 接连挂掉
因为 Doris 的元数据采用多数写策略,即一条元数据 journal 必须至少写入多数个 FOLLOWER FE 后(比如 3 个 FOLLOWER,必须写成功 2 个),才算成功。而如果写入失败,FE 进程会主动退出。那么假设有 A、B、C 三个 FOLLOWER,C 先挂掉,然后 B 再挂掉,那么 A 也会跟着挂掉。所以如
最佳实践
一节中所述,如果你没有丰富的元数据运维经验,不建议部署多 FOLLOWER。 -
fe.log 中出现
get exception when try to close previously opened bdb database. ignore it
如果后面有
ignore it
字样,通常无需处理。如果你有兴趣,可以在BDBEnvironment.java
搜索这个错误,查看相关注释说明。 -
从
show frontends;
看,某个 FE 的Join
列为true
,但是实际该 FE 不正常通过
show frontends;
查看到的Join
信息。该列如果为true
,仅表示这个 FE 曾经加入过 集群。并不能表示当前仍然正常的存在于集群中。如果为false
,则表示这个 FE 从未加入过 集群。 -
关于 FE 的配置
master_sync_policy
,replica_sync_policy
和txn_rollback_limit
master_sync_policy
用于指定当 Leader FE 写元数据日志时,是否调用 fsync(),replica_sync_policy
用于指定当 FE HA 部署时,其他 Follower FE 在同步元数据时,是否调用 fsync()。在早期的 Doris 版本中,这两个参数默认是WRITE_NO_SYNC
,即都不调用 fsync()。在最新版本的 Doris 中,默认已修改为SYNC
,即都调用 fsync()。调用 fsync() 会显著降低元数据写盘的效率。在某些环境下,IOPS 可能降至几百,延迟增加到 2-3ms(但对于 Doris 元数据操作依然够用)。因此我们建议以下配置:- 对于单 Follower FE 部署,
master_sync_policy
设置为SYNC
,防止 FE 系统宕机导致元数据丢失。 - 对于多 Follower FE 部署,可以将
master_sync_policy
和replica_sync_policy
设为WRITE_NO_SYNC
,因为我们认为多个系统同时宕机的概率非常低。
如果在单 Follower FE 部署中,
master_sync_policy
设置为WRITE_NO_SYNC
,则可能出现 FE 系统宕机导致元数据丢失。这时如果有其他 Observer FE 尝试重启时,可能会报错:Node xxx must rollback xx total commits(numPassedDurableCommits of which were durable) to the earliest point indicated by transaction xxxx in order to rejoin the replication group, but the transaction rollback limit of xxx prohibits this.
意思有部分已经持久化的事务需要回滚,但条数超过上限。这里我们的默认上限是 100,可以通过设置
txn_rollback_limit
改变。该操作仅用于尝试正常启动 FE,但已丢失的元数据无法恢复。 - 对于单 Follower FE 部署,