Gibi
Yakın gelecekte piyasaya sürmeyi planladığımız Alvin ile uzun gecikmeler nedeniyle bir gün canımı sıkan bir e-postayla uyandım. Özellikle müşteri, gecikme bütçemizin çok üzerinde, 99 ms civarında yüzde 50'luk bir gecikme yaşadı. Hizmeti kapsamlı bir şekilde, özellikle de yaygın bir şikayet olan gecikme konusunda test ettiğim için bu şaşırtıcıydı.
Alvin'i teste sokmadan önce, saniyede 40 sorgu (QPS) ile çok sayıda deney yaptım ve bunların tümü 10 ms'den daha az gecikme gösterdi. Sonuçlarına katılmadığımı beyan etmeye hazırdım. Ancak mektuba tekrar baktığımda yeni bir şey fark ettim: Bahsettikleri koşulları tam olarak test etmemiştim, QPS'leri benimkinden çok daha düşüktü. 40k QPS'de test ettim, ancak onlar yalnızca 1k'de. Sırf onları yatıştırmak için bu sefer daha düşük bir QPS ile başka bir deney yaptım.
Bu konuda blog yazdığıma göre muhtemelen sayıların doğru olduğunu zaten anlamışsınızdır. Sanal istemcimi tekrar tekrar test ettim ve aynı sonuçla karşılaştım: isteklerin sayısının az olması yalnızca gecikmeyi artırmakla kalmıyor, aynı zamanda gecikmesi 10 ms'den fazla olan isteklerin sayısını da artırıyor. Başka bir deyişle, 40k QPS'de saniyede yaklaşık 50 istek 50 ms'yi aşarsa, 1k QPS'te saniyede 100 ms'nin üzerinde 50 istek vardı. Paradoks!
Aramayı daraltma
Pek çok bileşene sahip dağıtılmış bir sistemde gecikme sorunuyla karşılaşıldığında ilk adım, kısa bir şüpheli listesi oluşturmaktır. Alvin'in mimarisine biraz daha derinlemesine bakalım:
İyi bir başlangıç noktası, tamamlanan G/Ç geçişlerinin (ağ çağrıları/disk aramaları vb.) listesidir. Gecikmenin nerede olduğunu bulmaya çalışalım. Alvin, istemciyle olan bariz G/Ç'nin yanı sıra fazladan bir adım daha atıyor: veri deposuna erişiyor. Ancak bu depolama Alvin ile aynı kümede çalıştığından gecikmenin istemcidekinden daha az olması gerekir. Yani, şüphelilerin listesi:
- İstemciden Alvin'e ağ çağrısı.
- Alvin'den veri deposuna ağ çağrısı.
- Veri deposundaki diskte arama yapın.
- Veri ambarından Alvin'e ağ çağrısı.
- Alvin'den bir müşteriye ağ çağrısı.
Bazı noktaların üzerini çizmeye çalışalım.
Veri depolamanın bununla hiçbir ilgisi yok
Yaptığım ilk şey Alvin'i istekleri işlemeyen bir ping-ping sunucusuna dönüştürmek oldu. Bir istek aldığında boş bir yanıt döndürür. Gecikme azalırsa Alvin'de veya veri ambarı uygulamasında bir hata duyulmamış bir şey değildir. İlk deneyde aşağıdaki grafiği elde ederiz:
Gördüğünüz gibi ping-ping sunucusunu kullanırken herhangi bir gelişme yok. Bu, veri ambarının gecikmeyi artırmadığı ve şüpheli listesinin yarıya indirildiği anlamına gelir:
- İstemciden Alvin'e ağ çağrısı.
- Alvin'den bir müşteriye ağ çağrısı.
Harika! Liste hızla daralıyor. Neredeyse sebebini bulduğumu sanıyordum.
gRPC
Şimdi sizi yeni bir oyuncuyla tanıştırmanın zamanı geldi: gRPC
iyi optimize edilmiş ve yaygın olarak kullanılmış, bu boyuttaki bir sistemde ilk kez kullanıyordum ve uygulamamın en hafif tabirle optimalin altında olmasını bekliyordum.
kullanılabilirlik gRPC
yığında yeni bir soru ortaya çıktı: belki bu benim uygulamamdır ya da kendimdir gRPC
gecikme sorununa neden oluyor mu? Listeye yeni bir şüpheli ekleniyor:
- Müşteri kütüphaneyi arar
gRPC
- Kütüphane
gRPC
istemcideki kütüphaneye ağ çağrısı yapargRPC
sunucuda - Kütüphane
gRPC
Alvin ile iletişim kurar (ping-pong sunucusu durumunda işlem yapılmaz)
Kodun neye benzediğine dair bir fikir vermek gerekirse, müşteri/Alvin uygulamam istemci-sunucu uygulamalarından pek farklı değil
Not: Yukarıdaki liste biraz basitleştirilmiştir çünkü
gRPC
yürütme yığınının iç içe geçtiği kendi (şablon?) iş parçacığı modelinizi kullanmanızı mümkün kılargRPC
ve kullanıcı uygulaması. Basitlik adına bu modele bağlı kalacağız.
Profil oluşturma her şeyi düzeltecektir
Veri depolarının üzerini çizdikten sonra neredeyse işimin bittiğini düşündüm: “Artık çok kolay! Profili uygulayalım ve gecikmenin nerede oluştuğunu bulalım.” BEN
Dört profil aldım: hem istemci tarafında hem de sunucu tarafında yüksek QPS'li (düşük gecikmeli) ve düşük QPS'li (yüksek gecikmeli) bir ping-pong sunucusuyla. Her ihtimale karşı örnek bir işlemci profili de aldım. Profilleri karşılaştırırken genellikle anormal bir çağrı yığını ararım. Örneğin, yüksek gecikme süresine sahip kötü tarafta çok daha fazla bağlam anahtarı vardır (10 kat veya daha fazla). Ancak benim durumumda bağlam anahtarlarının sayısı neredeyse aynıydı. Beni dehşete düşüren, orada önemli bir şey yoktu.
Ek Hata Ayıklama
Çaresizdim. Başka hangi araçları kullanabileceğimi bilmiyordum ve bir sonraki planım, sorunu açıkça teşhis etmek yerine esas olarak farklı varyasyonlarla deneyleri tekrarlamaktı.
Farzedelim
En başından beri, 50 ms'lik gecikme konusunda endişeliydim. Bu çok büyük bir zaman. Bu hataya tam olarak hangi parçanın neden olduğunu bulana kadar kodun bazı kısımlarını kesmeye karar verdim. Daha sonra işe yarayan bir deney geldi.
Her zamanki gibi geriye dönüp baktığımızda her şeyin apaçık olduğu görülüyor. İstemciyi Alvin ile aynı makineye yerleştirdim ve ona bir istek gönderdim. localhost
. Ve gecikmedeki artış ortadan kalktı!
Ağda bir sorun vardı.
Ağ mühendisi becerilerini öğrenme
İtiraf etmeliyim ki ağ teknolojileri konusundaki bilgim berbat, özellikle de onlarla her gün çalıştığım gerçeği göz önüne alındığında. Ancak asıl şüpheli ağdı ve benim de ağda nasıl hata ayıklayacağımı öğrenmem gerekiyordu.
Neyse ki internet öğrenmek isteyenleri seviyor. Ping ve tracert kombinasyonu, ağ aktarım sorunlarının hatalarını ayıklamak için yeterince iyi bir başlangıç gibi görünüyordu.
Öncelikle başlattım
Sonra denedim
Yani gecikmeye neden olan benim kodum, gRPC uygulaması veya ağ değildi. Bunu hiçbir zaman anlayamayacağım diye endişelenmeye başlamıştım.
Şimdi hangi işletim sistemi üzerindeyiz
gRPC
Linux'ta yaygın olarak kullanılır, ancak Windows'ta egzotiktir. İşe yarayan bir deney yapmaya karar verdim: Bir Linux sanal makinesi oluşturdum, Alvin'i Linux için derledim ve dağıttım.
Ve şöyle oldu: Veri kaynağı farklı olmasa da Linux pinpon sunucusu benzer bir Windows ana bilgisayarıyla aynı gecikmelere sahip değildi. Sorunun Windows için gRPC uygulamasında olduğu ortaya çıktı.
Nagle'ın algoritması
Bunca zaman bir bayrağı kaçırdığımı sanıyordum gRPC
. Şimdi gerçekte ne olduğunu anlıyorum gRPC
Windows bayrağı eksik. Tüm bayraklar kümesinde işe yarayacağından emin olduğum dahili bir RPC kitaplığı buldum
Neredeyse Bitti: Sebebini tam olarak belirleyebilmek için, gerileme dönene kadar eklenen işaretleri birer birer kaldırmaya başladım. Rezil bir şeydi
gRPC
bu bayrak, TCP yuvaları için Linux uygulamasında ayarlandı, ancak Windows'ta ayarlanmadı. ben buyum
Sonuç
Düşük QPS'deki yüksek gecikmenin nedeni işletim sistemi optimizasyonudur. Geçmişe bakıldığında, profil oluşturma işlemi çekirdek modunda yapıldığı için gecikmeyi tespit edemedi.
Localhost deneyine gelince, muhtemelen gerçek ağ koduna dokunmadı ve Nagle'nin algoritması çalışmadı, dolayısıyla müşteri localhost aracılığıyla Alvin'e ulaştığında gecikme sorunları ortadan kalktı.
Bir dahaki sefere saniye başına istek sayısı azaldıkça gecikmede bir artış gördüğünüzde, Nagle'ın algoritması şüpheliler listenizde olmalıdır!
Kaynak: habr.com