한 줄 요약: FEDERATED 는 다른 MySQL 서버의 테이블을 로컬에서 일반 테이블처럼 SELECT/INSERT 할 수 있게 하는 스토리지 엔진임. 데이터 자체는 들고 있지 않고
CONNECTION문자열만 가짐. 8.4 에서도 살아 있지만 기본 비활성이라--federated옵션을 켜야 쓸 수 있고, 트랜잭션·외래키·인덱스 활용 같은 핵심 운영 기능을 포기해야 함.
이 글은 2022-06-03 에 5.x · 8.0 환경에서 운영 중이던 FEDERATED 셋업을 정리한 메모가 출발점임. 2026-04 시점에 MySQL 8.4.8 컨테이너에서 동일 시나리오를 다시 실행해 명령·출력·에러 코드를 8.4 LTS 기준으로 갱신했음.
개요
FEDERATED 는 MySQL 5.0 부터 제공돼 온 스토리지 엔진으로, 테이블 정의(.frm 또는 8.0+ 데이터 딕셔너리 메타데이터)와 원격 서버 접속 정보(CONNECTION 문자열)만 가지고 있고 실제 row 는 다른 MySQL 서버에 있음. 로컬에서 SELECT * FROM 테이블 을 던지면 엔진이 그 자리에서 mysql 클라이언트 프로토콜로 원격 서버에 접속해 결과를 받아 옴. INSERT·UPDATE·DELETE 도 동일한 경로로 원격에 반영됨.
쓰기 좋은 케이스는 분리된 두 데이터베이스를 임시로 한 SQL 안에서 조인·검증해야 할 때나, 단순 ETL 연결자로 SELECT-만-필요한 짧은 작업임. 영속적인 분산 데이터 액세스 계층이 아니라 “잠시 다리를 놓는” 도구임.
| 항목 | 내용 |
|---|---|
| 도입 | MySQL 5.0 |
| 8.4 기본 상태 | OFF — SHOW ENGINES 의 Support 가 NO. 사용하려면 기동 옵션 필요 |
| 활성화 방법 | mysqld --federated 또는 my.cnf [mysqld] 섹션에 federated 추가 후 재기동 |
| 트랜잭션 | 미지원 — START TRANSACTION 자체는 받지만 ROLLBACK 이 원격에 반영 안 됨 |
| XA / Savepoint | 미지원 |
| 인덱스 활용 | 로컬 인덱스 정보는 옵티마이저 힌트로만 쓰이고, 실제 실행은 원격 풀 스캔에 의존 |
| 외래키 | 미지원 |
| 권한 모델 | CONNECTION 에 박힌 원격 계정의 권한이 곧 이 테이블의 권한 |
| 통신 프로토콜 | mysql 클라이언트 프로토콜 (TCP). SSL 옵션은 별도 명시 필요 |
MySQL 8.4.8 에서 직접 확인 — 옵션 없이 기동된 인스턴스에서
SHOW ENGINES의 FEDERATED 행이Support=NO로 나오고, FEDERATED 로CREATE TABLE을 시도하면ERROR 1286 (42000): Unknown storage engine 'FEDERATED'가 떨어짐.
결론 / 정리
어떤 상황에 적합한가
| 상황 | FEDERATED 적합성 |
|---|---|
| 일회성 데이터 검증·비교용 임시 다리 | 적합 — 짧은 SELECT 단발성 트래픽이면 가장 단순함 |
| 가벼운 운영 ETL (소량 row, 일/시간 단위) | 조건부 적합 — 양방향이면 정합성 검토 필요 |
| 트랜잭션이 필요한 분산 쓰기 | 부적합 — 롤백·격리 보장 없음 |
| 대용량 OLAP 조인 | 부적합 — 인덱스가 안 먹히고 매 쿼리마다 풀 fetch |
| 영속적 분산 액세스 계층 | 부적합 — Vitess·미들웨어·CDC(Debezium 등) 사용 권장 |
보안 민감 데이터 (CONNECTION 에 평문 자격증명이 박힘) | 부적합 — DDL 텍스트에 비밀번호가 노출됨 |
핵심은 한 가지로 압축됨 — “임시 다리” 이상으로 쓰지 말 것. 트랜잭션·인덱스·격리 수준 가정이 무너지므로 운영 데이터의 일관성·성능 어느 쪽도 보장되지 않음.
FEDERATED vs 대안 비교
| 시나리오 | FEDERATED | 권장 대안 |
|---|---|---|
| 짧은 SELECT 한두 번 | OK | 그냥 SSH·DBA 도구로 직접 접속 |
| 단방향 데이터 동기화 | 권장 안 함 — 정합성 보장 없음 | binlog 기반 replication / CDC (binlog-cdc-overview 참조) |
| 양방향 분산 쓰기 | 권장 안 함 — 트랜잭션 없음 | Vitess·ProxySQL·애플리케이션 레벨 라우팅 |
| 다른 RDBMS 와의 연동 | 못 함 (MySQL 프로토콜 전용) | dblink·외부 ETL |
사용법
1단계 — 로컬 서버에서 FEDERATED 활성화
8.4 기본 이미지는 FEDERATED 가 꺼져 있음. my.cnf 또는 기동 옵션으로 켬.
# /etc/my.cnf 또는 /etc/mysql/conf.d/federated.cnf
[mysqld]
federated도커로 검증할 때는 옵션을 컨테이너 명령에 직접 붙이는 게 가장 간단함.
docker run -d --name blog-test-mysql-fed-local \
-e MYSQL_ROOT_PASSWORD=test1234 \
-e MYSQL_DATABASE=local_db \
mysql:8.4 --federated활성화 확인.
SHOW ENGINES;+--------------------+---------+----------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------+--------------+------+------------+
...
| FEDERATED | YES | Federated MySQL storage engine | NO | NO | NO |
...
+--------------------+---------+----------------------------------+--------------+------+------------+Transactions / XA / Savepoints 모두 NO 가 박혀 나오는 것이 핵심임 — 활성화돼도 이 한계는 그대로임.
2단계 — 원격 서버에 실제 테이블·전용 계정 준비
원격 측에는 일반 InnoDB 테이블이 있어야 함. FEDERATED 테이블이 접근할 전용 계정을 만들고 그 테이블에 한해 최소 권한만 부여함.
-- 원격 (remote_db)
CREATE TABLE user_permissions (
permission_id INT NOT NULL AUTO_INCREMENT,
role_name VARCHAR(50) NOT NULL,
read_users TINYINT NOT NULL DEFAULT 0,
write_users TINYINT NOT NULL DEFAULT 0,
read_orders TINYINT NOT NULL DEFAULT 0,
write_orders TINYINT NOT NULL DEFAULT 0,
PRIMARY KEY (permission_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE USER 'fed_reader'@'%' IDENTIFIED BY 'fed_pwd_1234';
GRANT SELECT, INSERT, UPDATE, DELETE
ON remote_db.user_permissions
TO 'fed_reader'@'%';운영 시 주의 — CONNECTION 문자열에 비밀번호가 평문으로 박히고 SHOW CREATE TABLE 결과에도 그대로 나옴. 전용 계정·최소 권한 원칙으로 피해 범위를 줄여놓아야 함.
3단계 — 로컬에 FEDERATED 테이블 생성
로컬 테이블 정의는 원격과 컬럼 이름·타입·NULL 여부가 일치해야 함 (AUTO_INCREMENT·PRIMARY KEY 도 그대로). CONNECTION 만 추가됨.
-- 로컬 (local_db)
CREATE TABLE user_permissions_fed (
permission_id INT NOT NULL AUTO_INCREMENT,
role_name VARCHAR(50) NOT NULL,
read_users TINYINT NOT NULL DEFAULT 0,
write_users TINYINT NOT NULL DEFAULT 0,
read_orders TINYINT NOT NULL DEFAULT 0,
write_orders TINYINT NOT NULL DEFAULT 0,
PRIMARY KEY (permission_id)
) ENGINE=FEDERATED DEFAULT CHARSET=utf8mb4
CONNECTION='mysql://fed_reader:fed_pwd_1234@<원격호스트>:3306/remote_db/user_permissions';CONNECTION 문자열 형식은 mysql://<user>:<password>@<host>:<port>/<database>/<table> 임. 호스트는 IP 또는 DNS 이름 모두 가능하고, 이 글의 컨테이너 검증에서는 같은 docker network 내에서 컨테이너 이름으로 해석됨.
CREATE SERVER 로 접속 정보를 분리해서
CONNECTION='server_name/원격테이블'형태로 쓰는 변형도 가능함. DDL 에 평문 비밀번호가 박히는 걸 피할 수 있어 운영에는 이쪽이 권장됨.
테스트
테스트 환경: MySQL 8.4.8 인스턴스 두 개 — 원격 역할은 일반 InnoDB, 로컬 역할은
--federated활성화. 두 인스턴스는 같은 Docker network 에 묶어 호스트명을 해석함.
1. 활성화 전 — CREATE TABLE 자체가 거부됨
--federated 없이 기동된 인스턴스에서 FEDERATED 테이블을 만들려 하면 즉시 실패함.
CREATE TABLE federated_off_test (id INT PRIMARY KEY)
ENGINE=FEDERATED CONNECTION='mysql://u:p@127.0.0.1:3306/x/y';ERROR 1286 (42000): Unknown storage engine 'FEDERATED'같은 메시지를 8.0·5.7 시절에도 봤었음. “엔진이 없어 보이지만 실제로는 비활성 상태” 라는 의미라 보고 my.cnf 의 federated 옵션부터 점검하면 됨.
2. 원격 row 가 그대로 보이는지
원격에 3건 시드 후, 로컬 FEDERATED 테이블에서 SELECT.
-- 원격
INSERT INTO user_permissions (role_name, read_users, write_users, read_orders, write_orders) VALUES
('admin', 1, 1, 1, 1),
('operator', 1, 0, 1, 1),
('viewer', 1, 0, 1, 0);
-- 로컬
SELECT * FROM user_permissions_fed;+---------------+-----------+------------+-------------+-------------+--------------+
| permission_id | role_name | read_users | write_users | read_orders | write_orders |
+---------------+-----------+------------+-------------+-------------+--------------+
| 1 | admin | 1 | 1 | 1 | 1 |
| 2 | operator | 1 | 0 | 1 | 1 |
| 3 | viewer | 1 | 0 | 1 | 0 |
+---------------+-----------+------------+-------------+-------------+--------------+원격 데이터가 그대로 보임. row 가 로컬에 복사된 게 아니라 SELECT 시점에 원격에서 끌어와 보여주는 것임 — 다음 줄 SELECT 사이에 원격에서 row 를 변경하면 즉시 반영됨.
3. 로컬 INSERT 가 원격으로 전파되는지
로컬에 INSERT 후 원격에서 직접 조회.
-- 로컬
INSERT INTO user_permissions_fed (role_name, read_users, write_users, read_orders, write_orders)
VALUES ('auditor', 1, 0, 1, 0);
-- 원격
SELECT * FROM user_permissions;+---------------+-----------+------------+-------------+-------------+--------------+
| permission_id | role_name | read_users | write_users | read_orders | write_orders |
+---------------+-----------+------------+-------------+-------------+--------------+
| 1 | admin | 1 | 1 | 1 | 1 |
| 2 | operator | 1 | 0 | 1 | 1 |
| 3 | viewer | 1 | 0 | 1 | 0 |
| 4 | auditor | 1 | 0 | 1 | 0 |
+---------------+-----------+------------+-------------+-------------+--------------+로컬 INSERT 가 원격에 반영됐고, 로컬에서 부여한 permission_id=4 도 원격 AUTO_INCREMENT 가 매긴 그 값임 — FEDERATED 는 원격이 발급한 값을 받아 클라이언트에게 그대로 돌려줌.
4. 트랜잭션 ROLLBACK 이 통하지 않음
여기서부터가 운영에서 가장 자주 데는 부분임. FEDERATED 는 트랜잭션을 흉내내지만 실제 ROLLBACK 능력이 없음.
START TRANSACTION;
INSERT INTO user_permissions_fed (role_name) VALUES ('temp_role');
ROLLBACK;
SELECT role_name FROM user_permissions_fed WHERE role_name='temp_role';+-----------+
| role_name |
+-----------+
| temp_role |
+-----------+ROLLBACK 이 에러 없이 통과했지만 row 는 이미 원격에 반영돼 남아 있음. INSERT 시점에 원격으로 즉시 전송되고, 로컬은 그 결과를 되돌릴 권한이 없기 때문임. 읽기 외의 작업은 트랜잭션 보호가 사라진다고 보고 설계해야 함.
5. 연결 실패 — 에러 코드 확인
CONNECTION 의 호스트·포트가 잘못된 경우.
CREATE TABLE bad_fed (id INT PRIMARY KEY)
ENGINE=FEDERATED CONNECTION='mysql://nope:nope@127.0.0.1:13399/x/y';
SELECT * FROM bad_fed;ERROR 1429 (HY000): Unable to connect to foreign data source:
Can't connect to MySQL server on '127.0.0.1:13399' (111)CREATE TABLE 시점에는 원격 검증이 없으므로 통과되지만, 첫 SELECT 에서 ER_CONNECT_TO_FOREIGN_DATA_SOURCE (1429) 가 떨어짐. 모니터링에서 1429 코드를 잡아두면 FEDERATED 테이블의 원격 가용성을 헬스체크 대용으로 쓸 수 있음.
참고
- MySQL 8.4 — The FEDERATED Storage Engine — 엔진 개요,
--federated활성화 방법, 사용 시점에 대한 공식 권고 - MySQL 8.4 — Creating a FEDERATED Table Using CONNECTION —
mysql://user:password@host:port/database/tablenameCONNECTION문자열 문법 - MySQL 8.4 — Creating a FEDERATED Table Using CREATE SERVER —
CREATE SERVER로 자격증명을 분리해CONNECTION='server_name/원격테이블'형태로 쓰는 변형 - MySQL 8.4 — FEDERATED Storage Engine Notes and Tips — 트랜잭션·인덱스·
ALTER TABLE·prepared statement·partitioning 비지원 항목 정리 - MySQL 8.4 — Server Error Reference: ER_CONNECT_TO_FOREIGN_DATA_SOURCE (1429) — FEDERATED 연결 실패 시 떨어지는 에러 코드 정의