Xiaomi açık kaynak dağıtılmış KV depolama sistemi Pegasus

Yazar Sun Weijie

Düzenle Xiaozhi

Xiaomi kısa süre önce dağıtılmış KV depolama sistemi Pegasus'u açtı.Bu Xiaomi'nin kendi kendine yaptığı jantların arkasındaki tasarım konseptleri ve teknik detaylar neler?

Önüne yaz

Bu sefer size getirdiğim tema "Şeylerin Dağıtık Gerçekleşmesi - Pegasus'un Arkasındaki Hikaye". Bu konuşmada Pegasus'un mimarisi ve uygulamasında karşılaştığımız bazı tuzakları açıklamaya odaklandım.

Xiaomi'den geliyorum ve ağırlıklı olarak Pegasus'un araştırma ve geliştirmesini yapıyorum. Pegasus, Xiaomi tarafından üretilen dağıtılmış bir KV depolama çarkıdır. Tekerlek yapmak hakkında ne düşündüğünüzü bilmiyorum. Bana kalırsa, tekerlek yapmaktan kaçınılmalıdır. Sorunu çözebilecek daha iyi bir çözüm varsa, önce diğer çözümler kullanılmalı; işin gelişmesiyle birlikte seçilebilecek iyi bir çözüm olmadıkça, sadece bir tane kendimiz oluşturabiliriz.

Pegasus yapma süreci bu şekilde.

Pegasus'un doğuşu

Pegasus projesi kurulmadan önce, Xiaomi'nin dağıtılmış depolaması çoğunlukla HBase kullanıyordu. 10 yıldan fazla geliştirmenin ardından, HBase'nin kendisi nispeten kararlıdır ve işlevsel arayüzleri de daha uygundur. Bununla birlikte, tasarım ve uygulamadaki bazı sorunlar nedeniyle, hala kullanımda olan bazı tuzaklar var.

Bir HBase kazasını hatırla

HBase'nin mimarisine aşina olmanız gerektiğine inanıyorum. Yukarıdaki şekilde gösterildiği gibi, HBase, tüm kümenin durumunu yönetmek için bir Ana düğüme sahiptir. Ana düğümün genel yönetimi altında, Bölge Sunucusu düğümü, istemci okuma ve yazma isteklerinden sorumludur; Bölge Sunucusunun verileri, harici bir dağıtılmış dosya sistemi HDFS'de depolanır. Zookeeper, Bölge Sunucusunun kalp atışı tespitinden ve Master'ın yüksek kullanılabilirliğinden sorumludur.

Aslında onu kullandığımızda, Zookeeper'dan birçok sorun ortaya çıkıyor. Zookeeper, tasarımının başlangıcında nispeten düşük yük gerektiren bir sistemdi ve bu nedenle, Xiaomi tarafında, Zookeeper çoğunlukla birden fazla işletme tarafından kullanılıyordu. HBase'e ek olarak, diğer birçok işletme düğüm tespiti ve hizmet kaydı için Zookeeper'a güveniyor. Ancak, bazı işletmeler Zookeeper'ı kullandığında, Zookeeper'a aşırı baskı uygulayacak ve bu da Zookeeper'ın istikrarsızlığına yol açacaktır. Ek olarak, erişim sırasında soket bağlantılarını paylaşmama gibi Zookeeper'ın bazı yanlış kullanımları da Zookeeper hizmetinde istikrarsızlık kaynaklarıdır.

Çeşitli yanlış kullanım faktörlerinin varlığı, Zookeeper'ın sık sık çökmelerle karşılaşmasına neden olacaktır. HBase için, Zookeeper'ın çökmesi, Bölge Sunucusunun da çökmesi anlamına gelir. Xiaomi'nin işletmelerinin çoğu HBase'e güveniyor. HBase çöktüğünde, Xiaomi'nin işletmelerinin çoğu hizmet sağlayamayacak.

HBase'nin eksiklikleri

Bir dizi HBase sorununu inceledikten sonra, bahsetmeye değer birkaç nokta olduğunu düşünüyoruz:

1. HBase söz konusu olduğunda, önemli "düğüm algılama" görevini Zookeeper'a devretmesi tartışmaya açıktır. Çünkü operasyon ve bakım yeterince detaylı değilse Zookeeper, HBase'nin stabilitesini etkileyen bir çukur haline gelecektir.

HBase'de, Bölge Sunucusu "Zookeeper oturumu zaman aşımını" "intihar" olarak ele alır. Bölge Sunucusunda, "birden çok bölgenin birlikte HDFS'ye WAL yazması" uygulaması, "intiharın" maliyetini artıracaktır, çünkü intihardan sonra WAL bölünecek ve sunucu yeniden başlatıldığında yeniden oynatılacaktır. Bu, HBase kümesinin tamamı kapalıysa, HBase'i yeniden yukarı çekmenin uzun zaman alacağı anlamına gelir.

2. Zookeeper'ın kararlılığını garanti edebilsek bile, "düğüm algılama" işlevi çok kararlı bir şekilde çalışamaz. Çünkü HBase Java'da uygulanmaktadır. GC'nin varlığı, Zookeeper'ın normal olarak çalışan Bölge Sunucusunu yanlış olarak değerlendirmesine neden olacak ve bu da Bölge Sunucusunun intiharını tetikleyecektir; bunun üzerindeki Bölge, hizmetleri sağlamak için diğer sunucuların HDFS'den WAL'ı yüklemesini ve yeniden oynatmasını gerektirir. Ve bu süreç aynı zamanda nispeten zaman alıcıdır. Bu süre zarfında, Bölge tarafından sunulan anahtarlar okunamaz ve yazılabilir değildir.

Bu sorun, "düğüm tespiti" nin zaman eşiği uzatılarak çözülebilir. Ancak bu, gerçek "Bölge Sunucusu ölümünü" zamanında keşfedilemez hale getirecek ve diğer tarafta kullanılabilirlik sorunlarına neden olacaktır.

3. GC ile ilgili diğer bir sorun, HBase'nin okuma ve yazma gecikmelerinde aksaklıklara sahip olmasıdır. Bu tür aksaklıkların reklam ve tavsiyelerde olabildiğince önlenebileceğini, yani nispeten istikrarlı bir gecikme olabileceğini umuyoruz.

Yukarıdaki üç noktayı özetleyerek, HBase'nin kullanılabilirlik ve performans gecikmesi açısından hala bazı kusurları olduğuna inanıyoruz. Bu sorunlar, parametrelerin onarılması ve ayarlanmasıyla hafifletilebilir. Ancak bunu temelden çözmek kolay değil.

Pegasus konumlandırma

HBase alamadığımız için, birini kendimiz yeniden oluşturmalıyız. HBase gibi bir ölçüt olduğu için, konumlandırmada da çok netiz: HBase'yi tamamlamak için. Özellikle:

  • HBase'in tutarlı görünümü ve dinamik ölçeklendirmesi, korumayı umduğumuz depolama sistemindeki iki çok iyi özelliktir;

  • HBase'in performans gecikmesi ve kullanılabilirlik sorunları için, sistemi daha fazla iş kullanımı için kapsayacak şekilde mimari ve uygulama yoluyla telafi etmeliyiz.

Bu konumlandırmalarla, mimarimiz de nispeten net bir şekilde ortaya çıktı:

Bir bakışta Pegasus mimarisi

Genel olarak, mimari çok sayıda HBase içeriğine dayanır:

  • Pegasus aynı zamanda merkezi yönetime sahip dağıtılmış bir depolama sistemidir. MetaServer, HBase'in HMaster'ına benzer şekilde kümenin küresel durumunu yönetmekten sorumludur; ReplicaServer, HBase'nin RegionServer'ına benzer şekilde veri okuma ve yazmadan sorumludur.

  • Ölçeklenebilirlik hususları için, anahtarı farklı bölümlere de ayırıyoruz.

HBase'den farkı şudur:

  • Heartbeat, Zookeeper'a dayanmaz, ancak ayrı olarak çıkarılır ve doğrudan MetaServer tarafından yönetilir

  • Veriler üçüncü taraf DFS'ye yazılmaz, ancak doğrudan ReplicaServer'a düşer.

  • Tek bir ReplicaServer arızasıyla mücadele etmek için, her Partition'da farklı ReplicaServer'lara dağıtılan üç kopya bulunur.

Şu anda, MetaServer'ın yüksek kullanılabilirliği, proje geliştirmenin basitliği için bir avantaj olan Zookeeper'a dayanmaktadır. Sal, Zookeeper'a olan bağımlılığı tamamen ortadan kaldırmak için daha sonra tanıtılabilir.

Çok kopyalı konsensüs protokolü

Daha önce de belirtildiği gibi, Bölümlerimizin her birinin birden fazla kopyası vardır. Birden fazla kopya durumunda güçlü tutarlılığı karşılamak için, bir konsensüs protokol algoritması benimsemeliyiz. MSRA tarafından yayınlanan PacificA'yı kullanıyoruz. PacificA ve Raft arasındaki karşılaştırma için lütfen burada ayrıntılı olarak açıklanmayacak olan github projesindeki belgelerimize bakın. Genel olarak, PacificA'nın raporuna göre kullanılabilir bir depolama sistemi uygulamanın Raft'tan daha az zor olduğuna inanıyoruz.

Pegasus yazma talebi süreci

PacificA protokolünde, okuma ve yazma taleplerini kabul etmekten sorumlu olan, Raft'taki lidere eşdeğer olan birincil olarak adlandırılır; replikasyon isteklerini kabul eden diğer ikisi ikincildir ve bu Raft'taki takipçiye eşdeğerdir. Bu mimaride, bir bölüme yazma isteği de nispeten basittir: İstemcinin bir yazma isteği varsa, önce MetaServer'dan anahtarın konumunu sorgulaması ve ardından birincilin bulunduğu ReplicaServer'a bir yazma isteği başlatması ve ardından birincil bunu ikincil ile senkronize etmesi gerekir. , Her ikisi de başarılı olduktan sonra, müşteri başarılı bir yanıt yazar.

Pegasus okuma talebi akış şeması

Okuma isteği işlemi daha basittir İstemci, birincil ile doğrudan bir okuma isteği başlatır ve birincil, tüm verilere sahip olduğu için doğrudan yanıt verir.

Gerçekleştirmeyle ilgili çukurlar

Bir önceki bölümde Pegasus'un tasarım konuları ve genel mimarisi kısaca gözden geçirildi. Şimdi konumuza geçelim, böyle bir mimarinin uygulama problemlerine bir bakalım?

Ölçeklenebilirlik

Önce ölçeklenebilirliğe bakın. Ölçeklenebilirlik iki noktaya ayrılmıştır:

  • Bölüm şeması sorunu: tam bir anahtar alanının farklı bölümlere nasıl bölüneceği;

  • Yük dengesi sorunu: Bölme şeması belirlenirse, bu parçaların daha iyi bir algoritma kullanılarak farklı makinelere nasıl bölüneceği.

Bölüm şeması seçimi

Bölme şeması için, endüstride genellikle iki çözüm vardır, birincisi hashing ve ikincisi de sıralama.

Karma oluşturma için tüm anahtarlar birçok gruba bölünür. Bir kova bir bölümdür ve daha sonra anahtarın karma değerine göre bir kovaya atanır; sıralama için tüm anahtarlar başlangıçta tek bir kova içindedir. Ardından kepçe kapasitesine göre dinamik olarak bölün ve birleştirin.

Bu iki şemayı karşılaştırdığımızda, sıralamanın hashingden daha fazla doğal avantajı, sıralama şemasının global bir sıralama etkisine sahip olmasıdır. Bununla birlikte, sıralama sürekli dinamik bölme gerektirdiğinden, uygulanması daha zahmetlidir.

Ek olarak, karma bölüm şeması kullanılıyorsa, veritabanı iş erişim modelleri nedeniyle önemli sorunlara eğilimli değildir. Sıralama Tüm anahtarlar sırayla düzenlendiğinden, aynı ön eke sahip istekler büyük olasılıkla bir veya bitişik bölümlerde yoğunlaşır ve bu istekler büyük olasılıkla aynı makineye düşecektir. Hash için tüm anahtarlar önceden ayrılmıştır, bu nedenle doğal olarak bu sorunu yaşamaz.

Ancak, iki çözümün artılarını ve eksilerini basitçe karşılaştırmak anlamlı değildir ve yine de işten başlamamız gerekiyor. İnternet iş senaryosunda, farklı anahtarlar arasında (iki kullanıcının adları gibi) kısmi bir sipariş ilişkisine gerek olmadığına inanıyoruz, bu nedenle tarttıktan sonra bir karma şeması benimsiyoruz.

Hash şema uygulama yöntemi

HashSchema'yı uygularken karşılaştığımız ilk sorun "verilerin nasıl saklanacağı" idi. "Hash değerine göre bir kovaya bir anahtar koyun", bu sadece idealize edilmiş bir soyutlamadır. Gerçek sistem uygulamasında, farklı işletmeleri ayırmak için bir "tablo" kavramı katmanı da sağlamalısınız. Masa kavramı ile uygulamada farklılıklar yaşamaya başladık. Spesifik olarak, "çok masalı karışık depolama" ve "ayrı depolama" olmak üzere toplam iki depolama çözümümüz var.

Sözde çoklu tablo karma depolama, yeni bir karma değeri hesaplamak için tablo kimliği ve karma anahtarı birleştirmek ve bu karma değere dayalı erişim için küresel olarak benzersiz bölme alanından bir bölüm seçmektir. Yukarıdaki şeklin sol yarısında gösterildiği gibi.

Ayrı depolama için, tablonun anlam bilgisi depolama katmanına doğru itilir. Yukarıdaki şeklin sağ yarısında gösterildiği gibi: her tablonun ayrı bir bölme alanı vardır Bir okuma / yazma talebi olduğunda, önce tablo kimliğine göre ilgili bölme alanını bulun ve ardından hash anahtarına göre karşılık gelen bölmeyi bulun.

Peki bu iki çözümden hangisi daha iyi? Teorik olarak, çok tablalı karma depolama çözümünün daha iyi olduğuna inanıyoruz çünkü yazılım mühendisliğindeki hiyerarşik düşünceye daha uygun; karma depolamanın uygulanması da daha kolay çünkü yönetmek için yalnızca bir meta veri gerekiyor ve yük dengeleme daha basit. Ancak iş açısından bakıldığında, her tabloyu ayrı ayrı saklama şemasını kullanmak daha iyidir. Çünkü ayrı depolama, tablolar, tablo düzeyinde izleme ve tablo silme işlemleri arasında daha basit kaynak kısıtlamaları anlamına gelir. İşletim ve bakımdaki yanlış işlemleri hesaba katarsak, ayrı depolama da daha avantajlıdır.Bir bölümü yanlışlıkla silseniz bile, yanlış işlemin farklı işler üzerinde daha az etkisi olacaktır.

Aşağıdaki tablo, iki çözümü karşılaştırmamızı göstermektedir:

İkisine kıyasla, biri teoride daha güzel, diğeri ise pratikte daha iş dostu. Sonunda işten başladık, daha güzel ve uygulaması daha kolay olan teoriden vazgeçip iş dostu bir çözüm seçtik.

Hash şemasının yük dengelemesi

Hash şeması hakkında konuştuktan sonra, bir sonraki adım yük dengeleme problemidir. Aşağıda, yük dengelemede genel dağıtılmış KV depolamanın hedefleri listelenmiştir:

  • Tek bir Anahtarın isteği aşırı ısındı: Hangi depolama şeması olursa olsun çözümü kolay değil. Okuyorsa, salt okunur bir önbellek katmanı eklemeyi düşünebilirsiniz; yazıyorsa, yalnızca işletmenin anahtarı daha fazla bölmesine izin verebilirsiniz

  • Tek bir Bölümün isteği aşırı ısındı: Anahtar karma dağınık olduğundan, karma şemayı dikkate almaya gerek yok.

  • Bölme kapasitesi eşit olmayan bir şekilde dağıtılmıştır: Anahtar karma dağınık olduğundan, karma şemayı dikkate almaya gerek yoktur.

  • Bölümlerin sayısı farklı makinelere eşit olarak dağıtılmamaktadır: bununla ilgilenilmesi gerekir ve bu ele alındıktan sonra, farklı ReplicaServers'taki okuma ve yazma talepleri daha dengelidir.

Yük dengeleme hedefi

Özellikle, yük dengeleme amacının iki noktası vardır:

A. Birincil ve ikincil ReplicaServer'ı paylaşamaz

B. Her tablo için, birincil ve ikincil, farklı ReplicaServer'a eşit olarak dağıtılabilir

Yukarıdaki şekil, B hedefinin basit bir örneğidir: eğer bir tabloda dört Bölüm varsa ve toplamda üç ReplicaServers varsa, 12 Kopyanın dağılımının (1, 3), (2, 2), (1) olmasını umuyoruz. , 3).

Yük dengeleme algoritması

Yük dengeleme algoritmamızı uygularken, dikkat edilmesi gereken çok önemli bir nokta vardır: rol değiştirme, veri kopyalamadan daha iyidir, çünkü rol değiştirmenin maliyeti çok düşüktür.

Bu noktanın açıklaması için, yukarıdaki şekildeki iki duruma başvurabilirsiniz:

  • Soldaki resimde, 4 Birincil ReplicaServer2 ve ReplicaServer3 üzerinde dağıtılmıştır, ancak ReplicaServer1'de Primary yoktur. Şu anda, ReplicaServer3'te Birincil A ve ReplicaServer1'de İkincil A rollerini değiştirerek, Birincil dengesi karşılanabilir.

  • Sağdaki şekilde, 4 Birincil'in dört ReplicaServers'daki dağılımı (2, 1, 1, 0) şeklindedir. Birincil olanı dengelemek istiyorsanız, ReplicaServer1'deki bir birincil'i ReplicaServer4'e taşımanız gerekir, ancak birincilin doğrudan taşınması verilerin kopyalanmasını gerektirir. Bu noktada, ara düğüm ReplicaServer2'yi tanıtırsak, önce ReplicaServer1'in Primary A'sı ve ReplicaServer2'nin Secondary A'sının rollerini değiştirin ve ardından Primary'nin dengesini elde etmek için ReplicaServer2'nin Primary D'sini ReplicaServer4'ün Secondary D'si ile değiştirin.

  • Bu durumların üstesinden gelmek için, kümedeki birincilin olası akışı için yönlendirilmiş bir grafik oluşturduk ve sonra birincil geçişi yapmak ve değiştirmek için Ford-Fulkerson yöntemini kullandık. Belirli algoritma artık genişletilmemiştir, açık kaynak proje kodumuza başvurabilirsiniz.

    Gerçek yük dengelemede dikkate alınması gereken birçok durum vardır:

    • Daha iyi hata toleransı için, bir Bölümün birkaç kopyası aynı rafa yerleştirilmemelidir.

    • Farklı ReplicaServers, farklı depolama kapasitelerine sahip olabilir ve replikaların sayısının mutlak dengesi çok makul olmayabilir.

    • Yük dengeli veri kopyası yaparken, mevcut sınıra dikkat etmeli ve asla çok fazla sistem kaynağı kullanmamalısınız.

    Mevcut Pegasus açık kaynak projesinde bazı durumlar göz önünde bulundurulmamıştır. Dikkatinizi verebilmeniz için gelecekte yük dengelemeyi optimize etmeye devam edeceğiz.

    Tutarlılık ve kullanılabilirlik

    Ölçeklenebilirlik daha önce tanıtıldı, ardından tutarlılık ve kullanılabilirlik geldi. Tasarım değerlendirmelerimiz zaten açıklanmıştır:

    • Hayvan bakıcısına bağımlılığı azaltın

    • Veriler DFS'ye yazılmaz

    • Güçlü tutarlılık sağlamak için çoklu kopya, PacificA algoritması

    Sistemi bu tasarım hedeflerine uygun olarak uyguladığımızda ve bir iş denemesi bulmaya hazır olduğumuzda, iş cümlesi bizi geri itti: "Sıcak yedekleme için çift bilgisayar odanız var mı?"

    Bunu neden tek başına söylüyorsun? Çünkü son derece tutarlı bir dağıtılmış depolama sistemi için, bilgisayar odaları arasında hata toleransı zahmetli bir şeydir:

    • Bir yandan, bir Bölümün birden çok kopyası iki bilgisayar odasına dağıtılırsa, bir bilgisayar odası çoğunluğa sahip olmalıdır. Bu bilgisayar odasının genel kapalı kalma süresi, kümeye hizmet verilemeyeceği anlamına gelir (güçlü tutarlılık sağlama ihtiyacı nedeniyle).

    • Öte yandan, Bölmenin birden çok kopyası üç bilgisayar odasına yerleştirilirse, bilgisayar odaları arasında güvenlik gerçekten garanti edilir. Ancak bu, her yazma isteğinin, performansı etkileyen bilgisayar odası genelinde çoğaltmaya sahip olması gerektiği anlamına gelir.

    Bu konu üzerinde derinlemesine düşünerek, aslında "mükemmel bir sistem olma" boynuzuna sahip olduğumuzu düşünüyoruz. İş açısından bakıldığında, eksiksiz bir depolama sistemi olarak, gerçekten de çeşitli anormal durumların üstesinden gelmek gerekir. Bununla birlikte, anormal durumların ortaya çıkma olasılığı azaldıkça, tutarlılık için iş gereksinimleri aslında yavaş yavaş gevşer:

    İşletmenin ihtiyaçlarını anladıktan sonra, Pegasus için farklı risklerle başa çıkmak için çok seviyeli bir artıklık stratejisi tasarladık:

    • Uygunluk anlaşması: tek makineli arıza riskine direnmek için tek makine odası dağıtımı için kullanılır

    • Bilgisayarlar arası oda çoğaltma: her bölümün günlüğünü eşzamansız olarak çoğaltın, her iki oda da yazılabilir ve son tutarlılık NTP zaman damgasına göre

    • Anlık Görüntünün periyodik olarak soğuk yedeklemesi: bölgeler arası çoğaltma, aşırı arızalar durumunda alt satır stratejisi, bazı veriler kaybolabilir

    Yukarıdaki artıklık stratejisi hakkında birkaç not:

    • NTP'nin zaman damgası yeterince doğru olmayabilir. İki bilgisayar odası aynı anahtarı birbiri ardına yazar ve nihai sonuç, birincisinin ikincisini geçersiz kılması olabilir. Şu anda bunu aşmak için başka bir önlemimiz yok, çünkü amacımız "nihai tutarlılık", yani "zamanla iki bilgisayar odasının nihai sonucu aynı", yani önce yazılsa bile Üzerine yazdıktan sonra, iki bilgisayar odasındaki son durum performansı da aynıdır.

    • HBase'nin bakımı konusundaki deneyimlerimize göre, işletmedeki iki bilgisayar odasının aynı anda bir anahtar yazması pek olası değildir. Bu nedenle, NTP'nin getirdiği "önce yaz ve sonra üzerine yaz" sorunu, işle ilgilenmeyi gerektirir.

    • Çok seviyeli artıklık stratejisi, daha fazla veri yedeklemesine neden olabilir. Her şeyden önce, tüm işletmeler çok fazla yedeklilik düzeyine ihtiyaç duymaz, ancak belirli ihtiyaçlara göre çevrimiçi olarak yapılandırılır. Bu nedenle, bu kısıtlayıcı artıklık şu anda, küme seviyesinde zorunlu olmaktan ziyade değiştirilebilen tablo düzeyinde parametrelere dönüştürülmektedir. Ayrıca, anlık görüntülerin soğuk yedeklemesi gibi bazı yedeklemelerde çok ucuz depolama ortamı bulunur.

    • Makineler arası oda çoğaltma ve anlık görüntü soğuk yedeklemesinin işlevleri hala dahili test aşamasındadır ve açık kaynak sürümü henüz yayınlanmamıştır.

    Gecikme garantisi

    Son olarak, gecikme performansını garanti etme konusunu tanıtacağım. Bu soru ile ilgili olarak iki noktanın vurgulanması gerekir:

    • Hangi uygulama dili seçilmeli

    • Mutabakat protokolü nasıl verimli bir şekilde uygulanır?

    Uygulama dilinde, C ++ 'yı seçtik. Nedeni daha önce de söylendi, performansı garantilemek için çalışma zamanı GC'siz bir dil benimsemeliyiz. Başka bir seçenek de Rust olabilir. Neden Rust yerine C ++ 'yı seçtiğimize ilişkin düşüncelerimiz aşağıdaki gibidir:

    • Projenin kurulduğu sırada Rust çok popüler değildi ve üçüncü taraf kütüphaneleri C ++ 'dan uzaktı.

    • Bazı programlama özelliklerini takip ettiğiniz sürece, C ++ 'nın kontrol edilmesi özellikle zor değildir.

    • İnsanları işe almak için C ++ kullanmak daha uygundur

    Tabii ki, bu seçim muhafazakar ve dil seviyesindeki tartışma burada bitiyor. Odak noktası hala uzlaşı protokolümüzün uygulanmasıdır.

    Pratik bir bakış açısıyla, mutabakat protokolünü doğru ve verimli bir şekilde uygulamak ve kodun bakımı ve testinin kolay olduğundan emin olmak zordur. Asıl sebep, eksiksiz bir talebin birçok Aşamalarda IO, eşzamanlılık gereksinimleriyle birlikte aşamalar arasında oluşturulacaktır ve genellikle kodun çok ince bir şekilde kilitlenmesini gerektirir.

    Aşağıdaki şekil, eksiksiz bir yazma talebinin basitleştirilmiş bir süreç diyagramını göstermektedir:

    Yukarıdaki şekilden de görülebileceği gibi, istemci bir yazma isteği başlattığında, bu istek yerel diske yazma ve ağ RPC'si gönderme gibi birden çok olay üretecektir.Olayın başarılı veya başarısız olmasına bakılmaksızın, ortak tutarlılık durumunun kontrol edilmesi gerekir. Erişin veya değiştirin. Bu tür bir mantık, hatalara çok açık olan tutarlı durumda çok hantal iş parçacığı senkronizasyonu gerçekleştirmemize neden olacaktır.

    Peki bu tür bir problemle nasıl başa çıkılır? Deneyimlerimize dayanarak, kodu "kritik bölüm için rekabet" ten "kilit serileştirmeden kuyruğa alma" arasında organize etmek gerekir. Kod mimarimizi göstermek için bir resim kullanmama izin verin:

    Spesifik olarak, "tutarlılık durumunu" çekirdek olarak almak, durum değişikliklerini içeren tüm olayları bir kuyruğa dizmek ve kuyruk olaylarını ayrı bir iş parçacığı aracılığıyla yürütmektir. Sözde yürütme, tutarlılık durumunu değiştirmektir. GÇ, yürütme sırasında tetiklenirse, saf zaman uyumsuz yöntem kullanılır ve GÇ tamamlandıktan sonraki yanıt olayı sıraya dizilir. Aşağıda gösterildiği gibi:

    Ek olarak, çok fazla iş parçacığı oluşturmaktan kaçınmak için, iş parçacığı havuzu yaklaşımını benimsedik. Bir "tutarlı durum" veri yapısı yalnızca bir iş parçacığı tarafından değiştirilebilir, ancak birden çok yapı bir evreyi paylaşabilir; kopya ve iş parçacığı çoka bir ilişkiye sahiptir.

    Genel olarak, bu olay odaklı ve tamamen eşzamansız yaklaşım sayesinde, tutarlı duruma erişirken ayrıntılı kilit senkronizasyonundan kaçınabiliriz. CPU, GÇ beklemede yakalanmaz ve iş parçacığı havuzu kullanılır ve performans garanti edilir. Ek olarak, bu uygulama okuma ve yazma sürecini izlememiz için çok uygundur çünkü bir yazma talebini açıkça farklı aşamalara böler, bu da projenin performans analizi için çok faydalıdır.

    Deterministik test

    Ardından, testin nasıl yapıldığına odaklanacağız.

    Dağıtılmış sistemlerin kararlılığı

    Sistemi bitirdiğimizde, uzun zamandır bizi gerçekten rahatsız eden şeyin sistemin nasıl kararlı hale getirileceğini keşfettik.

    Bu sorunun ana yönleri nelerdir? Özetten sonra şu üç nokta var:

  • Test etmesi zordur ve sistem sorunlarını test etmenin etkili bir yolu yoktur. Mevcut deneyim, onu bir kara kutu olarak ele almak, okurken ve yazarken görevleri sonlandırmak, modüllerinden birinde sorun yaşatmanın bir yolunu bulmak ve ardından genel durumda sorun olup olmadığını kontrol etmektir. Bununla birlikte, böyle bir test yöntemi yalnızca hataları etkileyebilir, çünkü sorunlar olasılıksal olarak ortaya çıkar.

  • Çoğalmak zordur. Hatalar olasılığa dayalı olarak meydana geldiğinden, test yoluyla bir sorun bulunsa bile, sorunu yeniden oluşturmak kolay değildir ve bu da hata ayıklamada daha fazla sorun çıkarır.

  • Geri dönmek zor. Günlüğe bakarak, fenomeni gözlemleyerek ve kodu analiz ederek sorunun özünü bulursanız. Onarım yönteminiz etkili ve ikna edici mi? Bu sorunu çözecek mi? Yeni sorunlara neden olacak mı? Sürekli tekrar eden bir yöntem olmadığından, bu iki sorunun yanıtlanması zordur.

  • Temel neden: belirsizlik

    Öyleyse yukarıdaki zorlukların temel nedeni nerede? Özetlemek gerekirse, bunun programın kendisinin belirsizliği olduğunu düşünüyoruz. Bu belirsizlik iki açıdan yansıtılmaktadır:

    • Programın kendisinin rastgeleliği: zamanlama, zamanlayıcılar, rastgele sayıların kullanımı ve birden çok düğüm arasında paralellik gibi sistem API'leri.

    • IO: Program periferik IO içerebilir. IO'nun olasılık hatası, zaman aşımı, paket kaybı, düzensizliği vb. De program belirsizliğine yol açar.

    Özetlemek için bir formül kullanın:

    Küçük IO hatası olasılığı + rastgele yürütme yolu = yeniden üretilmesi kolay olmayan anormal durum

    Peki bu sorunu nasıl çözmeliyiz?

    Problemi çevrimiçi olarak yeniden üretmek zor olduğu için bir simülasyon senaryosu oluşturabilir miyiz: Bu simülasyon senaryosunda, IO hatalarının olasılığını simüle edebilir ve programın yürütme sırasını kontrol edebiliriz. Daha sonra kodu böyle bir simülasyon senaryosunda çalıştırın, mantıkla ilgili bir sorun varsa, sorunu aynı yürütme sırasında yeniden üretebiliriz. Mantık değiştirildikten sonra, zor regresyon probleminin çözülmesi için bir birim testine dönüştürülebilir.

    Elbette bu sorunu bu şekilde tarif etmek hala çok soyut. Burada açıklamak için basit bir örnek vereceğim:

    Alice ve Bob adında iki kişinin bulunduğu ve hesap bakiyelerinin her biri 100 yuan olduğu ve her ikisinin de iki makinede depolandığı ve her ikisinin de birbirlerine transfer işlemlerini başlatabildiği böyle bir hesap sistemi olduğunu varsayalım. Şimdi Alice, Bob'a 5 yuan transfer etmek istiyor. En basit uygulama, Alice'in hesabındaki bakiyeden 5 yuan düşmesi ve ardından Bob'un makinesine 5 yuan artırmak için bir talep başlatmasıdır. Bob'un hesabı 5 yuan artırıldıktan sonra, transferin başarılı olduğu Alice'e bildirilebilir.

    Makine çalışmazsa, disk arızalı olmaz ve ağ sorun olmazsa, bu basit uygulama tamamdır. Ancak böyle bir varsayım asla doğru olmayacaktır, bu nedenle bu sorunlarla başa çıkmak için, hesap sistemini daha güvenilir hale getirmek için işlem günlükleri eklemek ve işlem ve hesap bilgilerini birden çok makineye yedeklemek gibi bir dizi önlem ekleyebiliriz. Bazı dağıtılmış işlem teknolojilerini tanıtın. Bu yöntemlerin tanıtılması, sistemimizi daha karmaşık hale getirecektir.

    Böylesine karmaşık bir sistemle karşı karşıya kaldığımızda, herhangi bir anormal veritabanı durumu, Alice ve Bob'un hesap bilgilerindeki aşağıdaki değişiklikler gibi, kafamızı karıştıracaktır:

    (Alice_100, Bob_100) - > (Alice_105, Bob_105)

    Programda hata olmadığında, Alice ve Bob'un hesaplarının bakiyelerinin toplamının 200'e eşit olduğunu varsayabiliriz. Artık bakiye toplamı 210 haline geldiğine göre, bazı bağlantılarda bir sorun olmalı. Belki de iki kişinin aynı anda birbirlerine para aktardığı ve sonra bir şey bir hatayı tetiklediği zamandı; belki veri paketi iki kez gönderilmiştir. Yasadışı bir duruma girmek için pek çok olası durum vardır, ancak olasılıksal donanım arızası ve Alice ile Bob arasındaki karmaşık (belki de paralel) aktarım kayıtları, yasadışı durumun nedenini bulmamızı ve yeniden üretmemizi zorlaştıracaktır.

    Böyle bir sorun için silahlarımız analog ve sözde rastgele. Bu iki yöntem sayesinde, programın tekrarlanabilir olaylar dizisi halinde çalışabileceğini umuyoruz. Bu şekilde, program yasadışı bir duruma girdiği için çökerse, yeniden üretebilir, hata ayıklayabilir ve duruma geri dönebiliriz.

    Örnek olarak Alice ve Bob arasındaki yukarıdaki işlemi ele alalım. Her iki tarafın da aynı anda para transfer ettiği bir süreç, simüle edilmiş bir ortamda şu şekilde çalışabilir: Alice transferi başlatır - > Bob transferi başlatır. > Alice yazmaya başlar. > Alice, RPC'yi başlatır > Alice RPC başarılı- > Bob yazmaya başlar. > Alice diske yazamadı

    Diğer bir deyişle:

    • Başlangıçta paralel olarak yürütülen iki mantık kümesi, simülatörde eşzamanlı olarak araya eklenebilir.

    • Serpiştirme sırasında seçim zamanlaması sözde rastgeledir.Farklı simülatör örneklerini çalıştırırken, durum geçiş süreçleri tamamen farklıdır; ancak her durumda, aynı rastgele sayı çekirdeği seçildiği sürece geçiş süreci kesindir

    • IO arızaları da belirli bir sözde rastgele olasılığa göre enjekte edilir

    Böyle bir ortamı varsayarsak, dağıtılmış iş mantığında hata ayıklamanın zorluğu kesinlikle çok düşecektir. Bir yandan rastlantısallığın varlığı, çeşitli yürütme dizilerini test etmemizi sağlarken, diğer yandan sözde rasgele ve hata enjeksiyonu karşılaştığımız sorunları yeniden üretmemizi sağlar.

    Kontrol belirsizliği

    Öyleyse, spesifik kontrol nasıl belirsizdir?

    Belirsizlik oluşturan arayüzler bir soyutlama katmanı sağlar. Mevcut sistem toplam beş soyut arabirim sağlar: iş parçacığı havuzu, RPC, disk GÇ, iş parçacığı senkronizasyonu ve ortam işlemi. Her arayüz bir simülasyon uygulamasına (test) ve simülasyon olmayan bir uygulamaya (dağıtım ve çalıştırma) sahiptir Dağıtılmış iş mantığı (Uygulama Mantığı) kodu yalnızca sistemin soyut arayüzünü (Çalışma Zamanı) çağırır

    Sistem, dağıtılmış bir sistemi simüle etme etkisini elde etmek için tek bir işlemde birden fazla hizmet düğümünü simüle etme yeteneği sağlar.

    Runtime katmanının simülasyon uygulaması zor bir noktadır. Temel noktalar şunları içerir:

    Yalnızca tamamen eşzamansız bir programlama arabirimi sağlanır ve düğümün çalışma modu, olay kuyruğundaki görevlerin iş parçacığı yürütme sürecidir.

    İş mantığı, Runtime API aracılığıyla Runtime modülüne çağrıldığında, Runtime mevcut düğümü askıya alır ve sözde rastgele bir şekilde yürütme için yeni bir düğüm seçer. Tüm süreç tek çekirdekli çok görevli bir işletim sistemi gibidir.Çalışma zamanı çekirdek modu gibidir, dağıtılmış mantık Düğümü kullanıcı modu süreci gibidir ve çalışma zamanı API'si bir sistem çağrısı gibidir. Aşağıda gösterildiği gibi:

    Olay kuyruğuna gönderilen IO olayları için, hataları sözde rastgele belirli bir olasılıkla enjekte ederiz. Ek olarak, durum her değiştiğinde küresel durumun yasal olup olmadığını kontrol etmek için bazı küresel durum algılama modülleri tanıtıldı (örneğin, Alice ve Bob'un hesap bakiyelerinin toplamının 200'den az olup olmadığını kontrol edin); aynı zamanda, Uygulama Mantığı kodu da çok şey ekledi. Node durumunun yasal olup olmadığını kontrol etme iddiası. Program çöktükten sonra, aynı rasgele sayı çekirdeği çoğaltma ve hata ayıklama için kullanılabilir. Aşağıda gösterildiği gibi:

    Pegasus'un birim testleri de bu test çerçevesi kullanılarak gerçekleştirilmektedir. Birim testinde, bir sahneye uygulanan eylemleri ve beklenen durumu açıklamak için bir komut dosyası kullanacağız.Yukarıdaki şekilde App Logic Checker'ın işlevi, komut dosyasını yüklemek ve ardından programın durumunun komut dosyasına göre beklentileri karşılayıp karşılamadığını kontrol etmektir.

    Pegasus tarafından benimsenen test çerçevesinin kavramı ve uygulaması, Microsoft'un açık kaynak çerçevesi rDSN'sinden türetilmiştir. Tüm çerçevenin anlaşılması zordur ve burada prensiplerinin kısa bir açıklaması bulunmaktadır. Eğer ilgileniyorsanız, doğrudan kaynak kodunu görüntüleyebilirsiniz.

    Durum ve plan

    Şimdi Pegasus, yaklaşık bir yıldır Xiaomi bünyesinde istikrarlı bir şekilde hizmet veriyor ve yaklaşık on işletmeye hizmet veriyor. Pegasus'un depolama motoru, performansı ve tasarımı hakkında daha fazla ayrıntı için, başka bir Arch Summit 2016 paylaşımına geçebilir (makaleden sonra bir bağlantı vardır) veya github'daki ilgili belgelerimize bakabilirsiniz.

    Gelecekte, verilerin sıcak ve soğuk yedeklemesi, bölümlere ayırma, vb. Gibi açık kaynaklı işlevler açacağız. Lütfen dikkat etmeye devam edin. Hayatın her kesiminden insanlar da Xiaomi'ye katılabilir ve ekibimize katılabilir.

    Sonuna yaz

    Son olarak, tüm makalenin içeriğini özetleyin.

    Bir projeyi araştırırken veya uygularken, üç noktaya dikkat etmeliyiz:

    • İşe odaklanın: Proje iş ihtiyaçlarını karşılıyor mu?

    • Mimariye odaklanın: Projenin mimarisi makul mü Dağıtılmış depolama sistemleri için tutarlılık, kullanılabilirlik, ölçeklenebilirlik ve performanstır.

    • Yazılım mühendisliğine odaklanın: Projenin testi tamamlandı mı, kodun sürdürülebilirliği iyi mi ve proje izlenebilir mi?

    Somut ve renkli, Mi 8 ekran parmak izi sürümüyle başlayın
    önceki
    Yerli bağımsız oyun "Aish" PS Store ve Steam'de
    Sonraki
    Büyük dalgalara sahip Hong Kong tarzı kırmızı elbise Chen Duling sonunda doğru görünümü buldu! Saf görünüm ve ağır makyaj için mükemmel bir eşleşme
    "WANNA ONE" "News" 190325 Yong Shengyou denizaşırı seyahatini bitirdikten sonra Çin'e geri döndü. Tamamen siyah görünümler yetenekli bir moda sergiliyor
    Liu Yifei, ailesiyle oynamak için dışarı çıktı ve bir kaplan gibi davranıyor. Bağdaş kurup çocuklarla çok arkadaş canlısı etkileşime giriyor.
    Microsoft AI Night stadyumda oynamanızı bekliyor: gerçekten büyük ineklerle rekabet edin!
    190325 Kendini adamış bir aktör olan Chen Linong, sabah erkenden işten iner ve gece sahneleri çekmek için havaalanından ayrılır.
    Yang Chaoyue, adını çok tanınmış biri olarak kullandı ve adını değiştirmek zorunda kaldı. Bugün gerçek adı ortaya çıkıyor. Netizenler: Adı erken değiştirmeyin
    Yeni komedi "Charlie Arrived" ilk fotoğraf dalgasını yayınladı ve tüm sezon boyunca 3 / 15'te Netflix platformunda olduğu doğrulandı.
    Yıldızlar ve bebek bakıcıları: Xiong Dailin kasıtlı olarak hesaplanmıştı, kimse Jacky Cheungun evine bebek bakıcısı olarak gitmeye cesaret edemezdi
    "Sound into the Heart" onları övdü ve değerleri fırladı, ancak netizenler moda fotoğrafları hakkında şikayet ettiler
    Liu Xiaoqing, hayranlarının çektiği eski fotoğrafları paylaşarak görünüşte iyileşmediğini ve neden bir makyaj yapıldığını merak etti.
    Bellekte eski zaman, SONY CD kaseti entegre retro hoparlör
    "Bilgi" nin perde arkası: Zhao Liying bebeğini sete getiriyor, Usta Sheng drama nedeniyle Zhao Liying ve Feng Shaofeng'den bahsediyor
    To Top