TheKoguryo's 기술 블로그

 Version 2024.05.05

17.3 Kafka Connect, Debezium로 OCI MySQL Database Service에 CDC 구성하기

OCI Streaming - Kafka Connect, Debezium로 MySQL CDC 구성하기을 먼저 본 것을 전제로 합니다.


이전 문서에서 debezium에서 제공하는 컨테이너 이미지를 사용하여, Source MySQL -> Debezium Connector -> OCI Streaming -> JDBC Connector -> Target MySQL 구성하고, CDC를 테스트하였습니다.

여기서는 MySQL을 OCI MySQL Database Service로 만들어진 MySQL을 사용할때, Kafka Connect를 구성시 주의사항이 있는 지 확인해 보도록 하겠습니다.

Source, Target MySQL Database Service 인스턴스 구성

먼저, Source, Target으로 사용할 MySQL 데이터베이스 인스턴스를 만듭니다.

Debezium release overview

  • Debezium 2.6 릴리즈 문서에서 테스트된 버전이라는 MySQL 8.0.x, 8.2 을 사용합니다. OCI MySQL Database Service로 생성시 해당 버전으로 선택합니다.
    2.7 - development2.6 - latest stable2.5
    Java11+11+11+
    Kafka Connect2.x, 3.x2.x, 3.x2.x, 3.x
    MySQLDatabase: 8.0.x, 8.2
    Driver: 8.3.0
    Database: 8.0.x, 8.2
    Driver: 8.0.33
    Database: 8.0.x, 8.2
    Driver: 8.0.33

Source MySQL 생성 정보

  1. 왼쪽 상단의 Navigation Menu를 클릭하고 Databases로 이동한 다음 MySQL HeatWave 하위 DB systems를 선택 합니다.

  2. 생성을 위해 Create DB system을 클릭합니다.

  3. Development or testing 유형을 선택합니다.

  4. Provide DB system information:

    • Name: 이름을 입력합니다. 예) mysql-source
  5. Create Administrator credentials: 관리자 이름과 암호를 입력합니다.

    • Username: admin

    • Password: 예) Password123!

      • Administrator password must be between 8 and 32 characters, and contain at least 1 uppercase, 1 lowercase, 1 numeric, and 1 special characters.

      • OCI MySQL Database Service에서 Administrator는 root user랑은 다르며, root user보다는 제한된 권한을 가지고 있습니다. Default MySQL Privileges을 참조하세요

  6. DB system 타입: Standalone을 선택합니다.

  7. Configure networking: Private IP만을 사용하므로, Kafka Connect와 같은 서브넷 또는 접근 가능한 서브넷을 선택합니다.

  8. Configure placement: 기본값을 선택

  9. Configure hardware:

    • Enable HeatWave: 체크 해제
    • Shape Details: 기본 선택된 MySQL.2을 사용합니다.
  10. Configure backup plan

    • Enable automatic backups: 체크 해제
  11. 고급 옵션을 엽니다.

    • Configuration
      • MySQL version: Debezium release을 기준으로 8.0.x을 선택합니다. 예, 8.0.37을 선택
  12. Create 버튼을 클릭하여, DB를 생성합니다.

  13. 일단 시작되면 MySQL DB가 프로비저닝됩니다. 위 설정기준으로 Active 상태로 되기까지, 약 10~15분 정도 걸립니다.

  14. Security List Ingress 규칙에 3306 포트를 개방합니다.

Target MySQL 생성 정보

  1. 이름만 달리하여, MySQL Database Service 인스턴스를 하나 더 만듭니다.
    • Name: mysql-target

Source DB에 설정 확인

Debezium Setting up MySQL을 기준으로 설정값을 확인해 봅니다.

  1. Administrator로 MySQL에 접속

    mysql --host <Source-MySQL-Public-IP> -u admin --password=Password123!
    
  2. Enabling the binlog: ON으로 이미 설정됨

    mysql> SELECT variable_value as "BINARY LOGGING STATUS (log-bin) ::"
        -> FROM performance_schema.global_variables WHERE variable_name='log_bin';
    +------------------------------------+
    | BINARY LOGGING STATUS (log-bin) :: |
    +------------------------------------+
    | ON                                 |
    +------------------------------------+
    1 row in set (0.00 sec)
    
  3. Enabling GTIDs: ON으로 이미 설정됨

    mysql> show global variables like '%GTID%';
    +----------------------------------------------+-------+
    | Variable_name                                | Value |
    +----------------------------------------------+-------+
    ...
    | enforce_gtid_consistency                     | ON    |
    ...
    | gtid_mode                                    | ON    |
    ...
    +----------------------------------------------+-------+
    9 rows in set (0.00 sec)
    
  4. Enabling query log events: ON으로 이미 설정됨

    mysql> show global variables where variable_name = 'binlog_rows_query_log_events';
    +------------------------------+-------+
    | Variable_name                | Value |
    +------------------------------+-------+
    | binlog_rows_query_log_events | ON    |
    +------------------------------+-------+
    1 row in set (0.00 sec)
    
  5. Validating binlog row value options: "" - 설정값이 없어야 하나 PARTIAL_JSON 로 설정된 상태

    mysql> show global variables where variable_name = 'binlog_row_value_options';
    +--------------------------+--------------+
    | Variable_name            | Value        |
    +--------------------------+--------------+
    | binlog_row_value_options | PARTIAL_JSON |
    +--------------------------+--------------+
    1 row in set (0.00 sec)
    
    • PARTIAL_JSON인 경우 빈 값으로 설정해야 하나, Administrator 권한으로 설정할 수 없습니다.

      mysql> set @@global.binlog_row_value_options="" ;
      ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER or SYSTEM_VARIABLES_ADMIN privilege(s) for this operation
      
    • PARTIAL_JSON로 설정된 경우, UPDATE 이벤트를 처리하는 데 실패할 수 있다고 합니다.

      • 문서 상의 원문: make sure that value is not set to PARTIAL_JSON, since in such case connector might fail to consume UPDATE events.

Source DB에 CDC 관련 권한 설정

  1. Administrator로 MySQL에 접속

    mysql --host <Source-MySQL-Public-IP> -u admin --password=Password123!
    
  2. 데이터베이스 및 유저 생성

    CREATE DATABASE sourcedb;
    
    CREATE USER 'mysqluser'@'%' IDENTIFIED BY 'Password123!';
    
    GRANT ALL PRIVILEGES ON sourcedb.* TO 'mysqluser'@'%';
    
  3. 복제를 위한 권한 mysqluser 유저에 설정

    GRANT SELECT, RELOAD, SHOW DATABASES, LOCK TABLES, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'mysqluser'@'%';
    
    • 이 중 RELOAD는 Administrator가 부여할 수 없는 권한으로 제외하고, 나머지 권한을 부여

      ### RELOAD는 Administrator가 부여할 수 없는 권한
      mysql> GRANT RELOAD ON *.* TO 'mysqluser'@'%';
      ERROR 1045 (28000): Access denied for user 'admin'@'%' (using password: YES)
      
      ### RELOAD 제외하고 권한 부여
      GRANT SELECT, SHOW DATABASES, LOCK TABLES, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'mysqluser'@'%';
      
      • Debezium에서 설명하는 유저 권한을 snapshot을 실행할 때 이 RELOAD 권한이 필요하다고 합니다. 당장 테스트에는 문제가 없지만, 참고합니다.

        KeywordDescription
        RELOADEnables the connector the use of the FLUSH statement to clear or reload internal caches, flush tables, or acquire locks. This is used only when performing a snapshot.
  4. 접속을 종료합니다.

    quit
    

Target DB 접속 확인

  1. Administrator로 MySQL에 접속

    mysql --host <Target-MySQL-Public-IP> -u admin --password=Password123!
    
  2. 데이터베이스 및 유저 생성

    CREATE DATABASE targetdb;
    
    CREATE USER 'mysqluser'@'%' IDENTIFIED BY 'Password123!';
    
    GRANT ALL PRIVILEGES ON targetdb.* TO 'mysqluser'@'%';
    
  3. 접속종료

    quit
    
  4. mysqluser 로 접속

    mysql --host <Target-MySQL-Public-IP> -u mysqluser --password=Password123!
    

OCI Streaming 및 Kafka Connect 설치 및 구성

OCI Streaming - Kafka Connect, Debezium로 MySQL CDC 구성하기과 동일합니다. Connector에서 MySQL 서버 주소 및 접속 사용자 정보만 변경하면 됩니다.

CDC 테스트 #1

Source DB에 데이터 변경분 발생

  1. 데이터베이스 접속

    mysql --host <Source-MySQL-Public-IP> -u mysqluser --password=Password123!
    
  2. DATABASE 선택

    use sourcedb;
    
  3. 샘플 테이블 생성

    create table employees (
        emp_no      int             not null,
        birth_date  date            not null,
        first_name  varchar(14)     not null,
        last_name   varchar(16)     not null,
        gender      enum ('M','F')  not null,    
        hire_date   date            not null,
        primary key (emp_no)
    );
    
  4. 새 데이터 삽입

    INSERT INTO employees VALUES (10001,'1953-09-02','Georgi','Facello','M','1986-06-26');
    
  5. 데이터를 확인합니다.

    mysql> select * from employees;
    +--------+------------+------------+-----------+--------+------------+
    | emp_no | birth_date | first_name | last_name | gender | hire_date  |
    +--------+------------+------------+-----------+--------+------------+
    |  10001 | 1953-09-02 | Georgi     | Facello   | M      | 1986-06-26 |
    +--------+------------+------------+-----------+--------+------------+
    1 row in set (0.00 sec)
    

Target DB에 데이터 확인

  1. 데이터베이스 접속

    mysql --host <Target-MySQL-Public-IP> -u mysqluser --password=Password123!
    
  2. DATABASE 접속

    use targetdb;
    
  3. 현재 데이터 확인합니다. 테이블이 생성되고 데이터가 들어간 것을 확인할 수 있습니다.

    mysql> select * from employees;
    +--------+------------+------------+-----------+--------+------------+
    | emp_no | birth_date | first_name | last_name | gender | hire_date  |
    +--------+------------+------------+-----------+--------+------------+
    |  10001 | 1953-09-02 | Georgi     | Facello   | M      | 1986-06-26 |
    +--------+------------+------------+-----------+--------+------------+
    1 rows in set (0.00 sec)
    
  4. Target DB에 동일 테이블이 생성되고 데이터도 동기화되었습니다.

CDC 테스트 #2 - UPDATE

Source DB에 데이터 변경분 발생

  1. DATABASE 선택

    use sourcedb;
    
  2. 업데이트 및 새 데이터 삽입

    UPDATE employees SET last_name='Facello - New' WHERE emp_no=10001;
    INSERT INTO employees VALUES (10002,'1964-06-02','Bezalel','Simmel','F','1985-11-21');
    
  3. 데이터를 확인합니다.

    mysql> select * from employees;
    +--------+------------+------------+---------------+--------+------------+
    | emp_no | birth_date | first_name | last_name     | gender | hire_date  |
    +--------+------------+------------+---------------+--------+------------+
    |  10001 | 1953-09-02 | Georgi     | Facello - New | M      | 1986-06-26 |
    |  10002 | 1964-06-02 | Bezalel    | Simmel        | F      | 1985-11-21 |
    +--------+------------+------------+---------------+--------+------------+
    2 rows in set (0.00 sec)
    

Target DB에 데이터 확인

  1. DATABASE 접속

    use targetdb;
    
  2. 현재 데이터 확인합니다. 테이블이 생성되고 데이터가 들어간 것을 확인할 수 있습니다.

    mysql> select * from employees;
    +--------+------------+------------+-----------+--------+------------+
    | emp_no | birth_date | first_name | last_name | gender | hire_date  |
    +--------+------------+------------+-----------+--------+------------+
    |  10001 | 1953-09-02 | Georgi     | Facello   | M      | 1986-06-26 |
    |  10002 | 1964-06-02 | Bezalel    | Simmel    | F      | 1985-11-21 |
    +--------+------------+------------+-----------+--------+------------+
    2 rows in set (0.01 sec)
    
  3. binlog_row_value_options=PARTIAL_JSON 설정 때문인지, 추가 UPDATE, INSERT 변경분에 대해서 INSERT만 반영되고, UPDATE한 last_name 변경분은 Target DB에 반영되지 않은 것을 볼 수 있습니다.

OCI MySQL Database Service 인스턴스를 Debezium MySQL Connector로 사용시 제한사항 확인결과
  • 필요한 권한 중에서 RELOAD 권한을 Administrator로는 설정할 수 없어, snapshot 관련 기능을 사용하는 데 제한사항이 있습니다.
  • binlog_row_value_options=PARTIAL_JSON 설정값을 Administrator 빈값으로 변경 설정할 수 없어, Source DB 변경분 중에서 UPDATE 변경분을 반영할 수 없었습니다.


이 글은 개인으로서, 개인의 시간을 할애하여 작성된 글입니다. 글의 내용에 오류가 있을 수 있으며, 글 속의 의견은 개인적인 의견입니다.

Last updated on 5 May 2024