Moskova Borsası ticaret ve takas sisteminin mimarisinin evrimi. Bölüm 2

Moskova Borsası ticaret ve takas sisteminin mimarisinin evrimi. Bölüm 2

Bu, Borsa'nın çalışmasını sağlayan güçlü, yüksek yüklü bir sistem yaratmaya yönelik zorlu yolumuz hakkındaki uzun hikayenin devamıdır. İlk bölüm burada: habr.com/en/post/444300

Gizemli hata

Çok sayıda testin ardından güncellenen ticaret ve takas sistemi devreye alındı ​​ve hakkında dedektif-mistik bir hikaye yazabileceğimiz bir hatayla karşı karşıya kaldık.

Ana sunucuda başlatıldıktan kısa bir süre sonra işlemlerden biri hatalı bir şekilde gerçekleştirildi. Ancak yedekleme sunucusunda her şey yolundaydı. Ana sunucudaki üssü hesaplamaya yönelik basit bir matematiksel işlemin gerçek argümandan olumsuz sonuç verdiği ortaya çıktı! Araştırmamıza devam ettik ve SSE2 kaydında kayan noktalı sayılarla çalışırken yuvarlamadan sorumlu olan bir bitte fark bulduk.

Yuvarlama bit seti ile üssü hesaplamak için basit bir test aracı yazdık. Kullandığımız RedHat Linux sürümünde, talihsiz bit eklendiğinde matematiksel fonksiyonla çalışırken bir hata olduğu ortaya çıktı. Bunu RedHat'a bildirdik, bir süre sonra onlardan bir yama aldık ve kullanıma sunduk. Hata artık oluşmuyor ancak bu parçanın nereden geldiği belli değil mi? Fonksiyon bundan sorumluydu fesetround Varsayılan hatayı bulmak için kodumuzu dikkatlice analiz ettik: tüm olası durumları kontrol ettik; yuvarlama kullanan tüm işlevlere baktım; başarısız bir oturumu yeniden oluşturmaya çalıştı; farklı seçeneklere sahip farklı derleyiciler kullanıldı; Statik ve dinamik analiz kullanıldı.

Hatanın nedeni bulunamadı.

Daha sonra donanımı kontrol etmeye başladılar: işlemcilerin yük testlerini gerçekleştirdiler; RAM'i kontrol ettim; Hatta tek bir hücrede çok düşük bir ihtimal olan çok bitli hata senaryosuna yönelik testler bile yaptık. Hiçbir faydası yok.

Sonunda yüksek enerji fiziği dünyasından bir teori üzerinde karara vardık: Yüksek enerjili bir parçacık veri merkezimize uçtu, kasanın duvarını deldi, işlemciye çarptı ve tetik mandalının o parçaya sıkışmasına neden oldu. Bu saçma teoriye "nötrino" adı verildi. Parçacık fiziğinden uzaksanız: nötrinolar neredeyse dış dünyayla etkileşime girmez ve kesinlikle işlemcinin çalışmasını etkileyemezler.

Arızanın nedeni bulunamadığı için "sorunlu" sunucu her ihtimale karşı kullanımdan kaldırıldı.

Bir süre sonra sıcak yedekleme sistemini geliştirmeye başladık: "sıcak yedekler" (sıcak) - eşzamansız kopyalar olarak adlandırılanları tanıttık. Farklı veri merkezlerinde bulunabilecek bir işlem akışı aldılar, ancak ısınmalar diğer sunucularla aktif olarak etkileşime girmedi.

Moskova Borsası ticaret ve takas sisteminin mimarisinin evrimi. Bölüm 2

Bu neden yapıldı? Yedekleme sunucusu arızalanırsa, ana sunucuya sıcak bağlantı yeni yedek olur. Yani, bir arıza sonrasında sistem, işlem seansının sonuna kadar tek bir ana sunucuda kalmaz.

Sistemin yeni versiyonu test edilip devreye alındığında ise yuvarlama biti hatası tekrar oluştu. Üstelik sıcak sunucuların sayısının artmasıyla birlikte hata daha sık görülmeye başlandı. Aynı zamanda somut bir kanıt olmadığı için satıcının gösterecek hiçbir şeyi yoktu.

Durumun bir sonraki analizi sırasında sorunun işletim sistemiyle ilgili olabileceğine dair bir teori ortaya çıktı. Sonsuz döngüde fonksiyon çağıran basit bir program yazdık fesetround, mevcut durumu hatırlar ve uyku aracılığıyla kontrol eder ve bu, birçok rakip iş parçacığında yapılır. Uyku parametrelerini ve iş parçacığı sayısını seçtikten sonra, yardımcı programı çalıştırdıktan yaklaşık 5 dakika sonra bit hatasını tutarlı bir şekilde yeniden oluşturmaya başladık. Ancak Red Hat desteği bunu yeniden oluşturamadı. Diğer sunucularımız üzerinde yapılan testler, yalnızca belirli işlemcilere sahip olanların hataya açık olduğunu göstermiştir. Aynı zamanda yeni bir çekirdeğe geçmek sorunu çözdü. Sonunda sadece işletim sistemini değiştirdik ve hatanın gerçek nedeni belirsizliğini korudu.

Ve aniden geçen yıl Habré hakkında bir makale yayınlandı “Intel Skylake işlemcilerinde nasıl bir hata buldum?" Burada anlatılan durum bizimkine çok benziyordu ancak yazar araştırmayı daha da ileri götürerek hatanın mikro kodda olduğuna dair bir teori ortaya attı. Ve Linux çekirdekleri güncellendiğinde üreticiler mikro kodu da günceller.

Sistemin daha da geliştirilmesi

Hatadan kurtulmamıza rağmen bu hikaye bizi sistem mimarisini yeniden düşünmeye zorladı. Sonuçta bu tür hataların tekrarından korunmadık.

Aşağıdaki ilkeler, rezervasyon sistemindeki sonraki iyileştirmelerin temelini oluşturdu:

  • Kimseye güvenemezsin. Sunucular düzgün çalışmayabilir.
  • Çoğunluk rezervasyonu.
  • Fikir birliğinin sağlanması. Çoğunluk rezervasyonuna mantıklı bir katkı olarak.
  • Çift arıza mümkündür.
  • Canlılık. Yeni sıcak bekleme şeması öncekinden daha kötü olmamalıdır. Ticaret son sunucuya kadar kesintisiz devam etmelidir.
  • Gecikmede hafif bir artış. Herhangi bir kesinti, büyük mali kayıplara neden olur.
  • Gecikmeyi mümkün olduğu kadar düşük tutmak için minimum ağ etkileşimi.
  • Saniyeler içinde yeni bir ana sunucu seçme.

Piyasadaki çözümlerin hiçbiri bize uymadı ve Raft protokolü henüz emekleme aşamasındaydı, bu nedenle kendi çözümümüzü oluşturduk.

Moskova Borsası ticaret ve takas sisteminin mimarisinin evrimi. Bölüm 2

Ağ oluşturma

Rezervasyon sistemine ek olarak ağ etkileşimini de modernleştirmeye başladık. G/Ç alt sistemi, titreşim ve gecikme üzerinde en kötü etkiye sahip olan birçok süreçten oluşuyordu. TCP bağlantılarını yöneten yüzlerce işlem nedeniyle bunlar arasında sürekli geçiş yapmak zorunda kalıyorduk ve mikrosaniye ölçeğinde bu oldukça zaman alıcı bir işlem. Ancak en kötü yanı, bir süreç işlenmek üzere bir paket aldığında, bunu bir SystemV kuyruğuna göndermesi ve ardından başka bir SystemV kuyruğundan bir olay beklemesidir. Bununla birlikte, çok sayıda düğüm olduğunda, bir süreçte yeni bir TCP paketinin gelmesi ve diğerinde kuyruktaki verilerin alınması, işletim sistemi için iki rakip olayı temsil eder. Bu durumda, her iki görev için de fiziksel işlemci yoksa biri işlenir, ikincisi ise bekleme kuyruğuna alınır. Sonuçlarını tahmin etmek imkansızdır.

Bu gibi durumlarda dinamik süreç öncelik kontrolü kullanılabilir ancak bu, kaynak yoğun sistem çağrılarının kullanılmasını gerektirecektir. Sonuç olarak, klasik epoll kullanarak tek iş parçacığına geçtik, bu, hızı büyük ölçüde artırdı ve işlem işlem süresini kısalttı. Ayrıca SystemV aracılığıyla ayrı ağ iletişim süreçlerinden ve iletişiminden kurtulduk, sistem çağrılarının sayısını önemli ölçüde azalttık ve operasyon önceliklerini kontrol etmeye başladık. Yalnızca I/O alt sisteminde senaryoya bağlı olarak yaklaşık 8-17 mikrosaniye tasarruf etmek mümkün oldu. Bu tek iş parçacıklı şema o zamandan beri değişmeden kullanıldı; kenar boşluğuna sahip bir epoll iş parçacığı tüm bağlantılara hizmet vermek için yeterlidir.

Hareket işleme

Sistemimizdeki artan yük, neredeyse tüm bileşenlerinin yükseltilmesini gerektiriyordu. Ancak ne yazık ki son yıllarda işlemci saat hızlarındaki büyümedeki durgunluk artık süreçleri doğrudan ölçeklendirmeyi mümkün kılmıyor. Bu nedenle Motor sürecini üç seviyeye ayırmaya karar verdik; bunların en yoğun olanı, hesaplardaki fon kullanılabilirliğini değerlendiren ve işlemleri kendisi oluşturan risk kontrol sistemidir. Ancak para farklı para birimlerinde olabilir ve taleplerin işlenmesinin hangi temelde bölünmesi gerektiğini bulmak gerekiyordu.

Mantıksal çözüm bunu para birimine bölmektir: bir sunucu dolar, diğeri pound ve üçüncüsü euro ile işlem yapar. Ancak böyle bir planla farklı para birimleri satın almak için iki işlem gönderilirse, cüzdan senkronizasyonunun bozulması sorunu ortaya çıkacaktır. Ancak senkronizasyon zor ve pahalıdır. Bu nedenle cüzdanlara göre ayrı, enstrümanlara göre ayrı ayrı parçalamak doğru olacaktır. Bu arada, Batılı borsaların çoğunun riskleri bizim kadar keskin bir şekilde kontrol etme görevi yok, bu nedenle çoğu zaman bu çevrimdışı yapılıyor. Çevrimiçi doğrulamayı uygulamamız gerekiyordu.

Bir örnekle açıklayalım. Bir tüccar 30 $ satın almak istiyor ve talep işlem doğrulamaya gidiyor: bu tüccarın bu ticaret moduna izin verilip verilmediğini ve gerekli haklara sahip olup olmadığını kontrol ediyoruz. Her şey yolundaysa istek risk doğrulama sistemine gider; bir işlemi sonuçlandırmak için fonların yeterliliğini kontrol etmek. Gerekli miktarın şu anda bloke edildiğine dair bir not var. Talep daha sonra işlemi onaylayan veya reddeden ticaret sistemine iletilir. Diyelim ki işlem onaylandı - daha sonra risk doğrulama sistemi paranın blokesinin kaldırıldığını ve rublelerin dolara dönüştüğünü işaret ediyor.

Genel olarak, risk kontrol sistemi karmaşık algoritmalar içerir ve çok miktarda kaynak yoğun hesaplamalar gerçekleştirir ve ilk bakışta göründüğü gibi yalnızca "hesap bakiyesini" kontrol etmez.

Engine sürecini seviyelere ayırmaya başladığımızda bir sorunla karşılaştık: O dönemde mevcut olan kod, tüm kod tabanının yeniden yazılmasını gerektiren doğrulama ve doğrulama aşamalarında aktif olarak aynı veri dizisini kullanıyordu. Sonuç olarak, modern işlemcilerden talimatları işlemek için bir teknik ödünç aldık: her biri küçük aşamalara bölünmüştür ve bir döngüde birkaç eylem paralel olarak gerçekleştirilir.

Moskova Borsası ticaret ve takas sisteminin mimarisinin evrimi. Bölüm 2

Kodun küçük bir uyarlamasından sonra, paralel işlem işleme için işlemin 4 aşamaya bölündüğü bir işlem hattı oluşturduk: ağ etkileşimi, doğrulama, yürütme ve sonucun yayınlanması

Moskova Borsası ticaret ve takas sisteminin mimarisinin evrimi. Bölüm 2

Bir örneğe bakalım. Seri ve paralel olmak üzere iki işlem sistemimiz var. İlk işlem gelir ve her iki sistemde de doğrulama için gönderilir. İkinci işlem hemen gelir: paralel bir sistemde hemen çalışmaya alınır ve sıralı bir sistemde, ilk işlemin mevcut işlem aşamasından geçmesini bekleyen bir sıraya konur. Yani, boru hattı işlemenin temel avantajı, işlem kuyruğunu daha hızlı işlememizdir.

ASTS+ sistemini bu şekilde ortaya çıkardık.

Doğru, konveyörlerde de her şey o kadar düzgün değil. Diyelim ki komşu bir işlemdeki veri dizilerini etkileyen bir işlemimiz var; bu bir borsa için tipik bir durumdur. Böyle bir işlem bir boru hattında yürütülemez çünkü başkalarını etkileyebilir. Bu duruma veri tehlikesi denir ve bu tür işlemler basitçe ayrı ayrı işlenir: kuyruktaki "hızlı" işlemler bittiğinde işlem hattı durur, sistem "yavaş" işlemi işler ve ardından işlem hattını yeniden başlatır. Neyse ki, bu tür işlemlerin genel akıştaki oranı çok küçüktür, dolayısıyla boru hattı o kadar nadiren durur ki genel performansı etkilemez.

Moskova Borsası ticaret ve takas sisteminin mimarisinin evrimi. Bölüm 2

Daha sonra üç yürütme iş parçacığının senkronize edilmesi sorununu çözmeye başladık. Sonuç, sabit boyutlu hücrelere sahip halka tamponuna dayalı bir sistemdi. Bu sistemde her şey işlem hızına tabidir, veriler kopyalanmaz.

  • Gelen tüm ağ paketleri tahsis aşamasına girer.
  • Bunları bir diziye yerleştirip 1. aşama için uygun olarak işaretliyoruz.
  • İkinci işlem geldi, yine 1. aşamaya geçildi.
  • İlk işlem dizisi mevcut işlemleri görür, bunları işler ve bunları ikinci işlem dizisinin bir sonraki aşamasına taşır.
  • Daha sonra ilk işlemi işler ve karşılık gelen hücreyi işaretler. deleted — artık yeni kullanıma hazır.

Sıranın tamamı bu şekilde işlenir.

Moskova Borsası ticaret ve takas sisteminin mimarisinin evrimi. Bölüm 2

Her aşamanın işlenmesi birimler veya onlarca mikrosaniye sürer. Ve eğer standart işletim sistemi senkronizasyon şemalarını kullanırsak, senkronizasyonun kendisinde daha fazla zaman kaybederiz. Bu yüzden spinlock kullanmaya başladık. Ancak gerçek zamanlı bir sistemde bu çok kötü bir formdur ve RedHat kesinlikle bunu yapmanızı önermez, bu nedenle 100 ms boyunca bir döndürme kilidi uyguluyoruz ve ardından kilitlenme olasılığını ortadan kaldırmak için semafor moduna geçiyoruz.

Bunun sonucunda saniyede 8 milyona yakın işlem performansına ulaştık. Ve kelimenin tam anlamıyla iki ay sonra Makale LMAX Disruptor hakkında aynı işlevselliğe sahip bir devrenin açıklamasını gördük.

Moskova Borsası ticaret ve takas sisteminin mimarisinin evrimi. Bölüm 2

Artık bir aşamada birden fazla yürütme iş parçacığı olabilir. Tüm işlemler alınış sırasına göre tek tek gerçekleştirildi. Bunun sonucunda en yüksek performans saniyede 18 bin işlemden 50 bin işleme yükseldi.

Döviz risk yönetim sistemi

Mükemmelliğin sınırı yok ve kısa sürede yeniden modernizasyona başladık: ASTS+ çerçevesinde risk yönetimi ve uzlaştırma operasyon sistemlerini otonom bileşenlere taşımaya başladık. Esnek, modern bir mimari ve yeni bir hiyerarşik risk modeli geliştirdik ve mümkün olan her yerde sınıfı kullanmaya çalıştık. fixed_point yerine double.

Ancak hemen bir sorun ortaya çıktı: Yıllardır çalışan tüm iş mantığı nasıl senkronize edilip yeni sisteme nasıl aktarılır? Sonuç olarak, yeni sistemin prototipinin ilk versiyonunun terk edilmesi gerekti. Şu anda üretimde çalışan ikinci versiyon, hem ticaret hem de risk kısımlarında çalışan aynı koda dayanmaktadır. Geliştirme sırasında yapılması en zor şey iki versiyon arasında git merge idi. Meslektaşımız Evgeniy Mazurenok bu operasyonu her hafta gerçekleştirdi ve her seferinde çok uzun süre küfretti.

Yeni bir sistem seçerken hemen etkileşim sorununu çözmemiz gerekiyordu. Bir veri yolu seçerken istikrarlı titreşim ve minimum gecikmeyi sağlamak gerekiyordu. InfiniBand RDMA ağı bunun için en uygunudur: ortalama işlem süresi 4 G Ethernet ağlarına göre 10 kat daha azdır. Ama bizi asıl büyüleyen yüzdelik dilimlerdeki farktı: 99 ve 99,9.

Elbette InfiniBand'ın da zorlukları var. İlk olarak, farklı bir API - yuvalar yerine fiiller. İkincisi, neredeyse hiç yaygın olarak kullanılabilen açık kaynaklı mesajlaşma çözümü yoktur. Kendi prototipimizi yapmaya çalıştık, ancak bunun çok zor olduğu ortaya çıktı, bu yüzden ticari bir çözüm seçtik: Confinity Low Latency Messaging (eski adıyla IBM MQ LLM).

Daha sonra risk sistemini doğru şekilde bölme görevi ortaya çıktı. Risk Motorunu kaldırırsanız ve bir ara düğüm oluşturmazsanız, iki kaynaktan gelen işlemler karıştırılabilir.

Moskova Borsası ticaret ve takas sisteminin mimarisinin evrimi. Bölüm 2

Ultra Düşük Gecikme adı verilen çözümler bir yeniden sıralama moduna sahiptir: iki kaynaktan gelen işlemler, alındıktan sonra gerekli sıraya göre düzenlenebilir; bu, siparişle ilgili bilgi alışverişi için ayrı bir kanal kullanılarak uygulanır. Ancak henüz bu modu kullanmıyoruz: tüm süreci zorlaştırıyor ve bazı çözümlerde hiç desteklenmiyor. Ek olarak, her işleme karşılık gelen zaman damgalarının atanması gerekir ve bizim planımızda bu mekanizmanın doğru şekilde uygulanması çok zordur. Bu nedenle klasik şemayı bir mesaj aracısıyla, yani Risk Motoru arasında mesajları dağıtan bir dağıtıcıyla kullandık.

İkinci sorun istemci erişimiyle ilgiliydi: Eğer birden fazla Risk Ağ Geçidi varsa, istemcinin bunların her birine bağlanması gerekir ve bu, istemci katmanında değişiklik yapılmasını gerektirir. Bu aşamada bundan uzaklaşmak istedik, böylece mevcut Risk Gateway tasarımı tüm veri akışını işliyor. Bu, maksimum verimi büyük ölçüde sınırlar ancak sistem entegrasyonunu büyük ölçüde basitleştirir.

kopya

Sistemimizde tek bir arıza noktası olmamalıdır, yani mesaj aracısı dahil tüm bileşenlerin kopyalanması gerekir. Bu sorunu CLLM sistemini kullanarak çözdük: iki dağıtıcının master-slave modunda çalışabildiği bir RCMS kümesi içeriyor ve biri arızalandığında sistem otomatik olarak diğerine geçiyor.

Yedek veri merkeziyle çalışma

InfiniBand, yerel bir ağ olarak çalışmak, yani rafa monte ekipmanı bağlamak için optimize edilmiştir ve bir InfiniBand ağı, coğrafi olarak dağıtılmış iki veri merkezi arasına yerleştirilemez. Bu nedenle, normal Ethernet ağları aracılığıyla mesaj deposuna bağlanan ve tüm işlemleri ikinci bir IB ağına aktaran bir köprü/gönderici uyguladık. Bir veri merkezinden geçiş yapmamız gerektiğinde hangi veri merkeziyle çalışacağımızı artık seçebiliyoruz.

sonuçlar

Yukarıdakilerin hepsi bir anda yapılmadı; yeni bir mimarinin geliştirilmesi birkaç kez tekrarlandı. Prototipi bir ayda yarattık ama çalışır duruma gelmesi iki yıldan fazla sürdü. Artan işlem işlem süresi ile artan sistem güvenilirliği arasındaki en iyi uzlaşmayı sağlamaya çalıştık.

Sistem yoğun bir şekilde güncellendiğinden veri kurtarmayı iki bağımsız kaynaktan uyguladık. Mesaj deposu herhangi bir nedenden dolayı düzgün çalışmıyorsa, işlem günlüğünü ikinci bir kaynaktan, Risk Motorundan alabilirsiniz. Bu prensip sistemin tamamında gözetilmektedir.

Diğer şeylerin yanı sıra, istemci API'sini korumayı başardık, böylece ne komisyoncular ne de başkaları yeni mimari için ciddi bir yeniden çalışma gerektirmeyecek. Bazı arayüzleri değiştirmek zorunda kaldık ama işletim modelinde önemli değişiklikler yapmaya gerek yoktu.

Platformumuzun mevcut versiyonunu, mimarideki en dikkat çekici iki yeniliğin kısaltması olan Risk Engine ve BUS'un kısaltması olarak Rebus olarak adlandırdık.

Moskova Borsası ticaret ve takas sisteminin mimarisinin evrimi. Bölüm 2

Başlangıçta sadece temizleme kısmını tahsis etmek istedik ancak sonuç devasa bir dağıtılmış sistem oldu. Müşteriler artık Ticaret Ağ Geçidi, Takas Ağ Geçidi veya her ikisi ile etkileşime girebilir.

Sonuçta ne başardık:

Moskova Borsası ticaret ve takas sisteminin mimarisinin evrimi. Bölüm 2

Gecikme düzeyi azaltıldı. Küçük işlem hacimlerinde sistem önceki sürümle aynı şekilde çalışır ancak aynı zamanda çok daha yüksek bir yüke de dayanabilir.

Zirve performansı saniyede 50 bin işlemden 180 bin işleme yükseldi. Daha fazla artış, yalnızca sipariş eşleştirme akışı nedeniyle engellenmektedir.

Daha fazla iyileştirmenin iki yolu vardır: eşleştirmeyi paralel hale getirmek ve Gateway ile çalışma şeklini değiştirmek. Artık tüm Ağ Geçitleri, böyle bir yük altında normal şekilde çalışmayı bırakan bir kopyalama şemasına göre çalışmaktadır.

Son olarak kurumsal sistemlere son verecek olanlara bazı tavsiyelerde bulunabilirim:

  • Her zaman en kötüsüne hazırlıklı olun. Sorunlar her zaman beklenmedik bir şekilde ortaya çıkar.
  • Mimariyi hızlı bir şekilde yeniden yapmak genellikle imkansızdır. Özellikle birden fazla göstergede maksimum güvenilirliğe ulaşmanız gerekiyorsa. Ne kadar çok düğüm olursa, destek için o kadar çok kaynak gerekir.
  • Tüm özel ve tescilli çözümler, araştırma, destek ve bakım için ek kaynaklar gerektirecektir.
  • Arızalardan sonra sistem güvenilirliği ve kurtarma sorunlarını çözmeyi ertelemeyin; bunları ilk tasarım aşamasında dikkate alın.

Kaynak: habr.com

Yorum ekle