MSA(마이크로서비스 아키텍처) 환경에서 데이터베이스의 변경 사항을 실시간으로 감지하고 전파하는 것은 매우 중요합니다. 이때 가장 먼저 떠오르는 도구가 바로 Debezium입니다. Debezium은 데이터베이스의 트랜잭션 로그를 직접 읽어 변경된 데이터를 캡처(CDC, Change Data Capture)하는 강력한 Kafka 커넥터입니다.
하지만 큰 문제가 있습니다. SQL Server의 무료 버전인 Express Edition은 CDC 기능을 공식적으로 지원하지 않습니다. 이 때문에 많은 개발자가 “SQL Server Express에서는 Debezium을 쓸 수 없나?”라는 질문에 부딪히게 됩니다.
결론부터 말하면, 직접적인 사용은 불가능하지만, 몇 가지 똑똑한 우회 방법이 존재합니다. 이 글에서는 SQL Server Express에서 CDC와 유사한 기능을 구현하고 Kafka와 연동하는 3가지 현실적인 대안을 소개합니다.
핵심 문제: 왜 SQL Server Express에서는 Debezium을 바로 쓸 수 없나?
Debezium은 데이터베이스의 트랜잭션 로그(Transaction Log)를 읽어 변경 내역(INSERT, UPDATE, DELETE)을 감지하는 방식으로 작동합니다. SQL Server에서는 이 기능을 CDC(Change Data Capture)라고 부릅니다. 하지만 안타깝게도 이 CDC 기능은 Standard, Enterprise와 같은 유료 에디션에서만 제공되며, Express 에디션에서는 비활성화되어 있습니다.
따라서 Debezium 커넥터를 SQL Server Express에 직접 연결하면 CDC 기능이 없다는 오류와 함께 실패하게 됩니다.
해결을 위한 3가지 대안
CDC 없이 Debezium과 같은 실시간 데이터 연동을 구현할 수 있는 세 가지 방법을 소개합니다. 각 방법의 장단점을 비교해보고 프로젝트에 가장 적합한 방법을 선택해 보세요.
✅ 방법 1: 트리거 + 변경 로그 테이블 + Kafka Connect (가장 안정적인 추천 방법)
가장 널리 쓰이고 안정적인 우회 방법입니다. 데이터베이스의 트리거(Trigger)를 이용해 변경 사항을 별도의 로그 테이블에 쌓고, Kafka Connect가 이 로그 테이블을 주기적으로 읽어가는 방식입니다.
Step 1. 변경 로그 테이블(ChangeLog) 생성
먼저, 모든 변경 내역을 기록할 테이블을 하나 만듭니다. ID
는 순차적으로 증가하도록 설정하여 Kafka Connect가 어디까지 읽었는지 추적하는 데 사용합니다.
CREATE TABLE ChangeLog (
ID INT IDENTITY(1,1) PRIMARY KEY,
TableName NVARCHAR(100),
OperationType NVARCHAR(10),
ChangedData NVARCHAR(MAX),
ChangeDate DATETIME DEFAULT GETDATE()
);
Step 2. 원본 테이블에 INSERT, UPDATE, DELETE 트리거 추가
변경을 감지할 원본 테이블(YourTableName
)에 각 작업(INSERT, UPDATE, DELETE)이 발생할 때마다 ChangeLog
테이블에 기록을 남기는 트리거를 생성합니다. 변경된 데이터는 FOR JSON AUTO
를 사용해 JSON 형태로 저장하면 나중에 처리하기 편리합니다.
-- INSERT 트리거
CREATE TRIGGER trg_YourTable_AfterInsert
ON dbo.YourTableName
AFTER INSERT
AS
BEGIN
INSERT INTO ChangeLog (TableName, OperationType, ChangedData)
SELECT 'YourTableName', 'INSERT', (SELECT * FROM inserted FOR JSON AUTO)
FROM inserted;
END;
GO
-- UPDATE 트리거
CREATE TRIGGER trg_YourTable_AfterUpdate
ON dbo.YourTableName
AFTER UPDATE
AS
BEGIN
INSERT INTO ChangeLog (TableName, OperationType, ChangedData)
SELECT 'YourTableName', 'UPDATE', (SELECT * FROM inserted FOR JSON AUTO)
FROM inserted;
END;
GO
-- DELETE 트리거
CREATE TRIGGER trg_YourTable_AfterDelete
ON dbo.YourTableName
AFTER DELETE
AS
BEGIN
INSERT INTO ChangeLog (TableName, OperationType, ChangedData)
SELECT 'YourTableName', 'DELETE', (SELECT * FROM deleted FOR JSON AUTO)
FROM deleted;
END;
GO
Step 3. Kafka Connect JDBC Source Connector 설정
이제 Debezium 대신 Kafka Connect에 기본 포함된 JDBC Source Connector를 사용하여 ChangeLog
테이블을 폴링(Polling)하도록 설정합니다.
{
"name": "jdbc-mssql-express-changelog-connector",
"config": {
"connector.class": "io.confluent.connect.jdbc.JdbcSourceConnector",
"connection.url": "jdbc:sqlserver://your_server_address:1433;databaseName=YourDatabaseName",
"connection.user": "YourUser",
"connection.password": "YourPassword",
"mode": "incrementing", // 증가하는 컬럼을 기준으로 데이터 추출
"incrementing.column.name": "ID", // ID 컬럼을 기준으로 새로운 데이터 추적
"table.whitelist": "dbo.ChangeLog", // 읽어올 테이블 지정
"topic.prefix": "mssql-changelog-", // 생성될 Kafka 토픽의 접두사
"poll.interval.ms": "5000" // 5초마다 테이블을 확인
}
}
- 장점: 설정이 간단하고 안정적입니다. DB 부하를 예측하기 쉽습니다.
- 단점: 모든 테이블에 트리거를 생성해야 합니다.
ChangeLog
테이블이 비대해질 수 있어 주기적인 관리가 필요합니다.
✅ 방법 2: 애플리케이션 레벨에서 변경 사항 직접 전송
데이터베이스에 의존하지 않고, 데이터를 변경하는 애플리케이션 코드에서 직접 Kafka로 메시지를 보내는 방법입니다.
어떻게 동작하나요?
애플리케이션(예: Java, Python, Node.js)이 DB에 INSERT
, UPDATE
, DELETE
쿼리를 실행한 직후, 해당 변경 내용을 담은 메시지를 Kafka Producer를 통해 직접 발행합니다.
Python 예시 코드:
from kafka import KafkaProducer
import json
producer = KafkaProducer(bootstrap_servers='your_kafka_broker:9092',
value_serializer=lambda v: json.dumps(v).encode('utf-8'))
def save_user_and_notify(user_data):
# 1. 데이터베이스에 데이터를 저장하는 로직
# db.save(user_data)
# 2. 변경 내용을 Kafka로 직접 전송
message = {"operation": "INSERT", "data": user_data}
producer.send('user-changes-topic', message)
producer.flush()
# 애플리케이션에서 함수 호출
save_user_and_notify({"id": 123, "name": "Kafka User"})
- 장점: DB에 트리거나 폴링으로 인한 추가 부하가 없습니다. 구현이 유연하고 실시간에 가깝습니다.
- 단점: 모든 데이터 변경 로직에 Kafka 전송 코드를 추가해야 하므로 누락될 위험이 있습니다. 애플리케이션 코드의 복잡성이 증가합니다.
✅ 방법 3: 트랜잭션 로그 직접 분석 (고급)
가장 복잡하지만 진정한 CDC에 가장 가까운 방법입니다. SQL Server가 내부적으로 사용하는 트랜잭션 로그를 fn_dblog
와 같은 비공식 함수로 직접 읽어 변경 내역을 파싱하는 방식입니다.
❗ 주의: 이 방법은 공식적으로 지원되지 않으며, SQL Server 버전에 따라 동작이 다르거나 예고 없이 변경될 수 있습니다. 시스템에 대한 깊은 이해가 필요하며, 운영 환경 적용 시 매우 신중한 테스트가 필수입니다.
어떻게 동작하나요?
sys.fn_dblog
함수를 사용해 트랜잭션 로그를 조회하고, 여기서 INSERT
, UPDATE
, DELETE
와 관련된 로그를 필터링하여 변경 데이터를 추출한 후 Kafka로 전송하는 별도의 애플리케이션을 구현해야 합니다.
-- 트랜잭션 로그를 조회하는 예시 쿼리
SELECT
[Current LSN],
Operation,
[Transaction ID],
AllocUnitName,
[Transaction Name]
FROM sys.fn_dblog(NULL, NULL)
WHERE Operation IN ('LOP_INSERT_ROWS', 'LOP_MODIFY_ROW', 'LOP_DELETE_ROWS');
- 장점: DB 스키마나 애플리케이션 코드를 변경할 필요가 없습니다.
- 단점: 구현이 매우 복잡하고 불안정합니다. SQL Server 시스템에 부하를 줄 수 있으며, 공식 지원이 없어 유지보수가 어렵습니다.
결론: 어떤 방법을 선택해야 할까?
세 가지 방법의 장단점과 추천 시나리오를 표로 정리했습니다.
방법 | 장점 | 단점 | 추천 대상 |
---|---|---|---|
1. 트리거 + ChangeLog (추천) | 설정 간단, 안정적, DB 부하 예측 가능 | 모든 테이블에 트리거 추가 필요, ChangeLog 테이블 관리 필요 | 대부분의 중소규모 프로젝트, 안정성이 중요한 경우 |
2. 애플리케이션 레벨 CDC | DB 부하 없음, 실시간에 가까움, 유연함 | 모든 코드 수정 필요, 누락 위험, 코드 복잡성 증가 | 애플리케이션 코드 수정이 자유롭고 빠른 응답이 필요한 경우 |
3. 트랜잭션 로그 직접 분석 (고급) | 코드/스키마 변경 불필요, CDC와 유사 | 매우 복잡하고 불안정, 성능 저하 우려, 유지보수 어려움 | 특수한 상황에서 최후의 수단으로 고려해볼 만한 방법 |
SQL Server Express에서 CDC 기능이 없어 Debezium을 바로 사용할 수는 없지만, 보신 것처럼 여러 훌륭한 대안이 존재합니다.
대부분의 경우 1번 방법인 ‘트리거와 변경 로그 테이블’ 방식이 가장 안정적이고 현실적인 해결책입니다. 프로젝트의 요구사항, 개발 리소스, 허용 가능한 지연 시간을 고려하여 가장 적합한 방법을 선택하시기 바랍니다. 🚀