프로젝트/[어플리케이션] 토닥

[토닥] 경계선 지능인을 위한 앱 서비스 시스템 아키텍처 구현

마달랭 2025. 5. 26. 17:24

개요

백엔드 개발자로서 현재 프로젝트에서 API 게이트웨이 기반 MSA아키텍처 구현과 전반적인 인프라 세팅을 맡았다. Docker 기반 서비스 컨테이너 관리나 CI/CD 파이프라인 구현같은 경우 이미 이전 프로젝트를 진행하며 경험을 쌓았기 때문에 인프라 구현에 딱히 어려운 일은 없었다.

API 게이트웨이 또한 따른 시간 내에 구현을 완료하였고, Java 기반의 SpringBoot와 Python 기반의 FastAPI 웹 프레임워크를 같은 마이크로서비스로 묶은 경험도 매우 뜻깊었다. 또한 RDS, S3 등 클라우드 DB와 스토리지를 활용한 것도 주요 경험이 되었다.

 

각설하고 이번 프로젝트에서 시스템 아키텍처를 어떻게 설계했는지 기록을 남기고자 한다.

 

 

시스템 아키텍처

 

우선 API 게이트웨이, 마이크로서비스와 Kafka, ElasticSearch, Kibana, Redis, React는 모두 같은 docker 네트워크로 묶어주었다. 아 면밀히 말하면 Kafka-ElasticSearch-Kibana는 별도의 로그 네트워크로 묶고 API 게이트웨이 관련 네트워크와는 extern처리해 주었다.

Kafka를 거의 프로젝트 막바지에 적용하여 매핑 경로를 Kafka기반으로 변경하기엔 어려움이 있었고, 그로 인해 HTTP 요청에 관련 로깅 시스템만 ElasticSearch로 남기고자 위오 같은 아키텍처를 사용하게 되었다.

기존 프로젝트와는 다르게 DB와 스토리지를 AWS기반으로 사용하였다. 시스템 리소스가 분산되긴 한다만 서비스가 너무 많은 탓인지 커넥션 수가 현저히 부족하여 만족스러운 경험은 아니었다.

S3는 이미지 파일 및 용량이 다소 큰 파일들을 저장하기 위해 사용해 주었고, Firebase는 유저 알림을 위해 사용하였으나 해당 기능은 내가 구현하지 않았다.

 

웹/앱으로 부터 API호출 요청이 들어올 경우 Auth-Service를 제외한 모든 서비스는 JWT토큰 검증을 하게 된다. 유효한 토큰일 경우 X-User-ID를 헤더에 포함시켜 각 서비스에 전달되고 해당 ID를 기준으로 쿼리를 수행, 클라이언트에게 응답이 가게 된다. 이 과정에서 모든 HTTP요청에 대한 로깅이 Kafka로 전달되어 ElasticSearch로 전달되고 Kibana를 통해 시각화 되어 시스템 현황과 이상 징후에 대한 모니터링을 할 수 있게 되었다.

 

이전 메타버스 게임 프로젝트에서도 다수의 데디케이트 서버 관리를 통해 MSA구조를 가졌지만 SpringBoot 기반의 API 게이트웨이와 MSA구조 설계는 처음이었다.

 

 

ERD


RDBMS에서 사용할 ERD를 작성하였다. 정규화를 최대한 진행하였고, 공통 필드를 User기반으로 작성하였고, 센터, BIUser, 부모로 세분화를 진행하였고, 각 객체간 관계를 설정하여 종속성을 추가해 주었다.

 

 

물리 스키마

-- 사용자 테이블
CREATE TABLE User (
    id CHAR(36) PRIMARY KEY,
    type VARCHAR(20) NOT NULL,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(100) UNIQUE,
    pwd VARCHAR(255) NOT NULL,
    phone VARCHAR(20),
    addr TEXT,
    created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 경계선 지능인 테이블
CREATE TABLE BIUser (
    user_id CHAR(36) PRIMARY KEY,
    birth DATE,
    gender VARCHAR(20),
    image VARCHAR(255),
    needs TEXT,
    created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES User(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 부모 테이블
CREATE TABLE Parent (
    user_id CHAR(36) PRIMARY KEY,
    created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES User(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 지원 센터 테이블
CREATE TABLE Center (
    user_id CHAR(36) PRIMARY KEY,
    descr TEXT,
    created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES User(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 가게 테이블
CREATE TABLE Store (
    id CHAR(36) PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    addr TEXT,
    phone VARCHAR(20),
    image VARCHAR(255),
    descr TEXT,
    created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 경계선 지능인 간의 친구 관계 테이블 (다대다)
CREATE TABLE BIFriend (
    id CHAR(36) PRIMARY KEY,
    bi_user_id1 CHAR(36) NOT NULL,
    bi_user_id2 CHAR(36) NOT NULL,
    rel_status VARCHAR(20) DEFAULT 'pending',
    status VARCHAR(20) DEFAULT 'active',
    end_date DATE,
    created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (bi_user_id1) REFERENCES BIUser(user_id) ON DELETE CASCADE,
    FOREIGN KEY (bi_user_id2) REFERENCES BIUser(user_id) ON DELETE CASCADE,
    CHECK (bi_user_id1 != bi_user_id2)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 부모-자녀 관계 테이블 (다대다, 부모는 최대 2명)
CREATE TABLE ParentChild (
    id CHAR(36) PRIMARY KEY,
    parent_user_id CHAR(36) NOT NULL,
    child_user_id CHAR(36) NOT NULL,
    rel_type VARCHAR(50),
    status VARCHAR(20) DEFAULT 'active',
    created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (parent_user_id) REFERENCES Parent(user_id) ON DELETE CASCADE,
    FOREIGN KEY (child_user_id) REFERENCES BIUser(user_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 지원 센터-경계선 지능인 관계 테이블 (다대다)
CREATE TABLE CenterBI (
    id CHAR(36) PRIMARY KEY,
    center_user_id CHAR(36) NOT NULL,
    bi_user_id CHAR(36) NOT NULL,
    status VARCHAR(20) DEFAULT 'active',
    start_date DATE NOT NULL,
    end_date DATE,
    created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (center_user_id) REFERENCES Center(user_id) ON DELETE CASCADE,
    FOREIGN KEY (bi_user_id) REFERENCES BIUser(user_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 경계선 지능인-가게 배치 관계 테이블 (다대다)
CREATE TABLE BIStore (
    id CHAR(36) PRIMARY KEY,
    bi_user_id CHAR(36) NOT NULL,
    store_id CHAR(36) NOT NULL,
    start_date DATE NOT NULL,
    end_date DATE,
    role VARCHAR(100),
    status VARCHAR(20) DEFAULT 'active',
    created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (bi_user_id) REFERENCES BIUser(user_id) ON DELETE CASCADE,
    FOREIGN KEY (store_id) REFERENCES Store(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 센터-가게 관계 테이블 (다대다)
CREATE TABLE CenterStore (
    id CHAR(36) PRIMARY KEY,
    center_user_id CHAR(36) NOT NULL,
    store_id CHAR(36) NOT NULL,
    start_date DATE NOT NULL,
    end_date DATE,
    status VARCHAR(20) DEFAULT 'active',
    created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (center_user_id) REFERENCES Center(user_id) ON DELETE CASCADE,
    FOREIGN KEY (store_id) REFERENCES Store(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 인덱스 생성
CREATE INDEX idx_user_type ON User(type);
CREATE INDEX idx_bifriend_user1 ON BIFriend(bi_user_id1);
CREATE INDEX idx_bifriend_user2 ON BIFriend(bi_user_id2);
CREATE INDEX idx_parentchild_parent ON ParentChild(parent_user_id);
CREATE INDEX idx_parentchild_child ON ParentChild(child_user_id);
CREATE INDEX idx_centerbi_center ON CenterBI(center_user_id);
CREATE INDEX idx_centerbi_user ON CenterBI(bi_user_id);
CREATE INDEX idx_bistore_user ON BIStore(bi_user_id);
CREATE INDEX idx_bistore_store ON BIStore(store_id);
CREATE INDEX idx_centerstore_center ON CenterStore(center_user_id);
CREATE INDEX idx_centerstore_store ON CenterStore(store_id);

 

ERD기반의 MariaDB물리 스키마를 작성하고 쿼리 최적화를 위한 인덱스를 배분해 주었다.

728x90