𝗨𝗻𝗱𝗲𝗿𝘀𝘁𝗮𝗻𝗱𝗶𝗻𝗴 𝗥𝗘𝗦𝗣: 𝗧𝗵𝗲 𝗣𝗿𝗼𝘁𝗼𝗰𝗼𝗹 𝗕𝗲𝗵𝗶𝗻𝗱 𝗥𝗲𝗱𝗶𝘀
আমার আগের পোস্টে, আমি Node.js দিয়ে তৈরি আমার Redis ক্লোন সম্পর্কে একটি ধারণা শেয়ার করেছিলাম। এখন, আমি এই প্রজেক্টের একটি গুরুত্বপূর্ণ অংশ ব্যাখ্যা করতে চাই: RESP, বা Redis Serialization Protocol।
Redis সুন্দর কোনো JavaScript array গ্রহণ করে না। এটি একটি TCP socket-এর মাধ্যমে raw bytes গ্রহণ করে। কাজ করার জন্য, এই bytes গুলোর একটি কাঠামো (structure) প্রয়োজন। সার্ভারকে জানতে হবে একটি কমান্ড কোথায় শুরু এবং কোথায় শেষ হচ্ছে। তাকে জানতে হবে কতগুলো আর্গুমেন্ট (argument) আছে এবং প্রতিটি কত বড়।
RESP এই কাঠামোটি প্রদান করে। এটি হলো সেই ভাষা যা ক্লায়েন্ট এবং সার্ভার কথা বলার জন্য ব্যবহার করে।
উদাহরণস্বরূপ, RESP-এ GET name কমান্ডটি দেখতে এরকম:
*2\r\n$3\r\nGET\r\n$4\r\nname\r\n
এখানে বিস্তারিত দেওয়া হলো:
*2মানে ২ টি এলিমেন্ট বিশিষ্ট একটি array।$3মানে পরবর্তী অংশটি ৩ বাইট লম্বা:GET।$4মানে পরবর্তী অংশটি ৪ বাইট লম্বা:name।
Parser এই bytes গুলোকে ["GET", "name"]-এ রূপান্তর করে। এখন ইঞ্জিনটি কমান্ডটি চালাতে পারে।
কেন শুধু স্পেস দিয়ে স্ট্রিং স্প্লিট (split) করা হয় না?
সাধারণ স্প্লিট পদ্ধতিটি সেই সব ভ্যালুর ক্ষেত্রে ব্যর্থ হয় যেগুলোতে স্পেস থাকে, যেমন SET message "hello world"। এটি বাইনারি ডেটার ক্ষেত্রেও ব্যর্থ হয়। RESP প্রতিটি ভ্যালুর দৈর্ঘ্য (length) অন্তর্ভুক্ত করার মাধ্যমে এই সমস্যার সমাধান করে। সার্ভার ঠিক ততগুলোই বাইট পড়ে যতটুকু নির্দিষ্ট করা হয়েছে। এটি এটিকে binary-safe এবং নির্ভরযোগ্য করে তোলে।
সবচেয়ে কঠিন শিক্ষাটি ছিল এটি জানা যে TCP হলো stream-based, message-based নয়। একটি সার্ভার সবসময় একবারে একটি সম্পূর্ণ কমান্ড পায় না। একটি কমান্ড দুটি আলাদা চাঙ্কে (chunk) আসতে পারে। অথবা, একাধিক কমান্ড একটি মাত্র চাঙ্কে আসতে পারে।
এর মানে হলো, parser ধরে নিতে পারে না যে একটি ডেটা ইভেন্ট মানেই একটি কমান্ড। parser-কে একটি ইন্টারনাল বাফার (internal buffer) ব্যবহার করতে হবে।
আমার RESP parser এভাবে কাজ করে:
- Socket থেকে bytes গ্রহণ করা।
- Bytes গুলো একটি buffer-এ যোগ করা।
- একটি সম্পূর্ণ কমান্ড parse করার চেষ্টা করা।
- যদি কমান্ডটি অসম্পূর্ণ থাকে, তবে আরও ডেটার জন্য অপেক্ষা করা।
- যদি কমান্ডটি সম্পূর্ণ হয়, তবে সেটি রিটার্ন করা।
- যদি অতিরিক্ত ডেটা অবশিষ্ট থাকে, তবে পরবর্তী parse-এর জন্য সেটি buffer-এ রাখা।
একটি ডাটাবেস প্রোটোকল লেয়ার থেকেই শুরু হয়। Redis ডেটা স্টোর করার আগে, তাকে কমান্ডটি বুঝতে হবে। একটি ভ্যালু রিটার্ন করার আগে, তাকে রেসপন্সটি এনকোড (encode) করতে হবে।
RESP ইমপ্লিমেন্ট করা একটি সাধারণ TCP সার্ভারকে একটি সত্যিকারের Redis-compatible সিস্টেমে পরিণত করেছে। এটি ব্যাকএন্ড সিস্টেম সম্পর্কে আমার দৃষ্টিভঙ্গি বদলে দিয়েছে। একটি প্রোটোকল কেবল একটি ফরম্যাট নয়; এটি দুটি সিস্টেমের মধ্যে একটি চুক্তি (contract)।
আমার পরবর্তী পোস্টে, আমি in-memory storage layer নিয়ে আলোচনা করব।
রিপোজিটরি: https://github.com/Abhinov007/redis_clone লাইভ স্যান্ডবক্স: https://abhinov007.github.io/Redis_Clone/ উৎস: https://dev.to/abhinov007/understanding-resp-the-protocol-behind-redis-50p4