Mikhail Salosin. Meetup Golang. Menggunakan Go di backend aplikasi Watch +

Mikhail Salosin (selanjutnya - MS): - Halo semuanya! Nama saya adalah Michael. Saya bekerja sebagai pengembang backend di MC2 Software, dan saya akan berbicara tentang menggunakan Go di backend aplikasi seluler Watch +.



Adakah yang hadir seperti hoki?



Maka aplikasi ini adalah untuk Anda. Ini untuk Android dan iOS, digunakan untuk menonton siaran berbagai acara olahraga online dan dalam rekaman. Juga dalam aplikasi terdapat berbagai statistik, siaran teks, tabel untuk konferensi, turnamen, dan informasi lain yang berguna bagi penggemar.



Juga dalam aplikasi ada hal-hal seperti momen video, yaitu, Anda dapat melihat momen akut pertandingan (gol, perkelahian, baku tembak, dll.). Jika Anda tidak ingin menonton seluruh siaran, Anda hanya dapat menonton yang paling menarik.

Apa yang digunakan dalam pengembangan?


Badan utama ditulis dalam Go. API yang dikomunikasikan dengan klien seluler ditulis dalam Go. Juga, sebuah layanan ditulis di Go untuk mengirim pemberitahuan push ke ponsel. Kami juga harus menulis ORM kami sendiri, yang suatu hari nanti dapat kami bicarakan. Nah, beberapa layanan kecil ditulis di Go: mengubah ukuran dan memuat gambar untuk editor ...

Kami menggunakan Postgres (PostgreSQL) sebagai basis data. Antarmuka untuk editor ditulis dalam Ruby on Rails menggunakan permata ActiveAdmin. Impor statistik dari penyedia statistik juga ditulis di Ruby.

Untuk pengujian API sistem, kami menggunakan Python unittest (Python). Memcached digunakan untuk membatasi permintaan pembayaran API, Chef untuk mengontrol konfigurasi, Zabbix untuk mengumpulkan dan memantau statistik sistem internal. Graylog2 - untuk mengumpulkan log, Slate adalah dokumentasi API untuk klien.



Pemilihan protokol


Masalah pertama yang kami temui: kami harus memilih protokol untuk interaksi backend dengan klien seluler, berdasarkan poin berikut ...

  • Persyaratan paling penting: data klien harus diperbarui secara real time. Artinya, setiap orang yang sedang menonton siaran harus menerima pembaruan hampir secara instan.
  • Untuk kesederhanaan, kami menerima bahwa data yang disinkronkan dengan klien tidak dihapus, tetapi disembunyikan menggunakan bendera khusus.
  • Semua jenis permintaan langka (seperti statistik, lineup, statistik tim) diterima oleh permintaan GET biasa.
  • Plus, sistem itu seharusnya menahan 100.000 pengguna pada saat yang sama.

Berdasarkan ini, kami memiliki dua opsi protokol:
  1. Soket web. Tetapi kami tidak membutuhkan saluran dari klien ke server. Kami hanya perlu mengirim pembaruan dari server ke klien, jadi soket web adalah opsi yang berlebihan.
  2. Server-Sent Events (SSE) muncul tepat! Ini cukup sederhana dan pada dasarnya memuaskan semua yang kita butuhkan.

Acara yang Dikirim Server


Beberapa kata tentang bagaimana hal ini

bekerja ... Ini berfungsi di atas koneksi http. Klien mengirim permintaan, server merespons dengan Content-Type: text / event-stream dan tidak menutup koneksi dengan klien, tetapi terus menulis data ke koneksi:



Data dapat dikirim dalam format yang disepakati dengan klien. Dalam kasus kami, kami mengirimkan formulir ini: di bidang acara, nama struktur yang diubah (orang, pemain) dikirim, dan di bidang data - JSON dengan bidang yang baru dan diubah untuk pemain.

Sekarang tentang bagaimana interaksi itu sendiri bekerja.
  • Pertama-tama, klien menentukan kapan sinkronisasi terakhir dibuat dengan layanan: itu melihat database lokalnya dan menentukan tanggal perubahan terakhir yang dicatat darinya.
  • Dia mengirim permintaan dengan tanggal ini.
  • Sebagai tanggapan, kami mengirimkan kepadanya semua pembaruan yang terjadi pada tanggal ini.
  • Setelah itu, ia membuat koneksi ke saluran langsung dan tidak menutup sampai ia membutuhkan pembaruan ini:



Kami mengirimkan kepadanya daftar perubahan: jika seseorang mencetak gol - kami mengubah skor pertandingan, cedera - juga mengirimnya dalam waktu nyata. Dengan demikian, dalam arus pertandingan, pelanggan langsung menerima data yang relevan. Secara berkala, sehingga klien memahami bahwa server belum mati, bahwa tidak ada yang terjadi padanya, kami mengirim stempel waktu setiap 15 detik - sehingga ia tahu bahwa semuanya beres dan tidak perlu tersambung kembali.

Bagaimana koneksi langsung dilayani?


  • Pertama-tama, kami membuat saluran tempat pembaruan dengan buffer akan datang.
  • Setelah itu, kami berlangganan saluran ini untuk menerima pembaruan.
  • Atur tajuk yang benar sehingga klien tahu bahwa semuanya baik-baik saja.
  • ping. timestamp .
  • , . timestamp, , .



Masalah pertama yang kami temui adalah sebagai berikut: untuk setiap koneksi yang dibuka dengan klien, kami membuat timer yang berdetak setiap 15 detik - ternyata jika kami memiliki 6.000 koneksi dengan satu mesin (dengan satu server API), 6 ribu timer dibuat. Ini mengarah pada fakta bahwa mesin tidak menahan beban yang diperlukan. Masalahnya tidak begitu jelas bagi kami, tetapi mereka sedikit membantu kami, dan kami menghilangkannya.

Akibatnya, sekarang kami memiliki ping yang berasal dari saluran yang sama dari mana pembaruan datang.

Dengan demikian, hanya ada satu timer yang berdetak setiap 15 detik sekali.

Berikut adalah beberapa fungsi pembantu - mengirim header, ping, dan struktur itu sendiri. Yaitu, nama tabel (orang, pertandingan, musim) dan informasi tentang catatan ini dikirimkan di sini:



Mekanisme untuk mengirim pembaruan


Sekarang sedikit tentang dari mana perubahan itu berasal. Kami memiliki beberapa orang, editor, yang menonton siaran secara langsung. Mereka menciptakan semua peristiwa: seseorang telah dihapus, seseorang terluka, semacam penggantian ...

Dengan bantuan CMS, data masuk ke dalam basis data. Setelah itu, database yang menggunakan mekanisme Listen / Notify memberi tahu server API tentang ini. Server API sudah mengirimkan informasi ini ke klien. Jadi, pada kenyataannya, kami hanya memiliki beberapa server yang terhubung ke database dan tidak ada beban khusus pada database, karena klien tidak berinteraksi langsung dengan database dengan cara apa pun:



PostgreSQL: Dengar / Beritahu


Mekanisme Listen / Notify di Postgres memungkinkan Anda untuk memberi tahu pelanggan tentang peristiwa yang beberapa peristiwa telah ubah - semacam catatan telah dibuat dalam database. Untuk melakukan ini, kami menulis pemicu dan fungsi sederhana:



Saat menyisipkan atau mengubah catatan, kami memanggil fungsi notifikasi pada saluran data_updates, mentransfer nama tabel dan pengidentifikasi catatan yang diubah atau disisipkan di sana.

Untuk semua tabel yang harus disinkronkan dengan klien, kami menetapkan pemicu bahwa, setelah mengubah / memperbarui catatan, memanggil fungsi yang ditunjukkan pada slide di bawah ini.
Bagaimana API berlangganan perubahan ini?

Mekanisme Fanout dibuat - mengirimkan pesan ke klien. Dia mengumpulkan semua saluran pelanggan dan mengirimkan pembaruan yang dia terima melalui saluran ini:



Di sini pq pustaka standar, yang terhubung ke database dan mengatakan bahwa ia ingin mendengarkan saluran (data_updates), memeriksa apakah koneksi terbuka dan semuanya baik-baik saja. Saya menghilangkan pemeriksaan kesalahan untuk menghemat ruang (jangan centang penuh).

Selanjutnya, kami mengatur Ticker secara tidak sinkron, yang akan mengirim ping setiap 15 detik, dan mulai mendengarkan saluran tempat kami berlangganan. Jika kami mendapat ping, kami menerbitkan ping ini. Jika kami menerima catatan, maka kami menerbitkan catatan ini untuk semua pelanggan Fanout ini.

Bagaimana cara kerja fan-out?


Dalam bahasa Rusia, ini diterjemahkan sebagai "pembagi". Kami memiliki satu objek yang mendaftarkan pelanggan yang ingin menerima pembaruan apa pun. Dan segera setelah pembaruan untuk objek ini tiba, menyebar pembaruan ini ke semua pelanggan yang dimilikinya. Cukup sederhana:



Bagaimana ini diterapkan pada Go:



Ada struktur, disinkronkan menggunakan Mutex. Ia memiliki bidang yang menyimpan status koneksi Fanout ke basis data, yaitu, saat ini ia mendengarkan dan akan menerima pembaruan, serta daftar semua saluran yang tersedia - peta, yang kuncinya adalah saluran dan struct dalam bentuk nilai (pada kenyataannya, itu tidak digunakan dengan cara apa pun).

Dua metode - Tersambung dan Terputus - memungkinkan Anda memberi tahu Fanout bahwa kami memiliki koneksi ke pangkalan, muncul dan bahwa koneksi ke pangkalan terputus. Dalam kasus kedua, Anda perlu memutuskan semua klien dan memberi tahu mereka bahwa mereka tidak dapat lagi mendengarkan apa pun dan bahwa mereka terhubung kembali, karena koneksi dengan mereka telah ditutup.

Ada juga metode Berlangganan yang menambahkan saluran ke pendengar:



Ada metode Berhenti Berlangganan yang menghapus saluran dari pendengar jika klien terputus, serta metode Terbitkan yang memungkinkan Anda mengirim pesan ke semua pelanggan.

Pertanyaan: - Apa yang ditransmisikan melalui saluran ini?

MS: - Sebuah model ditransmisikan yang telah berubah atau ping (pada dasarnya hanya angka, integer).

MS:- Anda dapat mengirim apa pun, menerbitkan struktur apa pun, hanya berubah menjadi JSON dan hanya itu.

MS: - Kami mendapat notifikasi dari Postgres - ini berisi nama tabel dan pengenal. Dengan nama tabel yang kita dapatkan dan pengidentifikasi kita mendapatkan catatan yang kita butuhkan, dan sudah struktur ini dikirim untuk publikasi.

Infrastruktur


Seperti apa infrastrukturnya? Kami memiliki 7 server besi: salah satunya sepenuhnya didedikasikan untuk pangkalan, komputer virtual berputar pada enam sisanya. Ada 6 salinan API: setiap mesin virtual dengan API berjalan pada server besi yang terpisah - ini untuk keandalan.



Kami memiliki dua frontend di mana Keepalived diinstal untuk meningkatkan aksesibilitas, sehingga jika satu frontend dapat menggantikan yang lainnya. Dua salinan CMS lainnya.

Ada juga importir statistik. Ada Slave DB dari mana cadangan dibuat secara berkala. Ada Pigeon Pusher - aplikasi yang mengirimkan pushies kepada pelanggan, serta hal-hal infrastruktur: Zabbix, Graylog2 dan Chef.

Faktanya, infrastruktur ini berlebihan, karena 100 ribu dapat dilayani dengan server yang lebih sedikit. Tapi ada besi - kami menggunakannya (kami diberitahu bahwa itu mungkin - mengapa tidak).

Pros of Go


Setelah kami mengerjakan aplikasi ini, keuntungan yang jelas dari Go terungkap.
  • Pustaka http keren. Dengan menggunakannya, Anda dapat membuat cukup banyak di luar kotak.
  • Plus, saluran yang memungkinkan kami menerapkan mekanisme pengiriman pemberitahuan ke pelanggan dengan sangat mudah.
  • Detektor Ras yang luar biasa memungkinkan kami untuk menghilangkan beberapa bug kritis (staging-infrastruktur). Segala sesuatu yang bekerja pada pementasan sedang berjalan, dikompilasi dengan kunci Race; dan, karenanya, kita dapat melihat potensi masalah apa yang kita miliki pada infrastruktur pementasan.
  • Minimalisme dan kesederhanaan bahasa.




Kami mencari pengembang! Jika seseorang ingin - tolong.

Pertanyaan


Pertanyaan dari hadirin (selanjutnya - B): - Sepertinya saya bahwa Anda melewatkan satu poin penting tentang Penggeledahan. Saya mengerti benar bahwa ketika Anda mengirim respons ke klien, Anda diblokir jika klien tidak ingin membaca?

MS: - Tidak, kami tidak menghalangi. Pertama, kami memiliki semuanya di belakang nginx, yaitu, tidak ada masalah dengan klien yang lambat. Kedua, klien memiliki saluran dengan buffer - pada kenyataannya, kita dapat memasang hingga seratus pembaruan di sana ... Jika kita tidak dapat menulis ke saluran, maka itu menghapusnya. Jika kami melihat bahwa saluran tersebut diblokir, maka kami tutup saja salurannya, dan itu saja - klien akan menyambung kembali jika ada masalah. Karena itu, pada prinsipnya, pemblokiran tidak terjadi di sini.

T: - Bisakah Anda segera mengirim untuk Mendengarkan / Memberitahu catatan, bukan tabel pengenal?

MS:- Dengar / Beritahu memiliki batas 8 ribu byte per preload, yang dikirimkannya. Pada prinsipnya, akan mungkin untuk mengirim jika kami berurusan dengan sejumlah kecil data, tetapi menurut saya cara [seperti yang kita lakukan] lebih dapat diandalkan. Keterbatasan ada di Postgres itu sendiri.

T: - Apakah pelanggan menerima pembaruan pada pertandingan yang tidak mereka minati?

MS:- Secara umum, ya. Sebagai aturan, ada 2-3 pertandingan secara paralel, dan kemudian sangat jarang. Jika klien menonton sesuatu, maka biasanya dia menonton pertandingan yang sedang berlangsung. Kemudian, pada klien ada basis data lokal di mana semua pembaruan ini ditambahkan, dan bahkan tanpa koneksi Internet, klien dapat melihat semua kecocokan sebelumnya di mana ia memiliki pembaruan. Faktanya, kami menyinkronkan basis data kami di server dengan basis data lokal klien sehingga dapat bekerja offline.

T: - Mengapa Anda membuat ORM Anda?

Alexey (salah satu pengembang "Watch +"):- Pada waktu itu (setahun yang lalu) ORM kurang dari sekarang, ketika ada cukup banyak dari mereka. Dari sebagian besar ORM yang ada, yang paling saya sukai adalah kebanyakan dari mereka bekerja pada antarmuka kosong. Yaitu, metode yang dalam

ORM ini siap untuk melakukan apa saja: struktur, penunjuk struktur, angka, sesuatu yang tidak relevan sama sekali ... ORM kami menghasilkan struktur berdasarkan model data. Diri. Dan karena itu, semua metode konkret, tidak menggunakan refleksi, dll. Mereka menerima struktur dan berharap untuk menggunakan struktur yang datang.

T: - Berapa banyak orang yang berpartisipasi?

MS: - Pada tahap awal, dua orang berpartisipasi. Di suatu tempat di bulan Juni kami mulai, pada bulan Agustus bagian utama sudah siap (versi pertama). Pada bulan September ada rilis.

DI:- Di mana Anda menggambarkan SSE, Anda tidak menggunakan batas waktu. Mengapa demikian?

MS: - Sejujurnya, SSE masih merupakan protokol html5: standar SSE dirancang untuk berkomunikasi dengan browser, seperti yang saya mengerti. Ini memiliki fitur tambahan sehingga browser dapat terhubung kembali (dan sebagainya), tetapi kami tidak membutuhkannya, karena kami memiliki klien yang dapat menerapkan logika apa pun untuk menghubungkan dan menerima informasi. Kami lebih cenderung tidak SSE, tetapi sesuatu yang mirip dengan SSE. Ini bukan protokol itu sendiri.
Tidak perlu. Sejauh yang saya mengerti, klien menerapkan mekanisme koneksi dari awal. Pada prinsipnya mereka tidak peduli.

T: - Utilitas tambahan apa yang Anda gunakan?

MS:- Yang paling aktif kami menggunakan govet dan golint, sehingga gaya itu disatukan, serta gofmt. Mereka tidak menggunakan yang lain.

T: - Dengan apa yang Anda debug?

MS: - Pada umumnya, debugging dilakukan menggunakan tes. Tidak ada debugger, GOP yang tidak kami gunakan.

T: - Dapatkah Anda mengembalikan slide di mana fungsi Publikasikan diterapkan? Nama variabel satu huruf tidak mengganggu Anda?

MS: - Tidak. Mereka memiliki ruang lingkup yang cukup "sempit". Mereka tidak digunakan di tempat lain (kecuali di sini) (kecuali untuk bagian dalam kelas ini), dan sangat kompak - hanya membutuhkan 7 baris.

T: - Entah bagaimana itu masih tidak intuitif ...

MS:- Tidak, tidak, ini kode nyata! Ini bukan tentang gaya. Itu hanya utilitarian, kelas yang sangat kecil - hanya ada 3 bidang di dalam kelas ...



MS: - Secara umum, semua data yang disinkronkan dengan pelanggan (pertandingan musiman, pemain) tidak berubah. Secara kasar, jika kita akan melakukan beberapa olahraga lain di mana akan diperlukan untuk mengubah pertandingan, kami hanya akan mempertimbangkan segala sesuatu dalam versi baru dari klien, dan versi lama dari klien akan dilarang.

T: - Apakah ada paket pihak ketiga untuk manajemen ketergantungan?

MS: - Kami dulu pakai dep.

T: - Ada sesuatu tentang video dalam subjek laporan, tetapi tidak ada tentang video dalam laporan.

MS: - Tidak, saya tidak punya topik tentang video. Ini disebut "Lihat +" - ini adalah nama aplikasi.

DI:- Anda mengatakan bahwa Anda streaming ke pelanggan? ..

MS: - Kami tidak melakukan streaming video. Ini sepenuhnya dilakukan oleh Megaphone. Ya, saya tidak mengatakan bahwa aplikasi tersebut adalah megafon.

MS: - Pergi - untuk mengirim semua data - berdasarkan skor, pertandingan, statistik ... Go - ini adalah backend keseluruhan untuk aplikasi. Klien harus mencari tahu dari suatu tempat tautan mana yang digunakan untuk pemain sehingga pengguna dapat menonton pertandingan. Kami memiliki tautan ke video dan streaming yang disiapkan.


Sedikit iklan :)


Terima kasih untuk tetap bersama kami. Apakah Anda suka artikel kami? Ingin melihat materi yang lebih menarik? Dukung kami dengan melakukan pemesanan atau merekomendasikan kepada teman Anda VPS berbasis cloud untuk pengembang mulai $ 4,99 , analog unik dari server entry-level yang diciptakan oleh kami untuk Anda: Seluruh kebenaran tentang VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps mulai dari $ 19 atau cara membagi server? (opsi tersedia dengan RAID1 dan RAID10, hingga 24 core dan hingga 40GB DDR4).

Dell R730xd 2 kali lebih murah di pusat data Equinix Tier IV di Amsterdam? Hanya kami yang memiliki 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV dari $ 199 di Belanda!Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - mulai dari $ 99! Baca tentang Cara Membangun Infrastruktur Bldg. kelas c menggunakan server Dell R730xd E5-2650 v4 seharga 9.000 euro untuk satu sen?

All Articles