소개: 마이크로서비스 위기
Il 조직의 42% 마이크로서비스 아키텍처를 포기하거나 단순화하고 있습니다. 부문별 보고서에서 나온 이 데이터는 Amazon, Uber, Twitter 등 기업의 경험을 통해 확인되었으며, 소프트웨어 아키텍처 역사의 전환점이 되었습니다. 10년 동안 걷잡을 수 없는 열정 끝에, 해당 부문은 마침내 합의에 이르렀다. 숨겨진 비용 유통의.
이 시리즈의 첫 번째 기사에서는 "마이크로서비스에서 모듈형 모놀리스까지", 우리는 신호를 분석할 것입니다 마이크로서비스 아키텍처가 솔루션이 아닌 문제가 되는 시기를 나타내는 경고 신호 실제 실패사례를 살펴보고 그 내용을 소개하겠습니다. 모듈식 단일체 실용적인 대안으로.
이 기사에서 배울 내용
- 제대로 작동하지 않는 마이크로서비스 아키텍처의 5가지 경고 신호
- 마이크로서비스의 숨겨진 비용: 인프라, 대기 시간, 운영 복잡성
- 실제 사례 연구: Amazon Prime Video, Twitter, Segment
- 확장성의 오류: 실제로 개별적으로 확장할 필요가 없을 때
- 마이크로서비스와 대안 중에서 선택하기 위한 의사결정 프레임워크
- 새로운 패러다임으로 모듈식 모노리스 소개
분산형 모놀리스: 최악의 시나리오
마이크로서비스를 채택한 많은 조직은 실제로 분산된 단일체: 단일체의 단점(긴밀한 결합, 조정된 배포)과 단일체의 단점을 결합한 시스템입니다. 배포(네트워크 대기 시간, 운영 복잡성, 어려운 디버깅). 그리고 최악의 아키텍처 시나리오 가능합니다.
분산형 모놀리스는 다음과 같은 특성으로 인식할 수 있습니다.
- 동기화된 배포: 3~4개의 다른 서비스도 업그레이드하지 않으면 서비스를 배포할 수 없습니다.
- 공유 데이터베이스: 여러 서비스가 동일한 테이블에 액세스하여 데이터 수준 결합을 생성합니다.
- 체인 동기 호출: 사용자 요청은 5~8번의 서비스를 거쳐 완료됩니다.
- 차단된 팀: 서비스 간의 종속성으로 인해 팀이 독립적으로 작업할 수 없습니다.
// Esempio di distributed monolith: OrderService dipende da 4 servizi
public class OrderService {
private final UserServiceClient userClient;
private final InventoryServiceClient inventoryClient;
private final PaymentServiceClient paymentClient;
private final NotificationServiceClient notificationClient;
public Order createOrder(CreateOrderRequest request) {
// Chiamata sincrona 1: verifica utente
User user = userClient.getUser(request.getUserId());
// Chiamata sincrona 2: verifica disponibilità
InventoryCheck check = inventoryClient.checkAvailability(
request.getItems()
);
// Chiamata sincrona 3: processa pagamento
PaymentResult payment = paymentClient.processPayment(
user, request.getTotal()
);
// Chiamata sincrona 4: invia notifica
notificationClient.sendOrderConfirmation(user, order);
// Se un qualsiasi servizio e giù, l'intero flusso fallisce
return order;
}
}
이 예에서는 OrderService 이는 네 가지 개별 서비스에 대한 동기적 종속성을 갖습니다. 하나라도 있으면
그가 응답하지 않으면 질서를 만드는 전체 과정이 실패합니다. 이는 마이크로서비스가 아닙니다.
독립적: 네트워크를 통해 분산된 단일체입니다.
5가지 경고 신호
마이크로서비스 아키텍처가 하나가 되는 시기를 알려주는 5가지 주요 지표가 있습니다. 자산보다는 부채. 이를 조기에 인식하면 수개월의 작업 시간과 상당한 예산을 절약할 수 있습니다.
1. 복잡성 과부하
서비스 수가 팀의 관리 능력을 초과하면 복잡성은 제어할 수 없게 됩니다. 40개의 마이크로서비스를 관리하는 15명의 개발자로 구성된 팀에는 유지 관리, 모니터링 및 관리할 대역폭이 없습니다. 모든 서비스를 적절하게 업데이트하십시오. 이상적인 관계는 개발자당 최대 2~3개의 서비스, 그리고 이것은 이미 최적의 조건에 있습니다.
복잡성은 서비스 메시 구성, TLS 인증서 관리 등 구체적인 형태로 나타납니다. 서비스 간, 내부 API 버전 관리, 팀 간 계약 관리. 추가 서비스 복잡성이 크게 증가합니다 비선형.
2. 모노리스 대비 6배의 비용
업계 연구에 따르면 마이크로서비스 아키텍처의 운영 비용은 평균 6배 더 높음 동등한 단일체와 비교됩니다. 여기에는 다음이 포함됩니다.
- 하부 구조: 각 서비스에는 자체 컨테이너, 로드 밸런서, 상태 확인이 필요합니다.
- 관찰 가능성: 분산 추적, 로그 집계, 서비스별 지표
- 네트워킹: 서비스 메시, API 게이트웨이, 회로 차단기
- Team: 전담 DevOps, 플랫폼 팀, 전문 SRE
# Esempio: risorse Kubernetes per UN singolo microservizio
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 3
template:
spec:
containers:
- name: order-service
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
---
# Servono anche: Service, Ingress, HPA, PDB,
# ConfigMap, Secret, ServiceMonitor, NetworkPolicy...
# Moltiplica per 20+ servizi = complessità enorme
3. 지속 불가능한 운영 오버헤드
각 마이크로서비스에는 전용 CI/CD 파이프라인, 모니터링, 경고, 종속성 관리, 보안 패치. 서비스가 30개이면 유지 관리할 파이프라인이 30개, 세트가 30개입니다. 구성할 경고 수, 업데이트할 dockerfile 30개. 에서 보낸 시간 운영 능가하다 헌신적인 사람 기능 개발.
4. 지연 시간 증가
서비스 간의 각 호출에는 네트워크 대기 시간이 발생합니다. 5개 서비스를 넘나드는 요청이 누적됨 5개 네트워크 홉의 대기 시간, 직렬화/역직렬화 시간, 서비스 검색 조회. 모놀리스에서는 동일한 작업이 메서드 호출이 됩니다. 대기 시간이 진행 중인 순서는 다음과 같습니다. 나노초.
5. 분산된 취약성
분산 시스템에서는 오류가 예외가 아닌 일반적인 현상입니다. 의사소통의 모든 지점 서비스와 잠재적인 실패 지점 사이. 회로 차단기, 백오프로 재시도, 시간 초과, fallbacks: 이는 필수 패턴이지만 애플리케이션 코드에 상당한 복잡성을 추가합니다.
상식의 법칙
팀이 다음보다 많은 비용을 지출하는 경우 40%의 시간 운영 활동(배포, 디버깅, 인프라 구성) 기능 개발보다는 아키텍처가 당신을 위해서가 아니라 당신을 상대로 일합니다. 이제 아키텍처 선택을 재평가할 때입니다.
사례 연구: 자이언츠가 돌아올 때
선도적인 기술 기업의 경험은 분산에서 통합은 약점이 아니라 엔지니어링 성숙도의 신호입니다.
아마존 프라임 비디오
2023년 Amazon Prime Video 팀은 다음과 같은 적절한 사례를 공개했습니다. 처음에는 마이크로서비스 파이프라인으로 구축된 비디오 품질 모니터링 서버리스(AWS Step Functions + Lambda) 및 상태 하나의 프로세스로 통합. 결과는? 비용 절감 90% 그리고 상당한 개선이 있었습니다 확장성. 병목 현상은 애플리케이션 로직이 아니라 오케스트레이션 오버헤드였습니다. 분산된 구성요소 사이.
트위터 (X)
2022년 인수 이후 엔지니어링 팀은 마이크로서비스 수를 획기적으로 줄였습니다. 기능을 더 큰 서비스로 통합하고 간접 계층을 제거합니다. 상관없이 회사 경영진의 의견으로는 기술적 성과가 크게 감소한 것으로 나타났습니다. 인프라 비용 및 운영 단순화.
분절
고객 데이터 플랫폼인 Segment는 마이크로서비스에서 돌아온 경험을 문서화했습니다. 단일체로. 상대적으로 작은 팀이 140개 이상의 마이크로서비스를 관리하므로 유지 관리가 지속 불가능해졌습니다. 보다 확립된 아키텍처로의 마이그레이션은 배포 시간 단축80% 팀의 운영 부하 60%.
확장성 오류
마이크로서비스를 지지하는 가장 일반적인 주장은 다음과 같습니다. 독립적인 확장성: 가능성 필요한 서비스만 확장합니다. 하지만 실제로 필요한 조직은 얼마나 됩니까? 개별 구성요소를 다양한 수준으로 확장하시겠습니까?
현실은 대부분의 시스템에서 다음과 같습니다.
- Il 트래픽의 80% 엔드포인트의 20%에 영향을 미침
- Il 데이터베이스 거의 항상 실제 병목 현상은 컴퓨터가 아니라
- 잘 최적화된 단일 프로세스가 이를 처리합니다. 초당 수천 개의 요청
- 모놀리스 수평 확장(로드 밸런서 뒤의 여러 인스턴스)은 사례의 95%를 포괄합니다.
// La maggior parte delle applicazioni non ha bisogno
// di scaling indipendente per servizio.
// Un monolith scalato orizzontalmente e sufficiente:
// Scenario: 10.000 richieste/secondo
// Monolith: 4 istanze x 2.500 req/s ciascuna
// Microservizi: 20 servizi x 3 istanze = 60 container
// Costo monolith: 4 container x $50/mese = $200/mese
// Costo microservizi: 60 container x $30/mese = $1.800/mese
// + Load balancer, service mesh, monitoring = $500/mese
// Totale microservizi: ~$2.300/mese (11.5x più costoso)
의사결정 프레임워크: 언제 무엇을 선택할 것인가
보편적으로 최고의 아키텍처는 없습니다. 선택은 특정 상황에 따라 달라집니다. 조직의. 객관적인 기준에 따른 의사결정 프레임워크는 다음과 같습니다.
마이크로서비스를 선택하는 경우
- 당신은 대규모 팀(개발자 50명 이상) 완전한 자율성을 요구하는 사람
- 당신은 요구 사항이 있습니다 극단적인 스케일링 (초당 수백만 개의 요청) 구성 요소 간에 로드 패턴이 매우 다릅니다.
- 당신은 이기종 기술 요구 사항: 다른 언어나 런타임이 필요한 구성 요소
- 당신은 성숙한 DevOps/플랫폼 팀 인프라에 전념
- Il 시장 출시 시간 각 기능은 팀 간의 독립성에 따라 달라집니다.
모놀리스(모듈형)를 선택하는 경우
- 당신은 중소 규모 팀(개발자 3~30명)
- 귀하의 제품은 초기 또는 성장 단계 경계가 아직 명확하지 않습니다.
- 당신은 빠른 반복 배포의 단순성
- 인프라 예산 e 제한된
- 당신은 강력한 일관성 구성 요소 간(ACID 트랜잭션)
황금률
항상 모듈식 모놀리스로 시작하세요. 마이크로서비스가 있는 경우에만 추출 이를 정당화하는 구체적인 데이터: 로드 메트릭, 측정된 병목 현상, 특정 스케일링이 필요합니다. 마이크로서비스의 조기 추출이 원인 중 하나 건축 실패의 주요 원인.
모듈형 모노리스 소개
Il 모듈식 단일체 두 세계의 장점을 결합한 아키텍처: 단순성 마이크로서비스의 논리적 모듈성을 갖춘 모놀리스의 운영. 배포 가능한 단일 아티팩트 명확한 경계, 잘 정의된 내부 API 및 데이터 소유권을 갖춘 독립적인 모듈을 포함합니다. 모듈당.
이 아키텍처는 즉각적인 이점을 제공합니다.
- 간단한 배포: 단일 아티팩트, 하나의 파이프라인, 서비스 간 조정 없음
- 직접 디버깅: 전체 스택 추적, 분산 추적이 필요하지 않음
- ACID 거래: 프로세스 내에서 일관성이 보장됩니다.
- 안전한 리팩토링: 컴파일러는 모듈 간의 인터페이스를 확인합니다.
- 미래 추출: 모듈은 필요할 때 마이크로서비스가 될 수 있습니다.
// Struttura di un modular monolith in Java/Spring Boot
// Ogni modulo ha il proprio package con boundaries chiare
// com.app.order/ (modulo Order)
// ├── api/ -> interfacce pubbliche del modulo
// ├── internal/ -> implementazione privata
// ├── domain/ -> entità e logica di dominio
// └── infrastructure/ -> persistenza, eventi
public interface OrderModuleApi {
OrderDto createOrder(CreateOrderCommand cmd);
OrderDto getOrder(UUID orderId);
List<OrderDto> getOrdersByUser(UUID userId);
}
// L'implementazione e nascosta nel package internal
class OrderModuleImpl implements OrderModuleApi {
private final OrderRepository orderRepo;
private final EventPublisher eventPublisher;
public OrderDto createOrder(CreateOrderCommand cmd) {
Order order = Order.create(cmd);
orderRepo.save(order);
eventPublisher.publish(new OrderCreatedEvent(order.getId()));
return OrderDto.from(order);
}
}
다음 기사에서 살펴볼 내용
이 시리즈의 기사 8개 이해하는 것부터 완전한 여정을 안내해 드립니다. 실제 마이그레이션에 대한 문제:
- 제2조: 모듈형 모노리스의 세부 아키텍처, 모듈 경계, 내부 API, Spring Modulis
- 제3조: 모듈 경계를 정의하기 위한 제한된 컨텍스트 및 DDD
- 제4조: 데이터베이스 설계, 모듈 vs 공유 스키마, 데이터 소유권
- 제5조: 통신 패턴: 진행 중인 이벤트, 중재자, CQRS
- 제6조: 지능형 배포 및 확장, 기능 플래그, 청록색
- 제7조: 레거시 모놀리스에서 모듈식 모놀리스로 단계별 마이그레이션
- 제8조: 정량화된 ROI 및 전후 지표를 사용한 사례 연구
다음 기사
다음 글에서는 이에 대해 자세히 알아보겠습니다.모듈형 모노리스의 아키텍처: 모듈 사이의 경계를 정의하는 방법, 내부 API를 설계하는 방법, 프레임워크가 다음과 같은 방법을 사용하는 방법 스프링 계수 시간이 지나도 경계를 유지하는 데 도움이 될 수 있습니다. 우리는 통과할 것이다 아키텍처 다이어그램과 참조 코드를 통해 이론부터 실습까지.







