한 줄 요약: 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 기본 상태OFFSHOW 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 테이블의 원격 가용성을 헬스체크 대용으로 쓸 수 있음.


참고