Bagaimana Data Diproses dalam Basis Data Vektor?
Gambar sampul depan
Artikel ini ditulis oleh Zhenshan Cao dan diterjemahkan oleh Angela Ni.
Dalam dua artikel sebelumnya dalam seri blog ini, kami telah membahas arsitektur sistem Milvus, database vektor tercanggih di dunia, serta Python SDK dan API-nya.
Tulisan ini terutama bertujuan untuk membantu Anda memahami bagaimana data diproses di Milvus dengan mendalami sistem Milvus dan memeriksa interaksi antara komponen-komponen pemrosesan data.
Beberapa sumber daya yang berguna sebelum memulai tercantum di bawah ini. Kami merekomendasikan untuk membacanya terlebih dahulu untuk lebih memahami topik dalam tulisan ini.
- Mendalami arsitektur Milvus
- Model data Milvus
- Peran dan fungsi setiap komponen Milvus
- Pemrosesan data dalam Milvus
Antarmuka MsgStream
Antarmuka MsgStream sangat penting untuk pemrosesan data di Milvus. Ketika Start()
dipanggil, coroutine di latar belakang akan menulis data ke dalam log broker atau membaca data dari sana. Ketika Close()
dipanggil, coroutine akan berhenti.
Antarmuka MsgStream
MsgStream dapat berfungsi sebagai produsen dan konsumen. Antarmuka AsProducer(channels []string)
mendefinisikan MsgStream sebagai produsen sementara AsConsumer(channels []string, subNamestring)
mendefinisikannya sebagai konsumen. Parameter channels
digunakan bersama di kedua antarmuka dan digunakan untuk mendefinisikan saluran (fisik) mana yang akan digunakan untuk menulis data atau membaca data.
Jumlah pecahan dalam sebuah koleksi dapat ditentukan ketika koleksi dibuat. Setiap pecahan berhubungan dengan saluran virtual (vchannel). Oleh karena itu, sebuah koleksi dapat memiliki beberapa vchannel. Milvus memberikan setiap vchannel di log broker sebuah saluran fisik (pchannel).
Setiap saluran virtual/bongkahan berhubungan dengan saluran fisik.
Produce()
di antarmuka MsgStream yang bertugas menulis data ke dalam pchannel di log broker. Data dapat ditulis dalam dua cara:
- Penulisan tunggal: entitas ditulis ke dalam pecahan yang berbeda (vchannel) dengan nilai hash dari kunci primer. Kemudian entitas-entitas ini mengalir ke dalam pchannel yang sesuai di log broker.
- Broadcast write: entitas ditulis ke dalam semua pchannel yang ditentukan oleh parameter
channels
.
Consume()
adalah jenis API pemblokiran. Jika tidak ada data yang tersedia di pchannel yang ditentukan, coroutine akan diblokir ketika Consume()
dipanggil di antarmuka MsgStream. Di sisi lain, Chan()
adalah API non-blocking, yang berarti bahwa coroutine membaca dan memproses data hanya jika ada data yang ada di pchannel yang ditentukan. Jika tidak, coroutine dapat memproses tugas-tugas lain dan tidak akan diblokir ketika tidak ada data yang tersedia.
Seek()
adalah metode untuk pemulihan kegagalan. Ketika sebuah node baru dimulai, catatan konsumsi data dapat diperoleh dan konsumsi data dapat dilanjutkan dari tempat terputusnya dengan memanggil Seek()
.
Tulis data
Data yang ditulis ke dalam vchannels (pecahan) yang berbeda dapat berupa pesan sisipan atau pesan hapus. Vchannels ini juga dapat disebut DmChannels (saluran manipulasi data).
Koleksi yang berbeda dapat berbagi pchannels yang sama dalam log broker. Satu koleksi dapat memiliki beberapa pecahan dan karenanya memiliki beberapa vchannels yang sesuai. Entitas dalam koleksi yang sama, akibatnya mengalir ke beberapa pchannels yang sesuai di log broker. Sebagai hasilnya, manfaat dari berbagi pchannels adalah peningkatan volume throughput yang dimungkinkan oleh konkurensi yang tinggi dari log broker.
Ketika koleksi dibuat, tidak hanya jumlah pecahan yang ditentukan, tetapi juga pemetaan antara vchannels dan pchannels di log broker juga diputuskan.
Menulis jalur di Milvus
Seperti yang ditunjukkan pada ilustrasi di atas, pada jalur penulisan, proksi menulis data ke dalam log broker melalui antarmuka AsProducer()
pada MsgStream. Kemudian node data mengkonsumsi data, lalu mengubah dan menyimpan data yang dikonsumsi ke dalam penyimpanan objek. Jalur penyimpanan adalah jenis informasi meta yang akan direkam dalam etcd oleh koordinator data.
Diagram alir
Karena koleksi yang berbeda dapat berbagi pchannel yang sama dalam log broker, ketika mengkonsumsi data, node data atau node kueri perlu menilai ke koleksi mana data dalam pchannel. Untuk mengatasi masalah ini, kami memperkenalkan flowgraph di Milvus. Flowgraph ini bertugas untuk memfilter data dalam pchannel bersama berdasarkan ID koleksi. Jadi, kita dapat mengatakan bahwa setiap flowgraph menangani aliran data dalam pecahan (vchannel) yang sesuai dalam sebuah koleksi.
Diagram alir dalam jalur penulisan
Pembuatan MsgStream
Ketika menulis data, objek MsgStream dibuat dalam dua skenario berikut:
- Ketika proxy menerima permintaan penyisipan data, pertama-tama proxy mencoba mendapatkan pemetaan antara vchannel dan pchannel melalui koordinator root (root coord). Kemudian proxy membuat objek MsgStream.
Skenario 1
- Ketika node data dimulai dan membaca informasi meta saluran di etcd, objek MsgStream dibuat.
Skenario 2
Baca data
Baca jalur di Milvus
Alur kerja umum membaca data diilustrasikan pada gambar di atas. Permintaan kueri disiarkan melalui DqRequestChannel ke node kueri. Node-node kueri menjalankan tugas-tugas kueri secara paralel. Hasil kueri dari node kueri melewati gRPC dan proxy menggabungkan hasilnya dan mengembalikannya ke klien.
Untuk melihat lebih dekat proses pembacaan data, kita dapat melihat bahwa proxy menulis permintaan kueri ke dalam DqRequestChannel. Node query kemudian mengkonsumsi pesan dengan berlangganan ke DqRequestChannel. Setiap pesan dalam DqRequestChannel disiarkan sehingga semua node kueri yang berlangganan dapat menerima pesan tersebut.
Ketika node kueri menerima permintaan kueri, mereka melakukan kueri lokal pada data batch yang disimpan dalam segmen tertutup dan data streaming yang secara dinamis dimasukkan ke dalam Milvus dan disimpan dalam segmen yang sedang berkembang. Setelah itu, node kueri perlu menggabungkan hasil kueri di kedua segmen tertutup dan segmen yang berkembang. Hasil agregat ini diteruskan ke proxy melalui gRPC.
Proxy mengumpulkan semua hasil dari beberapa node kueri dan kemudian menggabungkannya untuk mendapatkan hasil akhir. Kemudian proxy mengembalikan hasil kueri akhir ke klien. Karena setiap permintaan kueri dan hasil kueri yang sesuai dilabeli dengan requestID unik yang sama, proxy dapat mengetahui hasil kueri mana yang sesuai dengan permintaan kueri yang mana.
Diagram alir
Diagram alir dalam jalur baca
Mirip dengan jalur tulis, flowgraph juga diperkenalkan di jalur baca. Milvus mengimplementasikan arsitektur Lambda terpadu, yang mengintegrasikan pemrosesan data tambahan dan data historis. Oleh karena itu, node kueri juga perlu mendapatkan data streaming real-time. Demikian pula, flowgraph dalam jalur baca menyaring dan membedakan data dari koleksi yang berbeda.
Pembuatan MsgStream
Membuat objek MsgStream di jalur baca
Ketika membaca data, objek MsgStream dibuat dalam skenario berikut:
- Di Milvus, data tidak dapat dibaca kecuali data tersebut dimuat. Ketika proxy menerima permintaan pemuatan data, proxy akan mengirimkan permintaan tersebut ke koordinator kueri yang akan menentukan cara untuk menugaskan pecahan ke node kueri yang berbeda. Informasi penugasan (yaitu nama-nama vchannels dan pemetaan antara vchannels dan pchannels yang sesuai) dikirim ke node kueri melalui pemanggilan metode atau RPC (panggilan prosedur jarak jauh). Selanjutnya, node kueri membuat objek MsgStream yang sesuai untuk mengonsumsi data.
Operasi DDL
DDL adalah singkatan dari bahasa definisi data. Operasi DDL pada metadata dapat dikategorikan ke dalam permintaan tulis dan permintaan baca. Namun, kedua jenis permintaan ini diperlakukan sama selama pemrosesan metadata.
Permintaan baca pada metadata meliputi:
- Skema pengumpulan kueri
- Informasi pengindeksan kueri Dan banyak lagi
Permintaan tulis meliputi:
- Membuat koleksi
- Menghapus koleksi
- Membangun indeks
- Jatuhkan indeks Dan banyak lagi
Permintaan DDL dikirim ke proxy dari klien, dan proxy selanjutnya meneruskan permintaan ini dalam urutan yang diterima ke root coord yang memberikan cap waktu untuk setiap permintaan DDL dan melakukan pemeriksaan dinamis pada permintaan. Proxy menangani setiap permintaan secara serial, yang berarti satu permintaan DDL pada satu waktu. Proxy tidak akan memproses permintaan berikutnya sampai selesai memproses permintaan sebelumnya dan menerima hasil dari root coord.
Operasi DDL.
Seperti yang ditunjukkan pada ilustrasi di atas, ada K
permintaan DDL dalam antrian tugas Root coord. Permintaan DDL dalam antrian tugas diatur dalam urutan yang diterima oleh root coord. Jadi, ddl1
adalah yang pertama dikirim ke root coord, dan ddlK
adalah yang terakhir dalam kelompok ini. Root coord memproses permintaan satu per satu dalam urutan waktu.
Dalam sistem terdistribusi, komunikasi antara proxy dan root coord diaktifkan oleh gRPC. Root coord menyimpan catatan nilai cap waktu maksimum dari tugas yang dieksekusi untuk memastikan bahwa semua permintaan DDL diproses dalam urutan waktu.
Misalkan ada dua proxy independen, proxy 1 dan proxy 2. Keduanya mengirimkan permintaan DDL ke root coord yang sama. Namun, satu masalah adalah bahwa permintaan yang lebih awal belum tentu dikirim ke root coord sebelum permintaan tersebut diterima oleh proxy lain. Sebagai contoh, pada gambar di atas, ketika DDL_K-1
dikirim ke root coord dari proxy 1, DDL_K
dari proxy 2 telah diterima dan dieksekusi oleh root coord. Seperti yang dicatat oleh root coord, nilai cap waktu maksimum dari tugas yang dieksekusi pada saat ini adalah K
. Jadi agar tidak mengganggu urutan waktu, permintaan DDL_K-1
akan ditolak oleh antrian tugas root coord. Namun, jika proxy 2 mengirimkan permintaan DDL_K+5
ke root coord pada saat ini, permintaan tersebut akan diterima ke antrian tugas dan akan dieksekusi nanti sesuai dengan nilai timestamp-nya.
Pengindeksan
Membangun indeks
Setelah menerima permintaan pembuatan indeks dari klien, proxy pertama-tama melakukan pemeriksaan statis pada permintaan dan mengirimkannya ke root coord. Kemudian root coord menyimpan permintaan pembuatan indeks ini ke dalam penyimpanan meta (etcd) dan mengirimkan permintaan ke koordinator indeks (index coord).
Membangun sebuah indeks.
Seperti yang diilustrasikan di atas, ketika index coord menerima permintaan pembuatan indeks dari root coord, pertama-tama ia akan menyimpan tugas tersebut di etcd untuk penyimpanan meta. Status awal dari tugas pembangunan indeks adalah Unissued
. Index coord menyimpan catatan beban tugas setiap simpul indeks, dan mengirimkan tugas yang masuk ke simpul indeks yang tidak terlalu banyak dimuat. Setelah menyelesaikan tugas, simpul indeks menulis status tugas, baik Finished
atau Failed
ke dalam penyimpanan meta, yaitu etcd di Milvus. Kemudian index coord akan mengetahui apakah tugas pembangunan indeks berhasil atau gagal dengan melihat di etcd. Jika tugas gagal karena sumber daya sistem yang terbatas atau node indeks putus, index coord akan memicu ulang seluruh proses dan memberikan tugas yang sama ke node indeks lain.
Menjatuhkan indeks
Selain itu, index coord juga bertanggung jawab atas permintaan untuk melepaskan indeks.
Menjatuhkan sebuah indeks.
Ketika root coord menerima permintaan untuk menjatuhkan indeks dari klien, pertama-tama ia menandai indeks sebagai "dijatuhkan", dan mengembalikan hasilnya ke klien sambil memberi tahu index coord. Kemudian index coord menyaring semua tugas pengindeksan dengan IndexID
dan tugas-tugas yang sesuai dengan kondisi tersebut akan dibatalkan.
Coroutine latar belakang dari index coord secara bertahap akan menghapus semua tugas pengindeksan yang ditandai sebagai "dijatuhkan" dari penyimpanan objek (MinIO dan S3). Proses ini melibatkan antarmuka recycleIndexFiles. Ketika semua file indeks terkait dihapus, informasi meta dari tugas pengindeksan yang dihapus akan dihapus dari penyimpanan meta (etcd).
Tentang Seri Deep Dive
Dengan pengumuman resmi ketersediaan umum Milvus 2.0, kami menyusun seri blog Milvus Deep Dive ini untuk memberikan interpretasi mendalam tentang arsitektur dan kode sumber Milvus. Topik-topik yang dibahas dalam seri blog ini meliputi:
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word