Kategori: Bilgi Bankası

  • Dosya Yükleme Örneği: Web Uygulamalarında Uzun Süren İşlemleri Nasıl Yönetiriz?

    Dosya Yükleme Örneği: Web Uygulamalarında Uzun Süren İşlemleri Nasıl Yönetiriz?

    Bir web uygulaması geliştirdiğinizi varsayalım, bu sitemde büyük bir dosya yüklenecek örneğin sipariş verisi. Sizden istenen sistem bu sipariş verisinin öncelikle yüklenmesi ve sonrasında işlenerek veritabanına aktarılmasını sağlamak.

    Bu süreçte hangi sorunlar ile karşılaşacaksınız ve ne tür çözümler bulacaksınız?

    Bu yazının amacı teknik bilgiden çok(zaten yapa zeka yapıyor) bir yazılımcı olarak bu süreci nasıl yönetirsiniz, hangi sorunlar iler karşılaşırsınız ve hangi teknolojileri kullanabilirsiniz bundan bahsedeceğim.

    Hemen başlayalım

    Problem

    Problem, bir web isteğinde içe aktarılamayacak kadar büyük bir verinin sisteme yüklenmeye çalışmasıdır.

    Eğer bu işlemi normal bir form şeklinde yaparsak kullanıcıyı bekleteceğiz yani tarayıcısı açık kalacak ve bu süreçte bu kişiye hiç bir bilgilendirmede bulunmayacağız?

    Çözüm Nedir?

    Burada sistemsel bir karar vermemiz gerekiyor, dosyayı yüklerken ve işlerken aynı zamanda kullanıcıya dönüş yapmalı ve bunu yaparken de olası kullanıcı bağlantı kopma ve tarayıcı kapatma durumlarının işlemi etkilemesini engellemeliyiz.

    Burada kullanıcı deneyimini ve sistem kısıtlarını göz önünde bulundurarak çözüm üretmeliyiz.

    Burada ilk yapılması gereken işi iki ayrı parçaya bölmek.

    İlk Aşama Dosya Yükleme Aşaması

    Öncelikle sistemi dosya yükleme ve işleme olmak üzere iki aşamaya bölmeliyiz.

    Birinci aşama olan dosya yükleme aşamasında kullanıcı tabiki tarayıcısını açık tutmalıdır.

    Burada neler yapabiliriz?

    • Yükleme işlemini ajax ile yaparak kullanıcının bir process bar ile bilgilendirilmesini sağlayarak daha iyi bir deneyim sunabiliriz.
    • Sunucumuzun dosya yükleme limitini html/js ile client tarafında da uygulayarak kullanıcının belirlediğimiz boyutlar arasında dosya yüklemesini sağlayabiliriz.
    • Sunucumuzun timeout değerini artırarak olası kullanıcı internet yavaşlığında hizmet vermeye devam edebiliriz.

    Bu önlemleri aldığımız zaman kullanıcı dosya yükleme sayfamızdan iyi bir deneyim elde edecektir.

    İkinci Aşama Dosyanın İşlenmesi

    Dosya işleme aşaması önemli ikinci aşamadır, ajax ile hem dosyayı yükleyip hem de o an işlemek sistemimizde aşırı yük oluşturabilir ve aynı zamanda kullanıcının tarayıcısının kapanması durumunda işlem yarıda kalabilir.

    Bunları önlemek için neler yapabiliriz?

    • Öncelikle RabbitMQ gibi bir Message Broker kullanarak, bu tarz arkaplan işlemlerini sistemde uygun kaynak bulunana kadar bekletebiliriz.
    • Uygun kaynağın işi ele alması ile birlikte web socket kullanarak kullanıcını işlemin durumu hakkında devamlı bilgilendirebiliriz.
    • Bu sayede kaynak ve kullanıcı bağlantı kopması gibi durumları çözmüş oluyoruz.

    Sonuç

    Bu yazıda bir sistem geliştirirken elimizdeki kaynakları ve kullanıcı deneyimini göz önünde bulundurarak nasıl karar vermemiz gerektiğini örneklendirdim. Örneğimizde çok bilindik bir yöntem olan dosya yükleme yöntemini kullandım.

  • Son ürünü iki kişinin aynı anda satın alması nasıl engellenir?

    Son ürünü iki kişinin aynı anda satın alması nasıl engellenir?

    Bir e-ticaret sitesi geliştirdiğinizi düşünelim, hangi dilde olduğu fark etmez, güncel teknolojiler kullandığınızı varsayalım.

    Trafik artmaya başladı ve ürün satışları da doğal olarak artıyor, ve zaman zaman özellikle düşük stoklu ürünlerde olmayan stokların satışını fark ettiniz.

    Stok’da son ürün kaldığında birden fazla kişinin bu ürünü satın aldığını fark ettiniz.

    Bunun literatürdeki adı race condition ve overselling şeklinde.

    Bu yazıda bu tarz bir durumda neler yapılabilir bundan bahsedeceğim, özellikle veritabanı seviyesine odaklanacağız. Bu operasyonları güvenli şekilde gerçekleştirmemiz için aşağıdaki veritabanlarından birini kullandığınızı varsayıyorum.

    Önerilen veritabanları

    • MSSQL
    • MYSQL
    • POSTGRESQL

    Bu veritabanlarının hepsi bu yazıda işleyeceğimiz özellikleri destekleyen SQL veritabanı yazılımlarıdır.

    Tüm yöntemlerde transaction açmanız ve başarılı olursa commit etmeniz gerektiğini hatırlatmak isterim, her maddede bunu tekrar etmemek için baştan söylüyorum.

    Hemen yöntemlere geçelim.

    Database Transaction + Lock

    Bu yöntem, çözümlerimiz arasında en çok kullanılan ve klasik bir yöntem diyebiliriz.

    Bu yöntemin temel mantığı veritabanında işlem yapmadan önce bu işlemi yaptığımız satırlarda başkası işlem yapmasın demek oluyor.

    Örnek SQL

    SQL
    SELECT * FROM products WHERE id = 1 FOR UPDATE;

    İşlemin başında satır kilitlenir.

    Diğer kullanıcılar işlemin bitmesini beklerler.

    İlk işlem bitince sıradaki işlem ile devam edilir.

    Yoğun trafikte yavaşlatır.

    Deadlock riski yaratır.

    Kullanım örneği ( Temsili kod SQL)

    SQL
    BEGIN TRANSACTION
    
    SELECT stock FROM products WHERE id=1 FOR UPDATE
    
    IF stock > 0:
        UPDATE products SET stock = stock - 1
        COMMIT
    ELSE:
        ROLLBACK

    Optimistic Lock

    Bu yöntem benim de en sevdiğim ve bir çok noktada bolca kullandığım bir yöntem, Optimistic Lock yöntemi yani versiyon sütunu eklemek.

    Ben sadece stok değil şifre değiştirme gibi durumlarda da bu sistemi kullanıyorum, veri tutarlılığını özellikle JWT üzerinden kontrol etmek için en garanti yöntem ama tabi bu yazının konusu JWT değil.

    Burada kullanacağımız mantık çok basit, bir version ve updated_at sütunu ile verinin sorguladığımız andaki ve güncellediğimiz andaki tutarlılığını kontrol ediyoruz.

    SQL
    UPDATE products
    SET stock = stock - 1, version = version + 1
    WHERE id = 1 AND version = 5;

    Dediğim gibi bir çok noktada kullanılabilecek bir yöntem. Farklı senaryolarda da ilaç gibi geliyor.

    Tek sıkıntısı çakışma durumunda işlemi iptal etmekden başka çaremiz yok.

    Atomic Update

    SQL
    UPDATE products
    SET stock = stock - 1
    WHERE id = 1 AND stock > 0;

    Burada da aslında benzer bir mantık, stok sıfır olmadığı sürece bir azaltmasını rica ediyoruz veritabanından. Bu çok da basit bir yöntem ben çok tercih etmiyorum ama tabi siz bilirsiniz.

    Yazımızın genelinden de anlayabileceğiniz gibi amacımız veritabanımızın sağladığı özelliklere öncelik vermek.

    Şimdi sırada ise farklı bir yöntem var, ek bir yazılımdan destek alacağız.

    Queue / Message Queue (RabbitMQ vb.)

    Bankacılık uygulamalarına kadar yüksek trafikli tüm işlemlerde bu yöntem kullanılır, Siparişler sıraya alınır ve arkaplanda kullanıcıyı da bekletmeden işlenir. Sonrasında kullanıcıya gerekli bildirimler yapılır.

    • Sipariş bekleme listesine alınır
    • Kulalnıcıya siparişinin onay beklediği ekran gösterilir
    • Arkaplanda sipariş işlenir (QUEUE)
    • Kullanici tarayici veya mail yoluyla bilgilendirilir/yönlendirilir

    Rezervasyon Sistemi

    Bir başka yöntem de kullanıcılar için sepete eklendiğinde rezerve stoklar atamaktır, bunun örneği bu yazımız için çok uzun olacak o yüzden çok ayrıntıya girmiyorum.

    • Kullanıcı sepete ekler
    • Sepete ekleme ile birlikte bir stok tutucu oluşturulur ve ürün bu kullancıya rezerve edilir bir süreliğine.
    • kullanıcı satın alma sırasında yine stok kontrolü ile birlikte satın alır
    • kullanıcı belli bir süre satın almazsa stok serbest bırakılır.

    Sonuç

    Benim önerim kesinlikle QUEUE sistemleri de içinde barındıran hibrit bir sistem.

    Örneğin Rabbit MQ + Database Transaction + Lock

    • Önce sipariş queue ye atılır.
    • Kullanıcı bekleme ekranına gönderilir.
    • Optimistik Lock + Database Transaction Lock ile birlikte sipariş işlenir.
    • Kullanıcı bilgilendirir.

  • RabbitMQ Nedir? Hangi Problemi Çözüyor?

    RabbitMQ Nedir? Hangi Problemi Çözüyor?

    RabbitMQ nedir sorusunu sormadan önce Event-driven architecture nedir sorusu ile yazıma başlamak istiyorum. RabbitMQ bu sistemde kullandığımız bir araçtır çünkü.

    Event Driven Architecture Nedir?

    EDA bir yazılım dizayn pattern’i dir ve yazılımımızın event yani olaylara vereceği reaction yani tepkileri vurgulayan ve bu şekilde ölçeklenebilir sistemler dizayn etmemizi sağlar.

    Bu yöntem çok popüler bir yöntemdir ve yazılımınızı alt bölümlere ayırmanızı birbirine bağlı olmadan bu bölümlerin çalışmasını sağlar.

    Projemiz büyüdüğünde bu sistemi geleneksel yazılım tasarımlarından daha iyi yönetilebilir projeler oluşturmamızı sağlar.

    Kısaca yazılımımızdaki olaylara verilecek tepkiler üzerinden sistemimizi tasarlamamıza verilen isimdir.

    Yazılımımızın başka başka parçaları farklı cihazlarda bile çalışabilir ve birbirlerinden haberdar olmalarına çok da gerek kalmaz, örneğin tek bilmeleri gereken yeni bir kullanıcının kaydoluğudur ve burumda gereken işlemi birbirlerinden haberleri olmadan gerçekleştirirler.

    Biz yazılımımızda üye kaydolma event’i gerçekleştiğinde trigger’lanacak sistemleri kaydederiz ve onlar da ayrı ayrı çalışır!

    Bu sistemlerden biri fail olursa diğeri zarar görmeden hayatına devam eder!

    Aynı kaynakları paylaşmadıkları için de birbirlerini bloklamazlar!

    Kullanıcı bir butona bastı ve bu butonun yapması gereken diyelim ki sipariş oluşturmak, fatura oluşturmak, stok düşmek ve aynı zamanda bunları gerekli yerlere mail göndermek diyelim. Bu durumda normal geleneksel uygulamalarda bunları sırayla yapar ve ziyaretçilerimizi bekletiriz. Ama event-driven architecture’da “order.created” event’i order bilgisi ile birlikte bu işlemleri yapan ayrı ayrı sistemlere mesaj gönderir, yeni sipariş oluştu her biriniz üzerinize düşenleri gerçekleştirin der ve kullanıcıya da siparişşin oluşturulduğu cevabını döner, kullanıcı bilgisayarını kapatır arkaplanda sistem faturayı, stok düşme işlemini, email ile bilgilendirme işlemlerini yapar ve ziyaretçinin bundan haberi bile olmaz!

    Evet bu sistemler birbiri ile nasıl haberleşecek sorusu aklına gelmiştir diye düşünüyorum, hemen burada çevreye neredeyse piyasa standartı olmuş bir sistem giriyor. RabbitMQ!

    RabbitMQ Nedir?

    RabbitMQ açık kaynak kodlu bir message broker yazılımıdır, bu event-driven architecture içerisinde sistemlerin birbiri ile iletişim kurmasını sağlar, bir event gerçekleştiğinde bu event’den haberdar olması gereken, o event’e abone olmuş consumer yani tüketicileri haberdar eder.

    RabbitMQ mesajları öncelikle “exchange” dediğimiz depolara gönderir ve ondan sonra da route key lerine göre abonelerine ulaştırır!

    RabbitMQ “First-in, First-out algoritmasına göre çalışır, ilk giren event ilk işlenir,

    RabbitMQ özellikle micro-servis mimarisinde oldukça popülerdir!