아키텍처 패턴 시리즈 14: 마이크로서비스 아키텍처 (Microservices Architecture)
마이크로서비스 아키텍처는 애플리케이션을 독립적으로 배포 및 관리할 수 있는 작은 서비스들로 나누는 아키텍처 패턴이다.
각 서비스는 특정 도메인에 집중하여 독립적으로 개발, 배포, 확장할 수 있다.
마이크로서비스 아키텍처의 필요성
다음과 같은 문제를 해결하기 위해 마이크로서비스 아키텍처가 사용된다:
- 모놀리식 아키텍처의 비효율성: 하나의 큰 코드베이스로 구성된 시스템은 배포 및 확장이 어려움.
- 빠른 배포 요구: 독립적인 배포를 통해 특정 서비스만 업데이트하거나 수정 가능.
- 복잡한 비즈니스 요구: 비즈니스 요구사항이 다양하고 확장 가능성이 클 때 유리.
예시: 전자 상거래 애플리케이션
전자 상거래 플랫폼은 일반적으로 다음과 같은 기능이 필요하다:
- 사용자 관리
- 상품 카탈로그
- 주문 처리
- 결제
마이크로서비스 아키텍처에서는 각각의 기능을 독립적인 서비스로 분리하여 관리한다.
마이크로서비스 아키텍처의 구조
주요 컴포넌트
- 서비스: 특정 기능을 담당하는 독립적인 모듈.
- API 게이트웨이: 클라이언트와 서비스 간의 중재자 역할.
- 서비스 디스커버리: 동적으로 서비스 위치를 찾기 위한 시스템.
- 데이터베이스: 각 서비스는 자신만의 데이터베이스를 가지며 데이터 독립성을 유지.
- 메시징 시스템: 서비스 간 비동기 통신을 처리.
구조 다이어그램
[Client]
|
[API Gateway]
|
[Service A] [Service B] [Service C]
| | |
[DB A] [DB B] [DB C]
동작 원리
- 클라이언트가 API 게이트웨이를 통해 요청을 보냄.
- API 게이트웨이는 요청을 적절한 서비스로 전달.
- 각 서비스는 독립적으로 요청을 처리하고, 필요시 다른 서비스와 통신.
- 데이터는 각 서비스의 독립적인 데이터베이스에 저장.
마이크로서비스 아키텍처 예시
Node.js 기반 마이크로서비스 구현
1. 사용자 서비스 (User Service)
const express = require('express');
const app = express();
app.use(express.json());
// 사용자 데이터
const users = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
// 사용자 목록 반환
app.get('/users', (req, res) => {
res.json(users);
});
// 사용자 추가
app.post('/users', (req, res) => {
const user = { id: users.length + 1, name: req.body.name };
users.push(user);
res.status(201).json(user);
});
app.listen(3001, () => {
console.log('User Service running on port 3001');
});
2. 주문 서비스 (Order Service)
const express = require('express');
const app = express();
app.use(express.json());
// 주문 데이터
const orders = [{ id: 1, user: 1, product: 'Book' }];
// 주문 목록 반환
app.get('/orders', (req, res) => {
res.json(orders);
});
// 주문 추가
app.post('/orders', (req, res) => {
const order = { id: orders.length + 1, user: req.body.user, product: req.body.product };
orders.push(order);
res.status(201).json(order);
});
app.listen(3002, () => {
console.log('Order Service running on port 3002');
});
3. API 게이트웨이
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
// 사용자 서비스로 요청 전달
app.get('/users', async (req, res) => {
const response = await axios.get('http://localhost:3001/users');
res.json(response.data);
});
// 주문 서비스로 요청 전달
app.get('/orders', async (req, res) => {
const response = await axios.get('http://localhost:3002/orders');
res.json(response.data);
});
app.listen(3000, () => {
console.log('API Gateway running on port 3000');
});
실행 방법
- 사용자 서비스, 주문 서비스, API 게이트웨이를 각각 실행한다.
- 클라이언트는 API 게이트웨이(
http://localhost:3000
)를 통해 요청을 보낸다.
마이크로서비스 아키텍처의 장점
- 독립적인 배포: 각 서비스는 독립적으로 배포 및 확장 가능.
- 높은 유지보수성: 서비스 단위로 코드베이스를 분리하여 관리 용이.
- 확장성: 필요에 따라 특정 서비스만 수평 확장 가능.
- 팀 분리: 각 팀이 특정 서비스에만 집중하여 개발 가능.
마이크로서비스 아키텍처의 단점
- 복잡한 관리: 서비스 수가 많아질수록 관리와 모니터링이 어려움.
- 통신 오버헤드: 서비스 간 통신 비용이 증가할 수 있음.
- 데이터 일관성 문제: 서비스별 데이터베이스로 인해 데이터 동기화가 어려움.
- 배포 복잡성: 다수의 서비스 배포 과정이 복잡해질 수 있음.
마무리
마이크로서비스 아키텍처는 대규모 시스템에서 확장성과 독립성을 극대화하는 데 적합하다.
그러나, 설계와 관리가 복잡하므로 신중한 접근이 필요하다.
아래 글에서 다른 아키텍쳐 패턴들을 확인할 수 있다.
아키텍처 패턴 모음