현재 참여하고 있는 프로젝트에서 샌드버드 같은 채팅 SDK를 만들고 있다. 프론트로 참여하고있지만 우연한 기회로 API 설계와 ERD 설계에 모두 관여하게 되어 ERD설계중 고려했던 사항을 포스트로 남겨두려고 한다.
먼저 설계한 API는 이 주소에서 확인할 수 있다.
https://rakuraku.gitbook.io/rakuraku-docs/api-docs/authentication
1대1 채팅과 그룹 채팅을 모두 지원하고 싶었고 실시간성을 유지하며 파일 공유가 가능하게끔 해야했다.
처음에는 사용자 정보, 채팅방 정보, 메시지 정보를 저장하기 위해 단순히 가장 기본적인 테이블인 users, chat_rooms, messages 테이블을 만들었다. 각각 사용자의 고유 정보를 관리하고, 채팅방을 정의하며, 메시지를 기록하는 역할을 수행하도록 했다. 기본적인 테이블 설계를 끝내고 골똘히 생각해보니 문제가 있다는 것을 깨달았다. 크게 두 가지 문제를 찾을 수 있었는데
첫번째
1대1 채팅과 그룹 채팅 모두를 지원하려면, 사용자와 채팅방 간의 다대다 관계를 처리해야만 했다.
두번째
SDK 특성상 여러 애플리케이션에서 이 설계를 사용할 수 있도록 멀티테넌시 지원해야 했다.
예를 들어 App A와 App B가 각각 자신의 사용자를 관리해야 하는데, 동일한 userId를 가진 다른 사용자가 두 앱에 존재할 경우 데이터 충돌이 발생할 수 있다. 또한 App A의 관리자가 자신의 사용자 데이터만 조회하고 싶어도, 데이터가 분리되지 않아 WHERE 조건으로 필터링하지 않으면 모든 애플리케이션의 데이터를 보게 된다. App A관리자가 App B 데이터까지 보게 된다는게 말이 안되었다.
이 두가지 문제를 아래와 같은 방법으로 해결했다.
1. 다대다 관계 처리
한 명의 사용자가 여러 채팅방에 참여할 수 있으며, 하나의 채팅방에 여러 사용자가 참여할 수 있기 때문에 다대다(M:N) 관계가 발생했다.
그리고 기본적으로 다대다 관계는 아래 테이블처럼 연결 관계 자체만을 표현하기 때문에
userId | roomId |
user_1 | room_1 |
user_2 | room_1 |
user_3 | room_1 |
- (오픈카톡같은)단체 익명 채팅방에서 누가 방 소유자인지 알 수 없다.
- 누가 관리자인지, 누가 일반 사용자(member)인지 구분할 수 없다.
결과적으로, 그룹 채팅의 동작(초대, 강퇴, 권한 변경 등)을 구현하기 어렵다는 문제점이 발생하고 있었다.
user_1 | room_1 | owner |
user_2 | room_1 | admin |
user_3 | room_1 | member |
따라서 UserChatRooms 테이블이란 중간테이블을 두어 다대다 문제 해결했다.이곳에는 각 사용자와 채팅방 간의 참여 정보, 사용자가 채팅방에 언제 참여했는지(joinedAt), 이전에 단순 연결관계를 넘어 좀더 풍부한 정보 및 느슨한 관계를 만들었고 role 필드를 통해 채팅방 내에서의 권한을 정할수도 있어 역할 기반 접근 제어(RBAC, Role-Based Access Control)로 권한을 추가하거나 변경할 수 있었다. 구체적으로 user_chat_rooms는 userId와 roomId를 외래 키로 참조하게 하여 이 두 키를 복합 기본 키로 설정하여 중복 데이터 삽입을 방지도 할 수 있었다.
2. 멀티테넌시 구조
모든 주요 테이블에 appId를 포함시켜 멀티테넌시를 지원했다. 이렇게 함으로써 appId를 기준으로 데이터를 논리적으로 분리하여 각 앱의 데이터를 독립적으로 관리할 수 있고 특정 앱에 속하지 않은 데이터에 대한 접근을 제한할 수 있었다.
예를 들어, users 테이블에서 appId를 기준으로 다음과 같은 데이터를 필터링할 수 있다:
SELECT * FROM users WHERE appId = 'app_12345';
Chaper 01. The Database Environment
An organization must make a commitment to implement Service-Oriented Architecture. Because services need to be able to integrate smoothly, information systems must be designed from the top down.
데이터도 서비스 지향 아키텍쳐를 채택해야한다. 데이터를 일종의 ‘서비스(Service)’로 봐야한다. 그리고 필요할 때 데이터를 공유하며 상호작용하는 방식을 채택해야한다. 데이터베이스, 애플리케이션, 네트워크 등 모든 정보 시스템이 개별적인 서비스 단위로 구성되는 것이 바람직하다. 서비스 지향으로 데이터를 구축해야 바텀업이 아닌 탑다운 방식을 유지할 수 있게된다.
이전에 DB설계 관련책에서 읽었던 인상깊은 구절인데 이번에 도움이 많이 되었던 것 같다. ERD를 개선하면서 느꼈던 것은 어떻게 백엔드가 데이터를 가져갈 것인가, 어떻게 (예를들어 앱별로 유저정보 끌어가는 것 같은) 비즈니스 로직이 데이터를 사용할 것인가? 를 생각할 때마다 좀더 나은 RDB 설계를 할 수 있었다. DB설계도 백엔드, 프론트 코드작성과 마찬가지로 결국 항상 염두해두어야할 것은 도메인 영역임을 느낄 수 있었던 좋은 경험이었다 :)
'Database' 카테고리의 다른 글
관계형 DB 설계할 때 유의해야할 규칙들 (0) | 2024.11.03 |
---|---|
ORM 이란? (0) | 2024.05.05 |