Apa Itu gRPC? Bagaimana Cara Bekerja dengan APISIX?
September 28, 2022
Apa itu gRPC
gRPC adalah kerangka kerja RPC yang dibuka sumber oleh Google yang bertujuan untuk menyatukan cara layanan berkomunikasi. Kerangka kerja ini menggunakan HTTP/2 sebagai protokol transfer dan Protocol Buffers sebagai bahasa deskripsi antarmuka. Ini dapat secara otomatis menghasilkan kode untuk panggilan antar layanan.
Dominasi gRPC
gRPC telah menjadi standar kerangka kerja RPC karena pengaruh luar biasa Google terhadap pengembang dan lingkungan cloud-native.
Ingin memanggil fungsi etcd? gRPC!
Ingin mengirim data OpenCensus? gRPC!
Ingin menggunakan RPC dalam layanan mikro yang diimplementasikan dalam Go? gRPC!
Dominasi gRPC sangat kuat sehingga jika Anda tidak memilih gRPC sebagai kerangka kerja RPC Anda, Anda harus memberikan alasan yang kuat mengapa. Jika tidak, seseorang akan selalu bertanya, mengapa Anda tidak memilih gRPC yang mainstream? Bahkan Alibaba, yang telah mempromosikan kerangka kerja RPC-nya Dubbo dengan gencar, telah melakukan revisi dramatis pada desain protokol dalam versi terbaru Dubbo 3, mengubahnya menjadi varian gRPC yang kompatibel dengan gRPC dan Dubbo 2. Sebenarnya, alih-alih mengatakan Dubbo 3 adalah peningkatan dari Dubbo 2, ini lebih seperti pengakuan atas supremasi gRPC.
Banyak layanan yang menyediakan gRPC juga menyediakan antarmuka HTTP yang sesuai, tetapi antarmuka tersebut seringkali hanya untuk tujuan kompatibilitas. Versi gRPC memiliki pengalaman pengguna yang jauh lebih baik. Jika Anda dapat mengaksesnya melalui gRPC, Anda dapat langsung mengimpor SDK yang sesuai. Jika Anda hanya dapat menggunakan API HTTP biasa, Anda biasanya akan diarahkan ke halaman dokumen, dan Anda perlu mengimplementasikan operasi HTTP yang sesuai sendiri. Meskipun akses HTTP dapat menghasilkan SDK yang sesuai melalui spesifikasi OpenAPI, hanya sedikit proyek yang memperlakukan pengguna HTTP dengan serius seperti gRPC karena HTTP adalah prioritas rendah.
Haruskah Saya Menggunakan gRPC
APISIX menggunakan etcd sebagai pusat konfigurasi. Sejak versi 3, etcd telah memigrasi antarmukanya ke gRPC. Namun, tidak ada proyek yang mendukung gRPC dalam ekosistem OpenResty, sehingga APISIX hanya dapat memanggil API HTTP etcd. API HTTP etcd disediakan melalui gRPC-gateway. Pada dasarnya, etcd menjalankan proxy HTTP ke gRPC di sisi server, dan kemudian permintaan HTTP eksternal dikonversi menjadi permintaan gRPC melalui gRPC-gateway. Setelah menerapkan metode komunikasi ini selama beberapa tahun, kami menemukan beberapa masalah dalam interaksi antara API HTTP dan API gRPC. Memiliki gRPC-gateway tidak berarti bahwa akses HTTP didukung dengan sempurna. Masih ada perbedaan halus.
Berikut adalah daftar masalah terkait yang kami temui dengan etcd selama beberapa tahun terakhir:
- gRPC-gateway dinonaktifkan secara default. Karena kelalaian pengelola, konfigurasi default etcd tidak mengaktifkan gRPC-gateway di beberapa proyek. Jadi kami harus menambahkan instruksi dalam dokumen untuk memeriksa apakah etcd saat ini memiliki gRPC-gateway yang diaktifkan. Lihat https://github.com/apache/apisix/pull/2940.
- Secara default, gRPC membatasi respons hingga 4MB. etcd menghapus batasan ini dalam SDK yang disediakannya tetapi lupa menghapusnya di gRPC-gateway. Ternyata etcdctl resmi (yang dibangun di atas SDK yang disediakannya) berfungsi dengan baik, tetapi APISIX tidak. Lihat https://github.com/etcd-io/etcd/issues/12576.
- Masalah yang sama - kali ini dengan jumlah maksimum permintaan untuk koneksi yang sama. Implementasi HTTP2 Go memiliki konfigurasi
MaxConcurrentStreamsyang mengontrol jumlah permintaan simultan yang dapat dikirim oleh satu klien, dengan default 250. Klien mana yang biasanya akan mengirim lebih dari 250 permintaan pada saat yang sama? Jadi etcd selalu menggunakan konfigurasi ini. Namun, gRPC-gateway, "klien" yang memproksi semua permintaan HTTP ke antarmuka gRPC lokal, mungkin melebihi batas ini. Lihat https://github.com/etcd-io/etcd/issues/14185. - Setelah etcd mengaktifkan mTLS, etcd menggunakan sertifikat yang sama sebagai sertifikat server dan sertifikat klien, sertifikat server untuk gRPC-gateway, dan sertifikat klien ketika gRPC-gateway mengakses antarmuka gRPC. Jika ekstensi autentikasi server diaktifkan pada sertifikat, tetapi ekstensi autentikasi klien tidak diaktifkan, akan terjadi kesalahan dalam verifikasi sertifikat. Sekali lagi, mengakses langsung dengan etcdctl berfungsi dengan baik (karena sertifikat tidak akan digunakan sebagai sertifikat klien dalam kasus ini), tetapi APISIX tidak. Lihat https://github.com/etcd-io/etcd/issues/9785.
- Setelah mengaktifkan mTLS, etcd memungkinkan konfigurasi kebijakan keamanan informasi pengguna sertifikat. Seperti disebutkan di atas, gRPC-gateway menggunakan sertifikat klien tetap saat mengakses antarmuka gRPC daripada informasi sertifikat yang digunakan untuk mengakses antarmuka HTTP di awal. Dengan demikian, fitur ini tidak akan berfungsi secara alami karena sertifikat klien tetap dan tidak akan diubah. Lihat https://github.com/apache/apisix/issues/5608.
Kami dapat merangkum masalah dalam dua poin:
- gRPC-gateway (dan mungkin upaya lain untuk mengonversi HTTP ke gRPC) bukanlah solusi ajaib yang memperbaiki semua masalah.
- Pengembang etcd tidak menekankan metode HTTP dengan cukup. Dan pengguna terbesarnya, Kubernetes, tidak menggunakan fitur ini.
Kami tidak membicarakan masalah perangkat lunak tertentu di sini, etcd hanyalah contoh tipikal yang menggunakan gRPC. Semua layanan yang menggunakan gRPC sebagai kerangka kerja RPC utama memiliki batasan serupa dalam dukungan mereka untuk HTTP.
Bagaimana APISIX 3.0 Menyelesaikan Masalah Ini
Ada pepatah, "jika gunung tidak datang ke Muhammad, maka Muhammad harus pergi ke gunung." Jika kami mengimplementasikan klien gRPC di bawah OpenResty, kami dapat berkomunikasi langsung dengan layanan gRPC.
Mempertimbangkan beban kerja dan stabilitas, kami memutuskan untuk mengembangkan berdasarkan pustaka gRPC yang umum digunakan alih-alih menciptakan kembali roda. Kami memeriksa pustaka gRPC berikut:
- Layanan gRPC NGINX. NGINX tidak mengekspos gRPC ke pengguna eksternal, bahkan tidak API tingkat tinggi. Jika Anda ingin menggunakannya, Anda hanya dapat menyalin beberapa fungsi tingkat rendah dan kemudian mengintegrasikannya ke antarmuka tingkat tinggi. Mengintegrasikannya akan menyebabkan beban kerja tambahan.
- Pustaka gRPC resmi untuk C++. Karena sistem kami berbasis NGINX, mengintegrasikan pustaka C++ bisa sedikit rumit. Selain itu, dependensi pustaka ini mendekati 2GB, yang akan menjadi tantangan besar untuk pembangunan APISIX.
- Implementasi resmi Go dari gRPC. Go memiliki toolchain yang kuat, dan kami dapat dengan cepat membangun proyek ke dalamnya. Namun, sayangnya kinerja implementasi ini jauh dari versi C++. Jadi kami melihat implementasi Go lainnya: https://github.com/bufbuild/connect-go/. Sayangnya, kinerja proyek ini juga tidak lebih baik dari versi resmi.
- Implementasi Rust dari pustaka gRPC. Pustaka ini akan menjadi pilihan alami untuk menggabungkan manajemen dependensi dan kinerja. Sayangnya, kami tidak familiar dengan Rust dan tidak akan bertaruh padanya.
Mempertimbangkan operasi klien gRPC pada dasarnya semua terikat IO, persyaratan kinerja bukanlah yang utama. Setelah pertimbangan matang, kami mengimplementasikannya berdasarkan Go-gRPC.
Untuk berkoordinasi dengan penjadwal coroutine Lua, kami menulis modul C NGINX: https://github.com/api7/grpc-client-nginx-module. Awalnya, kami ingin mengintegrasikan kode Go ke dalam modul C ini dengan mengompilasinya menjadi pustaka yang terhubung statis melalui cgo. Namun, kami menemukan bahwa karena Go adalah aplikasi multi-thread, proses anak tidak akan mewarisi semua thread dari proses induk setelah forking. Tidak ada cara untuk beradaptasi dengan arsitektur multi-proses master-worker NGINX. Jadi kami mengompilasi kode Go menjadi pustaka tautan dinamis (DLL) dan kemudian memuatnya ke dalam proses worker saat runtime.
Kami mengimplementasikan mekanisme antrian tugas untuk mengoordinasikan coroutine Go dengan coroutine Lua. Ketika kode Lua memulai operasi IO gRPC, ia mengirimkan tugas ke sisi Go dan menangguhkan dirinya sendiri. Sebuah coroutine Go akan mengeksekusi tugas ini, dan hasil eksekusi akan ditulis ke antrian. Sebuah thread latar belakang di sisi NGINX mengkonsumsi hasil eksekusi tugas, menjadwalkan ulang coroutine Lua yang sesuai, dan melanjutkan eksekusi kode Lua. Dengan cara ini, operasi IO gRPC tidak berbeda dengan operasi socket biasa di mata kode Lua.
Sekarang, sebagian besar pekerjaan modul C NGINX sudah selesai. Yang perlu kami lakukan adalah mengambil file .proto etcd (yang mendefinisikan antarmuka gRPC-nya), memodifikasinya, dan kemudian memuat file tersebut dalam Lua untuk mendapatkan klien etcd berikut:
local gcli = require("resty.grpc") assert(gcli.load("t/testdata/rpc.proto")) local conn = assert(gcli.connect("127.0.0.1:2379")) local st, err = conn:new_server_stream("etcdserverpb.Watch", "Watch", {create_request = {key = ngx.var.arg_key}}, {timeout = 30000}) if not st then ngx.status = 503 ngx.say(err) return end for i = 1, (ngx.var.arg_count or 10) do local res, err = st:recv() ngx.log(ngx.WARN, "received ", cjson.encode(res)) if not res then ngx.status = 503 ngx.say(err) break end end
Implementasi berbasis gRPC ini lebih baik daripada lua-resty-etcd, proyek klien etcd-HTTP dengan 1600 baris kode hanya dalam Lua.
Tentu saja, kami masih jauh dari menggantikan lua-resty-etcd. Untuk sepenuhnya terhubung dengan etcd, grpc-client-nginx-module juga perlu menyelesaikan fungsi berikut:
- Dukungan mTLS
- Dukungan konfigurasi metadata gRPC
- Dukungan konfigurasi parameter (misalnya
MaxConcurrentStreamsdanMaxRecvMsgSize) - Dukungan untuk permintaan dari L4
Untungnya, kami telah membangun fondasinya, dan mendukung hal-hal ini hanyalah masalah waktu.
grpc-client-nginx-module akan diintegrasikan ke dalam APISIX 3.0, kemudian pengguna APISIX dapat menggunakan metode modul ini dalam plugin APISIX untuk berkomunikasi langsung dengan layanan gRPC.
Dengan dukungan asli untuk gRPC, APISIX akan mendapatkan pengalaman etcd yang lebih baik dan membuka pintu kemungkinan untuk fitur seperti pemeriksaan kesehatan gRPC dan pelaporan data telemetri terbuka berbasis gRPC.
Kami sangat antusias melihat lebih banyak fitur berbasis gRPC dari APISIX di masa depan!