1 TB/sn hızında arama yapın

TL;DR: Dört yıl önce Google'dan yeni bir sunucu izleme aracı fikriyle ayrıldım. Buradaki fikir, genellikle izole edilmiş işlevleri tek bir hizmette birleştirmekti. koleksiyon ve günlük analizi, metriklerin toplanması, uyarılar ve kontrol panelleri. İlkelerden biri, hizmetin gerçekten olması gerektiğidir. hızlıgeliştiricilere kolay, etkileşimli ve keyifli bir deneyim sunuyor. Bu, bütçeyi aşmadan, çok gigabaytlık veri setlerinin saniyeden çok daha kısa sürede işlenmesini gerektirir. Mevcut günlük yönetimi araçları genellikle yavaş ve hantal olduğundan büyük bir zorlukla karşı karşıya kaldık: kullanıcılara yeni bir deneyim sunacak bir aracı akıllıca tasarlamak.

Bu makalede, Scalyr olarak eski usul yöntemleri, kaba kuvvet yaklaşımını uygulayarak, gereksiz katmanları ortadan kaldırarak ve karmaşık veri yapılarından kaçınarak bu sorunu nasıl çözdüğümüz açıklanmaktadır. Bu dersleri kendi mühendislik problemlerinize uygulayabilirsiniz.

Eski Okul Gücü

Günlük analizi genellikle bir aramayla başlar: belirli bir kalıpla eşleşen tüm mesajları bulun. Scalyr'de bunlar birçok sunucudan gelen onlarca veya yüzlerce gigabaytlık günlüklerdir. Modern yaklaşımlar, kural olarak, arama için optimize edilmiş bazı karmaşık veri yapılarının oluşturulmasını içerir. Bunu kesinlikle Google'da gördüm, bu tür şeylerde oldukça iyiler. Ancak biz çok daha kaba bir yaklaşıma karar verdik: günlüklerin doğrusal taranması. Ve işe yaradı; rakiplerimizden çok daha hızlı, aranabilir bir arayüz sağlıyoruz (sondaki animasyona bakın).

Temel fikir, modern işlemcilerin basit ve anlaşılır işlemlerde gerçekten çok hızlı olduğuydu. G/Ç hızına ve ağ işlemlerine dayanan karmaşık, çok katmanlı sistemlerde bunun gözden kaçırılması kolaydır ve bu tür sistemler günümüzde çok yaygındır. Bu nedenle katmanları ve fazla kalıntıları en aza indiren bir tasarım geliştirdik. Birden fazla işlemci ve sunucunun paralel çalışmasıyla arama hızı saniyede 1 TB'a ulaşır.

Bu makaleden önemli çıkarımlar:

  • Kaba kuvvet araması, gerçek dünyadaki büyük ölçekli sorunları çözmek için geçerli bir yaklaşımdır.
  • Kaba kuvvet bir tasarım tekniğidir, iş gerektirmeyen bir çözüm değildir. Her teknik gibi, bazı problemlere diğerlerinden daha uygundur ve iyi ya da kötü uygulanabilir.
  • Kaba kuvvet özellikle başarıya ulaşmak için iyidir kararlı üretkenlik.
  • Kaba kuvvetin etkili kullanımı, kodun optimize edilmesini ve yeterli kaynakların doğru zamanda uygulanmasını gerektirir. Sunucularınızın kullanıcı dışı yoğun yük altında olması ve kullanıcı işlemlerinin öncelikli kalması durumunda uygundur.
  • Performans sadece iç döngü algoritmasına değil, tüm sistemin tasarımına bağlıdır.

(Bu makalede bellekteki verinin aranması açıklanmaktadır. Çoğu durumda, bir kullanıcı bir günlük araması yaptığında, Scalyr sunucuları bunu zaten önbelleğe almıştır. Sonraki makale önbelleğe alınmamış günlüklerin aranmasını tartışacaktır. Aynı ilkeler geçerlidir: verimli kod, kaba kuvvet büyük hesaplama kaynaklarına sahip).

Kaba kuvvet yöntemi

Geleneksel olarak, büyük bir veri kümesi bir anahtar kelime dizini kullanılarak aranır. Sunucu günlüklerine uygulandığında bu, günlükteki her benzersiz kelimenin aranması anlamına gelir. Her kelime için tüm eklemelerin bir listesini yapmanız gerekir. Bu, bu kelimeyi içeren tüm mesajları bulmayı kolaylaştırır; örneğin 'error', 'firefox' veya "transaction_16851951" - dizine bakmanız yeterli.

Bu yaklaşımı Google'da kullandım ve işe yaradı. Ancak Scalyr'de günlükleri bayt bayt ararız.

Neden? Soyut algoritmik bir bakış açısından, anahtar kelime indeksleri kaba kuvvet aramalarından çok daha etkilidir. Ancak biz algoritma satmıyoruz, performans satıyoruz. Ve performans sadece algoritmalarla ilgili değil aynı zamanda sistem mühendisliğiyle de ilgilidir. Her şeyi göz önünde bulundurmalıyız: veri hacmi, arama türü, mevcut donanım ve yazılım bağlamı. Özel problemimiz için 'grep' gibi bir şeyin indeksten daha uygun olduğuna karar verdik.

Dizinler harikadır ancak sınırlamaları vardır. Bir kelimeyi bulmak kolaydır. Ancak 'googlebot' ve '404' gibi birden fazla kelime içeren mesajları aramak çok daha zordur. 'Yakalanmamış istisna' gibi bir ifadeyi aramak, yalnızca o kelimeyi içeren tüm mesajları değil, aynı zamanda kelimenin belirli konumunu da kaydeden daha hantal bir dizin gerektirir.

Asıl zorluk, kelimeleri aramadığınızda ortaya çıkar. Diyelim ki botlardan ne kadar trafik geldiğini görmek istiyorsunuz. İlk düşünce, günlüklerde 'bot' kelimesini aramaktır. Bazı botları bu şekilde bulacaksınız: Googlebot, Bingbot ve diğerleri. Ama burada 'bot' bir kelime değil, onun bir parçası. Dizinde 'bot' diye arama yaparsak 'Googlebot' kelimesini içeren herhangi bir yayın bulamayız. Dizindeki her kelimeyi kontrol edip ardından bulunan anahtar kelimeler için dizini tararsanız, arama büyük ölçüde yavaşlayacaktır. Sonuç olarak, bazı günlük programları kısmi sözcük aramalarına izin vermez veya (en iyi ihtimalle) daha düşük performansa sahip özel sözdizimine izin verir. Biz bundan kaçınmak istiyoruz.

Bir diğer sorun ise noktalama işaretleri. Tüm istekleri bulmak istiyor musunuz? 50.168.29.7? Aşağıdakileri içeren hata ayıklama günlüklerine ne dersiniz? [error]? Abonelikler genellikle noktalama işaretlerini atlar.

Son olarak mühendisler güçlü araçları severler ve bazen bir sorun yalnızca düzenli ifadeyle çözülebilir. Anahtar kelime dizini bunun için pek uygun değil.

Ayrıca endeksler karmaşık. Her mesajın birkaç anahtar kelime listesine eklenmesi gerekir. Bu listeler her zaman kolayca aranabilecek bir formatta tutulmalıdır. Cümlecikler, sözcük parçaları veya normal ifadeler içeren sorguların çok listeli işlemlere çevrilmesi ve sonuçların bir sonuç kümesi oluşturmak için taranması ve birleştirilmesi gerekir. Büyük ölçekli, çok kiracılı bir hizmet bağlamında bu karmaşıklık, algoritmalar analiz edilirken görülemeyen performans sorunları yaratır.

Anahtar kelime dizinleri de çok fazla yer kaplar ve depolama, günlük yönetim sisteminde büyük bir maliyettir.

Öte yandan, her arama çok fazla bilgi işlem gücü tüketebilir. Kullanıcılarımız benzersiz sorgular için yüksek hızlı aramaları takdir ediyor, ancak bu tür sorgular nispeten nadiren yapılıyor. Tipik arama sorguları için, örneğin bir kontrol paneli için, özel teknikler kullanırız (bunları bir sonraki makalede açıklayacağız). Diğer istekler o kadar nadirdir ki aynı anda birden fazla isteği işlemek zorunda kalmazsınız. Ancak bu, sunucularımızın meşgul olmadığı anlamına gelmez: yeni mesajları alma, analiz etme ve sıkıştırma, uyarıları değerlendirme, eski verileri sıkıştırma vb. işlerle meşguller. Bu nedenle, sorguları yürütmek için kullanılabilecek oldukça önemli bir işlemci kaynağımız var.

Kaba kuvvet, kaba bir sorununuz varsa (ve çok fazla güç) işe yarar

Kaba kuvvet, küçük iç döngülere sahip basit problemlerde en iyi sonucu verir. Çoğunlukla dahili döngüyü çok yüksek hızlarda çalışacak şekilde optimize edebilirsiniz. Kod karmaşıksa optimize etmek çok daha zordur.

Arama kodumuzun başlangıçta oldukça büyük bir iç döngüsü vardı. Mesajları sayfalarda 4K'da saklıyoruz; her sayfada bazı mesajlar (UTF-8'de) ve her mesaj için meta veriler bulunur. Meta veriler, değerin uzunluğunu, dahili mesaj kimliğini ve diğer alanları kodlayan bir yapıdır. Arama döngüsü şöyle görünüyordu:

1 TB/sn hızında arama yapın

Bu, gerçek kodun basitleştirilmiş bir versiyonudur. Ancak burada bile birden fazla nesne yerleşimi, veri kopyası ve işlev çağrıları görülebilir. JVM, işlev çağrılarını optimize etme ve geçici nesneleri ayırma konusunda oldukça iyidir, dolayısıyla bu kod hak ettiğimizden daha iyi çalıştı. Testler sırasında müşteriler bunu oldukça başarılı bir şekilde kullandılar. Ama sonunda bunu bir sonraki aşamaya taşıdık.

(Günlüklerle doğrudan çalışmak yerine, neden mesajları 4K sayfa, metin ve meta verilerle bu formatta sakladığımızı sorabilirsiniz. Dahili olarak Scalyr motorunun bir veri tabanından çok dağıtılmış bir veritabanına benzediği gerçeğine indirgenen birçok neden vardır. dosya sistemi. Metin arama genellikle günlük ayrıştırma sonrasında kenar boşluklarında DBMS tarzı filtrelerle birleştirilir. Aynı anda binlerce günlüğü aynı anda arayabiliriz ve basit metin dosyaları işlemsel, çoğaltılmış, dağıtılmış veri yönetimimiz için uygun değildir).

Başlangıçta bu tür bir kodun kaba kuvvet optimizasyonu için pek uygun olmadığı görüldü. "Gerçek iş" String.indexOf() CPU profiline bile hakim değildi. Yani tek başına bu yöntemin optimizasyonu önemli bir etki yaratmayacaktır.

Meta verileri her sayfanın başında saklıyoruz ve tüm mesajların metni UTF-8'de sayfanın diğer ucunda paketleniyor. Bundan yararlanarak, tüm sayfayı aynı anda aramak için döngüyü yeniden yazdık:

1 TB/sn hızında arama yapın

Bu sürüm doğrudan görünümde çalışır raw byte[] ve 4K sayfanın tamamındaki tüm mesajları aynı anda arar.

Kaba kuvvet yöntemi için bunu optimize etmek çok daha kolaydır. Dahili arama döngüsü, her gönderide ayrı ayrı çağrılmak yerine 4K sayfanın tamamı için aynı anda çağrılır. Verilerin kopyalanması veya nesnelerin tahsisi yoktur. Ve daha karmaşık meta veri işlemleri, her mesajda değil, yalnızca sonuç olumlu olduğunda çağrılır. Bu şekilde bir ton ek yükü ortadan kaldırdık ve yükün geri kalanı, daha fazla optimizasyon için çok uygun olan küçük bir dahili arama döngüsünde yoğunlaştı.

Gerçek arama algoritmamız şunları temel alır: Leonid Volnitsky'nin harika fikri. Boyer-Moore algoritmasına benzer, her adımda arama dizisinin yaklaşık uzunluğunu atlar. Temel fark, yanlış eşleşmeleri en aza indirmek için aynı anda iki baytı kontrol etmesidir.

Uygulamamız, her arama için 64K'lık bir arama tablosu oluşturmayı gerektiriyor, ancak bu, araştırdığımız gigabaytlarca veriyle karşılaştırıldığında hiçbir şey değil. İç döngü, tek bir çekirdekte saniyede birkaç gigabaytı işler. Uygulamada, her çekirdekte istikrarlı performans saniyede 1,25 GB civarındadır ve geliştirilmeye yer vardır. İç döngünün dışındaki ek yükün bir kısmını ortadan kaldırmak mümkündür ve Java yerine C'de bir iç döngü denemeyi planlıyoruz.

Güç kullanıyoruz

Günlük aramanın "kabaca" uygulanabileceğini tartıştık, ancak ne kadar "gücümüz" var? Bayağı çok.

1 yaşında: Modern bir işlemcinin tek çekirdeği, doğru kullanıldığında başlı başına oldukça güçlüdür.

8 çekirdek: Şu anda her biri 1.4 çekirdekli (2.4 iş parçacığı) Amazon hi8xlarge ve i16xlarge SSD sunucularında çalışıyoruz. Yukarıda da bahsettiğimiz gibi bu çekirdekler genellikle arka plan işlemleriyle meşgul. Kullanıcı bir arama yaptığında arka plan işlemleri askıya alınır ve 8 çekirdeğin tamamı arama için serbest bırakılır. Arama genellikle bir saniyede tamamlanır ve ardından arka plan çalışması devam eder (kısma programı, arama sorguları barajının arka plandaki önemli çalışmaları engellememesini sağlar).

16 çekirdek: Güvenilirlik için sunucuları ana/bağımlı gruplar halinde düzenliyoruz. Her master'ın emrinde bir adet SSD ve bir adet EBS sunucusu bulunmaktadır. Ana sunucunun çökmesi durumunda yerini hemen SSD sunucusu alır. Neredeyse her zaman, ana ve yardımcı sunucu iyi çalışır, böylece her veri bloğu iki farklı sunucuda aranabilir (EBS ikincil sunucunun zayıf bir işlemcisi vardır, bu nedenle bunu dikkate almıyoruz). Görevi aralarında paylaştırıyoruz, böylece toplam 16 çekirdeğe sahip oluyoruz.

Birçok çekirdek: Yakın gelecekte, verileri sunucular arasında, hepsinin önemsiz olmayan her isteğin işlenmesine katılmasını sağlayacak şekilde dağıtacağız. Her çekirdek çalışacaktır. [Not: planı uyguladık ve arama hızını 1 TB/s'ye çıkardık, makalenin sonundaki nota bakın].

Basitlik güvenilirliği garanti eder

Kaba kuvvet yönteminin bir diğer avantajı da oldukça tutarlı performansıdır. Tipik olarak arama, sorunun ve veri kümesinin ayrıntılarına çok duyarlı değildir (sanırım bu yüzden buna "kaba" deniyor).

Anahtar kelime dizini bazen inanılmaz derecede hızlı sonuçlar üretir, bazen de üretmez. Diyelim ki 'müşteri_50' teriminin tam olarak üç kez geçtiği 5987235982 GB'lık günlükleriniz var. Bu terimin aranması doğrudan dizindeki üç konumu sayar ve anında tamamlanır. Ancak karmaşık joker karakter aramaları binlerce anahtar kelimeyi tarayabilir ve uzun zaman alabilir.

Öte yandan, kaba kuvvet aramaları herhangi bir sorgu için aşağı yukarı aynı hızda gerçekleştirilir. Uzun kelimeleri aramak daha iyidir ancak tek bir karakteri aramak bile oldukça hızlıdır.

Kaba kuvvet yönteminin basitliği, performansının teorik maksimuma yakın olduğu anlamına gelir. Beklenmeyen disk aşırı yüklemeleri, kilit çekişmeleri, işaretçi takibi ve diğer binlerce başarısızlık nedeni için daha az seçenek vardır. Geçen hafta Scalyr kullanıcılarının en yoğun sunucumuzda yaptığı isteklere baktım. 14 talep vardı. Tam olarak sekiz tanesi bir saniyeden fazla sürdü; %000'u 99 milisaniyede tamamlandı (günlük analiz araçlarını kullanmadıysanız bana güvenin: hızlı).

Hizmetin kullanım kolaylığı açısından istikrarlı, güvenilir performans önemlidir. Periyodik olarak gecikme olursa, kullanıcılar onu güvenilmez olarak algılayacak ve kullanmakta isteksiz olacaklardır.

Günlük araması eylem halinde

Burada Scalyr aramasını çalışırken gösteren kısa bir animasyon var. Her halka açık Github deposundaki her etkinliği içe aktardığımız bir demo hesabımız var. Bu demoda bir haftalık veriyi inceliyorum: yaklaşık 600 MB ham log.

Video, özel bir hazırlık yapılmadan masaüstümde (sunucudan yaklaşık 5000 kilometre uzakta) canlı olarak kaydedildi. Göreceğiniz performans büyük ölçüde şunlara bağlıdır: web istemcisi optimizasyonu, ayrıca hızlı ve güvenilir bir arka uç. 'Yükleniyor' göstergesi olmayan bir duraklama olduğunda, basmak üzere olduğum şeyi okuyabilmeniz için ben duraklıyorum.

1 TB/sn hızında arama yapın

Sonuç olarak

Büyük miktarda veriyi işlerken iyi bir algoritma seçmek önemlidir ancak “iyi”, “süslü” anlamına gelmez. Kodunuzun pratikte nasıl çalışacağını düşünün. Algoritmaların teorik analizi, gerçek dünyada büyük önem taşıyabilecek bazı faktörleri dışarıda bırakır. Daha basit algoritmaların optimize edilmesi daha kolaydır ve uç durumlarda daha kararlıdır.

Ayrıca kodun yürütüleceği bağlamı da düşünün. Bizim durumumuzda arka plan görevlerini yönetmek için yeterince güçlü sunuculara ihtiyacımız var. Kullanıcılar aramaları nispeten seyrek başlatır, böylece her aramayı tamamlamak için gereken kısa süre boyunca bir grup sunucunun tamamını ödünç alabiliriz.

Kaba kuvvet yöntemi kullanarak bir dizi günlükte hızlı, güvenilir ve esnek bir arama uyguladık. Bu fikirlerin projeleriniz için yararlı olacağını umuyoruz.

değiştir: Başlık ve metin, son birkaç yıldaki performans artışlarını yansıtacak şekilde "Saniyede 20 GB'ta arama" yerine "Saniyede 1 TB'de arama" olarak değiştirildi. Hızdaki bu artışın temel nedeni, artan müşteri tabanımıza hizmet vermek için bugün kurduğumuz EC2 sunucularının türü ve sayısındaki değişikliklerdir. Yakında operasyonel verimlilikte çarpıcı bir artış sağlayacak değişiklikler olacak ve bunları paylaşmak için sabırsızlanıyoruz.

Kaynak: habr.com

Yorum ekle