Bir web API'sine yönelik bir ağ çağrısı ile çoklu veritabanı çağrıları gerçekten önemli mi?


16

İşverenlerimden birinde bir REST (ancak SOAP için de geçerli) API üzerinde çalıştık. Uygulama kullanıcı arabirimi olan istemci, API üzerinden web üzerinden (tipik üretim dağıtımlarında LAN) arama yapar. API, veritabanını arar.

Tartışmalarımızda tekrarlanan bir tema performanstır: takımdaki bazı kişiler performans nedeniyle tek bir API çağrısından birden fazla veritabanı çağrısı (genellikle okur) almamanız gerektiğine inanır; her bir API çağrısının yalnızca (tam olarak) bir veritabanı çağrısı olmasını sağlayacak şekilde optimize etmelisiniz.

Ama bu gerçekten önemli mi? Kullanıcı arayüzünün API'ye bir ağ çağrısı yapması gerektiğini düşünün; bu oldukça büyük (milisaniye büyüklük sırası). Veritabanları işleri bellekte tutmak ve okumaları çok, çok hızlı bir şekilde yürütmek için optimize edilmiştir (örn. SQL Server her şeyi RAM'de yükler ve tutar ve mümkünse neredeyse tüm ücretsiz RAM'inizi tüketir).

TLDR: LAN üzerinden bir ağ çağrısı yaparken birden fazla veritabanı çağrısı hakkında endişelenmek gerçekten önemli mi? Öyleyse neden?

Açık olmak gerekirse, büyüklük sırasından bahsediyorum - spesifikasyonlara bağlı olduğunu biliyorum (makine donanımı, API ve DB seçimi, vb.) O (milisaniye) alan bir çağrım varsa, DB için optimizasyon yapar daha az büyüklük gerektiren çağrılar, aslında önemli mi? Yoksa problemde bundan daha fazlası var mı?

Düzenleme: gelecek nesiller için bence bu koşullar altında veritabanı çağrılarını birleştirerek performansı artırmamız gerektiğini iddia etmek oldukça saçma - özellikle profilleme eksikliği. Ancak bunu yapıp yapmamamız benim kararım değil; Bunun web API çağrılarını optimize etmenin doğru bir yolu olduğunu düşünmenin ardındaki mantığı bilmek istiyorum.


API katmanı ile veritabanı arasında başka bir ağ çağrısı yok mu?
Sign

4
Zamanlama testleriniz ne gösterdi?
Dan Pichelman

@Sign API ile DB arasında ağ çağrısı yoktur. Anladığım kadarıyla aynı makinede olmaları garanti ediliyor.
ashes999

@ DanPichelman ben de bunu istiyorum. Kimse performansı alıp zamanlamıyor gibi görünüyor; "tüm DB çağrılarını tek bir çağrıda birleştirerek X'deki performansı düzeltmek" için gereken gereksinimleri alırız.
ashes999

Yanıtlar:


25

Ama bu gerçekten önemli mi? Kullanıcı arayüzünün API'ye bir ağ çağrısı yapması gerektiğini düşünün; bu oldukça büyük (milisaniye büyüklük sırası). Veritabanları işleri bellekte tutmak ve okumaları çok, çok hızlı bir şekilde yürütmek için optimize edilmiştir (örn. SQL Server her şeyi RAM'de yükler ve tutar ve mümkünse neredeyse tüm ücretsiz RAM'inizi tüketir).

Mantık

Teorik olarak haklısınız. Bununla birlikte, bu mantıkla birkaç kusur vardır:

  1. Belirttiğinize göre, uygulamanızı gerçekten test edip profillendirdiğiniz belli değil. Başka bir deyişle, aslında yok biliyorum API uygulamadan ağ transferleri yavaş bileşen olduğuna? Bu sezgisel olduğu için olduğunu varsaymak kolaydır. Ancak, performansı tartışırken asla varsaymamalısınız. İşverenimde performans lideriyim. İlk katıldığımda, insanlar darboğazların ne olması gerektiğine dair sezgiye dayanarak CDN'ler, çoğaltma vb. Hakkında konuşmaya devam ettiler. Görünüşe göre, en büyük performans sorunlarımız veritabanı sorgularını kötü bir şekilde gerçekleştiriyordu.

  2. Veritabanları veri almada iyi olduğu için, veritabanının mutlaka en yüksek performansta çalıştığını, en iyi şekilde kullanıldığını ve bunu iyileştirmek için yapılabilecek hiçbir şeyin olmadığını söylüyorsunuz. Başka bir deyişle, veritabanları hızlı olacak şekilde tasarlanmıştır, bu yüzden asla endişelenmemeliyim. Bir başka tehlikeli düşünce tarzı. Bu, bir arabanın hızlı hareket etmesi gerektiğini söylemek gibidir, bu yüzden yağı değiştirmem gerekmiyor.

  3. Bu düşünce tarzı bir seferde tek bir süreç varsayar ya da başka bir deyişle eşzamanlılık olmaz. Bir isteğin başka bir isteğin performansını etkileyemeyeceğini varsayar. Disk G / Ç, ağ bant genişliği, bağlantı havuzları, bellek, CPU döngüleri, vb. Gibi kaynaklar paylaşılır. Bu nedenle, bir veritabanı çağrısının paylaşılan kaynak kullanımını azaltması, diğer isteklerin yavaşlamasına neden olabilir. Mevcut işverenime ilk katıldığımda, yönetim 3 saniyelik bir veritabanı sorgusunun ayarlanmasının zaman kaybı olduğuna inanıyordu. 3 saniye çok az, neden harcanan zaman? Bir CDN veya sıkıştırma veya başka bir şeyle daha iyi olmaz mıydık? Ama 1 saniyede 3 saniyelik bir sorgu yapabilirsem, örneğin bir dizin ekleyerek 2/3 daha az engelleme, bir iş parçacığını işgal etmek için 2/3 daha az zaman ve daha da önemlisi, diskten daha az veri okuma,

Teori

Yazılım performansının sadece hız ile ilgili olduğu konusunda ortak bir görüş vardır .

Tamamen hız açısından, haklısınız. Bir sistem ancak en yavaş bileşeni kadar hızlıdır. Kodunuzu oluşturduysanız ve İnternet'in en yavaş bileşen olduğunu tespit ettiyseniz, her şey açıkçası en yavaş kısım değildir.

Bununla birlikte, yukarıdakiler göz önüne alındığında, umarım kaynak çekişmesi, endeksleme eksikliği, kötü yazılmış kodlar vb. Performansta şaşırtıcı farklılıklar yaratabilir.

Varsayımlar

Son bir şey. Bir veritabanı çağrısının, uygulamadan API'ya yapılan bir ağ çağrısına kıyasla ucuz olması gerektiğini belirttiniz. Ancak, uygulamanın ve API sunucularının aynı LAN'da olduğunu da belirttiniz. Bu nedenle, her ikisi de ağ aramalarıyla karşılaştırılamaz mı? Başka bir deyişle, her ikisi de aynı bant genişliğine sahip olduklarında neden API aktarımının veritabanı aktarımından daha yavaş büyüklük sırası olduğunu varsayıyorsunuz? Tabii ki protokoller ve veri yapıları farklı, bunu anlıyorum, ancak bunların farklı büyüklük sıraları olduğu varsayımına itiraz ediyorum.

Murkey nereden geliyor

Bütün soru "çoklu" ve "tek" veritabanı çağrıları ile ilgilidir. Ancak kaç tanesinin çoklu olduğu belli değil. Yukarıda söylediğimden dolayı, genel bir kural olarak, gerektiği kadar az veritabanı çağrısı yapmanızı öneririm. Ancak bu sadece temel bir kuraldır.

İşte nedeni:

  1. Veritabanları veri okumada mükemmeldir. Bunlar depolama motorlarıdır. Ancak, iş mantığınız başvurunuzda yaşar. Her API çağrısının tam olarak bir veritabanı çağrısıyla sonuçlandığına dair bir kural belirlerseniz, iş mantığınız veritabanında bulunabilir. Belki de sorun değil. Birçok sistem bunu yapıyor. Ama bazıları bilmiyor. Bu esneklikle ilgilidir.
  2. Bazen iyi bir ayırma elde etmek için, 2 veritabanı çağrısının ayrılmasını istersiniz. Örneğin, her HTTP isteği, kullanıcının DB'den doğru erişim haklarına sahip olduğunu doğrulayan genel bir güvenlik filtresi aracılığıyla yönlendirilir. Varsa, söz konusu URL için uygun işlevi yürütmeye devam edin. Bu işlev veritabanı ile etkileşime girebilir.
  3. Veritabanını bir döngüde çağırmak. Bu yüzden kaç tanesinin çoklu olduğunu sordum. Yukarıdaki örnekte, 2 veritabanı çağrınız olur. 2 iyidir. 3 iyi olabilir. N iyi değil. Veritabanını bir döngüde çağırırsanız, şimdi performans doğrusal hale getirmiş olursunuz, yani döngü girdisinde daha fazla zaman alır. Kategorik olarak, API ağ zamanının en yavaş olduğunu söyleyerek, veritabanınızın 10.000 kez çağıran henüz keşfedilmemiş bir döngü nedeniyle uzun süre alan trafiğinizin% 1'i gibi anomalileri tamamen göz ardı eder.
  4. Bazen, bazı karmaşık hesaplamalar gibi uygulamanızın daha iyi olduğu şeyler vardır. Veritabanından bazı verileri okumalı, bazı hesaplamalar yapmalı, sonra sonuçlara dayanarak, ikinci bir veritabanı çağrısına bir parametre iletmeniz gerekebilir (belki bazı sonuçlar yazmak için). Bunları yalnızca bir kez veritabanını çağırmak için tek bir çağrıda (saklı yordam gibi) birleştirirseniz, veritabanını uygulama sunucusunun daha iyi olabileceği bir şey için kullanmaya zorladınız.
  5. Yük dengeleme: 1 veritabanınız (muhtemelen) ve birden fazla yük dengeli uygulama sunucunuz var. Bu nedenle, uygulama ne kadar çok iş yapar ve veritabanı o kadar az çalışırsa ölçeklendirmek o kadar kolay olur çünkü bir uygulama sunucusu eklemek genellikle veritabanı çoğaltmasını kurmaktan daha kolaydır. Önceki madde işaretine bağlı olarak, bir SQL sorgusu çalıştırmak mantıklı olabilir, daha sonra uygulamadaki tüm hesaplamaları yapın, bu da birden fazla sunucuya dağıtılır ve ardından bitirildiğinde sonuçları yazar. Bu daha iyi verim sağlayabilir (toplam işlem süresi aynı olsa bile).

TL; DR

TLDR: LAN üzerinden bir ağ çağrısı yaparken birden fazla veritabanı çağrısı hakkında endişelenmek gerçekten önemli mi? Öyleyse neden?

Evet, ama sadece bir dereceye kadar. Pratik olduğunda veritabanı çağrılarının sayısını en aza indirmeye çalışmalısınız, ancak birbirleriyle hiçbir ilgisi olmayan çağrıları birleştirmek için birleştirmeyin. Ayrıca, veritabanını her ne pahasına olursa olsun bir döngüde çağırmaktan kaçının.


3

Ekibinizin bir nedeni olmadan önce optimizasyon yaptığı anlaşılıyor. Bu istekleri yerine getirme zamanını ölçtünüz mü? Şanslar, bu paradigmayı son kullanıcı için daha kötü bir performans yaratacaktır çünkü web sunucusuna gidiş-dönüş gezileri, web sunucusundan veritabanına bağlantı süresinden çok daha fazla gecikmeye sahip olacaktır. Üstelik çoğu web tarayıcısı tek bir web sunucusuna sadece 2 eşzamanlı bağlantı kuracaktır, bu nedenle karmaşık sayfalar için muhtemelen bir darboğazda karşılaşırsınız.

Her iki şekilde de optimizasyon kararları, verileri yedeklemek için veri olmadan alınmamalıdır. Ölçün ve uygulamanız için en iyi olanı bulun.


1
Bu, kötü performans uygulamalarımız hakkında iyi bir yorumdur, ancak zaten bir ağ çağrım olduğunda DB çağrılarının endişelenecek bir şey olup olmadığı hakkındaki sorumu yanıtlamıyor.
ashes999

1
Genel olarak, bir sorun olmamak için birden fazla veritabanı çağrıları yaptık bulduk. Bu çoğunlukla bağlantı havuzu ve DB ve web sunucusu arasındaki küçük gecikme nedeniyle. Bir sürü farklı db aramaları yapmanın performansı olumsuz etkileyeceği bir nokta var, ancak sizin için zor bir sayı yok. Her şey çevreye ve uygulamaya bağlıdır. Sadece ölçüm size aradığınız cevabı verecektir.
brianfeucht

(Mutlaka) spesifikasyonlara bağlı olmamalıdır, çünkü ben büyüklük sırasından bahsediyorum.
ashes999

Sadece kaba tahminler (ölçmeniz gerekir): Web Sunucusundan DB'ye bağlanmak için ortalama süre: 2ms İstemciden Web Sunucusuna bağlanmak için ortalama süre: 20 ms bir web servis çağrısı yapmak için gereken süre içinde veritabanı çağrıları. Veritabanı sorgularının aynı süre aldığını varsayarsak. Bu sayılar son derece çevreye bağımlı. Web servis çağrısı yapan müşteri yerel ise, bunu birkaç büyüklük derecesinde düşürebilir.
brianfeucht

2

Size söyleyemeyiz.

Sorgularınıza benzemiyoruz. Ne kadar sürede tamamlandıklarını bilmiyoruz. API sunucunuza yapılan her bir istekte ne kadar ek yük olduğunu bilmiyoruz. Müşterilerinizin coğrafi olarak ne kadar dağınık olduğunu bilmiyoruz. Vb.

Bu senaryo ise optimizasyon gerektirir hangi bir ve olup edebilir olmadığını bölünmüş karar veya birlikte görüşmelerine katılmak, sen kriter için bu iki yönde de ihtiyaç karar verin Eğer (UI gecikme için konum optimize, sunucu CPU yükü, çekişme, vb.) seçin ve optimizasyon hedefinize daha iyi ulaşanı seçin.


Bunun yanı sıra, göreli kesinlik ile ekleyebileceğim tek şey şudur:

Tek bir istekte, yanıt oluşturmak için gerçekleştirmeniz gereken tüm sorguları gerçekleştirmelisiniz.

Başka bir deyişle, yanıt tüm N sorguları gerçekleştirilinceye kadar oluşturulamıyorsa, genellikle bunları ayırmak anlamsızdır. Her bir sorgudan sonra orta veya tam anlamlı sonuçlar üretebiliyorsanız karşılaştırmaya başlayın.


1

İki düşünce:

İlk olarak, API kullanan tüketiciye, bir görevi yerine getirmek için bir çağrı yapıyor. Sunucunuz isteği doldurma çağrısını aldıktan sonra ne olacağı bu kadar katı olmamalıdır. Tüketiciden yapılan bu bir çağrı, verileri bir araya getirmek ve geri vermek için 10 alt iş öğesi gerektiriyorsa, bu kabul edilebilir olmalıdır.

İkincisi: Söz konusu işlemle ilgili gerçek bir veritabanı performans sorunu görüyor musunuz? Deneyimlerim, bir veritabanı isteğinin tüm yönlerini tek bir çağrıya koymaya çalışmanın, veri için üç veya dört çağrı yapmaktan daha az verimli bir çağrıya neden olabileceğini göstermiştir. Modern veritabanları önbellekleme ve yürütme planlarında çok verimlidir. Çoğunlukla, çok fazla yapmaya çalıştığınızda imleçlerle (performans için çok kötü çünkü veriler bir kerede bir set olarak değil, satır satır hareket ettiği için) ve kırılmış olmanıza göre daha az verimli bir planla sonuçlanan kodlar göreceksiniz. birkaç kolay adımda çağrılabilir.

Kodun basit organizasyonu dışında, her API çağrısının muhtemelen tek bir saklı yordam (veya db işlevi) çağırması gerektiğini kabul ediyorum ki bu da isteği doldurmaktan sorumludur. Prosedürde birden fazla adım olabilir.


Kimsenin yapmadığı görünen performans ölçümü konusunda size katılıyorum. Bunun daha hızlı olduğuna dair bir kanıt yok, ama ortaya çıkmaya devam ediyor. 1000 DB gibi bazı çağrılarımız olduğunda performans bir sorun olarak karşımıza çıkıyor SELECT.
ashes999

@ ashes999 db çağrılarının sayısına bakarak hız kazanabilirsiniz, ancak arama sayısını değil dizin oluşturma stratejisinde vb. Herkesin belirttiği gibi, performans verilerine bakın.
Richard

Richard, katılıyorum ve aslında bunu biliyorum. Benim sorum neden çeşitli insanlar dahil bir ağ çağrısı olduğunda "birden çok DB çağrıları yavaş" bu noktayı getirmeye devam ediyor. Gerçekten nasıl önemli olabileceğini anlamıyorum.
ashes999

@ ashes999 Üzgünüm, belki şebeke çağrısı hakkında biraz daha ayrıntıya girmelisiniz, çünkü bu açık görünüyor, sorunuzun biraz daha fazlası olduğunu düşünüyorum. Sorularınızda bir şey eksik olduğumuzu hissediyorum. Her zaman bir ağ gecikmesi yaşayacaksınız ve her arama potansiyel olarak her arama için "x" katına çıkacaktır (basit terimlerle). Nominal değerdeki deyim doğrudur, birden çok şebeke çağrısı db'ye yapılan bir şebeke çağrısından daha yavaş olacaktır. Bu yüzden bir saklı yordam için bir çağrı öneririz, o zaman, bu çoklu ağ çağrıları olmadan db birden çok çağrı yapabilirsiniz.
Richard

1

Veritabanı REST hizmetinizden farklı bir sunucudaysa, her veritabanı çağrısı bir ağ gidiş dönüşüyle ​​sonuçlanır ve bu da performansa önemli ölçüde zarar verebilir:

Bir keresinde tek bir web hizmeti çağrısının yaklaşık 500 veritabanı sorgusuna çevrildiğini gözlemledim - bu hem web hizmeti hem de veritabanı aynı makinede bulunduğunda neredeyse bir sorun değildi, ancak farklı olduklarında 6-7 saniyelik bir yanıt süresine dönüştü makineleri.

Açıkçası, veritabanına 500 gidiş dönüş oldukça aşırı. Performans gereksinimlerinizin ne olduğundan emin değilim, ancak genel bir kural olarak, REST çağrısı başına yaklaşık 10 veritabanı sorgusu altında kalırsanız, önemli bir performans isabeti yaşamamanız gerektiğini söyleyebilirim.


1

Çok, çok konuşkan olan birkaç uygulamamız var. Her biri için bir veritabanı çağrısı var. Tek. Küçük. Şey. Referans verilerinin tekrar tekrar sunulması sistemdeki iş yükünün önemli bir parçasıdır. Çalışan iş parçacıklarının tüm zamanlaması, kilitlerin alınması ve bırakılması, önbellek kontrolü vb. Gerçek disk GÇ'si olmasa bile toplanır. İşlemler birden çok DB çağrısı boyunca kilitleri tutmak zorunda kaldığından işlem daha yüksektir ve bu nedenle işlem hacmi olabileceğinden çok daha düşüktür. Bu takımlar şimdi yeni, çok pahalı DB sunucuları satın almak zorunda kalıyorlar.

Bu nedenle, sisteminizin geçerli yapılandırmasında geçen sürenin büyük bir kısmı REST API çağrıları ile alınsa da, DB düzeyinde performansı göz ardı etmek gelecekteki sorunları saklamaktadır.


0

Sunulan optimizasyon yolu, şeylere bakmak için yanlış bir yoldur.

API çağrıları atomik olmalıdır. Başka bir deyişle, istediğim eylemi gerçekleştirmek için 1 web API çağrısı yapabilmeliyim. Bu, veri almak, bir kaydı güncellemek veya her neyse. Eyleme neden olmak için ASLA 1'den fazla çağrı almamalıdır. Ve birden fazla çağrıda işlemlerden yararlanma girişimi veba gibi engellenmelidir.

Bazen tek bir eylem oldukça karmaşıktır. Örneğin, çeşitli kaynaklardan birleştirilmiş veriler getiriliyor: tekrar, bu tek bir çağrı olmalıdır. Ya her şey çalışır ya da her şey başarısız olur.

Şimdi, tek bir API çağrısı sadece bir DB sorgusu yürütmek gerektiğini söylemek biraz moronic olduğunu. İşaret ettiğiniz gibi, çağrıyı şebeke genelinde paylaşmanın getirdiği yük, genellikle toplam zaman açısından daha pahalı büyüklük sıralarıdır.

Ben yapabilirsiniz biraz kendi deyimi anlamaları tek bir sorgu çalışır hızlı birkaç daha can; ancak bu, toplam DB ve ağ yükünü yok sayarken yanlış bir gösterim verir. Sadece DB'den veri çekmenin çeşitli yollarını profilleyerek sorunun gerçekte ne olduğunu anlayabilirsiniz. Herkesin, belirli bir sorgunun beklenenden 100 kat daha sık yürütüldüğü bir hikayesi olduğundan emin olun, uygun bir dizin yerleştirilene kadar sistemi öldürdü ...

Nihayetinde onları sadece konuşma ile ikna edemeyeceksiniz. Her iki yaklaşım için de bir test durumu oluşturun ve profillerini oluşturun. İhtiyacınız olan veriyi elde etmek için toplam süreye, oluşturulan ağ trafiğinin miktarına, veritabanı çağrılarının sayısına ve zamanlamasına vb. Dikkat edin. Bütün sisteme baktığınız anlamına gelen bütünsel bir yaklaşım alın ve bol miktarda sonuç almalısınız. ya karga yemek ya da altın yolu göstermek için veri.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.