Arcjet menggabungkan WebAssembly dengan keselamatan kami sebagai SDK kod. Ini membantu pembangun melaksanakan fungsi keselamatan biasa seperti pengesanan PII dan pengesanan bot secara langsung dalam kod mereka. Kebanyakan logik dibenamkan dalam Wasm, yang memberikan kami kotak pasir selamat dengan prestasi hampir asli dan merupakan sebahagian daripada falsafah kami tentang keselamatan diutamakan tempatan.
Keupayaan untuk menjalankan kod yang sama merentas platform juga membantu semasa kami membina sokongan daripada JavaScript kepada susunan teknologi lain, tetapi ia memerlukan abstraksi penting untuk menterjemah antara bahasa (Wasm kami disusun daripada Rust).
Model Komponen WebAssembly ialah binaan berkuasa yang membolehkan ini, tetapi binaan hanya boleh menjadi sebaik pelaksanaan dan alatan yang mengelilinginya. Untuk Model Komponen, ini paling jelas dalam penjanaan kod untuk Hos (persekitaran yang melaksanakan Model Komponen WebAssembly) dan Tetamu (modul WebAssembly yang ditulis dalam mana-mana bahasa dan disusun kepada Model Komponen; Rust dalam kes kami).
Model Komponen mentakrifkan bahasa untuk komunikasi antara Hos dan Tetamu yang terutamanya terdiri daripada jenis, fungsi, import dan eksport. Ia cuba mentakrifkan bahasa yang luas, tetapi beberapa jenis, seperti varian, tupel dan sumber, mungkin tidak wujud dalam bahasa pengaturcaraan tujuan umum tertentu.
Apabila alat cuba menjana kod untuk salah satu bahasa ini, pengarang selalunya perlu kreatif untuk memetakan jenis Model Komponen kepada bahasa tujuan umum tersebut. Sebagai contoh, kami menggunakan jco untuk menjana pengikatan JS dan ini melaksanakan varian menggunakan objek JavaScript dalam bentuk { tag: string, value: string }. Ia juga mempunyai kes khas untuk hasil<_, _> taip di mana varian ralat ditukar menjadi Ralat dan dilemparkan.
Siaran ini meneroka cara Model Komponen Wasm mendayakan penyepaduan merentas bahasa, kerumitan penjanaan kod untuk Hos dan Tetamu, dan pertukaran yang kami lakukan untuk mencapai kod idiomatik dalam bahasa seperti Go.
Di Arcjet, kami perlu membina alat untuk menjana kod untuk Hos yang ditulis dalam bahasa pengaturcaraan Go. Walaupun SDK kami cuba menganalisis segala-galanya secara setempat, itu tidak selalu mungkin dan oleh itu kami mempunyai API yang ditulis dalam Go yang menambah keputusan setempat dengan metadata tambahan.
Go mempunyai sintaks dan sistem jenis yang sangat minimum mengikut reka bentuk. Mereka tidak mempunyai generik sehingga baru-baru ini dan mereka masih mempunyai had yang ketara. Ini menjadikan codegen daripada Component Model to Go kompleks dalam pelbagai cara.
Sebagai contoh, kita boleh menjana hasil<_, _> sebagai:
type Result[V any] struct { value V err error }
Walau bagaimanapun, ini mengehadkan jenis yang boleh disediakan dalam kedudukan ralat. Jadi kita perlu mengkodekannya sebagai:
type Result[V any] struct { value V err error }
Ini berfungsi tetapi menjadi menyusahkan untuk digunakan dengan Go idiomatik lain, yang sering menggunakan konvensyen val, err := doSomething() untuk menunjukkan semantik yang sama seperti jenis Hasil yang telah kami takrifkan di atas.
Selain itu, membina Keputusan ini adalah menyusahkan: Result[int, string]{value: 1, err: ""}. Daripada menyediakan jenis Hasil, kami mungkin mahu memadankan corak idiomatik supaya pengguna Go berasa semula jadi menggunakan pengikatan yang kami hasilkan.
Kod boleh dijana untuk berasa lebih semula jadi kepada bahasa atau ia boleh menjadi pemetaan yang lebih langsung kepada jenis Model Komponen. Kedua-dua pilihan tidak sesuai dengan 100% kes penggunaan jadi terpulang kepada pengarang alat untuk memutuskan mana yang paling masuk akal.
Untuk perkakas Arcjet, kami memilih pendekatan Go idiomatik untuk pilihan<_> dan hasil<_, _> jenis, yang memetakan ke val, ok := doSomething() dan val, err := doSomething() masing-masing. Untuk varian, kami mencipta antara muka yang perlu dilaksanakan oleh setiap varian, seperti:
type Result[V any, E any] struct { value V err E }
Ini memberikan keseimbangan yang baik antara keselamatan jenis dan pembalut yang tidak perlu. Sudah tentu, terdapat situasi di mana pembalut diperlukan, tetapi ia boleh dikendalikan sebagai kes tepi.
Pembangun mungkin bergelut dengan corak bukan idiomatik, yang membawa kepada verbose, kod yang kurang boleh diselenggara. Menggunakan konvensyen yang ditetapkan menjadikan kod itu terasa lebih biasa, tetapi memerlukan usaha tambahan untuk dilaksanakan.
Kami memutuskan untuk mengambil jalan idiomatik untuk meminimumkan geseran dan memudahkan pasukan kami supaya kami tahu apa yang diharapkan apabila bergerak di sekitar pangkalan kod.
Salah satu keputusan terbesar yang perlu dibuat oleh pengarang perkakas ialah konvensyen panggilan pengikatan. Ini termasuk menentukan cara/bila import akan disusun, jika modul Wasm akan disusun semasa persediaan atau instantiasi, dan pembersihan.
Dalam pangkalan kod Arcjet, kami memilih corak kilang/contoh untuk mengoptimumkan prestasi. Menyusun modul WebAssembly adalah mahal, jadi kami melakukannya sekali dalam pembina NewBotFactory(). Panggilan Instantiate() seterusnya adalah pantas dan murah, membolehkan daya pemprosesan yang tinggi dalam beban kerja pengeluaran.
type BotConfig interface { isBotConfig() } func (AllowedBotConfig) isBotConfig() {} func (DeniedBotConfig) isBotConfig() {}
Pengguna membina BotFactory ini sekali dengan memanggil NewBotFactory(ctx) dan menggunakannya untuk mencipta berbilang kejadian melalui kaedah Instantiate.
func NewBotFactory( ctx context.Context, ) (*BotFactory, error) { runtime := wazero.NewRuntime(ctx) // ... Imports are compiled here if there are any // Compiling the module takes a LONG time, so we want to do it once and hold // onto it with the Runtime module, err := runtime.CompileModule(ctx, wasmFileBot) if err != nil { return nil, err } return &BotFactory{runtime, module}, nil }
Instantiation sangat pantas jika modul telah disusun, seperti yang kita lakukan dengan runtime.CompileModule() semasa membina kilang.
BotInstance mempunyai fungsi yang dieksport daripada takrifan Model Komponen.
func (f *BotFactory) Instantiate(ctx context.Context) (*BotInstance, error) { if module, err := f.runtime.InstantiateModule(ctx, f.module, wazero.NewModuleConfig()); err != nil { return nil, err } else { return &BotInstance{module}, nil } }
Secara amnya, selepas menggunakan BotInstance, kami ingin membersihkannya untuk memastikan kami tidak membocorkan ingatan. Untuk ini kami menyediakan fungsi Tutup.
func (i *BotInstance) Detect( ctx context.Context, request string, options BotConfig, ) (BotResult, error) { // ... Lots of generated code for binding to Wazero }
Jika anda ingin membersihkan seluruh BotFactory, itu juga boleh ditutup:
type Result[V any] struct { value V err error }
Kami boleh menggabungkan semua API ini untuk memanggil fungsi pada modul WebAssembly ini:
type Result[V any, E any] struct { value V err E }
Corak pembinaan kilang dan contoh ini memerlukan lebih banyak kod untuk digunakan, tetapi ia dipilih untuk mencapai prestasi sebanyak mungkin dalam laluan panas perkhidmatan Arcjet.
Dengan memuatkan hadapan kos kompilasi, kami memastikan bahawa dalam laluan panas perkhidmatan Arcjet - di mana kependaman paling penting - pengendalian permintaan adalah seefisien mungkin. Pertukaran ini memang menambahkan sedikit kerumitan pada kod permulaan, tetapi ia berbaloi dengan overhed yang jauh lebih rendah bagi setiap permintaan - lihat perbincangan kami tentang pertukaran itu.
Pada bila-bila masa kita perlu mengintegrasikan dua atau lebih bahasa, ia penuh dengan pertukaran yang perlu dibuat—sama ada menggunakan FFI asli atau Model Komponen.
Siaran ini membincangkan beberapa cabaran yang kami hadapi di Arcjet dan alasan di sebalik keputusan kami. Jika kita semua membina set primitif yang sama, seperti Model Komponen dan WIT, kita semua boleh memanfaatkan set primitif berkualiti tinggi yang sama, seperti wit-bindgen atau wit-komponen , dan bina alatan untuk disesuaikan dengan setiap kes penggunaan. Inilah sebabnya mengapa bekerja ke arah standard membantu semua orang.
Model Komponen WebAssembly menawarkan abstraksi yang berkuasa untuk penyepaduan merentas bahasa, tetapi menterjemah jenisnya ke dalam bahasa seperti Go memperkenalkan cabaran reka bentuk yang halus. Dengan memilih corak idiomatik dan mengoptimumkan prestasi secara selektif - seperti menggunakan corak kilang/contoh - kami boleh memberikan pengalaman pembangun semula jadi sambil mengekalkan kecekapan.
Memandangkan perkakasan di sekitar Model Komponen berkembang, kami boleh menantikan pendekatan codegen yang lebih halus yang memudahkan penyepaduan ini.
Atas ialah kandungan terperinci Model Komponen Wasm dan codegen idiomatik. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!