Bir Cron'u Ölçeklendirme: Her Dakikada Yüzlerce Siteyi Kontrol Etme


Son yazımda Laravel Spark kullanarak nasıl bir bulut uygulaması oluşturduğumu anlatmıştım. Web Uptime, web sitenizin durumunu dünyanın çeşitli yerlerinden her dakika kontrol eden bir web sitesi çalışma süresi ve izleme uygulamasıdır.

Böyle bir uygulama geliştirme konusunda beni heyecanlandıran şey, her dakika yüzlerce, hatta binlerce web sitesinin durumunu kontrol etmenin teknik zorluğuydu. Bu yazıda, ihtiyaç duyacağımı düşündüğüm mimariye beni yönlendiren düşünce sürecini anlatacağım ve sonra karar verdiğim çözüme bakacağım.

Nereden Başlamalı

Tek bir web sitesinin durumunu düzenli olarak kontrol etme süreci yeterince kolaydır. Dakikada bir çalışan ve web sitesinin HTTP durumunu döndüren bir GET isteğini tetikleyen bir cron işi kurarsınız (GET isteği başarısız olursa veya bir hata durumu varsa, web sitesi kapalıdır!). Ancak, her dakika yüzlerce veya binlerce site için aynı işlemi nasıl gerçekleştireceğinizi düşünmeye başladığınızda, işler çok daha karmaşık hale gelir.

Web Uptime, Laravel (PHP) kullanılarak oluşturulmuştur, ancak PHP eşzamanlı bir dil değildir. Örneğin Python veya Node'dan farklı olarak, aynı anda birden fazla işlemi yürütmeyi veya çalıştırmayı desteklemez. Bu, her dakika her web sitesi kontrolü için tek bir işlemi başlatamayacağınız ve sonuçları toplayamayacağınız anlamına gelir. PHP'de iş parçacığı oluşturmayı sağlayan pthreads PECL uzantısı gibi projeler var, ancak sunucu bakım karmaşıklığımı artıracak bir şey istemedim. Bunun uygun bir seçenek olmadığına karar verdim. Peki bunu başka nasıl yapabilirdim?

  • Her site için ayrı bir cron oluşturun
  • Kontrolleri işlemek için AWS Lambda gibi bir şey kullanın
  • Gearman gibi bir iş kümesi çerçevesi kullanın
  • Bir iş sunucusu kümesiyle bir kuyruk kullanın

İlk planlamamda, her site için ayrı bir cron oluşturmanın yönetilmesinin veya ölçeklendirilmesinin kolay olmayacağına karar verdim (ve birden fazla kontrol için tek bir cron kullanmanın eşzamanlılık olmadan çok yavaş olacağına) bu yüzden işe yaramadı. AWS Lambda dil olarak PHP'yi desteklemiyor (yazma sırasında) ve farklı dillerde iki farklı kod tabanı sürdürmek istemedim, bu yüzden Lambda çıktı. Gearman oldukça umut verici görünüyordu, ancak çalışması için bir PECL uzantısı gerektirdi, bu yüzden onu pthreads PECL uzantısını kullanmakla aynı nedenden dolayı geri çevirdim. Ayrıca, kurulum için özellikle açık olan belgeleri bulamadım.

Bir sıra ve bir iş sunucusu kümesi kullanmanın son seçeneğiyle kaldım. Bu kulağa oldukça karmaşık gelse de, aslında uygulanması nispeten kolaydı. Laravel'in yerleşik kuyruk işleme özelliği vardır, böylece her bölgedeki bir kuyruğa yüzlerce iş eklemek için her dakika bir cron çalıştırabilir ve her bölgede işleri kuyruktan alıp çalıştırıp toplamak için küçük bir iş sunucusu kümesine sahip olabilirim. Sonuçlar. Kuyruklar çok dolduğunda, bazı yeni iş sunucularını çalıştırabilir ve ekstra yükün üstesinden gelmek için bunları kümeye ekleyebilirdim. AWS Simple Queue Service (SQS) kullanabileceğimi ve hatta yeni sunucuları başlatmak ve bunları benim için kümeye eklemek için AWS Auto Scaling'i kullanabileceğimi düşündüm.

Denendi ve Başarısız Oldu

Kuyruk + kümeyi kurduktan sonra doğru yolda olduğumdan emindim ve bu kurulumu kullanarak Web Uptime'ı mutlu bir şekilde başlattım. Tabii ki saflığım geri geldi ve kısa süre sonra sıralarımın dolduğuna ve daha fazla iş sunucusuna ihtiyaç duyulduğuna dair uyarılar almaya başladım ve beni oldukça çabuk ısırdı. Farkına varamadığım şey, bu iş sunucularının hala her bir kuyruk dinleyicisi başına (PHP'nin eşzamanlılık eksikliğinden dolayı) bir seferde yalnızca bir kontrol çalıştırabilmesiydi, bu da her dakika yüzlerce siteyi kontrol etmenin oldukça büyük bir iş sunucusu kümesi gerektireceği anlamına geliyordu. her bir sunucuda birden fazla kuyruk dinleyicisi çalıştırsam bile, yükü işlemek için her bölgede (“yük” burada hesaplama gücü değil, kontrolü gerçekleştirmek için geçen süredir).

Her bir kontrolün 1-10 saniye sürebileceği göz önüne alındığında (kontrol edilen sitenin yükleme süresine bağlı olarak), çok sayıda sunucuya ihtiyaç duyacağımı ve bunun da pahalı olacağını düşündüm. Web Uptime gibi küçük bir yan proje için çok pahalı olacaktı. Çizim tahtasına geri dönme zamanı.

Çözüm: curl_multi

Biraz daha araştırma yaptıktan ve uygun fiyatlı olacak eşzamanlı bir çözüme ihtiyacım olduğunu fark ettikten sonra, PHP'de daha önce hiç görmediğim bir şeyle karşılaştım. PHP'nin cURL uygulamasında, aynı anda birden çok istekte bulunmanıza izin veren bir dizi işlev ( curl_multi* ) vardı, yani aynı anda yüzlerce istekte bulunabilirsiniz (sebepler dahilinde) ve bu yalnızca en uzun isteğin geri dönmesi kadar sürerdi. sonuç.

Bu kulağa ideal geliyordu, bu yüzden kulağa geldiği kadar iyi olup olmadığını görmek için çabucak bir test hazırladım ve yeterince emindim, şimdi 7 saniye gibi kısa bir sürede yüz GET isteği gönderebiliyorum. Bu, her bölgede (uygun fiyatlı) tek bir sunucu kullanabileceğim ve öngörülebilir gelecek için her dakika yüzlerce kontrolü güvenle çalıştırabileceğim anlamına gelir. Uygulamamın görünümü kabaca şöyle oldu:

 $mh = curl_multi_init(); $handles = []; $errors = []; foreach ($monitors as $monitor) { try { $url = $monitor->site->url; $port = $monitor->port; if ($port == 80 && starts_with($url, 'https')) { $port = 443; } $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_PORT, $port); curl_setopt($curl, CURLOPT_TIMEOUT, 20); curl_setopt($curl, CURLOPT_HEADER, 1); curl_setopt($curl, CURLOPT_NOBODY, 1); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_USERAGENT, 'webuptime.io'); curl_setopt($curl, CURLOPT_PRIVATE, $monitor->id); curl_multi_add_handle($mh, $curl); $handles[] = $curl; } catch (\Exception $e) { \Log::error($e->getMessage()); } } $running = null; do { curl_multi_exec($mh, $running); $info = curl_multi_info_read($mh); if ($info !== false && isset($info['handle']) && isset($info['result'])) { $errors[(int) $info['handle']] = $info['result']; } usleep(100000); } while ($running > 0); $monitorResults = []; for ($i = 0; $i < count($handles); $i++) { $resourceId = (int) $handles[$i]; $monitorId = curl_getinfo($handles[$i], CURLINFO_PRIVATE); $statusCode = isset($errors[$resourceId]) ? $errors[$resourceId] : 0; $httpCode = curl_getinfo($handles[$i], CURLINFO_HTTP_CODE); $responseTime = curl_getinfo($handles[$i], CURLINFO_TOTAL_TIME); // Save results... curl_multi_remove_handle($mh, $handles[$i]); } curl_multi_close($mh);

Gördüğünüz gibi, bir grup curl örneği oluşturdum (normalde yaptığınız gibi) ancak bunları yürütmek yerine curl_multi_add_handle kullanarak çoklu tanıtıcıya ekliyoruz ve sonra bunları bir dizi $handles içinde saklıyoruz. Daha sonra, curl örneklerini aynı anda curl_multi_exec yapmak için bir do while döngüsü kullanırız. Döngü bittiğinde $handles dizisini kullanarak ihtiyacımız olan bilgiyi çıkarırız ve son olarak tutamaçları kaldırır ve çoklu bağlantı kaynağını kapatırız.

Hızlı ve kirli bir test komut dosyası kullanarak 95 siteyi kontrol etmek için normal curl_exec kullanmanın ~ 60 saniye sürdüğünü (makinemde) buldum. Aynı 95 siteyi kontrol etmek için curl_multi_exec kullanmak ~10 saniye sürdü. Açıkçası curl_exec kullanarak ne kadar çok site kontrol ederseniz, o kadar uzun sürer, ancak aynı şey curl_multi_exec için doğru değildir, bu yüzden böyle bir cron'u ölçeklendirmek için harikadır. Ayrıca, düzenli curl_exec istekleri kullanıyor olsaydım, bu hızda her 100 site için 1 sunucuya ihtiyacım olacağını (kontrolleri 60 saniye içinde tamamlayabileceğimden emin olmak için), eşzamanlı curl_multi_exec isteklerini kullanarak ihtiyaç duymadan önce potansiyel olarak binlerce istek çalıştırabileceğime dikkat edin. başka bir sunucu. Bu, küçük bir başlangıç ​​için büyük bir maliyet tasarrufu.

Sıradaki ne?

Bu çözüm, öngörülebilir bir gelecek için böyle bir cron işini ölçeklendirmenin ucuz bir yolu olsa da, kalıcı bir çözüm değildir. Web Uptime, şu anda bu tekniği kullanarak her ay yaklaşık 7 milyon kontrol çalıştırıyor ve her bir konumdaki tek bir sunucu iyi başa çıkıyor gibi görünüyor. Ancak, bir sunucunun kaynakları sonsuz değildir ve bu kontrolleri ölçeklendirmek için daha fazla sunucu eklemenin, hatta belki de tamamen farklı bir yaklaşımın gerekli olduğu zaman gelecektir. O zaman belki AWS Lambda gibi bir şeye boşaltmak daha mantıklı olabilir. Göreceğiz.

Hiç bir cron'u ölçeklendirmek zorunda kaldınız mı? Hiç curl_mutli işlevlerini kullandınız mı? Ölçeklendirme konusunda herhangi bir ipucunuz var mı? Yorumlarda bize bildirin.

Copyright statement: Unless otherwise noted, this article is Collected from the Internet, please keep the source of the article when reprinting.

Check Also

Divi's Theme Builder ile Özel Global Başlık Nasıl Oluşturulur

Artık Tema Oluşturucu burada olduğuna göre, web sitenizi A'dan Z'ye kurmanıza yardımcı olacak yeni eğitimlere dalmak için sabırsızlanıyoruz. Buna Divi'nin yerleşik seçeneğini kullanarak özel başlıklar oluşturma da dahildir. Bu eğitimde Divi's Theme Builder'ı kullanarak global bir başlık oluşturmaya odaklanacağız. Bu sayfaya veya gönderiye farklı bir başlık atamadıysanız, web sitenizin her yerinde genel bir başlık görünecektir.

Bir Cevap Yazın

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