Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Info

닷넷코어에서 카프카를 사용하는방법과 로컬 테스트 환경을 수행하는 방법에대해 알아보겠습니다.

추가적으로 로컬 유닛테스트 환경을 위해 비동기 메시지를 관찰자액터를 통해 검증하는 방법까지 살펴보겠습니다.

src : https://github.com/psmon/CQRSAkka


로컬컴퓨터에 도커가 설치되어야하며, 카프카는 아래와같은 구성으로 쉽게 런칭이 가능합니다.사전준비환경 : 로컬 도커환경 ( 맥,윈도우 개발환경 호환)

도커 네트워크 생성

Code Block
docker network create --driver=bridge --subnet=172.19.0.0/16 devnet

docker network inspect devnet

...

Code Block
titledocker-compose.yml
version: '3.5'
services:
  zookeeper:
    image: 'bitnami/zookeeper:latest'
    ports:
    - '2181:2181'
    networks:
      devnet:
        ipv4_address: 172.19.0.20
    environment:
    - ALLOW_ANONYMOUS_LOGIN=yes
  kafka:
    hostname: kafka
    image: 'bitnami/kafka:latest'
    ports:
    - '9092:9092'
    networks:
      devnet:
        ipv4_address: 172.19.0.21
    environment:
    - KAFKA_ADVERTISED_HOST_NAME=kafka
    - KAFKA_ZOOKEEPER_CONNECT=172.19.0.20:2181
    - ALLOW_PLAINTEXT_LISTENER=yes

networks:
  devnet:
    external:
      name: devnet

도커 환경이 구축이되었다고하면, 위 파일의 경로에서

docker-compose up  을 통해 카프카 수행이가능합니다.

...

토픽에따라 처리액터를 구분할수도 있고, 더 나아가 메시지 타잎에 따라 분기도 가능하지만 중요한것은 액터모델은 카프카의 단순한 메시지 설계를 더 확장할수 있는 장점이 메시지에 대한

필터처리를 유연하게할수 있는 장점이 있으며 AkkaStream과 연동시 스트림 Flow처리를 유연하게 할수 있습니다.


아래 유닛테스트 샘플은 , 생산→소비 의 카프카 라이프 사이클을 간단하게 확인할수 있는 유닛테스트이며

아래 최종 유닛 테스트는 액터모델을 통해 확장하고 이것이 얼마나 단순하고 로컬에서 수행될수 있는가를 알수있습니다복잡한 원격 비동기 메시지 처리를 직관적이고 단순화 시킬수 있는지 알수 있습니다.

카프카 유닛 테스트

Code Block
languagec#
themeEmacs
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Akka.Actor;
using Akka.TestKit;
using Akka.TestKit.NUnit3;
using DDDSample.Adapters.kafka;
using NUnit.Framework;


namespace DDDSampleTest.Kafka
{
    public class KafkaConsumerTest : TestKit
    {
        KafkaProduce kafkaProduce;
        KafkaConsumer kafkaConsumer;
        TestProbe probe;

        [SetUp]
        public void Setup()
        {
            kafkaConsumer = new KafkaConsumer("kafka:9092", "test_consumer");
            probe = this.CreateTestProbe();
            kafkaConsumer.CreateConsumer(probe).Start();
            
            kafkaProduce = new KafkaProduce("kafka:9092", "test_consumer");           
        }

        [Test]
        public void ProduceAndConsumerTest()
        {            
            kafkaProduce.Produce("SomeMessage");
            
            Within(TimeSpan.FromSeconds(3), () => {
                
                AwaitCondition(() => probe.HasMessages);
                
                probe.ExpectMsg<KafkaMessage>(TimeSpan.FromSeconds(0));

                KafkaMessage lastMessage = probe.LastMessage as KafkaMessage;

                Assert.AreEqual("SomeMessage", lastMessage.message);

            });
        }
    }
}

유닛테스트에대한 이야기를 잠깐하면  유닛테스트만으로 모듈사용에 대한 가이드를 제공하고, 개선 검증활동으로 이어져야한다는것입니다.

어려운 목표이지만, 로직에대한 흐름의 설명은 주석이 아닌 코드자체로 되어야 한다란것이며

위 코드만으로 카프카에대한 카프카에 대한 사용가 이해가 된다고하면, 위 유닛테스트 작성은 성공적이나 그렇지 않고 무엇을 의미하고 테스트를 하는것인가?

이해가 되지 않는다고 하면 지속적으로 개선되어야할 필요가 있습니다.

기술에대한 사용을 단순화하고 직관적으로 만들고 나서 , 복잡한 도메인에대한 처리를 준비해야하며 이와같이 도메인처리에대한 유닛테스트도 의미있고 직관적으로 만들기 위함입니다.


마무리

메시지 전송보장을 위해 조금더 개선해야할 부분이 남아있으며

"정확하게 한번 전송"에는 다양한 IT의 의미가 의미와 인프라적인 요소가 담겨져 있습니다.   -참고 : MessageDeliveryReliability

위 코드는, 다양한 도메인에따라 도메인의 요구사항에 따라 더 개선점이 있을수 있으며 , 도메인의 이해와함께 이해와 함께 카프카의 옵션을 같이 이해하고 직접 설계에 반영을 해야합니다.

...