İçeriğe geç

.Net Core ile Command Query Responsibility Segregation (CQRS) desenini mikro hizmetlere uygulamak

CQRS, veri okuma ve yazma modellerini birbirinden ayıran mimari bir desendir. Diğer bağlamlarda okuma/yazma işlemi için iki nesneye sahip olmak anlamına gelir. Okuma sorguları için cache: Redis, Elasticsearch, ve yazma sorguları için veritabanı: MsSql, MYSql, MongoDB kullanmaktır. CQRS tam olarak budur. Okuma ve yazma mantığını ayırmak CQRS’dir.

Örneğin facebook da çalıştığınızı hayal edin. Kullanıcının bir gönderi paylaşması durumu vardır. Yazma ve Okuma depolama alanlarını aşağıdaki gibi düşüne bilirsiniz.

YazmaOkuma
Id
Text
Date
UserId




{
“id”:”1234-asd3-54ts-199a”,
“text”:”post1″,
“date”:”2017-01-01″,
“User”: {
“id”:”dse4-qwe2-ert4-aad2″,
“username”:”fatih.erol”
}
}

Bu senaryoda, her iki hizmet farklı uygulamalarda olduğundan tablolar arasındaki ilişkiler kurulamaz. Gönderi mikro hizmeti Kullanıcı verilerini almak isterse, Kullanıcı hizmetindeki ilgili Kullanıcı detayları için HTTP hizmetine bir istek parametresi olarak Kullanıcı kimliğini iletebilir. 

Bu yaklaşımın sınırlaması, işlem yönetiminin düzgün bir şekilde ele alınamamasıdır. Kullanıcı verileri silinirse, o Kullanıcı için ilgili Gönderilerin de silinmesi gerekir.

Bu, Gönderi hizmetinde silme hizmetini çağırmak gibi geçici çözümlerle elde edilebilmesine rağmen, atomikliğe doğrudan bir yolla ulaşılamaz. Bunun özelleştirme ile ele alınması gerekiyor.

Bu sınırlamanın üstesinden gelmek için, CQRS mimarisini mikro hizmet bileşenlerimizle entegre edebiliriz.

Facebook da bir gönderi paylaştığınızı düşünün, Önce bunu Yazma depolama alanına yazar ve Message Broker aracılığı ile okuma veritabanına iter. Tabi ki öncesinde Kullanıcı detaylarını toplamak gibi görevler vardır bunu rest ile yapabiliz, fakat eş zamansız olduğundan pek umursamıyoruz.

Yazma işlemi için kodunuz şöyle gözükecektir

        public async Task<PostDto> Handle(CreatePostCommand request, CancellationToken cancellationToken)
        {
            var post = new Post();
            post.Text = request.Text;
            post.CreatedDate = DateTime.UtcNow;
            post.UserId = request.UserId
            await _postService.Create(post);

            var response = _mapper.Map<PostDto>(post);
            _eventBus.Publish(new CreatePostEvent() { PostId = post.Id, Text = post.Text, Date = post.Date, UserId = request.UserId});
            return response;
        }

Bir etkinliği Message Broker ile paylaştığımızda (CreatePostEvent) Aynı mikro hizmet tarafından dinlenmek üzere toplanır ve okuma veritabanına kaydedilir..

            //Rest user microservice
            var user = await _services.GetById();
            var post = new Post{
                User = new User {
                  UserId = user.Id,
                  UserName = user.UserName
                  ..
                }
            }
            _dbContext.Posts.Create(post);

Böylelikle okuma tarafındaki performansı arttırarak, relation yapmadan tek bir kimlikle sorgulama yapabileceğimiz görünüme sahip olduk.

Peki ya eş zamansız gönderileri, facebook nasıl başarıyor?

RabbitMQ = Saniyede 10k, Apache Kafka = Saniyede = 100K işleyen bir Message Broker’. docker üzerinde dağıttığımızı düşünelim, SignalR veya SocketIO üzerinde dağıtılması çokta uzun değil 🙂

Kod örneğini buradan bakabilirsiniz.

 2,782 Görüntüleme

Kategori:.Net CoreMicroservicesSoftware Architecture

3 Yorum

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir