Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Mikhail Salosin (bundan böyle – MS olarak anılacaktır): - Herkese selam! Benim adım Michael. MC2 Software'de backend geliştirici olarak çalışıyorum ve sizlere Look+ mobil uygulamasının backend'inde Go kullanımından bahsedeceğim.

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Burada hokeyi seven var mı?

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

O halde bu uygulama tam size göre. Android ve iOS içindir ve çeşitli spor etkinliklerinin yayınlarını çevrimiçi ve kayıtlı olarak izlemek için kullanılır. Uygulama aynı zamanda çeşitli istatistikler, metin yayınları, konferans tabloları, turnuvalar ve hayranlar için yararlı diğer bilgileri de içerir.

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Ayrıca uygulamada video anları diye bir şey var, yani maçların en önemli anlarını (goller, kavgalar, penaltı atışları vb.) izleyebilirsiniz. Yayının tamamını izlemek istemiyorsanız yalnızca en ilgi çekici olanları izleyebilirsiniz.

Geliştirmede ne kullandınız?

Ana kısım Go'da yazılmıştır. Mobil istemcilerin iletişim kurduğu API Go'da yazılmıştır. Go'da cep telefonlarına anlık bildirim gönderme hizmeti de yazıldı. Ayrıca bir gün hakkında konuşabileceğimiz kendi ORM'mizi de yazmamız gerekiyordu. Go'da bazı küçük hizmetler yazıldı: editörler için resimlerin yeniden boyutlandırılması ve yüklenmesi...

Veritabanı olarak PostgreSQL'i kullandık. Editör arayüzü Ruby on Rails'de ActiveAdmin gem'i kullanılarak yazılmıştır. Bir istatistik sağlayıcısından istatistiklerin içe aktarılması da Ruby'de yazılmıştır.

Sistem API testleri için Python Unittest'i kullandık. Memcached, API ödeme çağrılarını kısıtlamak için kullanılır, "Chef" yapılandırmayı kontrol etmek için kullanılır, Zabbix ise dahili sistem istatistiklerini toplamak ve izlemek için kullanılır. Graylog2 günlükleri toplamak içindir, Slate ise istemciler için API dokümantasyonudur.

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Protokol seçimi

Karşılaştığımız ilk sorun: Arka uç ile mobil istemciler arasındaki etkileşim için aşağıdaki noktaları temel alarak bir protokol seçmemiz gerekiyordu...

  • En önemli gereksinim: Müşterilere ilişkin verilerin gerçek zamanlı olarak güncellenmesi gerekir. Yani, yayını izleyen herkesin güncellemeleri neredeyse anında alması gerekir.
  • İşleri basitleştirmek için, istemcilerle senkronize edilen verilerin silinmediğini, ancak özel bayraklar kullanılarak gizlendiğini varsaydık.
  • Her türlü nadir istek (istatistikler, takım kompozisyonları, takım istatistikleri gibi) sıradan GET istekleriyle elde edilir.
  • Üstelik sistemin aynı anda 100 bin kullanıcıya rahatlıkla destek vermesi gerekiyordu.

Buna dayanarak iki protokol seçeneğimiz vardı:

  1. Web yuvaları. Ancak istemciden sunucuya giden kanallara ihtiyacımız yoktu. Yalnızca sunucudan istemciye güncellemeleri göndermemiz gerekiyordu, bu nedenle websocket yedek bir seçenektir.
  2. Sunucu Tarafından Gönderilen Etkinlikler (SSE) tam olarak doğru çıktı! Oldukça basit ve temelde ihtiyacımız olan her şeyi karşılıyor.

Sunucu Tarafından Gönderilen Olaylar

Bu şeyin nasıl çalıştığına dair birkaç söz...

Bir http bağlantısı üzerinde çalışır. İstemci bir istek gönderir, sunucu Content-Type: text/event-stream ile yanıt verir ve istemciyle bağlantıyı kapatmaz ancak bağlantıya veri yazmaya devam eder:

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Veriler müşterilerle kararlaştırılan bir formatta gönderilebilir. Bizim durumumuzda bunu şu şekilde gönderdik: değişen yapının adı (kişi, oyuncu) etkinlik alanına, oynatıcı için yeni, değiştirilmiş alanlarla birlikte JSON veri alanına gönderildi.

Şimdi etkileşimin nasıl çalıştığından bahsedelim.

  • İstemcinin yaptığı ilk şey, hizmetle senkronizasyonun en son ne zaman gerçekleştirildiğini belirlemektir: yerel veritabanına bakar ve kendisi tarafından kaydedilen son değişikliğin tarihini belirler.
  • Bu tarihle bir istek gönderir.
  • Yanıt olarak, o tarihten bu yana meydana gelen tüm güncellemeleri kendisine gönderiyoruz.
  • Bundan sonra canlı kanala bağlantı kurar ve şu güncellemelere ihtiyaç duyana kadar kapanmaz:

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Ona değişikliklerin bir listesini gönderiyoruz: Birisi gol atarsa ​​maçın skorunu değiştiririz, sakatlanırsa bu da gerçek zamanlı olarak gönderilir. Böylece müşteriler, maç etkinliği akışındaki güncel verileri anında alıyor. Periyodik olarak, istemcinin sunucunun ölmediğini, ona hiçbir şey olmadığını anlaması için, her 15 saniyede bir zaman damgası göndeririz; böylece her şeyin yolunda olduğunu ve yeniden bağlanmaya gerek olmadığını bilir.

Canlı bağlantı hizmeti nasıl sağlanır?

  • Öncelikle ara belleğe alınmış güncellemelerin alınacağı bir kanal oluşturuyoruz.
  • Bundan sonra güncellemeleri almak için bu kanala abone oluyoruz.
  • Müşterinin her şeyin yolunda olduğunu bilmesi için doğru başlığı ayarladık.
  • İlk ping'i gönderin. Sadece mevcut bağlantı zaman damgasını kaydediyoruz.
  • Bundan sonra güncelleme kanalı kapanana kadar kanaldan döngü halinde okuyoruz. Kanal periyodik olarak ya güncel zaman damgasını ya da açık bağlantılara yazmakta olduğumuz değişiklikleri alır.

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Karşılaştığımız ilk sorun şuydu: İstemciyle açılan her bağlantı için, her 15 saniyede bir çalışan bir zamanlayıcı oluşturduk - öyle görünüyor ki, bir makineyle (bir API sunucusuyla) 6 bin bağlantımız açıksa, 6 bin bağlantımız açıktı. binlerce zamanlayıcı oluşturuldu. Bu, makinenin gerekli yükü taşımamasına neden oldu. Sorun bizim için o kadar açık değildi ama biraz yardım aldık ve sorunu çözdük.

Sonuç olarak artık pingimiz güncellemenin geldiği kanaldan geliyor.

Buna göre her 15 saniyede bir çalışan tek bir zamanlayıcı vardır.

Burada birkaç yardımcı işlev vardır - başlığın gönderilmesi, ping ve yapının kendisi. Yani tablonun adı (kişi, maç, sezon) ve bu girişe ilişkin bilgiler buraya iletilir:

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Güncellemeleri gönderme mekanizması

Şimdi değişikliklerin nereden geldiği hakkında biraz. Yayını gerçek zamanlı olarak izleyen birkaç kişi, editörümüz var. Bütün olayları onlar yaratıyor: Birisi ihraç edildi, birisi yaralandı, bir çeşit yedek...

Bir CMS kullanarak veriler veritabanına girer. Bundan sonra veritabanı, Dinle/Bildir mekanizmasını kullanarak API sunucularına bu konuda bilgi verir. API sunucuları bu bilgileri zaten istemcilere göndermektedir. Bu nedenle, aslında veritabanına bağlı yalnızca birkaç sunucumuz var ve veritabanında özel bir yük yok çünkü istemci, veritabanıyla hiçbir şekilde doğrudan etkileşime girmiyor:

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

PostgreSQL: Dinle/Bildir

Postgres'teki Dinleme/Bildirme mekanizması, olay abonelerine bazı olayların değiştiğini - veritabanında bazı kayıtların oluşturulduğunu bildirmenize olanak tanır. Bunu yapmak için basit bir tetikleyici ve işlev yazdık:

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Bir kayıt eklerken veya değiştirirken, data_updates kanalındaki notify işlevini çağırırız ve buraya tablonun adını ve değiştirilen veya eklenen kaydın tanımlayıcısını iletiriz.

İstemciyle senkronize edilmesi gereken tüm tablolar için, bir kaydı değiştirdikten / güncelledikten sonra aşağıdaki slaytta belirtilen işlevi çağıran bir tetikleyici tanımlarız.
API bu değişikliklere nasıl abone olur?

Bir Fanout mekanizması oluşturulur - istemciye mesajlar gönderir. Tüm müşteri kanallarını toplar ve aldığı güncellemeleri şu kanallar üzerinden gönderir:

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Burada veritabanına bağlanan ve kanalı (data_updates) dinlemek istediğini söyleyen standart pq kütüphanesi, bağlantının açık olduğunu ve her şeyin yolunda olup olmadığını kontrol eder. Yer kazanmak için hata kontrolünü atlıyorum (kontrol etmemek tehlikelidir).

Daha sonra asenkron olarak her 15 saniyede bir ping gönderecek olan Ticker'ı kuruyoruz ve abone olduğumuz kanalı dinlemeye başlıyoruz. Bir ping alırsak bu pingi yayınlarız. Bir tür giriş alırsak, bu girişi bu Fanout'un tüm abonelerine yayınlarız.

Fan çıkışı nasıl çalışır?

Rusça'da bu "bölücü" olarak tercüme edilir. Bazı güncellemeleri almak isteyen aboneleri kaydeden bir nesnemiz var. Ve bu nesneye güncelleme geldiği anda bu güncellemeyi tüm abonelerine dağıtır. Yeterince basit:

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Go'da nasıl uygulanır:

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Bir yapı var, Mutex kullanılarak senkronize ediliyor. Fanout'un veritabanına bağlantı durumunu kaydeden bir alana sahiptir, yani şu anda dinliyor ve güncellemeleri alacak, ayrıca mevcut tüm kanalların bir listesi - anahtarı kanal ve yapı şeklinde olan harita değerler (esasen hiçbir şekilde kullanılmaz).

İki yöntem - Bağlandı ve Bağlantı Kesildi - Fanout'a üsle bağlantımız olduğunu, bunun ortaya çıktığını ve üsle bağlantının koptuğunu söylememize olanak tanır. İkinci durumda, tüm istemcilerin bağlantısını kesmeniz ve onlara artık hiçbir şey dinleyemediklerini ve onlarla bağlantı kesildiği için yeniden bağlandıklarını söylemeniz gerekir.

Kanalı “dinleyicilere” ekleyen bir Abone Ol yöntemi de vardır:

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

İstemcinin bağlantısı kesilirse kanalı dinleyicilerden kaldıran bir Abonelikten Çıkma yönteminin yanı sıra tüm abonelere mesaj göndermenize olanak tanıyan bir Yayınlama yöntemi de vardır.

Soru: – Bu kanal aracılığıyla neler aktarılıyor?

HANIM: – Değişen model veya ping iletilir (esasen sadece bir sayı, tamsayı).

HANIM: – Herhangi bir şeyi gönderebilir, herhangi bir yapıyı gönderebilir, yayınlayabilirsiniz – sadece JSON'a dönüşür ve hepsi bu.

HANIM: – Postgres'ten bir bildirim alıyoruz – tablo adını ve tanımlayıcıyı içeriyor. Tablo adı ve tanımlayıcıya göre ihtiyacımız olan kaydı alıyoruz ve ardından bu yapıyı yayına gönderiyoruz.

Altyapı

Altyapı açısından bakıldığında bu nasıl görünüyor? 7 donanım sunucumuz var: bunlardan biri tamamen veritabanına ayrılmış, diğer altısı sanal makineleri çalıştırıyor. API'nin 6 kopyası vardır: API'ye sahip her sanal makine ayrı bir donanım sunucusunda çalışır - bu güvenilirlik içindir.

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Erişilebilirliği geliştirmek için Keepalived yüklü iki ön ucumuz var, böylece bir şey olması durumunda bir ön uç diğerinin yerini alabilir. Ayrıca CMS'nin iki kopyası.

Ayrıca bir istatistik ithalatçısı da var. Periyodik olarak yedeklemelerin yapıldığı bir DB Slave bulunmaktadır. Müşterilere anlık bildirimlerin yanı sıra altyapı öğeleri de gönderen bir uygulama olan Pigeon Pusher var: Zabbix, Graylog2 ve Chef.

Aslında bu altyapı yedeklidir çünkü 100 bine daha az sunucuyla hizmet verilebilmektedir. Ama demir vardı - onu kullandık (bize bunun mümkün olduğu söylendi - neden olmasın).

Go'nun Artıları

Bu uygulama üzerinde çalıştıktan sonra Go'nun bu kadar bariz avantajları ortaya çıktı.

  • Harika http kütüphanesi. Bununla beraber kutunun dışında pek çok şey yaratabilirsiniz.
  • Ayrıca, müşterilere bildirim göndermek için bir mekanizmayı çok kolay bir şekilde uygulamamıza olanak tanıyan kanallar.
  • Harika bir şey olan Race dedektörü, birçok kritik hatayı (hazırlama altyapısı) ortadan kaldırmamıza olanak sağladı. Aşamalandırmada işe yarayan her şey, Race anahtarıyla derlenerek başlatılır; ve biz de buna göre hangi potansiyel sorunlarımızın olduğunu görmek için aşamalandırma altyapısına bakabiliriz.
  • Minimalizm ve dilin sadeliği.

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

Geliştiriciler arıyoruz! İsteyen varsa lütfen.

sorular

Dinleyicilerin sorusu (bundan sonra – B): – Bana öyle geliyor ki Fan-out ile ilgili önemli bir noktayı kaçırmışsınız. Bir müşteriye yanıt gönderdiğinizde, müşteri okumak istemezse onu engellediğinizi anlamakta haklı mıyım?

HANIM: - Hayır engellemiyoruz. Öncelikle nginx'in arkasında tüm bunlar var, yani yavaş istemcilerle ilgili herhangi bir sorun yok. İkincisi, istemcinin tamponlu bir kanalı var - aslında oraya yüze kadar güncelleme koyabiliriz... Kanala yazamazsak, o zaman onu siler. Kanalın engellendiğini görürsek, o zaman kanalı kapatacağız ve hepsi bu - herhangi bir sorun ortaya çıkarsa müşteri yeniden bağlanacak. Dolayısıyla prensip olarak burada herhangi bir engelleme yoktur.

In: – Tanımlayıcı tablo yerine hemen Dinle/Bildir'e kayıt göndermek mümkün olamaz mıydı?

HANIM: – Listen/Notify'ın gönderdiği ön yüklemede 8 bin byte sınırı bulunmaktadır. Prensip olarak, az miktarda veriyle uğraşıyor olsaydık göndermek mümkün olurdu, ancak bana öyle geliyor ki bu yol [bunu yapma şeklimiz] daha güvenilir. Sınırlamalar Postgres'in kendisindedir.

In: – Müşteriler ilgilenmedikleri maçlarla ilgili güncellemeler alıyor mu?

HANIM: - Genel olarak evet. Kural olarak, paralel olarak 2-3 maç oynanır ve o zaman bile oldukça nadirdir. Bir müşteri bir şey izliyorsa genellikle devam eden maçı izliyordur. Daha sonra müşteri, tüm bu güncellemelerin eklendiği yerel bir veritabanına sahip olur ve İnternet bağlantısı olmasa bile müşteri, güncellemeleri olan tüm geçmiş maçları görüntüleyebilir. Temel olarak, sunucudaki veritabanımızı müşterinin yerel veritabanıyla senkronize ederek çevrimdışı çalışabilmesini sağlarız.

In: – Neden kendi ORM'nizi yaptınız?

Alexey (Look+'ın geliştiricilerinden biri): – O zamanlar (bir yıl önceydi), oldukça fazla sayıda ORM olmasına rağmen şimdikinden daha az sayıda ORM vardı. Çoğu ORM'de en sevdiğim şey, çoğunun boş arayüzlerde çalışmasıdır. Yani, bu ORM'lerdeki yöntemler her şeyi üstlenmeye hazırdır: bir yapı, bir yapı işaretçisi, bir sayı, tamamen alakasız bir şey...

ORM'miz veri modeline dayalı yapılar oluşturur. Kendim. Ve bu nedenle tüm yöntemler somuttur, yansıma kullanmazlar vb. Yapıları kabul ederler ve gelen yapıların kullanılmasını beklerler.

In: – Kaç kişi katıldı?

HANIM: – İlk aşamada iki kişi katıldı. Haziran ayında bir yere başladık ve Ağustos ayında ana kısım hazırdı (ilk versiyon). Eylül ayında bir yayın vardı.

In: – SSE'yi tanımladığınız yerde zaman aşımı kullanmazsınız. Nedenmiş?

HANIM: – Dürüst olmak gerekirse SSE hala bir html5 protokolü: SSE standardı anladığım kadarıyla tarayıcılarla iletişim kurmak için tasarlandı. Tarayıcıların yeniden bağlanabilmesini sağlayan ek özelliklere sahiptir (vb.), ancak bunlara ihtiyacımız yok çünkü bağlantı kurmak ve bilgi almak için herhangi bir mantığı uygulayabilen istemcilerimiz vardı. SSE yapmadık, SSE'ye benzer bir şey yaptık. Bu protokolün kendisi değil.
Gerek yoktu. Anladığım kadarıyla istemciler bağlantı mekanizmasını neredeyse sıfırdan uyguladılar. Gerçekten umursamadılar.

In: – Hangi ek yardımcı programları kullandınız?

HANIM: – Stili birleştirmek için gofmt'nin yanı sıra govet ve golint'i de en aktif şekilde kullandık. Başka hiçbir şey kullanılmadı.

In: – Hata ayıklamak için ne kullandınız?

HANIM: – Hata ayıklama büyük ölçüde testler kullanılarak gerçekleştirildi. Herhangi bir hata ayıklayıcı veya GOP kullanmadık.

In: – Yayınla işlevinin uygulandığı slaydı geri verebilir misiniz? Tek harfli değişken adları kafanızı karıştırıyor mu?

HANIM: - HAYIR. Oldukça "dar" bir görünürlük kapsamına sahiptirler. Burası dışında başka hiçbir yerde kullanılmazlar (bu sınıfın iç kısımları hariç) ve çok kompakttır - yalnızca 7 satır alır.

In: – Her nasılsa hala sezgisel değil…

HANIM: - Hayır, hayır, bu gerçek bir şifre! Bu tarzla ilgili değil. O kadar kullanışlı ve küçük bir sınıf ki, sınıfın içinde sadece 3 alan var...

Mikhail Salosin. Golang Buluşması. Look+ uygulamasının arka ucunda Go'yu kullanma

HANIM: – Müşterilerle (sezon maçları, oyuncular) senkronize edilen tüm veriler genel olarak değişmez. Kabaca söylemek gerekirse, maçı değiştirmemiz gereken başka bir spor yaparsak, istemcinin yeni sürümündeki her şeyi hesaba katacağız ve istemcinin eski sürümleri yasaklanacak.

In: – Herhangi bir üçüncü taraf bağımlılık yönetimi paketi var mı?

HANIM: – Go dep’i kullandık.

In: – Raporun konusunda videoyla ilgili bir şeyler vardı ama raporda videoyla ilgili hiçbir şey yoktu.

HANIM: – Hayır, videonun konusuyla ilgili hiçbir şeyim yok. Buna "Look+" adı veriliyor - uygulamanın adı bu.

In: – Müşterilere aktarıldığını mı söylediniz?..

HANIM: – Video akışına dahil değildik. Bu tamamen Megafon tarafından yapıldı. Evet uygulamanın MegaFon olduğunu söylemedim.

HANIM: – Go – tüm verileri göndermek için – skor, maç olayları, istatistikler... Go, uygulamanın tüm arka ucudur. Kullanıcının maçı izleyebilmesi için, müşterinin oyuncu için hangi bağlantıyı kullanacağını bir yerden bilmesi gerekir. Hazırlanan video ve yayınlara bağlantılarımız mevcuttur.

Bazı reklamlar 🙂

Bizimle kaldığın için teşekkürler. Yazılarımızı beğeniyor musunuz? Daha ilginç içerik görmek ister misiniz? Sipariş vererek veya arkadaşlarınıza tavsiye ederek bize destek olun, Geliştiriciler için bulut VPS'si 4.99 ABD dolarından başlayan fiyatlarla, sizin için bizim tarafımızdan icat edilen benzersiz bir giriş seviyesi sunucu analoğu: 5$'dan başlayan fiyatlarla VPS (KVM) E2697-3 v6 (10 Çekirdek) 4GB DDR480 1GB SSD 19Gbps hakkındaki tüm gerçekler veya bir sunucu nasıl paylaşılır? (RAID1 ve RAID10, 24 adede kadar çekirdek ve 40 GB'a kadar DDR4 ile mevcuttur).

Amsterdam'daki Equinix Tier IV veri merkezinde Dell R730xd 2 kat daha mı ucuz? Sadece burada 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV 199$'dan Hollanda'da! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - 99$'dan! Hakkında oku Altyapı şirketi nasıl kurulur? Bir kuruş için 730 Euro değerinde Dell R5xd E2650-4 v9000 sunucuların kullanımı ile sınıf?

Kaynak: habr.com

Yorum ekle