BARU: Helius mengakuisisi Light Protocol
plugin Solana Geyser
Blog/Dasar-Dasar

Solana Geyser Plugins: Streaming Data Secepat Cahaya

Developer Experience Engineer0xIchigo di X0xIchigo di LinkedIn0xIchigo di GitHub
Bacaan 13 menit

Apa yang dibahas dalam artikel ini?

Geyser Plugins adalah komponen modular yang dirancang untuk mengirimkan data tentang akun, slot, blok, dan transaksi ke penyimpanan data eksternal. Dengan demikian, developer dapat mengurangi beban RPC (Remote Procedural Call) dari validator. Geyser Plugins menawarkan solusi fleksibel bagi developer yang ingin menyesuaikan kebutuhan streaming dan pemrosesan data mereka.

Dalam artikel ini, kita akan membahas seluk-beluk Solana Geyser Plugins. Kita akan mulai dengan mempelajari replika AccountsDB, pendekatan yang diusulkan untuk replikasi data dan pengelolaan beban, tetapi akhirnya ditinggalkan demi Geyser Plugins.

Kemudian, kita akan menguraikan pengertian Geyser Plugins, cara kerjanya, dan strukturnya melalui Plugin Interface.

Setelah itu, kita akan membahas Geyser Plugins yang umum tersedia dan memandu Anda melalui proses kompleks untuk membuat plugin sendiri. Terakhir, kita akan membahas Helius dan cara kami menyederhanakan streaming data di Solana.

Replika AccountsDB: Pendekatan Replikasi Data dan Beban RPC yang Ditinggalkan

Solana menjajaki berbagai cara untuk mengatasi beban RPC yang berat dan replikasi data. Salah satu pendekatan yang menjanjikan adalah penggunaan replika AccountsDB. Replika ini dirancang untuk memindahkan permintaan pemindaian akun dari validator utama ke replika AccountsDB. Meskipun menjanjikan, sistem ini pada dasarnya kompleks dan memerlukan serangkaian layanan baru untuk memastikan sinkronisasi antara validator utama dan replika. Pada akhirnya, proposal ini ditinggalkan demi Geyser Plugin System — solusi yang lebih mudah didukung oleh klien validator dan memberikan fleksibilitas lebih besar kepada developer saat mengimplementasikan aplikasi mereka.

Jadi, apa sebenarnya Solana Geyser Plugins itu?

Apa Itu Solana Geyser Plugins?

Solana Geyser Plugins menyediakan akses berlatensi rendah ke data Solana dan dapat melayani aplikasi sehingga tidak perlu melakukan panggilan RPC ke validator. Misalnya, jika validator harus melayani banyak panggilan getProgramAccounts secara berurutan dalam waktu singkat, lalu lintas yang padat ini dapat menyebabkan validator tertinggal dari jaringan.

Geyser Plugins mengatasi masalah ini dengan mengalihkan informasi tentang akun, blok, slot, dan transaksi ke penyimpanan data eksternal, seperti basis data relasional, basis data NoSQL, atau Kafka.

Pengalihan data ini memungkinkan layanan RPC menawarkan pengoptimalan yang lebih fleksibel dan terarah, seperti caching dan pengindeksan, bagi pihak yang ingin mengambil data dari penyimpanan eksternal tersebut.

Geyser Plugins bertindak sebagai jembatan antara Solana dan solusi penyimpanan data eksternal. Plugin ini memungkinkan developer memindahkan sebagian besar tugas pengelolaan data dari validator, sehingga meningkatkan performa dan mengurangi risiko potensi bottleneck.

Geyser Plugins memastikan validator tetap tersinkronisasi dengan jaringan, berapa pun volume lalu lintas RPC.

Geyser Plugin Interface

Developer dapat membuat Geyser Plugins menggunakan Solana Geyser Plugin Interface. Antarmuka ini menyediakan akses ke akun, transaksi, slot, metadata blok, dan entri. Antarmuka tersebut dideklarasikan dalam crate solana-geyser-plugin-interface dan ditentukan oleh trait GeyserPlugin.

Trait ini mendefinisikan berbagai metode, masing-masing diawali dengan update_, yang dipanggil setiap kali data baru dibuat atau data yang ada diperbarui. Geyser Plugins juga harus menentukan perilakunya selama proses pemuatan dan pembongkaran. Trait ini menjabarkan metode penting yang harus diimplementasikan Geyser Plugin untuk memastikan streaming data yang efisien berdasarkan perilaku plugin yang diinginkan.

Kode Sumber

Kode
pub trait GeyserPlugin:Any +Send +Sync +Debug {
    // Required method
    fn name(&self) -> &'static str;

    // Provided methods
    fn on_load(&mut self, _config_file: &str) ->Result<()> { ... }
    fn on_unload(&mut self) { ... }
    fn update_account(
        &self,
        account:ReplicaAccountInfoVersions<'_>,
        slot: Slot,
        is_startup:bool
    ) ->Result<()> { ... }
    fn notify_end_of_startup(&self) ->Result<()> { ... }
    fn update_slot_status(
        &self,
        slot: Slot,
        parent:Option,
        status:SlotStatus
    ) ->Result<()> { ... }
    fn notify_transaction(
        &self,
        transaction:ReplicaTransactionInfoVersions<'_>,
        slot: Slot
    ) ->Result<()> { ... }
    fn notify_entry(&self, entry:ReplicaEntryInfoVersions<'_>) ->Result<()> { ... }
    fn notify_block_metadata(
        &self,
        blockinfo:ReplicaBlockInfoVersions<'_>
    ) ->Result<()> { ... }
    fn account_data_notifications_enabled(&self) ->bool { ... }
    fn transaction_notifications_enabled(&self) ->bool { ... }
    fn entry_notifications_enabled(&self) ->bool { ... }
}

Deklarasi Trait

Trait GeyserPlugin berfungsi sebagai antarmuka dasar untuk semua plugin dalam ekosistem Solana Geyser Plugin. Trait ini dideklarasikan sebagai trait publik dengan batasan trait Any, Send, Sync, dan Debug dari pustaka standar Rust. Batasan trait tersebut adalah sebagai berikut:

  • Any memungkinkan refleksi tipe, yang memungkinkan downcasting ke tipe konkret
  • Send menunjukkan bahwa kepemilikan tipe yang mengimplementasikan trait ini dapat ditransfer antarthread
  • Sync menyiratkan bahwa referensi tipe yang mengimplementasikan trait ini dapat dibagikan antarthread
  • Debug memungkinkan pemformatan tipe untuk output, khususnya untuk keperluan debugging

Any dan Debug tidak terlalu penting bagi kita.

Hal yang benar-benar penting adalah GeyserPlugin memerlukan Send dan Sync agar program aman untuk thread.

Metode Wajib

Kode
fn name(&self) -> &'static str;

Metode name wajib ada untuk setiap tipe yang mengimplementasikan GeyserPlugin. Metode ini berfungsi sebagai pengidentifikasi Geyser Plugin. Metode ini mengembalikan potongan string statis yang mewakili nama Geyser Plugin.

Penggunaan &self alih-alih &mut self oleh metode ini dan semua metode lainnya, kecuali on_load dan on_unload, merupakan hal baru dalam pembaruan Solana 1.16. Perubahan ini meningkatkan performa secara drastis karena tidak perlu lagi membungkus Geyser Plugin dalam Read-Write Lock dan memperoleh write lock setiap kali salah satu fungsinya dipanggil.

Metode yang Disediakan

Trait ini memiliki sejumlah metode yang disediakan dan berisi implementasi default, yang dapat ditimpa oleh implementasi GeyserPlugin.

Kode
fn on_load(&mut self, _config_file: &str) ->Result<()> { ... }

Metode on_load adalah callback yang dipanggil saat plugin dimuat oleh sistem dan digunakan untuk inisialisasi apa pun yang diperlukan plugin. Metode ini menerima referensi ke string yang mewakili jalur menuju file konfigurasi. Konfigurasi harus berformat JSON5 dan menyertakan field libpath yang menunjukkan nama jalur lengkap pustaka bersama yang mengimplementasikan antarmuka ini.

Kode
fn on_unload(&mut self) { ... }

Metode on_unload adalah callback yang dipanggil untuk melakukan pembersihan sebelum plugin dibongkar oleh sistem.

Kode
fn update_account(
        &self,
        account:ReplicaAccountInfoVersions<'_>,
        slot: Slot,
        is_startup:bool
    ) ->Result<()> { ... }

Metode update_account dipanggil saat akun diperbarui pada tingkat konfirmasi processed, yang dapat terjadi beberapa kali dalam satu slot. Di sini, sangat penting untuk melacak slot yang telah dikonfirmasi agar dapat memperoleh pembaruan akun yang dimasukkan ke rantai kanonis.

Struct ReplicaAccountInfoVersions berisi metadata dan data akun yang dialirkan.

Parameter slot menunjuk ke slot tempat akun diperbarui.

Saat is_startup bernilai true, ini menunjukkan bahwa akun dimuat dari snapshot saat validator dimulai. Saat is_startup bernilai false, akun diperbarui selama pemrosesan transaksi.

Kode
fn notify_end_of_startup(&self) ->Result<()> { ... }

Metode notify_end_of_startup dipanggil untuk menandai akhir fase startup. Ini terjadi saat validator telah memulihkan basis data akun dari snapshot dan semua akun telah diperbarui sebagaimana mestinya.

Kode
fn update_slot_status(
        &self,
        slot: Slot,
        parent:Option,
        status:SlotStatus
    ) ->Result<()> { ... }

Metode update_slot_status dipanggil saat status slot diperbarui. Metode ini menerima Slot, Option<u64> untuk slot induk, dan instance SlotStatus enum.

SlotStatus menjabarkan tiga status slot di Solana:

  • Processed - slot tertinggi yang telah dikerjakan node. Meskipun slot tersebut belum dikonfirmasi atau difinalisasi, slot ini merupakan bagian dari rantai yang dianggap validator paling mungkin menjadi kanonis
  • Confirmed - slot telah menerima cukup suara untuk dianggap aman dan menjadi bagian dari rantai. Slot ini didukung oleh supermayoritas validator Solana
  • Rooted - slot kini menjadi bagian permanen dari blockchain dan semua versi atau fork rantai lainnya harus dibangun di atas slot ini. Artinya, semua cabang di jaringan berasal dari blok ini
Kode
fn notify_transaction(
        &self,
        transaction:ReplicaTransactionInfoVersions<'_>,
        slot: Slot
    ) ->Result<()> { ... }

Metode notify_transaction dipanggil saat transaksi diproses dalam suatu slot untuk memberi tahu plugin tentang detail transaksi tersebut.

ReplicaTransactionInfoVersions adalah wrapper enum yang menangani ReplicaTransactionInfo. Jika struktur RepicaTransactionInfo berubah, akan ada entri enum baru untuk versi yang lebih baru. Hal ini akan memaksa implementasi plugin menangani perubahan tersebut dengan mengakomodasi entri enum baru. Saat ini, enum membungkus dua varian:

  1. V0_0_1(&'a ReplicaTransactionInfo<'a>)
  2. V0_0_2(&'a ReplicaTransactionInfoV2<'a>)
Kode
pub struct ReplicaTransactionInfo<'a> {
    pub signature: &'a Signature,
    pub is_vote: bool,
    pub transaction: &'a SanitizedTransaction,
    pub transaction_status_meta: &'a TransactionStatusMeta,
}

pub struct ReplicaTransactionInfoV2<'a> {
    pub signature: &'a Signature,
    pub is_vote: bool,
    pub transaction: &'a SanitizedTransaction,
    pub transaction_status_meta: &'a TransactionStatusMeta,
    pub index: usize,
}

Perbedaan utama antara kedua varian tersebut adalah varian kedua menyimpan indeks transaksi di dalam blok.

Kode
fn notify_entry(&self, entry:ReplicaEntryInfoVersions<'_>) ->Result<()> { ... }

notify_entry memberi tahu plugin tentang entri baru. Metode ini menerima instance ReplicaEntryInfoVersions, yaitu wrapper untuk memastikan penanganan ReplicaEntryInfo tetap kompatibel di masa mendatang. Saat ini, wrapper tersebut berisi varian V0_0_1(&'a ReplicaEntryInfo<'a>).

Varian ini adalah struct yang berisi informasi tentang slot entri, indeksnya di dalam blok, jumlah hash sejak entri sebelumnya, hash SHA-256 entri tersebut, dan jumlah transaksi yang dieksekusi dalam entri.

Kode
fn notify_block_metadata(
        &self,
        blockinfo:ReplicaBlockInfoVersions<'_>
    ) ->Result<()> { ... }

Metode notify_block_metadata dipanggil saat metadata blok diperbarui. Metode ini menerima instance ReplicaBlockInfoVersions enum untuk informasi bloknya. Enum ini adalah wrapper untuk berbagai versi ReplicaBlockInfo, yang berisi informasi tentang blok, seperti slot, hash, reward, waktu blok, tinggi blok, dan sebagainya.

Kode
fn account_data_notifications_enabled(&self) ->bool { ... }
fn transaction_notifications_enabled(&self) ->bool { ... }
fn entry_notifications_enabled(&self) ->bool { ... }

Metode-metode ini masing-masing mengembalikan nilai boolean yang menunjukkan apakah plugin ingin mengaktifkan notifikasi untuk data akun, transaksi, dan entri.

Catatan tentang Tingkat Commitment

Geyser langsung mengirimkan pembaruan untuk data akun dan transaksi segera setelah diproses. Hal ini bermanfaat bagi kecepatan pengindeksan end-to-end. Namun, ada risiko bahwa slot yang telah diproses dapat dilewati.

Slot yang dilewati adalah slot lampau yang tidak menghasilkan blok, baik karena leader sedang offline maupun karena fork yang memuat slot tersebut ditinggalkan demi alternatif yang lebih baik. Sistem penyimpanan data tujuan streaming harus mengenali kemungkinan ini dan mengelola pembaruan sebagaimana mestinya.

Solana Geyser Plugins yang Umum

Developer dapat menggunakan beragam Solana Geyser Plugins, bahkan melakukan fork untuk memenuhi kebutuhan spesifik mereka. Beberapa plugin terkemuka meliputi:

  • PostgreSQL Plugin: untuk mengelola dan membuat kueri data menggunakan PostgreSQL
  • gRPC Service Streaming Plugin: untuk melakukan streaming pembaruan akun Solana ke layanan gRPC
  • RabbitMQ Producer Plugin: untuk memfasilitasi antrean pesan dengan RabbitMQ
  • Kafka Producer Plugin: untuk melakukan streaming data menggunakan Kafka
  • Amazon SQS Plugin: untuk antrean pesan yang memanfaatkan Simple Queue Service milik Amazon
  • Google BigTable Plugin: untuk mengelola dan membuat kueri data menggunakan Google BigTable

Plugin-plugin ini dapat disesuaikan untuk memenuhi beragam kasus penggunaan.

Sebagai contoh, Clockwork memanfaatkan Geyser Plugin untuk menjadwalkan transaksi dan membuat program Solana otomatis berbasis peristiwa. Meskipun proyek tersebut telah dihentikan, kode sumber terbukanya tetap menjadi sumber daya berharga yang dapat dilihat di GitHub mereka.

Kasus penggunaan lainnya dapat mencakup penggunaan Geyser Plugins untuk memantau saldo akun pada platform DeFi, menyediakan metrik kondisi jaringan, atau memantau peristiwa rantai pasok secara real-time.

Buat Solana Geyser Plugin Anda Sendiri

Berikut beberapa sumber daya dan komponen untuk membuat plugin Anda sendiri:

Solana Geyser Plugin Scaffold

Solana Geyser Plugin Scaffold adalah sumber daya termudah untuk memulai perjalanan Anda dalam pengembangan Solana Geyser Plugin. Scaffold ini berfungsi sebagai template minimalis yang mencatat interaksi antara Plugin Manager dan plugin itu sendiri. Ini merupakan titik awal yang sangat baik untuk memahami alur kerja plugin serta teknik debugging.

Plugin Manager

Plugin Manager adalah komponen inti yang mengatur siklus hidup dan interaksi semua Geyser Plugins. Komponen ini mampu memuat dan membongkar plugin secara dinamis saat runtime sehingga memberikan fleksibilitas dan modularitas yang lebih besar.

Saat runtime, Plugin Manager meneruskan jalur file konfigurasi ke plugin Anda. Hal ini memungkinkan pengaturan yang dapat disesuaikan dalam Geyser Plugins dan diubah tanpa mengubah kode plugin.

Untuk mengintegrasikan plugin ke validator, Anda perlu menentukan jalur pustaka dinamis menggunakan parameter --geyser-plugin-config. Parameter ini memberi tahu validator lokasi plugin dan konfigurasi terkaitnya.

Setidaknya, file konfigurasi harus berformat JSON dan berisi jalur menuju pustaka dinamis Geyser Plugin — file .so di Linux. File konfigurasi minimal akan terlihat seperti berikut:

Kode
{
    "libpath": "/.so"
}

Membuat Geyser Plugin dari Awal

Jika Anda ingin mengambil jalur yang belum banyak ditempuh dan membuat Geyser Plugin sendiri tanpa menggunakan scaffold atau memodifikasi plugin yang sudah ada, Anda perlu membuat kode plugin menggunakan Geyser Plugin Interface.

Plugin harus mengimplementasikan trait GeyserPlugin agar dapat bekerja dengan runtime. Selain itu, pustaka dinamis harus mengekspor fungsi “C” _create_plugin yang membuat implementasi plugin.

Contohnya adalah membuat plugin Webhook yang mengimplementasikan trait GeyserPlugin:

Kode
#[no_mangle]
#[allow(improper_ctypes_definitions)]
/// # Safety
///
/// This function returns the WebhookPlugin pointer as trait GeyserPlugin.
pub unsafe extern "C" fn _create_plugin() -> *mut dyn GeyserPlugin {
    let plugin = WebhookPlugin::new();
    let plugin: Box = Box::new(plugin);
    Box::into_raw(plugin)
}

Di sini, kita membuat fungsi publik unsafe yang menggunakan konvensi pemanggilan C, extern "C", sehingga kompatibel dengan C dan bahasa lainnya. Fungsi fn _create*_*plugin() -> *mut dyn GeyserPlugin itu sendiri mengembalikan pointer mentah yang dapat diubah ke dynGeyserPlugin, yaitu trait GeyserPlugin. Isi fungsi membuat instance baru WebhookPlugin, memasukkan instance ini ke dalam box sebagai objek trait, lalu mengubah objek trait dalam box tersebut menjadi pointer mentah agar dapat dikembalikan oleh fungsi.

Dengan demikian, langkah-langkah untuk membuat Geyser Plugin Anda sendiri adalah sebagai berikut:

  • Buat plugin yang mengimplementasikan antarmuka Solana Geyser Plugin
  • Ambil pustaka dinamis (file .so) dari folder target/release atau target/debug
  • Buat file geyser-config.json yang harus berisi jalur menuju pustaka dinamis Geyser Plugin di bawah field “libpath”
  • Jalankan validator Anda dengan flag --geyser-plugin-config geyser-config.json

Langkah-langkah ini terdengar cukup mudah. Namun, proses untuk benar-benar menjalankan dan memelihara Solana Geyser Plugin dapat sangat rumit.

Streaming Geyser Helius

Helius dikenal karena menawarkan pengalaman developer yang tak tertandingi di Solana. Fokus eksklusif pada Solana ini telah membekali Helius dengan pengalaman luas dalam menghadapi beragam tantangan dan memfasilitasi banyak integrasi berskala besar. Helius berada dalam posisi unik untuk menangani masalah apa pun yang mungkin dihadapi developer.

Di Helius, kami mengelola Geyser Plugins untuk beberapa tim berperforma tinggi dalam ekosistem Solana. Kami mengoperasikan cluster Geyser khusus dengan redundansi dan toleransi kesalahan tambahan untuk memastikan Anda tidak perlu mengkhawatirkan data yang hilang atau downtime. Akses API terprogram kami memungkinkan Anda memodifikasi Geyser Plugins secara dinamis tanpa perlu mengkhawatirkan keandalannya. Mengelola Geyser Plugins sering kali menjadi tugas berat karena Anda bertanggung jawab memastikan konsistensi, keandalan, dan ketersediaan data. Mengapa tidak membiarkan Helius melakukannya untuk Anda?

Jika tertarik dengan streaming Geyser, pesan node khusus di dasbor Helius Anda atau hubungi kami melalui Discord untuk memulai sekarang.

Kesimpulan

Selamat!

Dalam artikel ini, kita telah menelusuri kompleksitas replikasi data dan pengelolaan beban RPC dengan mengulas Solana Geyser Plugins. Memahami sistem ini bukanlah hal yang mudah — arsitekturnya canggih dan dokumentasinya sangat terbatas, tetapi sistem ini menawarkan banyak peluang penyesuaian dan pengoptimalan performa bagi developer Solana.

Pengetahuan yang diperoleh dari artikel ini sangat berharga, terutama jika Anda adalah developer atau bagian dari tim yang ingin membuat atau mengelola aplikasi berperforma tinggi di Solana. Geyser Plugins sangat penting untuk dipahami karena menawarkan solusi yang skalabel dan andal bagi ekosistem Solana.

Jika Anda sudah membaca sejauh ini, anon, terima kasih!

Sumber Daya Tambahan

Berlangganan Helius

Ikuti perkembangan terbaru dalam pengembangan Solana dan dapatkan pembaruan saat kami memublikasikan postingan