此文档提供 OceanBase 数据库开启和关闭归档的流程,以及归档过程中可能涉及的内部表查询方法,帮助用户进行问题定位和排查。以下查询 SQL 以 SYS 租户执行。
开启或关闭归档
执行如下 SQL 为用户租户配置归档目的端。
obclient> alter system set log_archive_dest='LOCATION=file:///data/1';
执行如下 SQL 开启归档。
obclient> alter system archivelog;
开启归档流程
- 用户执行
alter system archivelog后,由 RS 添加一行记录到该表,并且设置初始status为PREPARE。 - RS 在做初步检查等操作成功后,会将状态推到
BEGINNING。 - OBServer 通过监控该表状态为
BEGINNING或DOING感知到需要开启归档,会持续为日志流归档日志,并将日志流归档进度更新到另外一张日志流级别视图CDB_OB_LS_LOG_ARCHIVE_PROGRESS,并标示状态为DOING。 - RS 检测日志流状态表
CDB_OB_LS以及CDB_OB_LS_LOG_ARCHIVE_PROGRESS表,当所有日志流归档状态都是DOING,则 RS 将该表状态推到DOING。 - RS 检测到
CDB_OB_LS_LOG_ARCHIVE_PROGRESS中日志流归档状态为INTERRUPT,会将租户级归档视图CDB_OB_ARCHIVELOG状态置为INTERRUPT。
执行如下 SQL 关闭归档。
obclient> alter system noarchivelog;
关闭归档流程
- 用户执行
alter system noarchivelog,首先 RS 将该行记录状态设置为STOPPING。 - OBServer 检测到该表状态为
STOPPING,结束为日志流归档,并将__all_ls_log_archive_progress表已存在日志流的状态置为STOP。 - RS 检查到
CDB_OB_LS_LOG_ARCHIVE_PROGRESS表所有日志流归档状态都是STOP,将该表归档状态置为STOP。
内部表
问题排查涉及到内部表都是普通租户对应 meta 租户下的内部表。
CDB_OB_ARCHIVE_DEST
该表保存归档路径,也是可以发起归档的前置条件。如果该表为空,则该租户无法归档。
查询示例如下:
obclient> select * from CDB_OB_ARCHIVE_DEST where tenant_id = 100X;
+-----------+---------+-----------------------+--------------------------------------------------------+
| TENANT_ID | DEST_NO | NAME | VALUE |
+-----------+---------+-----------------------+--------------------------------------------------------+
| 1002 | 0 | binding | OPTIONAL |
| 1002 | 0 | dest_id | 1002 |
| 1002 | 0 | lag_target | 1d |
| 1002 | 0 | path | file:///data/1/shuning//ob_backup_mysql_tenant/archive |
| 1002 | 0 | piece_switch_interval | 1d |
| 1002 | 0 | state | ENABLE |
+-----------+---------+-----------------------+--------------------------------------------------------+
CDB_OB_ARCHIVELOG
该表为租户级归档进度表。
查询示例如下:
obclient> select * from oceanbase.CDB_OB_ARCHIVELOG where tenant_id = 1002\G;
*************************** 1. row ***************************
TENANT_ID: 1002
DEST_ID: 1001
ROUND_ID: 1
INCARNATION: 1
DEST_NO: 0
STATUS: STOP
START_SCN: 1706670992366131000
START_SCN_DISPLAY: 2024-01-31 11:16:32.366131
CHECKPOINT_SCN: 1706682875884361003
CHECKPOINT_SCN_DISPLAY: 2024-01-31 14:34:35.884361
COMPATIBLE: 1
BASE_PIECE_ID: 1
USED_PIECE_ID: 1
PIECE_SWITCH_INTERVAL: 86400000000
UNIT_SIZE: 1
COMPRESSION: none
INPUT_BYTES: 85090352
INPUT_BYTES_DISPLAY: 81.15MB
OUTPUT_BYTES: 85090352
OUTPUT_BYTES_DISPLAY: 81.15MB
COMPRESSION_RATIO: 1.00
DELETED_INPUT_BYTES: 0
DELETED_INPUT_BYTES_DISPLAY: 0.00MB
DELETED_OUTPUT_BYTES: 0
DELETED_OUTPUT_BYTES_DISPLAY: 0.00MB
COMMENT:
PATH: file:///home/admin/mwxarvg
1 row in set (0.041 sec)
其中:
status表示该租户归档状态,包括正常状态PREPARE、BEGINNING、DOING、STOPPING、STOP以及异常状态INTERRUPT。start_scn为租户归档起始时间,普通租户下所有日志流log_scn大于等于该值的日志都需要被归档出去。checkpoint_scn为租户归档进度,为所有日志流归档进度的最小值。
CDB_OB_LS_LOG_ARCHIVE_PROGRESS
该表为日志流级别归档进度表,开启归档后,每个日志流每个 piece 一行记录,其中状态包括正常 DOING、STOP 以及异常状态 INTERRUPT。
查询示例如下:
obclient [oceanbase]> select * from oceanbase.CDB_OB_LS_LOG_ARCHIVE_PROGRESS where tenant_id = 1002\G;
*************************** 1. row ***************************
TENANT_ID: 1002
DEST_ID: 1001
LS_ID: 1
ROUND_ID: 1
PIECE_ID: 1
INCARNATION: 1
START_SCN: 1706670992366131000
MIN_LSN: 3086819328
MAX_LSN: 3113961131
CHECKPOINT_SCN: 1706682875884361003
STATUS: STOP
FILE_ID: 47
FILE_OFFSET: 27141803
INPUT_BYTES: 27141803
OUTPUT_BYTES: 27141803
其中:
start_scn: 表示日志流该 piece 下已归档最小日志的log_scn,其中第一个 piece 比较特殊,是租户归档起始时间。max_lsn: 表示日志流该 piece 下已归档日志最大lsn。checkpoint_scn:表示该日志流该 piece 下已归档日志最大log_scn。file_id或file_offset:表示归档介质上该日志流该 piece 下最大归档文件编号以及文件内偏移。piece:由于 clog 需要源源不断归档到存储介质并需要长时间保存,因此无法像 clog 文件一样平铺在一级目录下,而 piece 即按照时间维度做的归档日志文件的切片,一个 piece 包含一段时间的日志。
在 __all_ls_log_archive_progress 中,每个 piece(通常为一天)一行记录,当更大 piece_id 的记录产生,旧的 piece 行记录不再修改。(例外,当关闭归档时,所有 piece 状态变为 STOP)。
obclient> select * from CDB_OB_LS_LOG_ARCHIVE_PROGRESS where piece_id = 2;
+-----------+---------+-------+----------+----------+-------------+---------------------+---------+----------+---------------------+--------+---------+-------------+-------------+--------------+
| TENANT_ID | DEST_ID | LS_ID | ROUND_ID | PIECE_ID | INCARNATION | START_SCN | MIN_LSN | MAX_LSN | CHECKPOINT_SCN | STATUS | FILE_ID | FILE_OFFSET | INPUT_BYTES | OUTPUT_BYTES |
+-----------+---------+-------+----------+----------+-------------+---------------------+---------+----------+---------------------+--------+---------+-------------+-------------+--------------+
| 1002 | 1002 | 1 | 1 | 2 | 1 | 1691115152597490000 | 9693359 | 10186648 | 1691115272257855453 | DOING | 1 | 493289 | 493289 | 493289 |
| 1002 | 1002 | 1001 | 1 | 2 | 1 | 1691115152597490000 | 151094 | 294108 | 1691115272257855453 | DOING | 1 | 143014 | 143014 | 143014 |
+-----------+---------+-------+----------+----------+-------------+---------------------+---------+----------+---------------------+--------+---------+-------------+-------------+--------------+
__all_virtual_archive_stat
日志流级别归档状态虚拟表,展示归档各个模块实时进度。其中 max_issued_log_lsn 为下文中 sequencer 模块进度(已产生读取日志任务 LSN),max_prepared_lsn 为 fetcher 模块进度(已读取日志最大 LSN),archive_lsn 为 sender 模块进度(已归档到介质日志最大 LSN)。
obclient> select * from __all_virtual_archive_stat \G
*************************** 1. row ***************************
tenant_id: 1002
ls_id: 1
svr_ip: 100.83.xx.xxx
svr_port: 42924
dest_id: 1002
incarnation: 1
round_id: 1
dest_type: Location
dest_value: DefaultDestLocation
lease_id: 0
round_start_scn: 1691115032597490972
max_issued_log_lsn: 738152448
issued_task_count: 1
issued_task_size: 28944113
max_prepared_piece_id: 3731
max_prepared_lsn: 709208335
max_prepared_scn: 1691562735282634001
wait_send_task_count: 0
archive_piece_id: 3731
archive_lsn: 709208335
archive_scn: 1691562735282634001
archive_file_id: 11
archive_file_offset: 156828
OBServer 开启归档
当 OBServer 周期性刷新
__all_log_archive_progress表,感知到 RS 已经进入BEGINNING或DOING状态,会进入归档状态,这由ObArchiveService线程执行。通过 OBServer 日志监测归档是否成功开启:
开启关闭或归档由普通租户
ObArchiveService线程执行,比如T1002_ArcSrv。grep “T1002_ArcSrv” observer.log以下皆为该线程关键日志打印。
检查 OBServer 是否需要开启或关闭归档。
grep "check_if_need_switch_log_archive_" observer.log检查是否将归档信息设置到本机。
grep "set log archive info succ" observer.log检查开启归档是否成功。
grep "start archive succ" observer.log检查关闭归档是否完成。
grep "switch log archive status from in_stopping to stopped succ" observer.log
当 OBServer 进入归档状态,会为本机
palf role为 LEADER 的日志流开启归档。开启归档是指确认日志流在本机上归档的起点,并添加日志流到归档管理任务中。确定归档起点包括该日志流第一次开启归档,也可能是开启归档后切主继续归档。说明
如果是第一次开启归档,从 palf 定位第一条大于等于归档起点的日志作为开启归档的起点。
如果是切主后继续归档,会从__all_ls_log_archive_progress表获取最新归档进度作为继续归档的起点。 可以查询虚拟表__all_virtual_archive_stat,或者grep日志add ls archive task succ检查该日志流开启归档的起点。下述的日志搜索需要以租户前缀过滤,如
T1002_Arc,以下省略该过滤。检查日志流开启归档成功。
grep "add ls archive task succ" observer.log查看第一次开启归档起点。
grep "locate_round_start_archive_point_ succ" observer.log继续开启归档。
grep "fetch exist archive progress succ" observer.log
sequencer 模块为所有本 OBServer 服务日志流定序。
产生归档调度任务。
grep "generate log fetch task succ" observer.log提交读取日志任务
grep "submit log fetch task succ" observer.log
fetcher 支持并行读取日志。
具体流程如下:
获取读取任务并进行处理。
如果没有读取日志任务,会周期性打印日志,可以通过如下命令查询相关日志。(该日志为 TRACE 级别日志)
grep "no task exist, just skip" observer.log日志读取任务需要 delay 处理, 比如没有聚合足够大小的块,可以通过如下命令查询相关日志。
grep "need delay" observer.log
初始化日志迭代器以及 helper。
执行如下命令,查询是否初始化成功。
grep "init helper succ" observer.log
开始迭代读取日志。
将任务 push 到 LSArchiveTask 并排序。
读取日志成功后会打印相关日志,可以通过如下命令查询。
grep "append log entry succ" observer.log处理读取日志任务成功后会打印相关日志,可以通过如下命令查询。
grep "handle log fetch task succ" observer.log将日志块提交排序成功后会打印相关日志,可以通过如下命令查询。
grep "push fetch log succ" observer.log提交排序后的日志块成功后会打印相关日志,可以通过如下命令查询。
grep "try consume task status succ" observer.log
顺序将日志提交到 sender 模块。
提交 send task 任务成功后会打印相关日志,可以通过如下命令查询。
grep "push succ" observer.log | grep sender
sender 归档日志。
如果归档介质有问题,会报错并打印相关日志,可以通过如下命令查询。
grep "push log failed" observer.log创建归档目录成功,仅在目录不存在时创建。
grep "archive dir make succ" observer.log
归档进度持久化
ObArchiveService 线程会周期性将归档进度持久化到内部表 __all_ls_log_archive_progress 表,如果虚拟表归档进度更新正常,而持久化到该表进度卡住,则可以查看日志分析。
查看持久化相关日志。
grep ob_archive_persist_mgr.cpp observer.log
根据 ObArchiveService 线程 grep 日志。
grep "T1002_ArcSrv" observer.log
日志流开启归档
第一次开启归档或者切主,都会为 LEADER 日志流开启归档,当遇到某个日志流没有归档任务或者落后,可以按照如下排查:
确认日志流是否有主。
select * from oceanbase.__all_virtual_log_stat where tenant_id = 1002 and ls_id = 1001;根据虚拟表确认日志流是否在做归档。
select * from oceanbase.__all_virtual_archive_stat where tenant_id = 1002 and ls_id = 1001;如果没有归档任务,找到 leader 所在 OBServer,
grep日志。grep "ob_start_archive_helper.cpp" observer.log
切 piece
归档按照 piece 组织目录,切 piece 是很关键也容易出现问题的地方。
关键日志,关键字
ARCHIVE,日志 observer.log。# fetcher 关键日志 # 发现新piece "set next piece succ" # sender 关键日志 # 前一个 piece 持久化进度未刷新到本地,需要等待本地进度更新成功 "pre piece archive progress not persist, just wait" # 前一个 piece 最大进度未持久化成功,需要等待。 "persist lsn not equal with send task" # 补偿空 piece "persist lsn equal with send task and gap of persist piece id"基本流程
- fetcher 消费日志,发现并产生新 piece,并结束旧 piece。
- sender 模块归档日志,当发现新 piece,1) 等旧的 piece 最大归档进度持久化到内部表成功,并刷新到本地;2) 如果发现 piece id 不连续,会补空 piece。
- sender 模块发现旧 piece 归档进度已经持久化成功,则开始归档新 piece 所属日志。
- 新的 piece 的进度更新到
__all_ls_log_archive_progress表。 - rs 监控
__all_ls_log_archive_progress表,并发现新 piece,更新租户级 piece 进度。
归档断流
归档断流,即归档状态为 INTERRUPT 状态,按照以下方式排查:
查询断流时间以及可能得原因:
select * from __all_server_event_history where event like 'mark_fatal_error' order by gmt_create desc limit 30;
如图是由于未归档完成 CLOG 已回收导致:

该记录的生成时间是断流时间,svr_ip 或 port 是断流 OBServer,查询断流附近日志。找到导致断流的线程日志上下文,大致可以了解是何原因导致的断流。
grep TXXXX_Arc observer.log
如图是某个归档到 OSS 环境 observer 日志信息:

其中 statistic 信息展示了归档 Sender 现场一些统计,比如单个 IO 耗时 17s,带宽仅 1.9M/s 等。 根据这些指标评估断流是不是因为归档速度跟不上 clog 写入速度。
典型问题
NFS hang
如果归档介质是 NFS,Docker 环境挂载 NFS 容易遇到 hang 的问题。NFS hang 直接表现为某个日志流或者全部日志流归档进度不推或者断流。在所有 OBServer 节点执行以下命令查看是否 hang。
cat /proc/`pidof observer`/task/*/stack|grep nfs
归档盘满
归档盘满体现为租户以及所有日志流归档进度不推或者断流。在租户日志流 leader 节点 grep 如下日志:
grep Txxxx_ArcSend observer.log | less
如果已经断流,则选择断流前附近一段日志,如果当前是卡住,可以看最新的几个 OBServer 日志文件。grep 如下日志,可以看到明显如下报错 **Disk quota exceeded**:
observer.log.20230927031011904:[2023-09-27 03:09:50.879969] WDIAG [STORAGE] pwrite (ob_storage_file.cpp:747) [130479][T1002_ArcSender][T1002][xxxxx-xxxxx-xxxxx-xxxxx] [lt=10][errcode=-4009] failed to write file(ret=-4009, one_write_size=-1, errno=122, path_=/archive/piece_d1001r1p1/logstream_1/log/1.obarc, errno_str="Disk quota exceeded"