Published on

MariaDB-FEDERATED엔진으로 DB 동기화 하기

Authors

MariaDB의 FEDERATED 엔진은 (remote)데이터베이스의 데이터를 복제하거나 클러스터링 없이도 액세스할 수 있게 해주는 스토리지 엔진입니다.

예를 들어서, 로컬 데이터베이스에서 FEDERATED 엔진으로 연결된 remoteDB의 테이블을 연결하면 데이터를 자동으로 가져오고 동기화 됩니다. 이 과정에서 양방향 read/write 또한 가능합니다.

이번 글에서는 docker compose 를 이용해서 로컬단에 구축된 MariaDB에서 FEDERATED 엔진을 사용해 연결하는 과정을 기록합니다.

참고로 MariaDB의 FEDERATED 엔진은 DB 링크와 유사하지만, 정확히는 다릅니다.

DB 링크는 Oracle에서 제공하는 기능으로, 세션을 열고 다양한 작업을 수행할 수 있는 반면, FEDERATED 엔진은 원격 데이터베이스의 테이블과 동기화하는 데 중점을 둡니다. 즉, FEDERATED는 복제나 클러스터링 없이 원격 데이터베이스의 데이터를 로컬에서 접근할 수 있도록 해주는 스토리지 엔진으로, DB 링크보다는 데이터 동기화에 더 가깝습니다.

이번글에 사용될 용어로, 원본은 origin / DB링크를 시도하는 카피본(?) 은 copied 라고 명명하겠습니다.

1. DB 세팅 (on docker)

아래는 Docker Compose를 사용하여 두 개의 MariaDB 데이터베이스(origin, copied)를 세팅하는 yml 입니다.

각 DB의 port가 충돌 되지 않게 포워딩을 3307/3308 해줘야 합니다.

1. docker-compose.yml

services:
  origin-db:
    image: mariadb:latest
    container_name: origin-db-container
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: origin_db
      MYSQL_USER: origin_db_user
      MYSQL_PASSWORD: password123
    ports:
      - "3307:3306"
    networks:
      - db_network

  copied-db:
    image: mariadb:latest
    container_name: copied-db-container
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: copied_db
      MYSQL_USER: copied_db_user
      MYSQL_PASSWORD: password123
    ports:
      - "3308:3306"
    networks:
      - db_network

networks:
  db_network:
    driver: bridge

2. Docker Compose 실행

docker compose up -d

각 데이터베이스에 접근해 user테이블(db 의 User아님)을 만들어줍니다. 링크가 잘되는지만 확인할 목적이기때문에 최대한 간단한 컬럼으로 구성합니다.

참고(도커로 디비 인스턴스 실행)

docker exec -it origin-db mysql -uorigin_db_user -ppassword123 origin_db

origin-DB

CREATE TABLE user (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(12),
);

copied-DB

링크 시켜줄 DB로 접속하여 테이블을 만들고, FEDERATED 테이블을 만드는 것인데, 아래 DB 링크를 통해서 커넥션을 맺어줍니다.

CREATE TABLE linked_user (
  id INT,
  name VARCHAR(100)
) ENGINE=FEDERATED CONNECTION='mysql://origin_db_user:password123@origin-db:3306/origin_db/user';

2. FEDERATED 엔진 설치

copied-db 컨테이너에서 MariaDB에 접속한 후 federated 엔진을 설치합니다.

만약 엔진을 활성해주지 않으면 strage engine 에 대한 에러가 발생합니다.(Unknown storage engine 'FEDERATED')

INSTALL PLUGIN FEDERATED SONAME 'ha_federated.so';

엔진을 설치할때는 당연히 세팅해둔 MYSQL_ROOT_PASSWORD 를 참고해서 root 계정으로 접속해서 설치합니다. 만약 INSERT command denied to user 'copied_db_user'@'~~~' for table mysql.plugin 처럼 권한에 대한 에러가 발생했다면 root 계정으로 시도 합니다.

엔진 설치 확인

SHOW ENGINES; 명령어로 FEDERATED 엔진이 활성화되었는지 확인합니다.

maria-db-federated

여기 까지 왔으면 아래처럼 각 DB에 user / linked_user 테이블이 잘 생성되었는지 확인합니다.

maria-db-federated

3. 연결확인

데이터 삽입

기대한 결과는 origin db에 데이터를 넣었을때, copied db 에서 확인(및 조회) 가 되는 것 입니다.

  1. origin-DB에 데이터 삽입

origin DB에 접속하여 employees 테이블에 테스트 데이터를 추가합니다

# origin_db 에서 실행
INSERT into user (name) VALUES ('브루노마스');
  1. copied-DB에서 데이터 확인
# copied_db 에서 실행
SELECT * FROM linked_user;
maria-db-federated

이제 copied DB에서 잘 보여지는지 확인하고 잘 보여진다면 완료 입니다.

4. Copied DB를 읽기 전용으로 세팅

위의 과정을 잘 수행했다면, origin-copied DB간 양방향 통신이 가능해야 합니다.

그 말은 곧 origin-DB에 데이터 삽입 시, copied-DB에도 보여져야 한다는 것 입니다.

‘물리적인 복제’ 와 ‘단방향 읽기권한’ 등이 요구사항이라면 DB-Link라는 방법이 적절하지 못한 방법이 됩니다.

여기서 부터는 읽기만 되도록하는 방법이 필요해서 세팅한 과정입니다.

참고로, 저의 경우 copied-DB 를 사용하는 곳이 WAS(Django)였고, 이런 경우에는 DB using 하는 부분에서 write 에 대한 로직을 손봐도 읽기만 세팅 되긴 합니다.

하지만 혹시 모를 상황을 생각한다면 WAS뿐이 아닌, copied-DB 에서도 읽기만 되는 것이 보다 안전하다고 생각합니다. ( 이중으로 안전장치를 마련해 두는 것이죠.)

origin-DB User 생성과 권한 부여

DB에 접속한 후, 읽기 전용 사용자 계정을 추가합니다.

CREATE USER 'read_only_user'@'%' IDENTIFIED BY 'read_only_password';
GRANT SELECT ON adb.* TO 'read_only_user'@'%';

FLUSH PRIVILEGES를 통해 권한을 반영합니다.

FLUSH PRIVILEGES;

read_only_user라는 사용자 계정을 만들고, 해당 origin-DB 의 User 에 대해 SELECT 권한만 부여합니다.

FLUSH PRIVILEGES;는 MySQL(MariaDB)에서 권한 테이블의 변경 사항을 적용하는 명령어입니다.

CREATE TABLE linked_user_but_read_only (
  id INT,
  name VARCHAR(100)
) ENGINE=FEDERATED CONNECTION='mysql://read_only_user:read_only_password@origin-db:3306/origin_db/user';

그리고 아래 처럼 링크되었지만, 연결조건에 read_only 제한을 걸어둔 테이블에 INSERT를 시도하게 되면 아래 에러가 발생합니다.(values에 박해일은 박해일 배우님으로, 인서트한 이유는 별거아닙니다..)

maria-db-federated

copied_db> INSERT into linked_user_but_read_only (name) VALUES ('박해일') Got error 10000 'Error on remote system: 1142: INSERT command denied to user 'read_only_user'@'!@#$!@' for table origin_db.user' from FEDERATED

5. 결론

이렇게 FEDERATED 으로 연결된 DB는 다음과 같은 특징이 있습니다.

  • origin-db & copied-db는 네트워크를 통해서 가상으로 동기화 되는 상태입니다.
    • origin-db 가 종료되면, copied-db에서 조회도 안됨
    • Unknown server host 'copied-db'
  • copied-db (의 origin-db와 connection 된) table 에서 데이터를 INSERT 하는 경우 orgin-db에도 생성됩니다.
  • 연결에 필요한건 엔진과 DB접속 정보이며, 유저권한에 대한 것도 그대로 동작합니다.

이러한 특징으로 인해, 개발 요구사항이 ‘가상테이블 개념의 실시간 동기화가 필요한 경우’ 이거나, ‘양방향 read/write’ 가 되어야하는 경우라면 DB Link 가 하나의 좋은 방법이 될 수 있습니다.

이번 글에서 사용된 코드 일부를 깃허브에 퍼블릭으로 업로드했으니, 필요하신분들은 참고하시길 바랍니다.

6. 참고 문서 링크

hongreat 블로그의 글을 봐주셔서 감사합니다!