Dari Pemula hingga Ikon Gaya: bagaimana kami membuat penghargaan di 2GIS



Setiap hari, pengguna 2GIS membantu kami menjaga akurasi data: mereka melaporkan perusahaan baru, menambahkan acara lalu lintas, mengunggah foto, dan menulis ulasan. Sebelumnya, kami hanya bisa berterima kasih kepada mereka dengan kata-kata atau mengatur hadiah. Namun seiring waktu, kata-kata dilupakan, dan tidak semua orang mendapat hadiah. Oleh karena itu, kami memutuskan untuk memastikan bahwa semua orang yang peduli tentang 2GIS melihat kontribusi mereka terhadap produk dan terima kasih kami untuk ini.

Jadi ada penghargaan - medali virtual yang kami dapatkan untuk berbagai jenis tugas: unggah foto ke kartu kafe, tulis ulasan tentang teater, tentukan jam kerja organisasi, dan sebagainya. Pengguna melihat hadiah yang diperoleh di profil 2GIS pribadi mereka dan pada tab "My 2GIS" di aplikasi seluler. Di sana kami menunjukkan berapa banyak yang tersisa hingga pencapaian berikutnya.

Untuk mengimplementasikan fitur ini, kami mempelajari cara memproses aliran peristiwa dengan volume 500 ribu catatan per jam (di tempat hingga 50 ribu catatan per detik) dan menganalisis data dari beberapa layanan. Dan juga - mereka menambahkan sedikit metaprogramming untuk menyederhanakan konfigurasi ketika mengembangkan penghargaan baru.

Bersama dengan Rapter , kami akan memberi tahu Anda apa yang ada di bawah tenda proses penghargaan.

Konsep


Untuk memahami kompleksitas fitur, Anda perlu memahami bagaimana masalah teknis terdengar. Kemudian - pertimbangkan gagasan implementasi dan skema umum komponen sistem. Inilah yang akan kita lakukan di bagian ini.

Persyaratan untuk Abstrak


Persyaratan - hal yang agak membosankan, jadi kami tidak akan melukis semua nuansa, kami akan berkonsentrasi pada hal-hal yang paling penting:

  • penghargaan hanya diberikan kepada pengguna yang berwenang;
  • memperbarui kemajuan pada hadiah harus secepat mungkin;
  • hadiah - hasil dari pengguna yang melakukan serangkaian tindakan dalam produk: mengunggah foto, menulis ulasan, menemukan arah, dll. Ada banyak sumber data.

Ide arsitektur


Gagasan implementasi tidak terlalu rumit. Itu dapat diungkapkan secara tesis:

  • penghargaan terdiri dari tugas-tugas, yang hasilnya digabungkan sesuai dengan formula yang ditentukan saat mengkonfigurasi penghargaan;
  • tugas menanggapi peristiwa tentang tindakan pengguna yang datang dari luar, memfilternya dan mendaftarkan perubahan yang sedang berlangsung dalam bentuk penghitung;
  • "Peristiwa eksternal" dihasilkan oleh sistem master (foto, umpan balik, layanan penyempurnaan, dll.) Atau layanan tambahan yang mengubah atau memfilter aliran acara yang sudah ada;
  • pemrosesan peristiwa terjadi secara tidak sinkron dan dapat dihentikan kapan saja jika perlu;
  • pengguna melihat status penghargaannya saat ini;
  • yang lainnya adalah detail ...

Entitas Kunci


Diagram di bawah ini menunjukkan entitas utama dari area subjek dan hubungannya:



Dua zona dibedakan dalam diagram:

  • Skema - zona untuk menggambarkan struktur penghargaan dan aturan untuk akrualnya;
  • Data - Area penghargaan untuk pengguna tertentu dan data yang terkait dengan status mereka saat ini.

Entitas dalam diagram:

  • Mencapai - informasi tentang penghargaan yang dapat diperoleh. Termasuk meta-informasi dan deskripsi cara menggabungkan hasil tugas - strategi.
  • Objektif - tugas, kondisi yang harus dipenuhi untuk maju untuk menerima penghargaan.
  • UserAchieve - kondisi hadiah saat ini untuk pengguna tertentu.
  • UserObjective - keadaan saat ini dari pekerjaan hadiah pengguna.
  • Pengguna - informasi tentang pengguna, yang diperlukan untuk pemberitahuan dan pemahaman tentang statusnya saat ini (hadiah jarak jauh dan banned tidak diperlukan).
  • ProcessingLog - log akrual untuk tugas. Berisi informasi tentang bagaimana suatu tindakan spesifik memengaruhi kemajuan penugasan.
  • Peristiwa - informasi minimum yang diperlukan tentang suatu peristiwa yang entah bagaimana mempengaruhi kemajuan tugas pengguna.

Struktur layanan


Sekarang pertimbangkan komponen utama dari layanan dan dependensinya:



  • Event Bus - sebuah bus acara yang dapat digunakan untuk menyelesaikan tugas. Kami menggunakan Apache Kafka.
  • Master dan Slave DB adalah gudang data utama. Dalam hal ini, cluster PostgreSQL.
  • ConsumingWorkers - penangan acara bus. Tugas utama adalah membaca peristiwa dari sumber tertentu (foto, ulasan, dll.), Menerapkannya pada tugas pengguna dan menyimpan hasilnya.
  • AchievesWorker - menceritakan kemajuan penghargaan pengguna sesuai dengan status tugas.
  • NotificationWorkers - seperangkat penangan untuk penjadwalan dan mengirim pemberitahuan tentang menerima penghargaan, pengumuman kemungkinan pencapaian baru, dll.
  • API Publik - antarmuka REST publik untuk aplikasi Web dan seluler.
  • API Pribadi - antarmuka REST untuk panel admin, yang membantu dalam penyelidikan insiden dan dukungan layanan. Ini tersedia untuk pengembang dan tim pendukung.

Masing-masing komponen terisolasi dalam hal logika dan bidang tanggung jawab, yang menghindari integrasi dan deadlock yang tidak perlu saat memodifikasi data. Di bawah ini kami menganggap hanya sebagian dari skema yang terkait dengan pemrosesan acara dan mengubahnya menjadi hadiah.

Penanganan acara


Konten


Hadiah utamanya adalah layanan agregasi data. Setiap sistem master menghasilkan beberapa jenis peristiwa. Sebagai aturan, setiap jenis peristiwa terkait erat dengan keadaan konten, model statusnya. Jadi, foto dapat dimoderasi, dihapus, diblokir, disembunyikan, atau aktif. Semua ini adalah peristiwa yang berbeda yang ditangani oleh pekerja terpisah yang berspesialisasi dalam sumber tertentu. Saat ini, ada interaksi dengan sumber-sumber berikut (sistem master):

  • Foto - menghasilkan berbagai peristiwa yang berhubungan dengan operasi yang dilakukan oleh pengguna pada foto.
  • Ulasan - acara yang terkait dengan operasi pada ulasan pengguna.
  • Datafeedback - peristiwa yang terkait dengan operasi penyempurnaan. Klarifikasi adalah perubahan informasi tentang suatu objek pada peta, baik itu perusahaan atau monumen.
  • Pemeriksaan - peristiwa yang berhubungan dengan aplikasi Pemeriksaan 2GIS.
  • BSS adalah peristiwa analitik yang menghasilkan aplikasi 2GIS. Misalnya, pembukaan perusahaan tertentu, perjalanan dengan navigator, dll.



Peristiwa yang dihasilkan oleh sistem master masuk ke dalam topik Kafka dalam urutan mengubah status mereka, yang memungkinkan untuk memindahkan progres penghargaan bagi pengguna tidak hanya maju, tetapi juga mengembalikannya. Misalnya, jika foto itu dalam status "aktif", dan karena alasan tertentu memperoleh status "diblokir", kemajuan penghargaan harus berubah ke bawah. Kemajuan penghargaan adalah interpretasi dari objek internal yang disebut penghitung konten.

Penghitung dapat bervariasi untuk data yang berbeda. Misalnya, untuk acara tentang foto, mereka adalah sebagai berikut: jumlah yang disetujui, jumlah moderasi, jumlah diblokir, dan untuk acara pembukaan kartu, Anda hanya perlu mempertimbangkan jumlah kartu yang dibuka oleh pengguna. Berdasarkan nilai saat ini dari penghitung konten, untuk pengguna tertentu, dalam kerangka penghargaan tertentu, jawaban atas pertanyaan berikut ditentukan:

  • Sudahkah penghargaan dimulai?
  • apa kemajuannya
  • Apakah hadiah sudah selesai?

Filter dan Aturan


Penghitung pekerjaan dari penghargaan tertentu diubah hanya jika suatu peristiwa telah tiba dengan jenis konten yang diinginkan, serta dengan data yang diperlukan yang diperlukan untuk menerima penghargaan.

Untuk melewati hanya konten yang sesuai untuk penghargaan, kami menjalankan setiap acara melalui serangkaian filter dan aturan.

Filter adalah batasan tertentu yang dikenakan pada konten. Dia hanya peduli dengan menjawab pertanyaan: "Apakah acara baru cocok dengan kondisi ini atau tidak?"
Aturan adalah filter khusus, yang tujuannya adalah untuk mengatakan: "Jika suatu peristiwa cocok dengan kondisi tersebut, lalu bagaimana seharusnya penghitung berubah?" Aturan termasuk algoritma untuk mengubah penghitung. Setiap penghargaan hanya berisi satu aturan.

Implementasi filter dan aturan ada dalam kode proyek, dan deskripsi filter (aturan) mana yang termasuk penghargaan tertentu ada di database dalam format JSON. Kami tidak langsung mengambil keputusan seperti itu. Awalnya, filter dan aturan tidak dapat diatur menggunakan konfigurasi melalui database, penghargaan sepenuhnya dijelaskan dalam kode, hanya pengenalnya yang disimpan dalam tabel. Keputusan ini memberikan sejumlah kelemahan signifikan:

  • Masalah mendukung beberapa lingkungan. Jika Anda ingin meluncurkan satu status dari daftar penghargaan ke lingkungan pengujian, dan mengirim yang lain ke pertempuran, Anda perlu mengetahui kode lingkungan dalam kode proyek atau memiliki file konfigurasi dengan daftar penghargaan. Pada saat yang sama, tidak mungkin untuk menggunakan basis data yang berbeda untuk tugas ini, meskipun mereka sudah ada untuk setiap lingkungan.
  • Kemampuan untuk mengonfigurasi pemfilteran hanya oleh pengembang. Karena semuanya dijelaskan dalam kode, hanya orang yang mengetahui proyek dan bahasa pemrograman yang dapat membuat perubahan, saya ingin dimungkinkan untuk melakukan ini hanya melalui API atau basis data pribadi.
  • Kerugian dari melihat. Ada banyak hadiah, terkadang Anda perlu melihat filter yang mereka gunakan. Setiap kali, melakukan ini dengan melihat kode sangat membosankan.

Pada awal aplikasi, kami mencocokkan dengan nama filter yang dimuat dari database dan menaruhnya dalam hadiah tertentu. Contoh deskripsi filter:

[ { "name":"SourceFilter", "config":{ "sources":["reviews"] } }, { "name": "ReviewsLengthFilter", "config": { "allowed_length": 100 } } ] 

Dalam hal ini, kami hanya akan mengambil ulasan tersebut (ini ditunjukkan oleh objek deskripsi pertama dari array filter), teks yang berisi lebih dari 100 karakter (filter kedua dalam daftar).

Deskripsi aturan contoh:

 {"name": "ReviewUniqueByObjectRule","config":{}} 

Aturan ini akan memungkinkan Anda untuk mengubah penghitung hanya jika pengguna menulis ulasan untuk objek, sementara hanya satu ulasan akan diperhitungkan untuk satu objek.

Bss


Mari kita bekerja secara terpisah untuk bekerja dengan aliran acara BSS. Setidaknya ada tiga alasan untuk ini:

  • Acara Analytics tidak dapat dibatalkan, tidak ada model status di dalamnya, yang secara umum logis, karena mengemudi melalui navigator atau membuat rute tidak dapat dibatalkan. Tindakan itu ada di sana atau tidak.
  • Volume. Biarkan saya mengingatkan Anda bahwa total pemirsa 2GIS adalah 50+ juta pengguna per bulan. Bersama-sama mereka membuat lebih dari 1,5 miliar permintaan pencarian, serta banyak tindakan lain: meluncurkan aplikasi, melihat kartu objek, dll. Pada puncaknya, jumlah acara dapat mencapai 50.000 per detik. Kami harus meneruskan semua informasi ini melalui filter untuk memberikan hadiah kepada pengguna.
  • Acara Analytics memiliki fitur: beberapa format, berbagai jenis.

Semua ini sangat mempengaruhi pemrosesan data dari topik BSS, karena jika kita membutuhkan waktu nyata, maka kita perlu waktu pemrosesan yang sangat dekat.

Untuk mengurangi perbedaan yang diuraikan, layanan terpisah telah dibuat yang menyiapkan acara semacam itu. Layanan ini dapat bekerja dengan seluruh variasi format pesan yang berasal dari analytics. Inti dari karyanya adalah sebagai berikut: seluruh aliran acara BSS dibaca, dari mana hanya yang diperlukan untuk Penghargaan yang diambil. Filter layanan seperti itu secara signifikan mengurangi beban (setelah pemfilteran, laju aliran adalah ≈300 peristiwa per detik) dari Hadiah prosesor aliran BSS, dan juga menghasilkan peristiwa dalam format tunggal, meratakan kerugian yang terkait dengan sejarah analitik internal.

Penghargaan


Jadi, kami menemukan cara untuk menangani acara dan menghitung kemajuan tugas. Sekarang saatnya untuk melihat proses pemberian hadiah kepada pengguna.

Pertanyaan pertama yang muncul adalah: mengapa mengalokasikan output ke pekerja yang terpisah, tidak dapatkah ia dihitung ulang saat memproses setiap peristiwa? Jawab: mungkin, tetapi tidak sepadan.

Ada beberapa alasan untuk mengalokasikan ekstradisi ke proses terpisah:

  1. Mentransfer penghitungan ulang ke setiap ConsumingWorker, kami mendapatkan Kondisi Balapan untuk operasi memperbarui kemajuan dengan hadiah, karena setiap penangan akan mencoba memperbarui kemajuan berdasarkan pada keadaan tugas yang diketahui, dan yang lain akan secara aktif mengubah status ini.
  2. Setiap kumpulan ConsumingWorker memproses acara dari Kafka dalam suatu transaksi. Dengan menambahkan sisipan ke tabel hadiah pengguna, kami akan memanggil kunci tambahan di tingkat basis data, yang akan menghambat penangan lain.
  3. Dalam proses mengeluarkan penghargaan, ada logika untuk mengirim pemberitahuan, yang hanya akan memperlambat pemrosesan aliran acara, yang tidak diinginkan.

Alasan munculnya AchievesWorker yang terpisah (penangan untuk pemberian penghargaan) diurutkan keluar. Sekarang Anda perlu berurusan dengan dua bagian penting dari pemrosesan:

  1. Ada satu set pencarian dalam hadiah. Ada satu set penghitung untuk tugas-tugas ini. Bagaimana memahami seberapa banyak penghargaan dibuat dan bagaimana mengekspresikannya dalam kode?
    Contoh: Anda perlu menulis 3 ulasan atau mengunggah 3 foto. Pengguna memiliki 1 ulasan dan 2 foto. Apa kemajuan dari penghargaan itu? Jawaban: 3, karena pengguna pasti akan yakin bahwa Anda membutuhkan total 3.
  2. Kami memiliki penangan terpisah untuk menerbitkan penghargaan. Setiap kali, menceritakan beberapa lusin penghargaan untuk setiap pengguna yang berwenang, yaitu beberapa puluh juta, tidak mungkin berhasil dengan cepat. Bagaimana dia bisa belajar tentang kemajuan pengguna mana dan pada tugas apa yang telah berubah sejak pemrosesan terakhir?

Kami akan mempertimbangkan setiap bagian secara terpisah.

Aliran kemajuan


Untuk pemahaman yang lebih baik tentang bagaimana Anda dapat menggambarkan bagaimana mengubah kemajuan tugas menjadi kemajuan dengan penghargaan, kami membagi penghargaan ke dalam kategori dan melihat transformasi.

"Selesaikan satu tugas per X unit." Contoh: Berkendara 10 km di navigator.



"Selesaikan beberapa tugas untuk masing-masing unit X." Contoh: unggah 5 foto dan tulis 5 ulasan dalam kartu - hanya 10 unit konten.



"Selesaikan beberapa tugas untuk unit X secara total." Contoh: tulis 5 ulasan atau unggah 5 foto.



"Selesaikan beberapa tugas yang dikelompokkan berdasarkan jenis." Contoh: unggah 5 unit konten (foto atau ulasan) dan kendarai 10 km di navigator.



Secara teoritis, mungkin ada kombinasi bersarang yang lebih kompleks. Namun, dalam kondisi nyata, tidak mungkin untuk menjelaskan kepada pengguna dalam dua atau tiga kalimat kombinasi logis kompleks yang harus dilakukan untuk menerima penghargaan. Oleh karena itu, dalam kebanyakan kasus, opsi ini sudah cukup.

Kami menyebut metode konversi sebagai strategi dan mencoba membuatnya lebih atau kurang universal dengan menyusun deskripsi formal dalam bentuk objek JSON. Anda tentu saja dapat berpikir untuk menulis dalam bentuk formula, tetapi kemudian Anda harus menggunakan persamaan eval atau menggambarkan tata bahasa dan mengimplementasikannya, dan ini jelas merupakan komplikasi berlebihan. Menyimpan strategi dalam kode sumber untuk setiap penghargaan sangat tidak nyaman, karena deskripsi penghargaan (bagian dalam database, dan bagian dalam kode) akan robek, dan itu juga tidak akan memungkinkan mengumpulkan penghargaan dari komponen yang sudah jadi di masa depan tanpa partisipasi dari pengembangan.

Strategi disajikan dalam bentuk pohon, di mana setiap simpul:

  • Mengacu pada kemajuan saat ini pada penugasan atau sekelompok node lain.
  • Mungkin memiliki batasan atas - sebenarnya indikasi kebutuhan untuk menggunakan min ().
  • Dapat memiliki koefisien normalisasi. Diperlukan untuk konversi sederhana dengan mengalikan hasilnya dengan angka. Kami berguna untuk mengonversi meter ke kilometer.

Untuk menggambarkan contoh di atas, satu operasi sudah cukup - jumlah. Sum sangat bagus untuk menunjukkan dengan jelas kemajuan pengguna dengan satu angka, tetapi operasi lain dapat digunakan jika diinginkan.

Berikut adalah contoh deskripsi strategi untuk kategori terakhir:

 { "goal": 15, "operation": "sum", "strategy": [ { "goal": 5, "operation": "sum", "strategy": [ { "objective_id": "photo" }, { "objective_id": "reviews" } ] }, { "goal": 10, "operation": "sum", "strategy": [ { "objective_id": "navi", "normalization_factor": 0.001 } ] } ] } 

Pembaruan yang Diperlukan


Ada beberapa penangan yang tanpa henti menganalisis peristiwa oleh pengguna dan menerapkan perubahan pada kemajuan tugas. Pencarian reguler semua pengguna dengan setiap penghargaan akan mengarah pada analisis puluhan juta penghargaan - tidak terlalu menggembirakan, asalkan pembaruan nyata akan diukur dalam ribuan. Bagaimana cara belajar hanya tentang ribuan dan tidak membuang-buang jutaan CPU?

Gagasan tentang bagaimana menghitung ulang kemajuan hanya pada penghargaan yang benar-benar berubah, datang dengan sangat cepat. Ini didasarkan pada penggunaan jam tangan vektor.

Sebelum uraian saya akan mengingatkan entitas:

  • UserObjective - data tentang kemajuan pengguna dengan menetapkan penghargaan.
  • UserAchieve - hadiahi data kemajuan pengguna.

Implementasinya terlihat seperti ini:

  • Kami mendapatkan bidang versi untuk UserObjective dan UserAchieve dan Sequence di PostgreSQL.
  • Setiap pembaruan entitas UserObjective mengubah versinya. Nilai diambil dari urutan (kami memilikinya umum untuk semua catatan).
  • Nilai versi untuk UserAchieve akan ditentukan sebagai maksimum dari versi UserObjective terkait.
  • Pada setiap siklus pemrosesan, AchievesWorker mencari UserObjective yang tidak ada UserAchieve atau UserAchieve.version <UserObjective.version. Masalahnya diselesaikan dengan satu permintaan ke database.

Perlu dicatat bahwa solusi memiliki batasan pada jumlah entri dalam tabel penghargaan dan penugasan, serta pada frekuensi perubahan dalam progres penugasan, tetapi dengan beberapa puluh juta penghargaan dan jumlah pembaruan kurang dari seribu per menit, sangat mungkin untuk hidup dengan solusi semacam itu. Entah bagaimana kami akan secara terpisah memberi tahu tentang bagaimana kami mengoptimalkan penerbitan untuk kontes " 2GIS Agents ".

Kesimpulan


Terlepas dari kenyataan bahwa artikel itu ternyata cukup banyak, banyak nuansa tetap di belakang layar, karena tidak mungkin untuk membicarakannya secara singkat.

Kesimpulan apa yang kami buat berkat Penghargaan:

  • Prinsip "memecah belah dan menaklukkan" dalam kasus ini dimainkan ke tangan kita. Alokasi penangan acara untuk setiap sumber membantu kami mengukur bila perlu. Pekerjaan mereka terisolasi menurut data dan hanya bersinggungan di daerah kecil. Menyoroti logika hadiah memungkinkan Anda untuk mengurangi overhead di penangan acara.
  • Jika Anda perlu mencerna banyak data dan pengolahannya cukup mahal, Anda harus segera memikirkan cara menyaring apa yang jelas tidak diperlukan. Pengalaman dengan memfilter aliran BSS adalah contohnya.
  • Sekali lagi kami yakin bahwa integrasi layanan melalui bus peristiwa umum sangat mudah dan memungkinkan Anda untuk menghindari beban yang tidak perlu pada layanan lain. Jika layanan Hadiah menerima data dari Foto, Ulasan, dll. Layanan melalui permintaan http, maka beberapa layanan harus disiapkan untuk pemuatan tambahan.
  • Sedikit metaprogramming dapat membantu menjaga integritas konfigurasi data dan lingkungan terpisah secara sewenang-wenang. Menyimpan filter, aturan, dan strategi dalam basis data menyederhanakan proses pengembangan dan pelepasan penghargaan baru.

Source: https://habr.com/ru/post/id470942/


All Articles