Ölçekleme Oynat! Binlerce Eşzamanlı İstek
Yayınlanan: 2022-03-11Scala Web Geliştiricileri, çoğu zaman binlerce kullanıcının uygulamalarımıza aynı anda erişmesinin sonuçlarını göz önünde bulundurmaz. Belki de hızlı prototiplemeyi sevdiğimiz içindir; belki de bu tür senaryoları test etmenin zor olmasındandır.
Ne olursa olsun, doğru araç setini kullanırsanız ve iyi geliştirme uygulamalarını takip ederseniz, ölçeklenebilirliği görmezden gelmenin göründüğü kadar kötü olmadığını tartışacağım.
Lojinha ve Oyun! Çerçeve
Bir süre önce, bir müzayede sitesi kurma girişimi olan Lojinha (Portekizce "küçük mağaza" anlamına gelen) adlı bir projeye başladım. (Bu arada, bu proje açık kaynaktır). Motivasyonlarım şu şekildeydi:
- Artık kullanmadığım bazı eski şeyleri gerçekten satmak istedim.
- Geleneksel müzayede sitelerini sevmiyorum, özellikle de burada, Brezilya'da bulunanları.
- Play ile “oynamak” istedim! Çerçeve 2 (punto amaçlı).
Açıkçası, yukarıda belirtildiği gibi, Play'i kullanmaya karar verdim! Çerçeve. İnşa etmenin ne kadar sürdüğünü tam olarak bilmiyorum, ancak sitemi http://lojinha.jcranky.com adresinde dağıtılan basit sistemle çalışır duruma getirmeden çok önce değildi. Aslında geliştirme süresinin en az yarısını Twitter Bootstrap kullanan tasarıma harcadım (unutmayın: Ben tasarımcı değilim…).
Yukarıdaki paragraf en az bir şeyi açıklığa kavuşturmalıdır: Lojinha'yı yaratırken performans konusunda çok fazla endişelenmedim.
Ve tam olarak benim amacım bu: doğru araçları kullanmanın gücü var—sizi doğru yolda tutan araçlar, yapıları gereği sizi en iyi geliştirme uygulamalarını takip etmeye teşvik eden araçlar.
Bu durumda, bu araçlar Play! Çerçeve ve Scala dili, Akka'nın bazı “misafir görünümleri” yapması.
Sana ne demek istediğimi göstereyim.
Değişmezlik ve Önbelleğe Alma
Değişebilirliği en aza indirmenin iyi bir uygulama olduğu genel olarak kabul edilir. Kısaca, değişebilirlik, özellikle herhangi bir paralellik veya eşzamanlılık sunmaya çalıştığınızda, kodunuz hakkında akıl yürütmeyi zorlaştırır.
Oyun! Scala çerçevesi, değişmezliği zamanın iyi bir bölümünde kullanmanızı sağlar ve Scala dilinin kendisi de öyle. Örneğin, bir denetleyici tarafından oluşturulan sonuç değişmezdir. Bazen bu değişmezliği "rahatsız edici" veya "sinir bozucu" olarak düşünebilirsiniz, ancak bu "iyi uygulamalar" bir nedenle "iyidir".
Bu durumda, sonunda bazı performans testleri yapmaya karar verdiğimde denetleyicinin değişmezliği kesinlikle çok önemliydi: Bir darboğaz keşfettim ve bunu düzeltmek için bu değişmez yanıtı önbelleğe aldım.
Önbelleğe alma ile, yanıt nesnesini kaydetmeyi ve herhangi bir yeni istemciye olduğu gibi aynı örneği sunmayı kastediyorum. Bu, sunucuyu sonucu baştan yeniden hesaplamak zorunda bırakmaktan kurtarır. Bu sonuç değiştirilebilir olsaydı, aynı yanıtı birden fazla istemciye sunmak mümkün olmazdı.
Dezavantajı: Kısa bir süre için (önbellek süresinin dolması), istemciler güncel olmayan bilgileri alabilir. Bu yalnızca, istemcinin gecikme toleransı olmaksızın en son verilere erişmesine kesinlikle ihtiyaç duyduğunuz senaryolarda bir sorundur.
Başvuru için, burada önbelleğe almadan bir ürün listesi içeren başlangıç sayfasını yüklemek için Scala kodu verilmiştir:
def index = Action { implicit request => Ok(html.index(body = html.body(Items.itemsHigherBids(itemDAO.all(false))), menu = mainMenu)) }Şimdi, önbelleği ekleyerek:
def index = Cached("index", 5) { Action { implicit request => Ok(html.index(body = html.body(Items.itemsHigherBids(itemDAO.all(false))), menu = mainMenu)) } }Oldukça basit, değil mi? Burada “index” önbellek sisteminde kullanılacak anahtardır ve 5 saniye cinsinden sona erme süresidir.
Bu değişikliğin etkisini test etmek için yerel olarak bazı JMeter testleri (GitHub deposuna dahil) çalıştırdım. Önbelleği eklemeden önce, saniyede yaklaşık 180 istek çıktısı elde ettim. Önbelleğe alındıktan sonra aktarım hızı saniyede 800 isteğe ulaştı. Bu, iki satırdan daha az kod için 4 kattan fazla bir gelişmedir.

Bellek Tüketimi
Doğru Scala araçlarının büyük bir fark yaratabileceği bir başka alan da bellek tüketimidir. İşte, yine Oynat! sizi doğru (ölçeklenebilir) yöne iter. Java dünyasında, sunucu uygulaması API'si ile yazılmış “normal” bir web uygulaması için (yani, hemen hemen tüm Java veya Scala çerçeveleri), API kolay kullanım sunduğundan, kullanıcı oturumuna çok sayıda önemsiz şey koymak çok caziptir. bunu yapmanıza izin veren çağrı yöntemleri:
session.setAttribute("attrName", attrValue);Kullanıcı oturumuna bilgi eklemek çok kolay olduğu için genellikle kötüye kullanılır. Sonuç olarak, muhtemelen iyi bir sebep olmaksızın çok fazla bellek kullanma riski de aynı derecede yüksektir.
Oyun ile! çerçeve, bu bir seçenek değildir—çerçevede sunucu tarafı oturum alanı yoktur. Oyun! çerçeve kullanıcı oturumu bir tarayıcı çerezinde tutulur ve onunla yaşamak zorundasınız. Bu, oturum alanının boyut ve tür olarak sınırlı olduğu anlamına gelir: yalnızca dizeleri saklayabilirsiniz. Nesneleri saklamanız gerekiyorsa, daha önce tartıştığımız önbelleğe alma mekanizmasını kullanmanız gerekir. Örneğin, oturumda mevcut kullanıcının e-posta adresini veya kullanıcı adını saklamak isteyebilirsiniz, ancak etki alanı modelinizden bir kullanıcı nesnesinin tamamını depolamanız gerekiyorsa önbelleği kullanmanız gerekecektir.
Yine, bu ilk başta bir acı gibi görünebilir, ama gerçekte, Oynat! sizi doğru yolda tutar, sizi bellek kullanımınızı dikkatli bir şekilde düşünmeye zorlar, bu da pratik olarak kümeye hazır olan ilk geçiş kodunu üretir - özellikle kümeniz boyunca yayılması gereken sunucu tarafı oturumu olmadığı için hayat yaratır sonsuz derecede kolay.
zaman uyumsuz destek
Bu Oyunda Sıradaki! çerçeve inceleme, Play nasıl inceleyeceğiz! ayrıca zaman uyumsuz (kronous) desteğinde de parlar. Ve yerel özelliklerinin ötesinde, Play! zaman uyumsuz işleme için güçlü bir araç olan Akka'yı gömmenizi sağlar.
Lojinha, Play ile basit entegrasyonu olan Akka'dan henüz tam olarak yararlanmasa da! gerçekten kolaylaştırdı:
- Eşzamansız bir e-posta hizmeti planlayın.
- Çeşitli ürünler için teklifleri aynı anda işleyin.
Kısaca Akka, Erlang'ın ünlü yaptığı Oyuncu Modelinin bir uygulamasıdır. Akka Oyuncu Modeline aşina değilseniz, sadece mesaj yoluyla iletişim kuran küçük bir birim olarak hayal edin.
Asenkron bir e-posta göndermek için önce uygun mesajı ve aktörü oluşturuyorum. O zaman, tek yapmam gereken şöyle bir şey:
EMail.actor ! BidToppedMessage(item.name, itemUrl, bidderEmail)Oyuncunun içinde e-posta gönderme mantığı uygulanır ve mesaj oyuncuya hangi e-postayı göndermek istediğimizi söyler. Bu, bir at ve unut şemasında yapılır, yani yukarıdaki satır isteği gönderir ve bundan sonra elimizde ne varsa onu yürütmeye devam eder (yani engellemez).
Play!'in yerel Async'i hakkında daha fazla bilgi için resmi belgelere bakın.
Çözüm
Özetle: Hızla küçük bir uygulama geliştirdim, Lojinha, çok iyi bir şekilde büyütüp küçültebilen. Sorunlarla karşılaştığımda veya darboğazlar keşfettiğimde, düzeltmeler hızlı ve kolaydı ve kullandığım araçlar (Play!, Scala, Akka vb.) sayesinde çok fazla takdir topladım, bu da beni verimlilik ve verimlilik açısından en iyi uygulamaları izlemeye itti. ölçeklenebilirlik. Performans için çok az endişeyle, binlerce eşzamanlı isteğe ölçeklendirmeyi başardım.
Bir sonraki uygulamanızı geliştirirken araçlarınızı dikkatlice düşünün.
