Memahami RESP: Protokol di Sebalik Redis

Dalam hantaran saya sebelum ini, saya telah berkongsi gambaran keseluruhan tentang klon Redis saya yang dibina dengan Node.js. Sekarang, saya ingin menjelaskan bahagian kritikal dalam projek ini: RESP, atau Redis Serialization Protocol.

Redis tidak menerima tatasusunan JavaScript yang kemas. Ia menerima bait mentah (raw bytes) melalui soket TCP. Untuk berfungsi, bait-bait ini memerlukan struktur. Pelayan mesti tahu di mana sesuatu arahan bermula dan berakhir. Ia mesti tahu berapa banyak argumen yang wujud dan berapa panjang setiap satu daripadanya.

RESP menyediakan struktur ini. Ia adalah bahasa yang digunakan oleh klien dan pelayan untuk berkomunikasi.

Sebagai contoh, arahan GET name kelihatan seperti ini dalam RESP: *2\r\n$3\r\nGET\r\n$4\r\nname\r\n

Berikut adalah perinciannya:

  • *2 bermaksud tatasusunan dengan 2 elemen.
  • $3 bermaksud bahagian seterusnya sepanjang 3 bait: GET.
  • $4 bermaksud bahagian seterusnya sepanjang 4 bait: name.

Parser menukarkan bait-bait ini kepada ["GET", "name"]. Kini enjin boleh menjalankan arahan tersebut.

Mengapa tidak memecahkan rentetan (string) menggunakan ruang kosong sahaja? Pemecahan ringkas akan gagal dengan nilai yang mengandungi ruang kosong, seperti SET message "hello world". Ia juga akan gagal dengan data binari. RESP menyelesaikan masalah ini dengan menyertakan panjang bagi setiap nilai. Pelayan akan membaca jumlah bait yang tepat seperti yang dinyatakan. Ini menjadikannya selamat untuk binari (binary-safe) dan boleh dipercayai.

Pengajaran yang paling sukar adalah mempelajari bahawa TCP berasaskan aliran (stream-based), bukan berasaskan mesej. Pelayan tidak sentiasa menerima satu arahan lengkap pada satu-satu masa. Sesuatu arahan mungkin tiba dalam dua bahagian (chunks) yang berasingan. Atau, beberapa arahan mungkin tiba dalam satu bahagian tunggal.

Ini bermakna parser tidak boleh menganggap satu acara data adalah bersamaan dengan satu arahan. Parser mesti menggunakan penimbal (buffer) dalaman.

Parser RESP saya berfungsi seperti ini:

  1. Terima bait daripada soket.
  2. Tambah bait ke dalam penimbal.
  3. Cuba parse arahan yang lengkap.
  4. Jika arahan tidak lengkap, tunggu lebih banyak data.
  5. Jika arahan lengkap, kembalikan ia.
  6. Jika terdapat data tambahan yang berbaki, simpan ia dalam penimbal untuk parse seterusnya.

Sebuah pangkalan data bermula pada lapisan protokol. Sebelum Redis boleh menyimpan data, ia mesti memahami arahan tersebut. Sebelum ia mengembalikan nilai, ia mesti mengekod (encode) respons tersebut.

Melaksanakan RESP telah mengubah pelayan TCP yang ringkas menjadi sistem yang benar-benar serasi dengan Redis. Ia mengubah cara saya melihat sistem backend. Protokol adalah lebih daripada sekadar format. Ia adalah satu kontrak antara dua sistem.

Dalam hantaran saya yang seterusnya, saya akan membincangkan tentang lapisan storan dalam memori (in-memory storage layer).

Repositori: https://github.com/Abhinov007/redis_clone Sandbox langsung: https://abhinov007.github.io/Redis_Clone/ Sumber: https://dev.to/abhinov007/understanding-resp-the-protocol-behind-redis-50p4