本文是三部分系列文章的一部分,旨在探讨如何使用 Debezium 和 Oracle LogMiner 从 Oracle 数据库摄取变更。在本系列文章中,我们将探讨设置 Debezium for Oracle 的概念验证 (POC) 部署的所有步骤。我们将讨论设置和配置,以及多租户的细微之处。我们还将深入探讨您可能需要了解的任何已知陷阱和注意事项,以及如何调试特定问题。最后,我们将讨论性能和监控,以维护健康的连接器部署。

通过本次演练,我们希望向您展示部署 Debezium for Oracle 的简单性。本系列的安装和设置部分可能看起来相当复杂,但其中许多步骤可能已经在现有的环境中存在。我们将逐一介绍每个步骤,解释如果您使用容器镜像部署,每个步骤的必要性。

那么,废话不多说,我们直接开始吧!

什么是 Oracle?

这个问题看似多余,但有些人可能不知道 Oracle 数据库是什么。Oracle 数据库是一个关系型数据库管理系统 (RBDMS),它存储和提供对通常相关的数据点的访问。该数据库由 Oracle 公司开发和销售,是市场上最值得信赖且广泛使用的关系型数据库引擎之一,提供了可扩展的关系数据库架构。

Oracle 数据库由一组模式组成,这些模式代表一组逻辑数据结构或模式对象。模式对象可以是触发器、视图、表、数据类型、序列、过程、函数等任何内容。此外,Oracle 12 引入了多租户架构,允许单个数据库实例充当多租户容器数据库 (CDB),其中包含零个、一个或多个客户创建的可插拔数据库 (PDB)。

目标是安装 Oracle 数据库,将其连接到 Debezium,并将捕获的更改转换为存储在 Apache Kafka 中的更改事件。

安装 Oracle

要开始,我们需要一个正在运行的 Oracle 数据库环境。最简单的方法之一是使用 Docker,通过部署一个运行 Oracle 数据库的容器来实现。Oracle 已在其 容器注册表 中发布了此类容器,允许任何人运行数据库并进行试用。如果您打算从现有 Oracle 数据库捕获更改,可以跳过此部分。

Oracle 容器镜像都已使用 Oracle 和多租户预先构建。这意味着我们将遵循多租户架构的设置。如果您使用的是不支持多租户的安装,可能需要进行一些小的调整。

在本示例中,我们将使用 此容器镜像。使用 docker pull 命令,在通过以下命令使用 Oracle 容器注册表进行身份验证后,将拉取该镜像。

docker pull container-registry.oracle.com/database/enterprise:latest

要启动容器,请使用 docker run 命令。由于数据库容器镜像必须首先安装 Oracle 数据库,因此需要几个环境变量,例如数据库 SID、可插拔数据库名称和密码。

docker run -d \
  --name dbz_oracle21 \
  -p 1521:1521 \
  -e ORACLE_SID=ORCLCDB \
  -e ORACLE_PDB=ORCLPDB1 \
  -e ORACLE_PWD=oraclepw \
  container-registry.oracle.com/database/enterprise:latest

ORACLE_SID 指的是用于标识数据库的系统/服务 ID。由于我们正在使用多租户,我们将使用名称 ORCLCDB 来表示容器数据库 (CDB)。在 Oracle 的多租户架构中,ORACLE_PDB 指的是用于标识可插拔数据库 (PDB) 的系统/服务 ID。最后,ORACLE_PWD 指的是用于 SYSSYSTEM 用户的密码,我们稍后将使用它。

容器会将数据持久化到容器文件系统上的数据库文件中。删除容器时,数据将丢失。要将数据持久化到容器外部,请参阅 Oracle 注册表的 README,了解如何在 docker run 命令中设置卷。

我们显式地将 docker 容器作为守护进程(后台进程)启动。如果您想查看容器内发生的情况,可以使用命令 docker logs -f dbz_oracle21 来跟踪容器的数据库日志。

在接下来的几分钟内,数据库将在容器内进行配置和安装,这会在新容器启动时发生,并且没有初始配置和数据库。通过查看日志中的一个横幅,您可以知道安装是否成功,该横幅将显示类似以下内容:

#########################
DATABASE IS READY TO USE!
#########################

此时,安装已完成,可以安全地继续下一部分。

配置 Oracle

要从 Oracle 数据库捕获更改,需要进行几项数据库配置。如果您使用的是预先存在的环境,则可以跳过其中一些步骤。

以下配置是必需的:

配置 Oracle:归档日志

Oracle 将填满的重做日志组(数据库事务日志)保存到一处或多处离线目标,这些目标统称为已归档重做日志或归档日志。通过归档日志,主数据库中的更改会被复制到逻辑或物理备用环境。

当重做日志填满并被归档时,会发生日志切换。Debezium 会捕获重做日志和归档日志中的更改。当重做日志被归档时,Debezium 需要访问归档日志来完成重做条目的处理。

安装 Oracle 部分使用的 Oracle 容器注册表镜像未启用归档日志记录。如果您使用其他镜像或预先存在的环境,则必须检查是否已启用归档日志记录。要检查状态,请使用 SYS 用户和安装期间为 ORACLE_PWD 定义的密码连接到 ORCLCDB 数据库并执行以下查询:

SELECT LOG_MODE FROM V$DATABASE

如果该列包含 ARCHIVELOG,则表示归档日志记录已启用。如果该列包含值 NOARCHIVELOG,则表示归档日志记录未启用,需要进一步配置。

在设置 Oracle 归档日志时,我们不仅需要启用日志记录功能,还需要指定磁盘上的一个位置来存储日志。如果您使用的是预先存在的环境,则需要咨询您的数据库管理员。大多数数据库服务器使用特殊路径存储归档日志文件,您需要知道 Oracle 自动存储管理 (ASM) 是否正在使用,或者数据库服务器上的哪个卷具有足够的空间。

让我们打开 Oracle 数据库容器的终端。我们想使用 SQL*Plus 连接到数据库容器,以便使用一个允许轻松卸载和重启数据库的客户端。所以,在新终端中执行:

docker exec -it dbz_oracle21 -e ORACLE_SID=ORCLCDB sqlplus sys as sysdba

如果您连接到现有的 Oracle 环境,也可以 ssh 到数据库服务器的 shell 来运行 SQL*Plus。

上面的命令将启动 Oracle 的 SQL*Plus,这是一个命令行 Oracle SQL 客户端。客户端会要求输入密码,该密码将与 ORACLE_PWD 环境变量相同,或者如果您使用的是 Oracle 注册表容器,则为 oraclepw。连接到现有 Oracle 环境时,请使用您环境的 SYS 用户密码。

我们需要设置两个数据库参数:

db_recovery_file_dest_size

可用于存储归档日志的字节数。

如果现有归档日志的大小加上下一个要归档的日志超过此配置值,Oracle 数据库的归档进程将阻塞。如果所有重做日志都需要归档,并且归档进程被阻塞,数据库将阻止更改,直到归档进程解除阻塞。使用 RMAN 工具删除较旧的归档日志可以解除归档进程的阻塞,从而允许任何待处理的重做日志被归档。因此,根据您的数据库保留策略选择一个合适的大小通常是一个好主意。

db_recovery_file_dest

归档日志存储在磁盘上的位置。

此位置必须可由 Oracle 数据库用户(通常称为 oracle 用户)读取和写入。

要设置这些值,我们将执行以下 SQL 命令,在已连接到数据库作为 SYS 用户的 SQL*Plus 终端窗口中执行。同样,如果您连接到预先存在的环境,请在继续之前咨询您的数据库管理员。

ALTER SYSTEM SET db_recovery_file_dest_size = 10G;
ALTER SYSTEM SET db_recovery_file_dest = '/opt/oracle/oradata/ORCLCDB' scope=spfile;
SHUTDOWN IMMEDIATE
STARTUP MOUNT
ALTER DATABASE ARCHIVELOG;
ALTER DATABASE OPEN;
ARCHIVE LOG LIST;

上面的 ALTER 语句调整了数据库参数,指定归档日志的保留时间最多为 10GB,并且日志存储在 /opt/oracle/oradata/ORCLCDB

SQL*Plus 的最终输出应显示以下内容:

SQL> Database log mode             Archive Mode
Automatic archival                 Enabled
Archive destination                USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence         1
Next log sequence to archive       3
Current log sequence               3

归档日志的配置已完成,当发生数据库日志切换时,Oracle ARCH 进程会将重做日志转换为存储在磁盘指定位置的归档日志。

Oracle 支持多个归档日志目标的概念,允许将重做日志存储在不同的文件位置。当使用 Oracle DataGuard 将归档日志副本传输到辅助服务器以进行灾难恢复或商业智能时,通常会使用多个存储位置。我们不会在本篇博客中介绍如何配置此功能,但值得注意的是,该功能存在并且可能很有用。

配置 Oracle:重做日志

Oracle 的事务日志称为重做日志。这些日志至关重要,因为它们用于在数据库崩溃或介质故障时恢复到检查点。不幸的是,Oracle 容器镜像通常使用对 Debezium 不太有用的重做日志配置。

Debezium 的 Oracle 连接器有两种 日志挖掘策略。该策略控制连接器如何与 Oracle LogMiner 交互,以及连接器如何捕获模式和表更改。

redo_log_catalog

数据字典会定期写入重做日志,导致随时间推移归档日志的生成量增加。此设置允许跟踪 DDL 更改,因此如果表的模式发生变化,此策略将是理想的选择。

online_catalog

数据字典不会定期写入重做日志,使归档日志的生成与当前行为保持一致。Oracle LogMiner 会大大加快挖掘更改的速度;但是,这种性能是以跟踪 DDL 更改为代价的。如果表的模式保持不变,此策略将是理想的选择。

当使用 online_catalog 模式时,您可以完全跳过此步骤。

当使用 redo_log_catalog 模式(默认)时,重做日志大小对于减少日志切换频率至关重要。日志切换发生时,LogMiner 会话会重新启动,数据字典会在重做日志中重新构建。当会话重新启动时,LogMiner 会读取字典并用于跟踪 DDL 更改,这可能会导致在字典表填充期间出现轻微的初始会话延迟。总的来说,当重做日志足够大以便将数据字典写入单个日志文件时,您可以获得更好的性能。

Oracle 容器注册表镜像配置的重做日志大小为 200MB。当使用默认的挖掘策略时,这个默认大小太小,所以我们将调整它,使日志使用 400MB 的大小。

当处理未启用多租户的 Oracle 安装时,400MB 可能仍然略显不足,因为根数据库中存在许多基本表,而在启用多租户的可插拔数据库中则不存在。如果您至少从未启用多租户的 Oracle 环境捕获更改,请使用 500MB

无论是否使用多租户,在生产环境中,这些值应该更大。您的 DBA 可以使用 Oracle 的大小指南,根据日志切换频率和系统负载来确定最佳值。

在进行任何更改之前,检查环境的当前状态至关重要。在您启用归档日志记录的同一终端中,执行以下 SQL 以确定当前的日志大小。

SELECT GROUP#, BYTES/1024/1024 SIZE_MB, STATUS FROM V$LOG ORDER BY 1;

Oracle 容器注册表镜像将返回以下输出:

    GROUP#    SIZE_MB STATUS
---------- ---------- ----------------
	 1	  200 INACTIVE
	 2	  200 INACTIVE
	 3	  200 CURRENT

此输出告诉我们有 3 个日志组,每个组每个日志占用 200MB 空间。此外,与每个组相关的状态至关重要,因为它代表了该日志的当前状态。

以下详细描述了日志状态:

INACTIVE

这意味着 Oracle 已初始化日志,目前未在使用中。

ACTIVE

这意味着 Oracle 已初始化日志,并且目前正在使用中。在发生故障时,需要重做日志并正在使用,以便数据库可以安全地恢复。

CURRENT

这意味着 Oracle 当前正在写入此日志。在处理 Oracle Real Application Clusters (RAC) 时,多个日志可以标记为当前,表示每个集群节点的日志。

UNUSED

这意味着 Oracle 未初始化日志,且未使用。

现在,使用同一个终端窗口,执行以下 SQL 以确定重做日志的文件名和位置。

SELECT GROUP#, MEMBER FROM V$LOGFILE ORDER BY 1, 2;

Oracle 容器注册表镜像将返回以下输出:

    GROUP# MEMBER
---------- ---------------------------------------------------
	 1 /opt/oracle/oradata/ORCLCDB/redo01.log
	 2 /opt/oracle/oradata/ORCLCDB/redo02.log
	 3 /opt/oracle/oradata/ORCLCDB/redo03.log

由此我们可以看出,每个日志组由单个重做日志组成。Oracle 支持每个组有多个日志的概念,这被称为复用。您通常只会在生产环境以及偶尔的测试环境中看到这种情况,但在开发或容器环境中很少见到。

目标是将 V$LOG 表中的 BYTES 列调整为 400MB。不幸的是,唯一进行此调整的方法是删除并重新创建日志组,并且仅当组的 STATUSINACTIVEUNUSED 时才能进行。由于日志组 1 在上面是 INACTIVE,我们将从它开始,但您可以安全地按任何顺序对日志组执行此过程。

在 SQL*Plus 正在运行的终端中,执行以下命令:

ALTER DATABASE CLEAR LOGFILE GROUP 1;
ALTER DATABASE DROP LOGFILE GROUP 1;
ALTER DATABASE ADD LOGFILE GROUP 1 ('/opt/oracle/oradata/ORCLCDB/redo01.log') size 400M REUSE;

这将删除并重新创建日志组,大小为 400MB。我们将使用 VLOGFILE 表中 MEMBER 列的相同日志文件名。如果数据库使用复用(每个日志组有多个日志文件),请使用逗号分隔的文件名列表来注册每个日志文件。

继续对所有日志组执行上述过程,相应地更改日志组和文件名,直到所有 INACTIVEUNUSED 的组的大小都为 400MB。一旦剩下的只能更改那些状态为 CURRENT 的组,您就可以在数据库上执行日志切换,以使用以下 SQL 将数据库推进到下一个重做日志:

ALTER SYSTEM SWITCH LOGFILE;

如果您重新检查 V$LOG 中的日志大小,您会看到输出如下:

SQL> SELECT GROUP#, BYTES/1024/1024 SIZE_MB, STATUS FROM V$LOG ORDER BY 1;

    GROUP#    SIZE_MB STATUS
---------- ---------- ----------------
	 1	  400 CURRENT
	 2	  400 UNUSED
	 3	  200 ACTIVE

现在我们需要等待数据库最终将日志组 3 的状态切换为 INACTIVE。切换可能需要几分钟,所以请耐心等待并定期重新检查大小。一旦状态变为 INACTIVE,请使用相同的过程修改最后一个日志组和文件名。

在最后一次检查 V$LOG 表后,我们将看到一切看起来都正常:

SQL> SELECT GROUP#, BYTES/1024/1024 SIZE_MB, STATUS FROM V$LOG ORDER BY 1;

    GROUP#    SIZE_MB STATUS
---------- ---------- ----------------
	 1	  400 CURRENT
	 2	  400 UNUSED
	 3	  400 UNUSED

至此,我们已经修改了所有重做日志的大小,从而减少了 Debezium 执行数据字典构建步骤时的日志切换频率。

配置 Oracle:补充日志记录

Oracle 重做日志主要用于实例和介质恢复,因为这些操作所需的数据会自动记录。默认情况下无法使用 LogMiner,因为 Oracle 默认不提供任何补充日志数据。由于 Debezium 依赖于 LogMiner,因此至少必须启用补充日志记录,Debezium 才能对 Oracle 进行任何更改数据捕获。

可以使用两种不同的策略来设置补充日志记录:

  1. 数据库补充日志记录

  2. 表补充日志记录

为了让 Debezium 与 LogMiner 交互并处理链式行和各种存储配置,至少需要启用数据库补充日志记录。要启用此级别,请在当前的 SQL*Plus 终端中执行以下 SQL:

ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;

我们将在后面的部分讨论基于表的补充日志记录,届时我们将配置连接器。

配置 Oracle:用户设置

为了让 Debezium 连接器捕获更改事件,它必须建立到数据库的 JDBC 连接并执行一系列 LogMiner API。用户帐户需要特定的权限才能访问这些 LogMiner API 并从捕获的表中收集数据。

在使用多租户架构(如 Oracle 容器注册表镜像中所使用的)时,我们实际上需要处理两个数据库:ORCLCDB(容器或根数据库)和 ORCLPDB1(可插拔数据库)。所有捕获的表都将在 PDB 内部创建和维护,但有时连接器需要访问根数据库来读取特定的系统表。

因此,在多租户架构中,我们必须首先设置用户帐户将使用的两个表空间。要创建这些表空间,请在 SQL*Plus 终端中执行以下 SQL:

CONNECT sys/oraclepw@ORCLCDB as sysdba;
CREATE TABLESPACE logminer_tbs DATAFILE '/opt/oracle/oradata/ORCLCDB/logminer_tbs.dbf'
  SIZE 25M REUSE AUTOEXTEND ON MAXSIZE UNLIMITED;

CONNECT sys/oraclepw@ORCLPDB1 as sysdba;
CREATE TABLESPACE logminer_tbs DATAFILE '/opt/oracle/oradata/ORCLCDB/ORCLPDB1/logminer_tbs.dbf'
  SIZE 25M REUSE AUTOEXTEND ON MAXSIZE UNLIMITED;

如果部署不在已启用多租户的 Oracle 数据库上,则无需在 ORCLPDB1 数据库内创建第二个表空间。此外,请确保为表空间、凭据和数据库 SID 提供的路径对于您的安装都是正确的。您可能需要咨询您的 DBA 来正确创建表空间。

一旦表空间存在,现在就可以创建用户帐户本身了。如果您使用的是多租户环境,用户名必须使用 common-user 前缀,以便 Oracle 在 CDB 根数据库和 PDB 可插拔数据库中都创建它;否则,用户名可以是任何名称。由于我们正在使用容器的多租户数据库安装,我们将创建一个名为 c##dbzuser 的用户帐户。

CONNECT sys/oraclepw@ORCLCDB as sysdba;

CREATE USER c##dbzuser IDENTIFIED BY dbz DEFAULT TABLESPACE LOGMINER_TBS
  QUOTA UNLIMITED ON LOGMINER_TBS
  CONTAINER=ALL;

用户帐户需要几个权限。在本文发布时,权限列表包括以下内容:

GRANT CREATE SESSION TO c##dbzuser CONTAINER=ALL;
GRANT SET CONTAINER TO c##dbzuser CONTAINER=ALL;
GRANT SELECT ON V_$DATABASE TO c##dbzuser CONTAINER=ALL;
GRANT FLASHBACK ANY TABLE TO c##dbzuser CONTAINER=ALL;
GRANT SELECT ANY TABLE TO c##dbzuser CONTAINER=ALL;
GRANT SELECT_CATALOG_ROLE TO c##dbzuser CONTAINER=ALL;
GRANT EXECUTE_CATALOG_ROLE TO c##dbzuser CONTAINER=ALL;
GRANT SELECT ANY TRANSACTION TO c##dbzuser CONTAINER=ALL;
GRANT SELECT ANY DICTIONARY TO c##dbzuser CONTAINER=ALL;
GRANT LOGMINING TO c##dbzuser CONTAINER=ALL;

GRANT CREATE TABLE TO c##dbzuser CONTAINER=ALL;
GRANT LOCK ANY TABLE TO c##dbzuser CONTAINER=ALL;
GRANT CREATE SEQUENCE TO c##dbzuser CONTAINER=ALL;

GRANT EXECUTE ON DBMS_LOGMNR TO c##dbzuser CONTAINER=ALL;
GRANT EXECUTE ON DBMS_LOGMNR_D TO c##dbzuser CONTAINER=ALL;

GRANT SELECT ON V_$LOG TO c##dbzuser CONTAINER=ALL;
GRANT SELECT ON V_$LOG_HISTORY TO c##dbzuser CONTAINER=ALL;
GRANT SELECT ON V_$LOGMNR_LOGS TO c##dbzuser CONTAINER=ALL;
GRANT SELECT ON V_$LOGMNR_CONTENTS TO c##dbzuser CONTAINER=ALL;
GRANT SELECT ON V_$LOGMNR_PARAMETERS TO c##dbzuser CONTAINER=ALL;
GRANT SELECT ON V_$LOGFILE TO c##dbzuser CONTAINER=ALL;
GRANT SELECT ON V_$ARCHIVED_LOG TO c##dbzuser CONTAINER=ALL;
GRANT SELECT ON V_$ARCHIVE_DEST_STATUS TO c##dbzuser CONTAINER=ALL;
GRANT SELECT ON V_$TRANSACTION TO c##dbzuser CONTAINER=ALL;

您可以参考最新的 文档 来查看所需授权是否可能已更改。我们已创建将在配置中使用的连接器用户,并授予了用户所有必要的数据库权限。

结论

在本系列的第一部分中,我们介绍了 Oracle 是什么以及它为何如此受欢迎。我们还介绍了如何使用容器安装 Oracle 数据库,以及如何配置 Oracle 实例以允许 Debezium 捕获更改。在系列 下一部分 中,我们将深入探讨在 Apache Kafka Connect 上部署 Debezium Oracle 连接器。

Chris Cranford

Chris 是 IBM 的一名软件工程师,之前在 Red Hat 工作,他致力于 Debezium 项目,并每天都在深入研究 Oracle 和 Change Data Capture 的各个方面。他此前曾从事 Hibernate(领先的开源 JPA 持久化框架)方面的工作,并且继续为 Quarkus 做贡献。Chris 居住在美国北卡罗来纳州。

   


关于 Debezium

Debezium 是一个开源的分布式平台,可以将现有数据库转变为事件流,使应用程序能够几乎即时地看到并响应数据库中已提交的每个行级更改。Debezium 构建在 Kafka 之上,并提供了 Kafka Connect 兼容的连接器,用于监控特定的数据库管理系统。Debezium 将数据更改的历史记录在 Kafka 日志中,这样您的应用程序可以随时停止和重新启动,并可以轻松地消费在未运行时错过的所有事件,确保所有事件都被正确且完整地处理。Debezium 在 Apache 许可证 2.0 下是 开源 的。

参与进来

我们希望您觉得 Debezium 有趣且有用,并希望尝试一下。在 Twitter @debezium 上关注我们,在 Zulip 上与我们聊天,或加入我们的 邮件列表 与社区交流。所有代码都在 GitHub 上开源,因此请在本地构建代码,帮助我们改进现有连接器并添加更多连接器。如果您发现问题或有改进 Debezium 的想法,请告诉我们或 记录一个问题

版权所有 © Debezium 及其作者。保留所有权利。有关我们的商标详情,请访问我们的 商标政策商标列表。第三方商标属于其各自所有者,在此提及并不表示任何认可或关联。
×