게시글
질문&답변
2024.09.18
20분정도에 말씀 하신 내용 질문 있습니다.
움 아키텍처를 설명하기 위해 개념적인 용어들을 사용했지만 이런 기능은 카프카 매커니즘이 이미 제공하고 있습니다. 예를 들어 간단히 구현해 보면 다음과 같습니다. 주문 서비스가 새로운 주문을 생성하면, 이 주문 정보를 Kafka에 이벤트로 보내고, 주문 이력 서비스가 이 이벤트를 읽어 데이터베이스에 주문 이력을 저장한 후, 메시지가 성공적으로 처리되었음을 확인하고 Kafka에서 해당 메시지를 제거하는 방식으로 구현할 수 있습니다.아래는 이 과정을 간단한 샘플 코드와 함께 설명하겠습니다.1. Kafka에 주문 이벤트 보내기 (주문 서비스)주문 서비스가 주문 정보를 Kafka에 보내는 과정입니다. Python의 kafka-python 라이브러리를 사용하여 Kafka에 메시지를 보내는 예제입니다.from kafka import KafkaProducer import json # Kafka 프로듀서 설정 producer = KafkaProducer( bootstrap_servers='localhost:9092', value_serializer=lambda v: json.dumps(v).encode('utf-8') ) # 주문 데이터 order = { 'order_id': '12345', 'customer_id': '67890', 'amount': 100.0 } # Kafka 토픽에 주문 이벤트 전송 producer.send('order-topic', order) producer.flush()2. 주문 이력 저장 및 Kafka 메시지 삭제 (주문 이력 서비스)주문 이력 서비스가 Kafka에서 메시지를 읽어 데이터베이스에 저장하고, 저장이 완료되면 Kafka에서 해당 메시지를 제거합니다. Python의 kafka-python과 mysql-connector-python을 사용한 예제입니다.from kafka import KafkaConsumer, KafkaProducer import mysql.connector import json # Kafka 컨슈머 설정 consumer = KafkaConsumer( 'order-topic', bootstrap_servers='localhost:9092', auto_offset_reset='earliest', group_id='order-history-group', value_deserializer=lambda x: json.loads(x.decode('utf-8')) ) # Kafka 프로듀서 설정 producer = KafkaProducer( bootstrap_servers='localhost:9092', value_serializer=lambda v: json.dumps(v).encode('utf-8') ) # MySQL 데이터베이스 설정 db_conn = mysql.connector.connect( host='localhost', user='youruser', password='yourpassword', database='yourdatabase' ) cursor = db_conn.cursor() # Kafka 메시지 처리 for message in consumer: order = message.value order_id = order['order_id'] customer_id = order['customer_id'] amount = order['amount'] # 주문 이력을 데이터베이스에 저장 cursor.execute( "INSERT INTO OrderHistory (order_id, customer_id, amount) VALUES (%s, %s, %s)", (order_id, customer_id, amount) ) db_conn.commit() # 메시지 처리가 완료된 후 Kafka에서 메시지 삭제 (offset 커밋) consumer.commit() # 메시지 전송 상태를 확인하고 로그 기록 또는 다른 작업 수행 print(f"Order {order_id} processed and saved to database.") 코드 복사요약주문 서비스: 주문을 Kafka 토픽에 메시지로 전송합니다.주문 이력 서비스:Kafka에서 메시지를 읽어 데이터베이스에 주문 이력을 저장합니다.메시지를 처리한 후 Kafka의 오프셋을 커밋하여 메시지가 더 이상 처리되지 않도록 합니다.엄밀히 말하면 Kafka에서 오프셋(offset)은 특정 파티션 내에서 메시지의 위치를 나타냅니다. 즉 소비자가 메시지를 처리한 후, Kafka의 컨슈머 그룹은 해당 메시지가 성공적으로 처리되었다는 것을 나타내기 위해 오프셋을 커밋합니다. 오프셋 커밋은 Kafka가 메시지를 어느 지점까지 읽었는지를 기록합니다. 즉, 컨슈머가 다음에 재시작될 때, 마지막으로 커밋된 오프셋부터 메시지를 읽기 시작합니다. 따라서 한번 전달된 메시지가 다시 전달되지 않음을 보장합니다. 그리고 카프카의 메시지는 카프카 로그 보존기간에 따라 자동으로 삭제되게 하면 됩니다.
- 0
- 2
- 65
질문&답변
2024.09.18
CQRS 6분정도 강의 질문드립니다.
안녕하세요. 강의자 입니다.여기서 이벤트 핸들러는 스프링 이벤트 핸드러 같은 구체적인 기술을 애길한 것은 아니고요. 개념적인 의미로 말씀 드린겁니다. cqrs가 명령( CUD)와 조회( R)를 분리하여 효율성을 높이는 패턴인데요. 예를 들면 주문 서비스가 커맨드 서비스 역할을 수행하고 주문이력 서비스가 조회서비스를 수행한다면, 각기 서비스가 분리되어 있기 때문에 주문이 입력되고, 주문이력이 입력되는 트랜젝션은 분리되기 때문에 분산 트랜젝션이 수행되어 합니다. 이 경우 2개 서비스의 정합성을 맞춰주기 위해 주문 서비스에서 주문 입력 트랜젝션 시 함께 비동기 이벤트를 발생시켜서 주문 이력 서비스에 주문이 들어왔다는 것을 알리는 것이죠. 여기서 주문 이력 서비스의 이벤트 핸들러는 이벤트가 들어왔다는 것을 알아채는 개념적인 기능를 설명하고 있는 겁니다. 여러 가지 기술로 구현 가능할 수 있죠. 주문이력서비스에서는 이벤트 핸들러를 통해 주문이 이벤트를 식별한 뒤 주문 이력 서비스에 주문 이력을 생성하면 주문서비스와 정합성 이 맞게 되는 거죠.
- 0
- 2
- 57
질문&답변
2024.09.09
질문드립니다,
강의자 한정헌입니다. 답변 드리면 다음과 같습니다.먼저 개념 정의부터 명확히 하면, 노드 및 컨테이너: 노드는 컨테이너가 실행되는 물리적 또는 가상 머신입니다. Kubernetes 클러스터의 각 노드는 여러 컨테이너를 호스팅할 수 있습니다. 따라서 3개의 노드와 8개의 컨테이너가 있는 경우 해당 컨테이너는 Kubernetes 스케줄러의 결정에 따라 3개 노드에 걸쳐 예약됩니다. 스케줄링: Kubernetes 스케줄러는 노드에 컨테이너(Pod로 패키징됨)를 배치하는 일을 담당합니다. 이는 taints , tolerations, affinity 규칙과 같은 다양한 요소를 기반으로 수행됩니다. 목표는 로드 균형을 맞추고 사용 가능한 리소스를 효율적으로 사용하는 것입니다. 따라서 특정 제약 조건이나 선호도 규칙이 없다고 가정하면 8개의 컨테이너(각 컨테이너가 자체 포드에서 실행된다고 가정)가 3개 노드에 배포됩니다. 그렇지만 분포가 고르지 않을 수도 있습니다. 예를 들어노드 1에는 포드가 3개 ,노드 2에는 포드가 3개 , 노드 3에는 포드가 2개 있을 수 있습니다. 요약하면 Kubernetes는 기본적으로 컨테이너를 노드 전체에 균등하게 나누지 않습니다. 대신 리소스 가용성 및 기타 요소를 기반으로 컨테이너를 예약합니다. 배포는 사용자가 설정한 다양한 구성 및 제약 조건의 영향을 받을 수 있습니다. Spring Cloud API Gateway 앞에서 NGINX를 Ingress 컨트롤러로 사용하는 경우 말씀하신 바대로네트워크 지연 가능성이 있을 수 있으나 매우 경미할 것 같네요. 이를 이중 프록시 레이어로 구성한다고 하는데요. 이런 경우에는 다음과 같이 역할을 줄 수 있겠죠. NGINX 수신 컨트롤러: Kubernetes 클러스터로 들어오는 외부 트래픽을 처리합니다. SSL 종료, 호스트 이름 또는 경로 기반 라우팅과 같은 작업을 수행하고 로드 밸런싱도 처리할 수 있습니다.Spring Cloud API 게이트웨이: 클러스터 내에서 작동하며 라우팅, 로드 밸런싱은 물론 인증, 속도 제한 등과 같은 추가 기능을 제공합니다. 이런 경우 각 계층은 추가 처리 및 네트워크 홉으로 인해 약간의 오버헤드 및 잠재적으로 대기 시간이 증가할 수 있습니다. 그렇지만 이런 아키텍처 결정 전에 우선NGINX와 Spring Cloud API 게이트웨이가 모두 필요한지 고민할 필요가 있을 것 같네요. 또 이런 결정시에는 각 요소의 아래와 같은 장단점을 고려해야 할 것 같네요. NGINX: 클러스터 가장자리에서 트래픽 라우팅 및 로드 밸런싱을 처리하는 데 매우 효과적 Spring Cloud API Gateway: 동적 라우팅, 속도 제한, 서비스 간 통신과 같은 고급 기능을 제공. 네 더 많은 물리적 서버 노드를 추가하여 Kubernetes 클러스터를 확장하는 것은 용량과 복원력을 높이는 강력한 방법이 될 수 있습니다 , 그렇지만 k8s 와 같은 경우 수평형 Pod Autoscaling 를 우선 고려하고 이것이 한계에 도달할 경우 Cluster Autoscaler를 구현하여 단계적으로 Pod 및 노드 수를 동적으로 조정하는 것이 일반적인 방법입니다. 또 Pod Autoscaling 를 고려하여 더 크거나 더 강력한 노드를 추가하는 것이 작은 노드를 많이 추가하는 것보다 더 효과적일 수 있습니다. 당연히 private 망에서도 k8s를 구성할 수 있습니다.예 로컬에 k8s 구성하는 경우 다음과 같이 구성 가능합니다. 개발/테스트: 노드 1개(마스터 및 작업자 역할이 모두 포함된 단일 노드 설정) ex) Minikube기본 프로덕션: 마스터 노드 1개 + 작업자 노드 1개(고가용성 부족으로 인해 프로덕션에는 적합하지 않음)권장 프로덕션: 마스터 노드 3개 + 작업자 노드 2개(고가용성 및 내결함성을 위해)
- 0
- 1
- 54
질문&답변
2024.09.05
레어어드 아케텍처 스타일 질문드립니다.
네 mvc모델에서 j2ee패턴의 dto 나 vo가 모델의 역할을 수행하는 거죠.즉 레이어드 아키텍처 스타일을 논하면서 mvc모델과 같은 개념으로 이해하는 분들이 많아서 언급한 내용이고요. 굳이 mvc모델을 레이어드 아키텍처와 매핑해보면 프리젠테이션 레이어의 역할과 매핑됩니다.그리고 두번째 질문에 답변을 드리면, 데이터 엑세스 계층은 제가 레이어드 아키텍처 예를 들며, 4개층 (프리젠테이션,비지니스,퍼시스턴스,데이터베이스) 이렇게 정의했는데 이건 개별 회사 및 시스템 마다 다를 수 있습니다. 용어도 다를 수 있고요. 어떤 프로젝트 에서는 (퍼블리싱,서비스,비지니스로직,데이터엑세스)이런식으로 구분하기도 합니다. 그렇지만 보통 데이터 엑세스 계증은 퍼스시턴스 계층과 같은 용어로 사용됩니다. 감사합니다.
- 0
- 1
- 64
질문&답변
2024.04.27
UserCase가 많은데... 이유?
네 강의자 한정헌입니다.말씀하신 바대로 헥사고널 아키텍처에서도 예를 들면 CUD단위로 하나의 유스케이스 인터페이스로 묶고 이를 구현하는 입력포트도 하나의 클래스로 작성할 수 있습니다. 처음에 간단했던 cud야 괜찮겠지만 비지니스가 점점 복잡해지면 유지보수가 거듭되면서 이 클래스가 점점 비대해질 가능성이 있습니다. 그래서 저는 기능 단위로 유스케이스와 입력포트를 분리하는 방법을 선호합니다. 유스케이스 단위로 클래스 생성하는 방식에 대해서는 클린코드의 저자 로버트 c 마틴이 ‘ 소리치는 아키텍처(코드의 명칭을 통해 그 의도롤 소리치게 하자.)’라고도 언급하며 강조를 하기도 했습니다. 왜냐면 이렇게 했을 경우 코드명으로 그 의도를 바로 식별할 수 있기 때문이죠. 즉 클래스 명만 보고 어떠한 유스케이스인지 쉽게 인지 가능하기 때문에 테스트 및 유지보수성 높아 질수 있음을 강조했다고 생각합니다.감사합니다.
- 0
- 1
- 280
질문&답변
2024.04.07
음성 부분이 너무 깨지는데...
강의자입니다. 죄송합니다.제가 음질을 개선 시킨다고 한것이 더 망쳐 놨네요.주변 잡음이 들린다 하셔서 잡음을 잡는 다는 것이 목소리가 너무 울리게 했네요.우선 목소리가 울리지 않고 잡음이 줄이는 방식으로 급히 조치를 했습니다.좀더 보완하고 개선하도록 노력하겠습니다.
- 0
- 1
- 238
질문&답변
2024.03.31
CQRS 질문 드립니다.
네 CQRS의 개념과 장점에 대해 정리해 보면 다음과 같습니다.관심 사항 분리: CQRS는 데이터를 수정하는 작업(명령)과 데이터를 읽는 작업(쿼리) 간의 명확한 분리를 촉진합니다. 이러한 분리는 각 구성 요소를 특정 책임에 집중함으로써 애플리케이션의 설계 및 유지 관리를 단순화합니다.최적화: 명령과 쿼리를 분리하여 각 측면을 특정 요구 사항에 따라 독립적으로 최적화할 수 있습니다. 예를 들어, 명령 측은 쓰기가 많은 워크로드에 최적화되어 빠르고 일관된 데이터 업데이트를 보장할 수 있으며, 쿼리 측은 읽기가 많은 워크로드에 최적화되어 효율적인 데이터 검색 및 표시가 가능합니다.확장성: CQRS를 사용하면 해당 작업 부하에 따라 명령 및 쿼리 구성 요소를 독립적으로 확장할 수 있습니다. 이러한 유연성을 통해 리소스 활용도를 높이고 성능을 조정하여 다양한 수준의 트래픽과 처리 요구 사항을 처리할 수 있습니다.복잡한 도메인 처리: 데이터 모델이나 비즈니스 로직이 복잡한 복잡한 도메인에서 CQRS는 보다 표현력이 뛰어나고 유지 관리가 쉬운 솔루션을 제공할 수 있습니다. 이를 통해 개발자는 도메인의 특정 요구 사항에 맞게 명령 및 쿼리 모델을 맞춤화하여 두 가지 책임을 단일 모델에 맞추려고 할 때 발생할 수 있는 타협을 피할 수 있습니다.이벤트 소싱 통합: CQRS는 또 다른 아키텍처 패턴인 이벤트 소싱과 함께 사용되는 경우가 많습니다. 이벤트 소싱에는 애플리케이션 상태에 대한 모든 변경 사항을 일련의 불변 이벤트로 캡처하는 작업이 포함됩니다. CQRS는 이벤트를 트리거하는 명령과 이를 사용하는 쿼리를 명확하게 구분하고 이벤트 기반 아키텍처를 촉진하며 변경 사항을 감사하고 재생하기 위한 강력한 메커니즘을 제공함으로써 이벤트 소싱을 보완합니다.유연성: CQRS는 애플리케이션의 다양한 부분에 적합한 데이터 저장 메커니즘과 쿼리 모델을 선택할 수 있는 유연성을 제공합니다. 예를 들어, 명령 측에서는 트랜잭션에 최적화된 기존 관계형 데이터베이스를 사용할 수 있고, 쿼리 측에서는 읽기 작업이 많은 워크로드에 최적화된 NoSQL 데이터베이스 또는 복잡한 쿼리를 위한 특수 인덱싱 솔루션을 사용할 수 있습니다.질문하신 내용을 개념에 대비해서 살펴보면 1,4번에 해당되는 것처럼 도메인 모델이 복잡해지는 것을 피하기 위해 단순 질의를 분리하면 유지보수성과 유연성이 높아 질 수 있습니다.커맨드 와 질의 에 대한 서버분리를 질문하셨는데 2,3의 최적화와 확장성을 위해서는 각각의 서버(서비스)를 분리하는 것이 효과적이라고 생각합니다.그리고 로직의 검증을 위한 조회나, 로직상 필요한 조회는 명령의 부분이라고 생각합니다.감사합니다.
- 0
- 1
- 230
질문&답변
2024.03.26
강의 음성 및 영상
불편을 드려 죄송합니다 😔제가 음성이 불명확하고 잘린부분을 살펴 금주중으로 보완하는 강의를 업로드 하도록 하겠습니다.
- 0
- 1
- 234
질문&답변
2024.03.13
모듈형 모노리스의 컨테이너화
좀더 상세히 말씀드리면 마이크로서비스가 아닌 모노리스 애플리케이션을 컨테이너화하고 이를 Kubernetes에 배포하는 것은 마이크로서비스로 변환하여 배포하는 장점보다는 못미치지만 그 정도로써의 충분한 이점( 확장성, 배포 및 탄력성 측면에서) 이점을 제공합니다. 장점은 다음과 같습니다. 확장성: Kubernetes를 사용하면 수요에 따라 컨테이너 인스턴스를 추가하거나 제거하여 애플리케이션을 수평으로 확장할 수 있습니다. Kubernetes에 컨테이너화되고 배포된 모놀리식 애플리케이션을 사용하면 이러한 확장성의 이점을 누릴 수 있습니다. 내부 모듈이 독립적으로 확장되도록 설계된 경우 모놀리스의 개별 구성 요소(모듈)을 쉽게 분리하여 확장하거나 더 많은 컨테이너 인스턴스를 추가하여 전체 모놀리스의 크기를 조정할 수 있습니다.배포: Kubernetes는 여러 노드 또는 클러스터에 애플리케이션을 배포하는 기능을 제공합니다. Kubernetes에 모놀리식 애플리케이션을 배포하면 여러 노드에 분산하여 내결함성과 가용성을 향상시킬 수 있습니다. 또한 Kubernetes는 로드 밸런싱 및 서비스 검색과 같은 기능을 제공하여 배포작업을 더욱 향상시킬 수 있습니다.탄력성: Kubernetes는 HPA(Horizontal Pod Autoscaler)와 같은 기능을 통해 수요에 따라 컨테이너에 할당된 리소스를 자동으로 조정할 수 있습니다. 즉, 모놀리식 애플리케이션은 트래픽이나 리소스 사용량의 변화에 따라 동적으로 확장하거나 축소할 수 있습니다. 탄력성은 애플리케이션이 성능과 비용 효율성을 유지하면서 리소스를 효율적으로 활용할 수 있도록 보장합니다.그렇지만 염두에 두어야 할 고려 사항도 있습니다.복잡성: Kubernetes에서 모놀리식 애플리케이션을 배포하고 관리하면 기존 모놀리식 서버 아키텍처에 비해 더 많은 복잡성이 발생합니다. 파드, 디플로이, 서비스와 같은 Kubernetes 리소스를 구성하고 관리해야 합니다. 이러한 복잡성으로 인해 학습 곡선과 운영 오버헤드가 증가할 수 있습니다.리소스 오버헤드: 컨테이너화 및 Kubernetes에는 약간의 리소스 오버헤드가 수반됩니다. Kubernetes는 컨테이너 관리를 위한 강력한 기능을 제공하지만 효과적으로 작동하려면 리소스도 필요합니다. 애플리케이션의 크기와 복잡성이 단순한 경우에는 Kubernetes로 인한 오버헤드가 정당화되지 않을 수 있습니다.마이그레이션 노력: 모놀리식 애플리케이션을 컨테이너화하고 이를 Kubernetes에 배포하려면 특히 애플리케이션이 컨테이너화를 염두에 두고 설계되지 않은 경우 상당한 노력이 필요할 수 있습니다. 컨테이너 친화적으로 만들기 위해 애플리케이션의 일부를 리팩터링해야 할 수도 있는데, 이는 시간이 많이 걸리고 어려울 수 있습니다.성능: Kubernetes는 확장성과 탄력성을 제공하지만 특히 분산 환경용으로 설계되지 않은 모놀리식 애플리케이션의 경우 성능에 영향을 미칠 수 있습니다. 구성 요소 간 통신 오버헤드, 네트워크 대기 시간 증가, 리소스 경합 등이 성능에 영향을 미칠 수 있는 요소입니다.결론적으로, Kubernetes에 모놀리식 애플리케이션을 배포하면 확장성, 배포 및 탄력성 측면에서 이점을 제공할 수 있지만 이점이 관련된 복잡성 및 고려 사항보다 중요한지 신중하게 평가하는 것이 중요합니다. 특정 사용 사례, 요구 사항 및 조직 기능에 따라 Kubernetes가 아키텍처에 가장 적합한 선택일 수도 있고 아닐 수도 있습니다. 결정을 내리기 전에 장단점을 고려하고 대체 접근 방식을 고려하는 것이 중요합니다.
- 1
- 1
- 289
질문&답변
2024.01.14
domain.model.event에 정의되는 객체들에 대한 질문이 있습니다
네 안녕하세요. 항상 저도 프로젝트를 할 때 마다 고민되는 부분을 어려운 질문주셨네요. 움 이러한 관계는 사실 기술 거버넌스에 관한 문제이기도 한 것 같아요. 우선 서비스를 소유하고 있는 조직 또는 팀의 역학관계에 따라 다양한 방안이 고려될 수 있을 것 같네요. 그런 부분을 논한 부분이 도메인 주도 설계의 서비스 매핑 패턴인데 상위스트림 서비스와 하위스트림 서비스 간의 관계를 설명하고 있는데 한번 참고해 보시고요. 그리고 해결방안은 기술 적인 부분보다는 협업의 문제인것 처럼 느껴집니다.우선 도메인 이벤트를 생산하는 생산자와 이를 소비하는 소비자의 관계는 Contract-First Design 라는 관점으로 봐야 할 것 같습니다. 이벤트가 아니라 API라고 생각하면 쉬울 것 같네요.따라서 각 생산자와 소비자는 코드를 직접 수정하기보다는 먼저 명확한 계약이나 인터페이스 사양을 정의하고 유지할 필요가 있겠죠. 참여 팀은 이 계약에 동의하고 이를 준수하고 변경이 필요할 경우 반드시 이전에 합의가 필요할 것 같고요.또 이것을 중복로 생각할 수 도 있을 것 같은데요. 마이크로서비스는 서비스의 자율적인 배포를 위해 어느정도의 중복을 통한 느슨한 결합을 추구한다고 생각하셔도 될 것 같네요. ^ ^;;;
- 0
- 1
- 255