
Plugin Solana Geyser: Truyền phát dữ liệu với tốc độ ánh sáng
Mục lục
- Bài viết này nói về điều gì?
- Bản sao AccountsDB: Phương pháp sao chép dữ liệu và xử lý tải RPC đã bị loại bỏ
- Plugin Solana Geyser là gì?
- Geyser Plugin Interface
- Mã nguồn
- Khai báo trait
- Phương thức bắt buộc
- Các phương thức được cung cấp
- Lưu ý về các mức commitment
- Các plugin Solana Geyser phổ biến
- Tạo plugin Solana Geyser của riêng bạn
- Solana Geyser Plugin Scaffold
- Plugin Manager
- Tạo plugin Geyser từ đầu
- Truyền phát Geyser với Helius
- Kết luận
- Tài nguyên bổ sung
Bài viết này nói về điều gì?
Plugin Geyser là các thành phần mô-đun được thiết kế để truyền dữ liệu về tài khoản, slot, block và giao dịch đến các kho dữ liệu bên ngoài, giúp nhà phát triển loại bỏ tải RPC (Remote Procedure Call) khỏi validator. Plugin Geyser mang đến giải pháp linh hoạt cho các nhà phát triển muốn tùy chỉnh nhu cầu truyền phát và xử lý dữ liệu.
Trong bài viết này, chúng ta sẽ đi sâu vào những chi tiết phức tạp của plugin Solana Geyser. Trước tiên, chúng ta sẽ tìm hiểu các bản sao AccountsDB, một phương pháp được đề xuất để sao chép dữ liệu và quản lý tải nhưng cuối cùng đã bị loại bỏ để chuyển sang plugin Geyser.
Sau đó, chúng ta sẽ phân tích plugin Geyser là gì, cách chúng hoạt động và cách chúng được cấu trúc thông qua Plugin Interface.
Tiếp theo, chúng ta sẽ thảo luận về các plugin Geyser phổ biến hiện có và hướng dẫn bạn qua quy trình phức tạp để tự tạo plugin. Cuối cùng, chúng ta sẽ nói về Helius và cách chúng tôi đơn giản hóa việc truyền phát dữ liệu trên Solana.
Bản sao AccountsDB: Phương pháp sao chép dữ liệu và xử lý tải RPC đã bị loại bỏ
Solana đã khám phá nhiều hướng để giải quyết thách thức về tải RPC lớn và sao chép dữ liệu. Một phương pháp đầy hứa hẹn là sử dụng các bản sao AccountsDB. Các bản sao này được thiết kế để chuyển các yêu cầu quét tài khoản từ validator chính sang bản sao AccountsDB. Dù đầy hứa hẹn, hệ thống vốn rất phức tạp và cần một tập hợp dịch vụ mới để đảm bảo đồng bộ giữa validator chính và các bản sao. Cuối cùng, đề xuất này đã bị loại bỏ để chuyển sang Geyser Plugin System — một giải pháp đơn giản hơn để validator client hỗ trợ, đồng thời mang lại cho nhà phát triển nhiều sự linh hoạt hơn khi triển khai ứng dụng.
Vậy chính xác thì plugin Solana Geyser là gì?
Plugin Solana Geyser là gì?
Plugin Solana Geyser cung cấp quyền truy cập có độ trễ thấp vào dữ liệu Solana và có thể phục vụ các ứng dụng thay thế nhu cầu thực hiện lệnh gọi RPC trên validator. Ví dụ, nếu một validator phải phục vụ nhiều lệnh gọi getProgramAccounts liên tiếp trong thời gian ngắn, lưu lượng lớn này có thể khiến validator tụt lại phía sau mạng.
Plugin Geyser giải quyết vấn đề này bằng cách chuyển hướng thông tin về tài khoản, block, slot và giao dịch đến các kho dữ liệu bên ngoài như cơ sở dữ liệu quan hệ, cơ sở dữ liệu NoSQL hoặc Kafka.
Việc chuyển hướng dữ liệu này cho phép các dịch vụ RPC cung cấp những phương án tối ưu linh hoạt và có mục tiêu hơn, chẳng hạn như lưu vào bộ nhớ đệm và lập chỉ mục, cho những ai cần truy xuất dữ liệu từ các kho bên ngoài này.
Plugin Geyser đóng vai trò là cầu nối giữa Solana và các giải pháp lưu trữ dữ liệu bên ngoài. Chúng cho phép nhà phát triển chuyển phần lớn tác vụ quản lý dữ liệu khỏi validator, nhờ đó cải thiện hiệu năng và giảm nguy cơ xảy ra điểm nghẽn.
Plugin Geyser đảm bảo validator luôn đồng bộ với mạng, bất kể lưu lượng RPC lớn đến đâu.
Geyser Plugin Interface
Nhà phát triển có thể xây dựng plugin Geyser bằng Solana Geyser Plugin Interface. Interface này cung cấp quyền truy cập vào tài khoản, giao dịch, slot, siêu dữ liệu block và entry. Nó được khai báo trong crate solana-geyser-plugin-interface và được định nghĩa bởi trait GeyserPlugin.
Trait này định nghĩa các phương thức, mỗi phương thức có tiền tố update_, được gọi bất cứ khi nào dữ liệu mới được tạo hoặc dữ liệu hiện có được cập nhật. Plugin Geyser cũng phải chỉ định hành vi trong quá trình tải và gỡ tải. Trait này mô tả các phương thức thiết yếu mà plugin Geyser cần triển khai để đảm bảo truyền phát dữ liệu hiệu quả theo hành vi mong muốn của plugin.
Mã nguồn
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 { ... }
}Khai báo trait
Trait GeyserPlugin đóng vai trò là interface nền tảng cho tất cả plugin trong hệ sinh thái Solana Geyser Plugin. Nó được khai báo là một trait công khai với các ràng buộc trait Any, Send, Sync và Debug từ thư viện chuẩn Rust. Các ràng buộc trait như sau:
Anycho phép phản chiếu kiểu, nhờ đó có thể downcast về một kiểu cụ thểSendcho biết quyền sở hữu kiểu triển khai trait này có thể được chuyển giữa các luồngSynccho biết các tham chiếu của kiểu triển khai trait này có thể được chia sẻ giữa các luồngDebugcho phép định dạng kiểu để xuất ra, cụ thể là phục vụ việc gỡ lỗi
Any và Debug không quá quan trọng đối với chúng ta.
Điều thực sự quan trọng là GeyserPlugin cần Send và Sync để bảo đảm chương trình an toàn với luồng.
Phương thức bắt buộc
fn name(&self) -> &'static str;Phương thức name là bắt buộc đối với mọi kiểu triển khai GeyserPlugin. Phương thức này đóng vai trò là mã định danh cho plugin Geyser. Nó trả về một lát cắt chuỗi tĩnh đại diện cho tên của plugin Geyser.
Việc phương thức này và tất cả phương thức khác, ngoại trừ on_load và on_unload, sử dụng &self thay vì &mut self là thay đổi mới trong bản cập nhật 1.16 của Solana. Điều này cải thiện đáng kể hiệu năng vì không còn cần bọc plugin Geyser trong Read-Write Lock và lấy khóa ghi mỗi khi gọi một hàm của plugin.
Các phương thức được cung cấp
Trait này có một số phương thức được cung cấp sẵn chứa phần triển khai mặc định, và các phần triển khai GeyserPlugin có thể ghi đè chúng.
fn on_load(&mut self, _config_file: &str) ->Result<()> { ... }Phương thức on_load là callback được gọi khi hệ thống tải một plugin và được dùng cho mọi thao tác khởi tạo mà plugin yêu cầu. Nó nhận một tham chiếu đến string đại diện cho đường dẫn đến tệp cấu hình. Cấu hình phải ở định dạng JSON5 và bao gồm trường libpath chỉ ra tên đường dẫn đầy đủ của thư viện dùng chung triển khai interface này.
fn on_unload(&mut self) { ... }Phương thức on_unload là callback được gọi để thực hiện mọi thao tác dọn dẹp trước khi hệ thống gỡ tải plugin.
fn update_account(
&self,
account:ReplicaAccountInfoVersions<'_>,
slot: Slot,
is_startup:bool
) ->Result<()> { ... }Phương thức update_account được gọi khi một tài khoản được cập nhật ở mức xác nhận processed, việc này có thể xảy ra nhiều lần trong một slot. Ở đây, việc theo dõi các slot đã được xác nhận là rất quan trọng để nhận được những cập nhật tài khoản đã được cam kết vào chuỗi chính tắc.
Struct ReplicaAccountInfoVersions chứa siêu dữ liệu và dữ liệu của tài khoản được truyền phát.
Tham số slot trỏ đến slot nơi tài khoản đang được cập nhật.
Khi is_startup là true, điều đó cho biết tài khoản được tải từ snapshot khi validator khởi động. Khi is_startup là false, tài khoản được cập nhật trong quá trình xử lý giao dịch.
fn notify_end_of_startup(&self) ->Result<()> { ... }Phương thức notify_end_of_startup được gọi để báo hiệu kết thúc giai đoạn khởi động. Việc này xảy ra khi validator đã khôi phục cơ sở dữ liệu tài khoản từ snapshot và tất cả tài khoản đã được cập nhật tương ứng.
fn update_slot_status(
&self,
slot: Slot,
parent:Option,
status:SlotStatus
) ->Result<()> { ... }Phương thức update_slot_status được gọi khi trạng thái slot được cập nhật. Nó nhận một Slot, một Option<u64> cho slot cha và một instance SlotStatus enum.
SlotStatus mô tả ba trạng thái của một slot trong Solana:
Processed- slot cao nhất mà node đã xử lý. Dù slot chưa được xác nhận hay hoàn tất, nó vẫn thuộc chuỗi mà validator cho là có khả năng cao nhất trở thành chuỗi chính tắcConfirmed- slot đã nhận đủ phiếu bầu để được coi là an toàn và là một phần của chuỗi. Slot này được đa số vượt trội các validator của Solana ủng hộRooted- slot hiện là một phần vĩnh viễn của blockchain và tất cả phiên bản hoặc fork khác của chuỗi phải xây dựng dựa trên slot này. Điều này có nghĩa là mọi nhánh trên mạng đều bắt nguồn từ block này
fn notify_transaction(
&self,
transaction:ReplicaTransactionInfoVersions<'_>,
slot: Slot
) ->Result<()> { ... }Phương thức notify_transaction được gọi khi một giao dịch được xử lý trong slot, qua đó cung cấp cho plugin thông tin chi tiết về giao dịch.
ReplicaTransactionInfoVersions là một wrapper enum xử lý ReplicaTransactionInfo. Nếu cấu trúc của RepicaTransactionInfo thay đổi, sẽ có một entry enum mới cho phiên bản mới hơn. Điều này buộc các phần triển khai plugin phải xử lý thay đổi bằng cách hỗ trợ một entry enum mới. Hiện tại, enum bọc hai biến thể:
V0_0_1(&'a ReplicaTransactionInfo<'a>)V0_0_2(&'a ReplicaTransactionInfoV2<'a>)
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,
}Điểm khác biệt chính giữa các biến thể là biến thể thứ hai lưu chỉ mục của giao dịch trong block.
fn notify_entry(&self, entry:ReplicaEntryInfoVersions<'_>) ->Result<()> { ... }notify_entry thông báo cho plugin về một entry mới. Nó nhận một instance của ReplicaEntryInfoVersions, đây là wrapper giúp bảo đảm khả năng tương thích trong tương lai cho việc xử lý ReplicaEntryInfo. Hiện tại, nó chứa biến thể V0_0_1(&'a ReplicaEntryInfo<'a>).
Biến thể này là một struct chứa thông tin về slot của entry, chỉ mục trong block, số lượng hash kể từ entry trước, hash SHA-256 của entry và số lượng giao dịch đã thực thi trong entry.
fn notify_block_metadata(
&self,
blockinfo:ReplicaBlockInfoVersions<'_>
) ->Result<()> { ... }Phương thức notify_block_metadata được gọi khi siêu dữ liệu của block được cập nhật. Nó nhận một instance ReplicaBlockInfoVersions enum chứa thông tin về block. Enum này là wrapper cho nhiều phiên bản ReplicaBlockInfo, chứa thông tin về block như slot, hash, phần thưởng, thời gian block, chiều cao block, v.v.
fn account_data_notifications_enabled(&self) ->bool { ... }
fn transaction_notifications_enabled(&self) ->bool { ... }
fn entry_notifications_enabled(&self) ->bool { ... }Các phương thức này lần lượt trả về giá trị boolean cho biết plugin có muốn bật thông báo về dữ liệu tài khoản, giao dịch và entry hay không.
Lưu ý về các mức commitment
Geyser gửi ngay các bản cập nhật dữ liệu tài khoản và giao dịch ngay sau khi chúng được xử lý. Điều này có lợi cho tốc độ lập chỉ mục đầu cuối, tuy nhiên vẫn có rủi ro một slot đã xử lý có thể bị bỏ qua.
Slot bị bỏ qua là một slot trong quá khứ không tạo ra block, do leader ngoại tuyến hoặc fork chứa slot đó bị loại bỏ để chọn một phương án thay thế tốt hơn. Các hệ thống lưu trữ dữ liệu nhận luồng dữ liệu cần nhận biết khả năng này và quản lý các bản cập nhật cho phù hợp.
Các plugin Solana Geyser phổ biến
Có rất nhiều plugin Solana Geyser để nhà phát triển sử dụng, thậm chí fork nhằm đáp ứng nhu cầu cụ thể. Một số plugin đáng chú ý gồm:
PostgreSQL Plugin: để quản lý và truy vấn dữ liệu bằng PostgreSQLgRPC Service Streaming Plugin: để truyền phát các bản cập nhật tài khoản Solana đến một dịch vụ gRPCRabbitMQ Producer Plugin: để hỗ trợ xếp hàng thông điệp bằng RabbitMQKafka Producer Plugin: để truyền phát dữ liệu bằng KafkaAmazon SQS Plugin: để xếp hàng thông điệp bằng Simple Queue Service của AmazonGoogle BigTable Plugin: để quản lý và truy vấn dữ liệu bằng Google BigTable
Các plugin này có thể được điều chỉnh để phục vụ vô số trường hợp sử dụng.
Ví dụ, Clockwork đã tận dụng một plugin Geyser để lên lịch giao dịch và xây dựng các chương trình Solana tự động, hướng sự kiện. Dù dự án đã ngừng hoạt động, mã nguồn mở của dự án vẫn là một tài nguyên giá trị mà bạn có thể xem trên GitHub.
Các trường hợp sử dụng khả thi khác có thể bao gồm dùng plugin Geyser để giám sát số dư tài khoản trên nền tảng DeFi, cung cấp các chỉ số về tình trạng mạng hoặc theo dõi sự kiện trong chuỗi cung ứng theo thời gian thực.
Tạo plugin Solana Geyser của riêng bạn
Dưới đây là một số tài nguyên và thành phần để xây dựng plugin của riêng bạn:
Solana Geyser Plugin Scaffold
Solana Geyser Plugin Scaffold là tài nguyên dễ sử dụng nhất để bắt đầu hành trình phát triển plugin Solana Geyser. Scaffold này đóng vai trò là một mẫu tối giản ghi lại các tương tác giữa Plugin Manager và chính plugin. Đây là điểm khởi đầu tuyệt vời để làm quen với quy trình hoạt động của plugin cũng như các kỹ thuật gỡ lỗi.
Plugin Manager
Plugin Manager là thành phần cốt lõi điều phối vòng đời và tương tác của tất cả plugin Geyser. Nó có thể tự động tải và gỡ tải plugin trong thời gian chạy, mang lại tính linh hoạt và mô-đun cao hơn.
Trong thời gian chạy, Plugin Manager truyền đường dẫn của tệp cấu hình đến plugin của bạn. Điều này cho phép tùy chỉnh các thiết lập của plugin Geyser mà không cần thay đổi mã của plugin.
Để tích hợp một plugin vào validator, bạn cần chỉ định đường dẫn thư viện động bằng tham số --geyser-plugin-config. Tham số này cho validator biết vị trí của plugin và cấu hình liên quan.
Ở mức tối thiểu, tệp cấu hình phải ở định dạng JSON và chứa đường dẫn đến thư viện động của plugin Geyser — tệp .so trên Linux. Một tệp cấu hình tối thiểu sẽ có dạng như sau:
{
"libpath": "/.so"
}Tạo plugin Geyser từ đầu
Nếu muốn đi theo con đường riêng và tự tạo plugin Geyser mà không dùng scaffold hay sửa đổi một plugin hiện có, bạn cần lập trình plugin bằng Geyser Plugin Interface.
Một plugin bắt buộc phải triển khai trait GeyserPlugin để hoạt động với runtime. Ngoài ra, thư viện động phải xuất một hàm “C” _create_plugin để tạo phần triển khai plugin.
Một ví dụ là tạo plugin webhook triển khai trait GeyserPlugin:
#[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)
}Ở đây, chúng ta đang tạo một hàm công khai không an toàn sử dụng quy ước gọi C, extern "C", giúp nó tương thích với C và các ngôn ngữ khác. Bản thân hàm fn _create*_*plugin() -> *mut dyn GeyserPlugin trả về một con trỏ thô có thể thay đổi đến dynGeyserPlugin, tức trait GeyserPlugin. Phần thân hàm tạo một instance mới của WebhookPlugin, đóng gói instance này thành một trait object, rồi chuyển trait object đã đóng gói thành con trỏ thô để hàm có thể trả về.
Vì vậy, các bước để tạo plugin Geyser của riêng bạn như sau:
- Xây dựng plugin triển khai Solana Geyser Plugin Interface
- Lấy thư viện động (tệp
.so) từ thư mụctarget/releasehoặctarget/debug - Tạo một tệp
geyser-config.json, trong đó phải chứa đường dẫn đến thư viện động của plugin Geyser dưới trường “libpath” - Khởi động validator với cờ
--geyser-plugin-config geyser-config.json
Các bước này nghe có vẻ khá đơn giản, nhưng quá trình thực sự vận hành và duy trì một plugin Solana Geyser có thể rất vất vả.
Truyền phát Geyser với Helius
Helius nổi tiếng vì mang đến trải nghiệm nhà phát triển vượt trội trên Solana. Việc tập trung hoàn toàn vào Solana đã giúp Helius tích lũy kinh nghiệm phong phú qua việc xử lý nhiều thách thức và hỗ trợ hàng loạt tích hợp quy mô lớn. Helius có vị thế đặc biệt để giải quyết mọi vấn đề mà nhà phát triển có thể gặp phải.
Tại Helius, chúng tôi quản lý plugin Geyser cho nhiều đội ngũ có hiệu suất cao trong hệ sinh thái Solana. Chúng tôi vận hành các cụm Geyser chuyên biệt với khả năng dự phòng và chịu lỗi bổ sung, bảo đảm bạn không bao giờ phải lo về việc thiếu dữ liệu hay thời gian ngừng hoạt động. Quyền truy cập API theo chương trình cho phép bạn tự động sửa đổi plugin Geyser mà không cần lo lắng về độ tin cậy. Quản lý plugin Geyser thường là một nhiệm vụ khó khăn vì bạn phải chịu trách nhiệm bảo đảm tính nhất quán, độ tin cậy và khả năng sẵn sàng của dữ liệu. Tại sao không để Helius làm việc đó cho bạn?
Nếu bạn quan tâm đến truyền phát Geyser, hãy đặt mua một node chuyên dụng trong bảng điều khiển Helius hoặc liên hệ với chúng tôi trên Discord để bắt đầu ngay hôm nay.
Kết luận
Chúc mừng!
Trong bài viết này, chúng ta đã tìm hiểu sự phức tạp của việc sao chép dữ liệu và quản lý tải RPC thông qua plugin Solana Geyser. Hiểu được hệ thống này không hề dễ dàng — đây là một kiến trúc phức tạp gần như không có tài liệu hướng dẫn, nhưng lại mang đến rất nhiều cơ hội tùy chỉnh và tối ưu hiệu năng cho các nhà phát triển Solana.
Kiến thức thu được từ bài viết này rất có giá trị, đặc biệt nếu bạn là nhà phát triển hoặc đội ngũ muốn xây dựng hay quản lý các ứng dụng hiệu năng cao trên Solana. Việc hiểu plugin Geyser rất quan trọng vì chúng cung cấp một giải pháp có khả năng mở rộng và đáng tin cậy cho hệ sinh thái Solana.
Nếu bạn đã đọc đến đây, cảm ơn bạn!
Tài nguyên bổ sung
Bài viết liên quan
Đăng ký nhận tin từ Helius
Luôn cập nhật những thông tin mới nhất về phát triển Solana và nhận thông báo khi chúng tôi đăng bài


