বাটলার ল্যাম্পসনের জেরক্স PARC ধারণাগুলোর ব্যবহারিক গাইড—নেটওয়ার্কিং, OS গঠন, নামকরণ, ক্যাশিং এবং RPC—এবং কেন এগুলো এখনও বৃহৎ স্কেলের সিস্টেমকে আকার দেয়।

বাটলার ল্যাম্পসন গত অর্ধ-শতাব্দীর অন্যতম প্রভাবশালী কম্পিউটার সিস্টেম ডিজাইনার ছিলেন। 1970-80-এর দশকে জেরক্স PARC-এ তিনি নেটওয়ার্কেড কম্পিউটার কিভাবে আচরণ করা উচিত তা গড়ে তুলতে সাহায্য করেছিলেন—ভিন্ন-ভিন্ন একক মেশিন হিসেবে নয়, বরং একটি শেয়ার্ড পরিবেশের অংশ হিসেবে যেখানে প্রোগ্রাম, ফাইল, প্রিন্টার এবং মানুষ নির্ভরযোগ্যভাবে পারস্পরিক ক্রিয়া করতে পারে।
ল্যাম্পসনের কাজ দীর্ঘস্থায়ী হওয়ার মূল কারণ হচ্ছে তিনি ভিত্তিগুলোতে নজর দিয়েছেন: এমন ইন্টারফেসগুলো যা স্কেলে চলে, এমন মেকানিজম যা মিলিতভাবে কাজ করে, এবং এমন সিস্টেম যা বাস্তব-জগতের ব্যর্থতাকে বিশেষ ঘটনা হিসেবে না নিয়ে নকশা করে।
“স্কেল” কেবল বিশাল ডেটা সেন্টার থাকার ব্যাপার নয়। এটা ঘটে যখন আপনার সিস্টেমে আছে অনেক ব্যবহারকারী, অনেক মেশিন, এবং বাস্তব-জগতের গন্ডগোল। ভাবুন: একটি অফিস যেখানে শত শত ল্যাপটপ ও সার্ভিস একই লগইন ও ফাইল শেয়ার করে; বা এমন একটি প্রোডাক্ট যা একসাথে হাজারো গ্রাহক ব্যবহার করে; বা এমন কোম্পানি অ্যাপ যা সার্ভার ডাউন হয়ে গেলেও, নেটওয়ার্ক লিংক ধীর হলেও বা আপডেট অসম্পূর্ণভাবে রোল আউট হলেও কাজ চালিয়ে যেতে হবে।
এই পর্যায়ে কঠিন সমস্যা বদলে যায়। আপনি আর জিজ্ঞাসা করেন না “এটা কি আমার কম্পিউটারে কাজ করে?” বরং শুরু করেন:
এটা কোনো ভিনটেজ-ট্যুর বা নোস্টালজিয়ার খোঁজ নয়। ল্যাম্পসনের কাজ দরকারী কারণ এটি ডিজাইন আইডিয়া দিল যা টিকে গেছে: পরিষ্কার ইন্টারফেস, সহজ বিল্ডিং ব্লক, এবং ব্যর্থতাকে মাথায় রেখে তৈরি সিস্টেম।
আমরা নজর দেব সেই ধারণাগুলোর উপর যা আধুনিক অপারেটিং সিস্টেম ও বিতরণকৃত কম্পিউটিংয়ে প্রভাব ফেলেছে—নেটওয়ার্কিং, RPC, নামকরণ, ক্যাশিং, এবং ব্যবহারিক নিরাপত্তা—তখন আপনি আজকের আর্কিটেকচারে এই প্যাটার্নগুলো চিনতে পারবেন এবং আপনার সার্ভিসে প্রয়োগ করতে পারবেন।
একটি অফিস কল্পনা করুন যেখানে প্রত্যেক ব্যক্তির ডেস্কে একটি শক্তিশালী পার্সোনাল কম্পিউটার আছে, যা শেয়ার্ড সার্ভিসের সাথে সংযুক্ত করে পুরো কর্মক্ষেত্রটিকে একটি সঙ্গতিপূর্ণ সিস্টেমের মতো অনুভব করায়। এটিই ছিল PARC-এর বাজি: কেবল “একটি কম্পিউটার” নয়, বরং একটি নেটওয়ার্ককৃত পরিবেশ যেখানে কম্পিউটিং, ডকুমেন্ট, এবং যোগাযোগ মানুষ ও মেশিনের মধ্যে সহজে প্রবাহিত হয়।
PARC প্রতিদিনের কাজ—লেখা, ডিজাইন, ফাইল শেয়ার, খসড়া প্রিন্ট, এবং সহযোগিতা—কে পার্সোনাল কম্পিউটিংকে ব্যবহারিক করে তোলার লক্ষ্য রেখেছিল, যাতে প্রয়োজন না হয় মেইনফ্রেম অপারেটর বা বিশেষ রিট্যুয়াল। লক্ষ্য ছিল একক ব্রেকথ্রু ডিভাইস না; বরং একটি কাজ করা সেটআপ যা দিনে পুরোপুরি ব্যবহার করা যাবে।
আল্টো ছিল “পার্সোনাল” অংশ: ইন্টারঅ্যাকটিভ কাজের জন্য ডিজাইন করা একটি কম্পিউটার। ইথারনেট ছিল “কর্মক্ষেত্র” অংশ: একটি দ্রুত লোকাল নেটওয়ার্ক যা আল্টো কে একে অপরের ও শেয়ার্ড রিসোর্সের সাথে কথা বলতে দিল।
শেয়ার্ড রিসোর্সগুলো অপশনাল ছিল না, প্রয়োজনীয় ছিল:
এই সংমিশ্রণ একটি নতুন মানসিক মডেল উত্পন্ন করল: আপনার কম্পিউটার নিজে শক্তিশালী, কিন্তু নেটওয়ার্ক সার্ভিসগুলো নির্ভরযোগ্যভাবে ব্যবহার করতে পারলে তা অত্যন্ত বেশি উপযোগী হয়ে ওঠে।
PARC প্রোটোটাইপ বা বিচ্ছিন্ন ডেমোতে থামেনি। তারা সমগ্র সিস্টেম—হার্ডওয়্যার, অপারেটিং সিস্টেম, নেটওয়ার্কিং, এবং অ্যাপ্লিকেশন—এগিয়ে নিয়ে মানুষের প্রকৃত ব্যবহার থেকে শিখেছে।
এই ফিডব্যাক লুপ সেই কঠিন সমস্যাগুলো উন্মোচন করল যা শুধুমাত্র ব্যবহারিকতায় দেখায়: নামকরণ, ওভারলোড হ্যান্ডেল করা, ব্যর্থতার মোকাবিলা, পারফরম্যান্স পূর্বানুমানযোগ্য রাখা, এবং শেয়ার্ড রিসোর্সকে “নিকটে” অনুভব করানো।
অনেক PARC সিস্টেমে একটি চিনিহ্নিত পন্থা দেখা যায়: সরল প্রিমিটিভ ও শক্তিশালী ইঞ্জিনিয়ারিং শৃঙ্খলা। ইন্টারফেসগুলো ছোট ও বোধগম্য রাখুন, এমন সার্ভিস তৈরি করুন যা পরিষ্কারভাবে মিলিত হতে পারে, এবং ধারণাগুলো বাস্তবে স্থাপন করে পরীক্ষা করুন। সেই শৈলীই একটি বড় কারণ যে পাঠগুলো আজকের দলগুলোর জন্যও প্রযোজ্য।
জেরক্স আল্টো কেবল “ডেস্কে একটি কম্পিউটার” ছিল না। এটি একটি টার্নিং পয়েন্ট ছিল কারণ এটি তিনটি ধারণাকে একসঙ্গে bundling করে: একটি পার্সোনাল মেশিন, উচ্চ-মানের গ্রাফিকাল ইন্টারফেস, এবং দ্রুত লোকাল নেটওয়ার্ক যা আপনাকে শেয়ার্ড রিসোর্সের সাথে যুক্ত করে।
এই সংমিশ্রণ অচিরেই প্রত্যাশাকে বদলে দিল। আপনার কম্পিউটার আপনাকে নিজের বলে মনে করাল—রেসপন্সিভ, ইন্টারঅ্যাকটিভ এবং সর্বদা উপলব্ধ—তবু এটি একই সঙ্গে একটি বড় সিস্টেমের দরজা হিসেবে কাজ করল: শেয়ার্ড ফাইল সার্ভার, প্রিন্টার, ও সহযোগিতামূলক টুল। এটিই ক্লায়েন্ট/সার্ভার মানসিকতার বীজ।
আল্টো-স্টাইল সিস্টেমের আগে, কম্পিউটিং প্রায়ই মানে ছিল মেশিনে যাওয়া (বা টার্মিনালে কাজ করা)। আল্টো সেটা উল্টে দিল: “ক্লায়েন্ট” ব্যবহারকারীর পাশে বাস করত, এবং নেটওয়ার্ক শক্তিশালী শেয়ার্ড ক্ষমতাগুলোকে নিকটে অনুভব করাত।
বাস্তবে, “ক্লায়েন্ট/সার্ভার” ছিল কেবল ডায়াগ্রাম নয়—এটি একটি ওয়ার্কফ্লো। কিছু কাজ লোকালি হতো কারণ তা তাত্ক্ষণিক প্রতিক্রিয়া চাইতো: টেক্সট এডিটিং, ড্রইং, উইন্ডো ইন্টারঅ্যাকশন। অন্য কাজ দূরে হতো কারণ সেগুলো স্বাভাবিকভাবেই শেয়ার্ড বা প্রতিটি ডেস্কে নকল করা ব্যয়বহুল: অথরিটেটিভ ডকুমেন্ট স্টোর করা, প্রিন্টিং ম্যানেজ করা, অ্যাক্সেস সমন্বয় করা, এবং পরে শেয়ার্ড সার্ভিস চালানো।
“আল্টো” বদলে “ল্যাপটপ” এবং “ফাইল/প্রিন্ট সার্ভার” বদলে “ক্লাউড সার্ভিস” বসালে মানসিক মডেলটি পরিচিত লাগে। আপনার ডিভাইস এখনও ক্লায়েন্ট: UI রেন্ডার করে, ডেটা ক্যাশ করে, আর কম-লেটেন্সি ইন্টারঅ্যাকশনগুলো হ্যান্ডেল করে। ক্লাউড এখনও সার্ভার সাইড: শেয়ার্ড স্টেট, সহযোগিতা, কেন্দ্রীভূত পলিসি, এবং ইলাস্টিক কম্পিউট প্রদান করে।
পাঠ হল—ভাল সিস্টেম এই বিভাজনকে গ্রহণ করে, লড়াই করে না। ব্যবহারকারীরা লোকাল রেসপন্সিভিটি ও অফলাইন টলারেন্স চায়, অথচ প্রতিষ্ঠানগুলো শেয়ার্ড ট্রুথ ও সমন্বিত অ্যাক্সেস চায়।
এই বিভাজন অপারেটিং সিস্টেম ও সিস্টেম ডিজাইনারদের জন্য ধারাবাহিক টেনশন সৃষ্টি করে:
PARC-যুগের কাজ সেই টেনশনকে আগেভাগে দৃশ্যমান করল। একবার আপনি ধরে নেন যে নেটওয়ার্ক কম্পিউটারের অংশ, তখন আপনাকে ইন্টারফেস, ক্যাশিং, এবং ব্যর্থতার আচরণ ডিজাইন করতে হয় যেন “লোকাল” ও “রিমোট” এক সিস্টেমের মতো মনে হয়—কিন্তু এই মিথ্যে স্বীকার না করে যে তারা একই।
ইথারনেটকে সহজেই অনির্বচনীয় মনে করা যায় কারণ এটি “শুধু নেটওয়ার্কিং” মনে হয়। জেরক্স PARC-এ এটি বাস্তবিক ব্রেকথ্রু যা একটি কক্ষে থাকা পার্সোনাল মেশিনগুলোকে একটি শেয়ার্ড সিস্টেমের মতো আচরণ করাতে পারল।
ইথারনেটের আগে, কম্পিউটার সংযুক্ত করা মানে ছিল ব্যয়বহুল, বিশেষায়িত লিঙ্ক। ইথারনেট অর্থনীতিকে বদলে দিল: তুলনামূলকভাবে সস্তা, শেয়ার করা মিডিয়াম যেখানে একাধিক মেশিন একসাথে যোগ দিতে পারে।
এটি ডিফল্ট অনুমানকে বদলে দিল—“একটি বড় কম্পিউটার” থেকে “অনেক ছোট কম্পিউটার মিলেমিশে কাজ করছে”, কারণ সহযোগিতা আর ত্যাগযজ্ঞের অবলম্বন করে করা লাগেনি।
ততটাই গুরুত্বপূর্ণ, ইথারনেটের শেয়ার্ড প্রকৃতি একটি নতুন ধরনের সিস্টেম ডিজাইনকে উত্সাহ দিল: সার্ভিসগুলো আলাদা মেশিনে থাকতে পারে, প্রিন্টার ও ফাইল সার্ভার নেটওয়ার্ক-অ্যাটাচড হতে পারে, এবং দলগুলো দ্রুত ইটারেট করতে পারে কারণ কানেক্টিভিটি বিলক্ষণ ছিল।
আজ আমরা নেটওয়ার্ককে এমনভাবে গ্রহণ করি যেমন OS মেমোরি বা স্টোরেজকে দেখে: এটা একটি অ্যাড-অন নয়, প্ল্যাটফর্মের অংশ। আপনার অ্যাপের “লোকাল” আচরণ প্রায়ই দূরের কল, দূরের ডেটা, দূরের পরিচয়, এবং দূরের কনফিগের উপর নির্ভর করে।
একবার আপনি এটা মেনে নেন, আপনি আর এমনভাবে ডিজাইন করেন না যেন নেটওয়ার্ক নম্রভাবে পথে নেই।
একটি শেয়ার্ড নেটওয়ার্ক মানে প্রতিযোগিতা। প্যাকেট দেরী হয়, ড্রপ হয়, বা অনুক্রম ভাঙে। পিয়াররা রিবুট করে। সুইচগুলো অতিভর্তি হয়ে যায়। এমনকি যখন কিছু “ভাঙেনি”, সিস্টেমটা ভাঙ্গা মনে হতে পারে।
তাই সঠিক দৃষ্টিভঙ্গি হচ্ছে অসম্পূর্ণ শর্তে স্বাভাবিক অপারেশনের জন্য তৈরী করা:
ইথারনেট বিতরণকৃত কম্পিউটিংকে সম্ভব করে তুলল; এটি একইসাথে সেই শৃঙ্খলাও আনতে বাধ্য করল যা বিতরণকৃত কম্পিউটিং দাবি করে।
জেরক্স PARC-এ, একটি “সার্ভিস” কেবল সেই নেটওয়ার্কে অন্যদের জন্য একটি নির্দিষ্ট কাজ করা প্রোগ্রাম ছিল।
একটি ফাইল সার্ভিস ডকুমেন্ট সংরক্ষণ ও ফেরত দিত। একটি প্রিন্ট সার্ভিস ডকুমেন্ট নিয়ে পেপারে আউটপুট দেয়। একটি ডাইরেক্টরি (নামকরণ) সার্ভিস আপনাকে সঠিক ফাইল সার্ভার, প্রিন্টার, বা ব্যক্তিকে খুঁজে পেতে সাহায্য করত মেশিনের বিস্তারিত মনে না রেখেই। প্রতিটি সার্ভিসের একটি স্পষ্ট উদ্দেশ্য, সংজ্ঞায়িত ইন্টারফেস, এবং ব্যবহারকারী (মানুষ বা অন্য প্রোগ্রাম) যাঁরা তার উপর নির্ভর করে।
একটি বড় সিস্টেমকে ছোট সার্ভিসে বিভক্ত করলে পরিবর্তন নিরাপদ ও দ্রুত হয়। যদি প্রিন্টিং সিস্টেমে নতুন ফিচার লাগে, তা ফাইল স্টোরেজ রিডিজাইন না করে বিবর্তিত হতে পারে। সীমারেখা দায়িত্বগুলো স্পষ্ট করে: “এখানেই ফাইল থাকে” বনাম “এখানেই প্রিন্টিং হয়”।
ততটাই গুরুত্বপূর্ণ, সার্ভিসগুলো ইন্টারফেস প্রথমে ডিজাইন করার অভ্যাসকে উৎসাহ দেয়। যখন আপনার প্রোগ্রামকে অন্য মেশিনের সাথে কথা বলতে হয়, তখন আপনাকে ইনপুট, আউটপুট, এবং ত্রুটির স্পেসিফিকেশন নির্ধারণ করতে হয়—যা মোনোলিথের ভিতরে প্রায়ই অস্পষ্ট থাকে।
বেশি সার্ভিস মানে বেশি নেটওয়ার্ক রিকোয়েস্ট। এটা লেটেন্সি বাড়াতে পারে, লোড বাড়াতে পারে, এবং নতুন ব্যর্থতা মোড তৈরি করবে: ফাইল সার্ভিস চালু থাকতে পারে কিন্তু প্রিন্ট সার্ভিস ডাউন থাকতে পারে, অথবা ডাইরেক্টরি সার্ভিস ধীর হতে পারে।
একটি মোনোলিথ “সমস্তই একসাথে” ব্যর্থ হয়; বিতরণকৃত সার্ভিসগুলো আংশিক ও বিভ্রান্তিকরভাবে ব্যর্থ হয়। সমাধান হল সার্ভিস এড়ানো নয়—বরং আংশিক ব্যর্থতার জন্য স্পষ্টভাবে ডিজাইন করা।
অনেক ক্লাউড অ্যাপ এখন অভ্যন্তরীণ সার্ভিস হিসেবে চলে: ইউজার অ্যাকাউন্ট, বিলিং, সার্চ, নোটিফিকেশন। PARC পাঠ এখনও প্রযোজ্য: স্পষ্টতা ও স্বাধীন বিবর্তনের জন্য বিভক্ত করুন—কিন্তু প্রথম দিন থেকেই নেটওয়ার্ক দেরি ও আংশিক আউটেজ পরিকল্পনা করুন।
প্রায়শই দলগুলো সার্ভিস বাউন্ডারিগুলোর সাথে বেসিক টাইমআউট, রিট্রাই, এবং স্পষ্ট ত্রুটি বার্তা জুড়ে দেয় (দেখুন /blog/failure-is-normal)।
রিমোট প্রসেডিউর কল (RPC) একটি সরল ধারণা যার বড় লাভ আছে: অন্য মেশিনে থাকা ফাংশনকে যেন লোকাল ফাংশন কল করে তোলা। ম্যানুয়ালি অনুরোধ প্যাকেজ করা, নেটওয়ার্কে পাঠানো, এবং রেসপন্স আনপ্যাক করা ছাড়াই, RPC একটি প্রোগ্রামকে বলতে দেয় “getUser(42) চালাও” এবং সিস্টেম বার্তা পাসিং পিছনে করে নেয়।
নেটওয়ার্ককে লোকাল মনে করানোর লক্ষ্য ছিল জেরক্স PARC-এর বিতরণকৃত কম্পিউটিং কাজের কেন্দ্র—and আজও দলগুলো यही চায়: পরিষ্কার ইন্টারফেস, পূর্বানুমানযোগ্য আচরণ, এবং অ্যাপ্লিকেশন কোডে কম চলমান জটিলতা।
ঝুঁকি হচ্ছে RPC অনেকটাই সাধারণ ফাংশন কলের মতো দেখা দিলে। একটি লোকাল কল বা তো চলে বা পক্রিয়াকে ক্র্যাশ করে; কিন্তু একটি নেটওয়ার্ক কল ধীর হতে পারে, অদৃশ্য হয়ে যেতে পারে, আংশিক সম্পন্ন হতে পারে, বা সফল হলেও আপনি রেসপন্স না পেতে পারেন। ভালো RPC ডিজাইনগুলিতে অনুপস্থিত বাস্তবতাগুলো ঢুকানো থাকে:
টাইমআউট ও ড্রপড রেসপন্স রিট্রাই অনিবার্য করে তোলে। এজন্য আইডেম্পোটেন্সি গুরুত্বপূর্ণ: একটি অপারেশন আইডেম্পোটেন্ট হলে একবার বা বহুবার করার ফলে একই প্রভাব হয়।
সরল উদাহরণ: chargeCreditCard(orderId, amount) স্বয়ংক্রিয়ভাবে আইডেম্পোটেন্ট নয়—টাইমআউট পরে রিট্রাই করলে দুইবার চার্জ হতে পারে। নিরাপদ ডিজাইন হলো chargeCreditCard(orderId) যেখানে orderId অনন্যভাবে চার্জ নির্ধারণ করে, এবং সার্ভার পুনরাবৃত্তিকে “আগেই হয়ে গেছে” হিসেবে ব্যাবহার করে। অনন্য অপারেশন-কী থাকার ফলে রিট্রাই নিরাপদ হয়।
আধুনিক API-গুলো সরাসরি RPC মানসিকতার উত্তরসূরি। gRPC দূরের পদ্ধতি কলের মডেলটি স্পষ্ট করে টাইপযুক্ত মেসেজ ও সংজ্ঞায়িত ইন্টারফেস দিয়ে। REST সাধারণত রিসোর্স-ভিত্তিক দেখায়, কিন্তু লক্ষ্য একই: সার্ভিসগুলো কিভাবে কথা বলবে স্ট্যান্ডার্ড করা, কন্ট্রাক্ট নির্ধারণ এবং ব্যর্থতা পরিচালনা।
যে স্টাইলে হোক, PARC-এর পাঠ একই থাকে: নেটওয়ার্ক একটি টুল, ইগনোর করার বিবরণ নয়। ভালো RPC বিতরণকে সুবিধাজনক করে—তবে বিনামূল্যে বলে প্রচার করে না।
একটি বিতরণকৃত সিস্টেম তখনই “বিবরণ্য” মনে হয় যখন কিছু ভেঙে যায়। অনেক দিন, এটি ভাঙা মনে হয় কারণ কিছু খুঁজে পাওয়া যাচ্ছে না।
নামকরণ কষ্টকর কারণ বাস্তব জীবন অচল থাকে না: মেশিন বদলে যায়, সার্ভিস নতুন হোস্টে চলে যায়, নেটওয়ার্ক রিনাম্বার হয়, এবং মানুষ এখনও স্থিতিশীল, স্মরণীয় পথ আশা করে যেমন “the file server” বা “LaserWriter-এ প্রিন্ট করো”। যদি আপনার টাইপ করা নামই অবস্থান হয়, প্রতিটি পরিবর্তন ব্যবহারকারীর জন্য দৃশ্যমান আউটেজে পরিণত হয়।
PARC-যুগের একটি মূল ধারণা হল আপনি যা চান তা এটি এখন কোথায় আছে থেকে আলাদা রাখা। একটি নাম স্থিতিশীল ও অর্থবহ হওয়া উচিত; একটি অবস্থান হল বাস্তবায়ন-বিবরণ যা বদলাতে পারে।
যখন এই দুই জড়িত থাকে, আপনি দুর্বল সিস্টেম পান: শর্টকাট, হার্ড-কোডেড IP, কনফিগারেশন ড্রিফট।
ডিরেক্টরি সার্ভিসগুলো প্রশ্নের উত্তর দেয় “X এখন কোথায়?” নামে লোকে অবস্থানে ম্যাপিং করে (এবং প্রায়ই টাইপ, মালিক, বা অ্যাক্সেস রুলের মত মেটাডেটাও দেয়)। শ্রেষ্ঠ ডিরেক্টরি কেবল লুকআপ সংরক্ষণ করে না—এটি কীভাবে একটি সংগঠন কাজ করে তা এনকোড করে।
ভালো নামকরণ ও ডিরেক্টরি ডিজাইনগুলো সাধারণত কয়েকটি ব্যবহারিক বৈশিষ্ট্য শেয়ার করে:
DNS শ্রেষ্ঠ উদাহরণ: একটি মানুষের জন্য সদর্থক নাম একটি চলমান IP সেটে ম্যাপ করে, TTL দিয়ে ক্যাশিং নিয়ন্ত্রিত থাকে।
অভ্যন্তরীণভাবে, সার্ভিস ডিসকভারি সিস্টেমগুলো (যেমন “service-a.prod” ব্যাক করা) একই প্যাটার্ন পুনরাবৃত করে: স্থির সার্ভিস নাম, পরিবর্তনশীল ইনস্ট্যান্স, এবং ক্যাশ পারফরম্যান্স বনাম আপডেট দ্রুততার মধ্যে টেনশন।
পাঠটি সহজ: যদি আপনি এমন সিস্টেম চান যা স্কেল করে—এবং বোধ্য থাকে—তাহলে নামকরণকে প্রথম শ্রেণীর ডিজাইন সমস্যা হিসেবে বিবেচনা করুন, পরে নয়।
ক্যাশিং একটি সরল ধারণা: আগে যে কিছু আপনি এনেছেন তার কাছাকাছি একটি কপি রাখুন যাতে পরবর্তী অনুরোধ দ্রুত হয়ে ওঠে। প্রতিবার নেটওয়ার্ক অতিক্রম করার বদলে (বা ধীর ডিস্ক/বিস্তারিত সার্ভার হিট করার বদলে) আপনি লোকাল কপি পুনরায় ব্যবহার করেন।
জেরক্স PARC-এ এটি গুরুত্বপূর্ণ ছিল কারণ নেটওয়ার্কড ওয়ার্কস্টেশন ও শেয়ার্ড সার্ভিসগুলো “ সার্ভারে আবার জিজ্ঞাসা করা” কে ব্যয়বহুল অভ্যাস করে তুলেছিল। ক্যাশিং দূরের রিসোর্সগুলোকে এমন কিছুতে পরিণত করল যা সহজ মনে হতো—অধিকাংশ সময়।
ক্যাচের ফাঁদ হল সতেজতা। একটি ক্যাশ ভুল হয়ে যেতে পারে।
ধারণা করুন একটি শেয়ার্ড ডকুমেন্ট সার্ভারে সংরক্ষিত আছে। আপনার ওয়ার্কস্টেশন ফাইলটি দ্রুত ওপেন করতে ক্যাশ করে। একজন সহকর্মী একই ডকুমেন্ট এডিট করে ও নতুন ভার্সন সেভ করে। যদি আপনার ক্যাশ জানতে না পারে, আপনি পুরোনো কন্টেন্ট দেখতে পারেন—বা খারাপ হয়ে আরও আগের কপি এডিট করে নতুন কাজ ওভাররাইট করতে পারেন।
তাই প্রতিটি ক্যাশিং ডিজাইন একটি ট্রেডঅফ কার্যকর করে:
দলগুলো সাধারণত এই ট্রেডঅফটি কয়েকটি বিস্তৃত টুল দিয়ে পরিচালনা করে:
আধুনিক সিস্টেমে একই প্যাটার্ন সর্বত্র দেখা যায়: CDN গুলো ওয়েব কনটেন্টকে ব্যবহারকারীর কাছে ক্যাশ করে, ব্রাউজার ও মোবাইল অ্যাপ অ্যাসেট ও API রেসপন্স ক্যাশ করে, এবং ডেটাবেস ক্যাশিং লেয়ার (Redis বা Memcached) প্রাইমারি স্টোরের লোড কমায়।
পাঠটি এখনও প্রযোজ্য: ক্যাশিং প্রায়ই সহজতম পারফরম্যান্স জেতা, কিন্তু শুধুমাত্র যদি আপনি স্পষ্টভাবে লিখে রাখেন প্রতিটি ডাটার জন্য “কতটা সতেজ যথেষ্ট”।
স্কেলে নিরাপত্তা কেবল “তুমি কে?” নয়—এটি একই সঙ্গে “তুমি এ মুহূর্তে এই নির্দিষ্ট রিসোর্সের সাথে কী করতে পারো?” ও বুঝে নেয়। ল্যাম্পসন ও জেরক্স PARC-র ঐতিহ্য একটি ব্যবহারিক ধারণা ধাক্কা দিয়েছে: ক্যাপাবিলিটি।
একটি ক্যাপাবিলিটি একটি অজিপ্ত টোকেন যা কিছু অ্যাক্সেস দেয়—যেমন একটি ফাইল, প্রিন্টার, মেইলবক্স, বা সার্ভিস অপারেশন। টোকেনটা থাকলে আপনি অনুমোদিত কাজটি করতে পারেন; না থাকলে পারবেন না।
মূল জিনিসটি হলো অজিপ্ত: সিস্টেম এটিকে গেস করে বৈধ টোকেন বানানো তেমনভাবে অসম্ভব করে তোলে।
এটা ভাবুন হোটেলের চাবি কার্ডের মতো যা শুধু আপনার রুম খুলে (আর আপনার থাকার সময়েই), হাতে লেখা নোট নয় যা বলে “আমি ঢুকতে পারি”।
অনেক সিস্টেম identity-ভিত্তিক নিরাপত্তার ওপর নির্ভর করে: আপনি একজন ব্যবহারকারী হিসেবে প্রমাণ করেন, তারপর প্রতিটি অ্যাক্সেস রিসোর্সের ACL (Access Control List) এর বিরুদ্ধে চেক করা হয়—কোন ব্যবহারকারী/গ্রুপ কী করতে পারে তা তালিকাভুক্ত করা।
ACL সহজবোধ্য, কিন্তু বিতরণকৃত সিস্টেমে এগুলো ঝামেলার কারণ হয়ে ওঠে:
ক্যাপাবিলিটি ডিফল্ট উল্টে দেয়। কেন্দ্রীয় কর্তৃপক্ষকে বারবার জিজ্ঞাসা করার বদলে আপনি এমন একটি টোকেন উপস্থাপন করেন যা আগেই অধিকারগুলো এনকোড করে।
বিতরণকৃত সিস্টেম বারবার মেশিনের মধ্যে কাজ পাস করে: একটি ফ্রন্টেন্ড একটি ব্যাকেন্ডকে কল করে; একটি শিডিউলার একটি ওয়ার্কারকে কাজ দেয়; একটি সার্ভিস আরেকটি সার্ভিস ট্রিগার করে। প্রতিটি হপে "ঠিক পরিমিত" অনুমতি বহন করার একটি নিরাপদ উপায় প্রয়োজন।
ক্যাপাবিলিটি এটি স্বাভাবিক করে: অনুরোধের সঙ্গে একটি টোকেন পাঠাতে পারেন, এবং গ্রহনকারী মেশিন এটি যাচাই করতে পারে পুনরায় প্রতিষেধক গড়ে তোলার প্রয়োজন ছাড়াই।
ভালভাবে করলে, এটা দুর্ঘটনাক্রমে অতিরিক্ত অনুমতি কমায় এবং সমস্যা ঘটলে ব্লাস্ট রেডিয়াস সীমিত করে।
ক্যাপাবিলিটি আজকের দিনের হিসেবে দেখা যায়:
পাঠটি সহজ: ডেলিগেশন, স্কোপ, এবং মেয়াদ শেষে শেষ হওয়ার দিকগুলোকে কেন্দ্র করে অ্যাক্সেস ডিজাইন করুন—শুধু দীর্ঘমেয়াদি পরিচয়ের ওপর নয়।
বিতরণকৃত সিস্টেম একভাবে “ভেঙে” না; তারা গুলীবিদ্ধ, আংশিকভাবে ভাঙে: একটি মেশিন মাঝপথে ক্র্যাশ করে আর ইন-মেমোরি স্টেট হারায়, একটি সুইচ রিবুট করে, নেটওয়ার্ক পাথ প্যাকেট ব্লক করে, অথবা একটি পাওয়ার ইভেন্ট এক র্যাককে নিচে ফেলে দেয় কিন্তু বাকি ঠিক থাকে।
ব্যবহারকারীর দৃষ্টিকোণ থেকে সার্ভিস "উপ" মনে হলে ও থাকলেও একটি অংশ অনুপ্রাপ্য হতে পারে।
একটি ব্যবহারিক ব্যর্থতার মডেল কড়া করে বলে:
একবার আপনি এটা মেনে নেন, আপনি ত্রুটিগুলোকে "এজ কেস" ভাবা বন্ধ করে দিতেন এবং এগুলোকে স্বাভাবিক কন্ট্রোল ফ্লো হিসাবে বিবেচনা করেন।
অধিকাংশ সিস্টেম নির্দিষ্ট কয়েকটি চলাফেরা ব্যবহার করে।
টাইমআউটস কলারকে চিরকাল অপেক্ষা করা থেকে রক্ষা করে। গুরুত্বপূর্ণ হচ্ছে বাস্তব ল্যাটেন্সি ডেটা থেকে টাইমআউট নির্ধারণ করা, অনুমানের উপর নয়।
রিট্রাই ক্ষণস্থায়ী ত্রুটি থেকে পুনরুদ্ধার করতে পারে, কিন্তু আউটেজের সময় লোড বাড়াতে পারে। এজন্য এক্সপোনেনশিয়াল ব্যাকঅফ (প্রতিটি রিট্রাইতে অপেক্ষার সময় বাড়ানো) ও জিটার (রেনডমনেস) গুরুত্বপূর্ণ: এগুলো সমসময়ের রিট্রাই-স্টর্ম রোধ করে।
ফেইলোভার (স্ট্যান্ডবাই ইনস্ট্যান্স বা রেপ্লিকা-এ স্যুইচ করা) সত্যিই কম্পোনেন্ট ডাউন হলে উপকারী, কিন্তু এটা কাজ করে যদি বাকি সিস্টেম নিরাপদভাবে ব্যর্থতা সনাক্ত ও দ্রুত রিপোর্ট করতে পারে।
যদি আপনি একটি অনুরোধ রিট্রাই করেন, তা হয়ত একাধিকবার চালানো হবে। সেটাই at-least-once delivery: সিস্টেম কঠোর প্রচেষ্টা করে কাজ হারাতে না, কিন্তু ডুপ্লিকেট হতে পারে।
Exactly-once মানে কাজটি একবারই হয়, কোনো ডুপ্লিকেট নেই। নেটওয়ার্ক বিভক্তির উপর এটি কঠিন প্রতিশ্রুতি।
অনেক দল বরং অপারেশনগুলোকে আইডেম্পোটেন্ট করে ডিজাইন করে, ফলে at-least-once গ্রহণযোগ্য হয়ে যায়।
সবচেয়ে নির্ভরযোগ্য দলেরা সক্রিয়ভাবে স্টেজিং (এবং কখনও কখনও প্রোডাকশনে) ব্যর্থতা ইনজেক্ট করে দেখেন: ইনস্ট্যান্স হত্যা করা, নেটওয়ার্ক পাথ ব্লক করা, ডিপেনডেন্সি ধীর করা, এবং অ্যালার্ম, রিট্রাই, ও ব্যবহারকারী প্রভাব যাচাই করা।
আউটেজগুলোকে এমন এক্সপেরিমেন্ট হিসেবে ভাবুন যা আপনার ডিজাইন উন্নত করে, না যে অপ্রত্যাশিত বিস্ফোরণ।
অপারেটিং সিস্টেমগুলো দ্রুত পরিবর্তিত হয়: প্রতিটি নতুন ফিচার ইন্টারঅ্যাকশনের উপায় বাড়ায়, এবং ঠিক সেখানে বাগগুলো লুকায়।
ল্যাম্পসনের চিন্তা—PARC-এ গড়া—OS গঠনকে একটি স্কেলিং কৌশল হিসেবে দেখে। যদি কোর এলোমেলো হয়, উপরে তৈরী সমস্ত জিনিসেই সেই এলোমেলো ভাবটি চলে যাবে।
PARC-যুগের পুনরাবৃত্ত পাঠ হচ্ছে কের্নেল (বা “ট্রাস্টেড কোর”)কে সরল রাখুন এবং সহজ, কম্পোজেবল প্রিমিটিভ দিয়ে তৈরি করুন। বহু বিশেষ-কেস বানানোর বদলে কয়েকটি মেকানিজমdefine করুন যা ব্যাখ্যা করা সহজ এবং ভুল ব্যবহার করা কঠিন।
স্পষ্ট ইন্টারফেসগুলোর মূল্য মেকানিজমের মতটাই—যখন সীমারেখাগুলো স্পষ্ট, আপনি ইমপ্লিমেন্টেশন বদলাতে পারেন, অংশগুলো আলাদাভাবে টেস্ট করতে পারেন, এবং আকস্মিক coupling এড়াতে পারেন।
আইসোলেশন ব্লাস্ট রেডিয়াস সীমিত করে। সেটা হোক মেমোরি সুরক্ষা, প্রসেস আলাদা করা, বা রিসোর্সে লিস্ট-প্রিভিলেজ অ্যাক্সেস—আইসোলেশন একটি বাগ "যেকোন্ জায়গায় সবকিছু ভেঙে দিতে পারে" কে "একটি বাগ সীমিত থাকবে"-তে রূপান্তর করে।
এই চিন্তা ক্যাপাবিলিটি-ধারার নিকটেও ঠেলে: কোডকে শুধু প্রয়োজনীয় ক্ষমতাই দিন, এবং অ্যাক্সেস স্পষ্ট রাখুন।
প্রয়োগিকতা পারফরম্যান্সেও দেখা যায়: সাধারণ অপারেশনের জন্য ফাস্ট পাথ বানান, এবং এমন ওভারহেড থেকে বাঁচুন যা নিরাপত্তা বা স্পষ্টতা বাড়ায় না।
লক্ষ্য সবকিছুতে মাইক্রো-অপ্টিমাইজ করা নয়—এটা হলো সাধারণ কেসকে তাত্ক্ষণিক অনুভূত করা এবং পাঠ্য সঠিকতা বজায় রাখা।
আজকের কের্নেল, ল্যাঙ্গুয়েজ রানটাইম, এবং কন্টেইনারাইজড প্ল্যাটফর্মগুলোতেই একই ধারনা দেখা যায়: একটি ছোট ট্রাস্টেড বেস, সুসংজ্ঞায়িত API, এবং আইসোলেশন বাউন্ডারি (প্রসেস, স্যান্ডবক্স, namespace) যা দলগুলোকে দ্রুত শিপ করতে দেয় ঝুঁকি শেয়ার না করে।
বিস্তারিত বদলেছে; কিন্তু ডিজাইন অভ্যাসগুলো এখনও মূল্য রাখে।
PARC-এর বড় জয় একটি একক আবিষ্কার নয়—এটি একটি সঙ্গতিপূর্ণ উপায় ছিল নেটওয়ার্কড সিস্টেম বানানোর যা মানুষ ব্যবহার করতে পারে। নামগুলো বদলে গেছে, কিন্তু মূল সমস্যা (লেটেন্সি, ব্যর্থতা, ট্রাস্ট, মালিকানা) একই আছে।
একটি দ্রুত “মানসিক অভিধান” ডিজাইন পর্যালোচনার সময় সাহায্য করে:
সকলকে এইটা ব্যবহার করে একটি স্কেল সিস্টেম মূল্যায়ন করতে বলুন:
একটি আধুনিক মোড় হল কিভাবে দলগুলো দ্রুত বিতরণকৃত আর্কিটেকচার প্রটোটাইপ করতে পারে। টুলগুলো যেমন Koder.ai (একটি vibe-coding প্ল্যাটফর্ম যা চ্যাট থেকে ওয়েব, ব্যাকএন্ড, ও মোবাইল অ্যাপ তৈরি করে) “প্রথম কাজ করা সিস্টেম” ধাপকে দ্রুত করতে সাহায্য করে—ফ্রণ্টএন্ডে React, ব্যাকএন্ডে Go + PostgreSQL, মোবাইলে Flutter—এবং সোর্স কোড এক্সপোর্ট করে পরবর্তী উৎপাদন অভিযোজনে সাহায্য করে।
তবে ল্যাম্পসন-যুগের পাঠ এখনও প্রযোজ্য: গতি কেবল তখনই জয় যখন আপনি ইন্টারফেসগুলো স্পষ্ট রাখেন, ব্যর্থতার আচরণ (টাইমআউট, রিট্রাই, আইডেম্পোটেন্সি) স্পষ্ট করেন, এবং নামকরণ, ক্যাশিং, ও অনুমতিকে প্রথম-শ্রেণীর ডিজাইন সিদ্ধান্ত মনে করেন।
কপি করুন শৃঙ্খলা: সরল ইন্টারফেস, স্পষ্ট কন্ট্রাক্ট, এবং আংশিক আউটেজের জন্য ডিজাইন। উপকরণ মানানসই করুন: আজকাল আপনি ম্যানেজড ডিসকভারি, API গেটওয়ে, এবং ক্লাউড IAM ব্যবহার করবেন—কাস্টম ডিরেক্টরি বা হ্যান্ড-রোল্ডেড অথ-এর বদলে।
এড়িয়ে চলুন অতিরিক্ত কেন্দ্রীয়করণ (একটি “গড সার্ভিস” যাতে সবাই নির্ভর করে) এবং অস্পষ্ট মালিকানা (যেখানে কম্পোনেন্টগুলোকে কেউ দায়িত্ব নেয় না)।
টুলিং বদলবে—নতুন রানটাইম, নতুন ক্লাউড, নতুন প্রোটোকল—কিন্তু বাধাগুলো থাকবে: নেটওয়ার্ক ব্যর্থ হয়, লেটেন্সি থাকে, এবং সিস্টেম শুধু তখনই স্কেল করে যখন মানুষগুলো সেগুলো পরিচালনা করতে পারে।
এই প্রাসঙ্গে “স্কেল” মানে হচ্ছে অনেক ব্যবহারকারী, অনেক মেশিন, এবং বাস্তব পৃথিবীর গুলাবাজি ব্যবহারের মধ্যে সিস্টেম চালানো। কঠিন সমস্যা তখনই সামনে আসে যখন অনুরোধগুলো একাধিক সার্ভিস জোড়ে চলে এবং ব্যর্থতা আংশিক হয়: কিছু অংশ কাজ করে, অন্যগুলো টাইমআউট করে, এবং সিস্টেমটি তখনও পূর্বানুমানযোগ্যভাবে আচরণ করতে হবে।
PARC একটি সম্পূর্ণ নেটওয়ার্কড কর্মক্ষেত্র তৈরি করেছিল: ব্যক্তিগত কম্পিউটার (Alto) ইথারনেটে জড়িত ছিল এবং ফাইল ও প্রিন্ট সার্ভার মতো শেয়ারের সার্ভিসের সাথে যুক্ত ছিল। মূল পাঠ হল—ব্যবহারকারীরা যদি প্রতিদিন একটি এন্ড-টু-এন্ড সিস্টেম ব্যবহার করে, তখনই প্রকৃত সমস্যাগুলো দেখা দেয়: নামকরণ, অতিরিক্ত লোড, ক্যাশিং, ব্যর্থতা, এবং নিরাপত্তা।
এটি একটি বাস্তবিক বিভাজনকে উৎসাহিত করেছিল যা আজও প্রাসঙ্গিক: লেটেন্সি-সংবেদনশীল কাজ লোকালি (UI, সম্পাদনা, রেন্ডারিং) করা এবং ভাগ করা/কেন্দ্রীভূত স্টেট সার্ভিসে রাখা (ফাইল, পরিচয়, সহযোগিতা, নীতিমালা)। ডিজাইনের লক্ষ্য হয়ে ওঠে দ্রুত লোকাল রেসপন্সিভিটি ও একজুট глобাল আচরণ যখন নেটওয়ার্ক ধীর বা অবিশ্বস্ত।
কারণ নেটওয়ার্ক একটি প্রথম-শ্রেণীর নির্ভরতা হয়ে ওঠে, পটভূমির বিবরণ নয়। একবার বহু মেশিন একই মাধ্যম ভাগ করলে সার্ভিসগুলো ঘন ঘন কথা বলে; তখন আপনাকে এইগুলো ধরে নিতে হবে:
প্রাকটিক্যাল ডিফল্ট: দ্রুত ইন্সট্রুমেন্ট করুন, টাইমআউট ব্যবহার করুন, এবং ব্যাকঅফসহ সাবধানে রিট্রাই করুন যাতে আউটেজ আরও বাড়ে না।
সিস্টেমকে ছোট সার্ভিসে ভাগ করলে স্পষ্টতা ও স্বতন্ত্র বিবর্তন সম্ভব হয়: প্রতিটি সার্ভিসের একটি ফোকাসড উদ্দেশ্য ও সংজ্ঞায়িত ইন্টারফেস থাকে। খরচ হচ্ছে—নেটওয়ার্ক হপ বাড়ে এবং আংশিক ব্যর্থতার মোড দেখা দেয়, তাই কনট্রাক্ট এবং বিশ্বাসযোগ্যতার (timeouts, retries) নীতি অক্ষরে পালন করতে হবে।
RPC দূরের মেশিনে একটি ফাংশন কল করার মত অভিজ্ঞতা দেয়, কিন্তু ভাল RPC নেটওয়ার্ক বাস্তবতাগুলোকে স্পষ্ট করে তোলে। বাস্তবে দরকার:
এইগুলো না থাকলে RPC একটি ক্ষতিকর মিথ্যে দেবে—“এটা লোকাল মনে হচ্ছে, তাই আমি ভেবে ফেলেছি এটা লোকাল”।
রিট্রাই এবং টাইমআউট অনিবার্য। তাই পুনরাবৃত্তি থেকে দুর্ঘটনাক্রমে দ্বিগুণ প্রভাব এড়াতে আইডেম্পোটেন্সি জরুরি:
orderId) দিয়ে ডিজাইন করাপেমেন্ট, প্রোভিশনিং বা নটিফিকেশন-এর মতো কাজের জন্য এটি অপরিহার্য।
যদি একটি নামই অবস্থান হয়ে যায় (হার্ডকোডেড হোস্ট/IP/path), তখন মাইগ্রেশন ও ব্যর্থতা ব্যবহারকারীর জন্য আউটেজে পরিণত হয়। স্থায়ী নাম ও পরিবর্তনশীল অবস্থান আলাদা রাখুন—নাম বোঝায় আপনি কী চান, অবস্থান বোঝায় এটা কোথায় আছে। ডিরেক্টরি/ডিসকভারি সিস্টেম ব্যবহার করে ক্লায়েন্টকে জিজ্ঞেস করান “X এখন কোথায়?” এবং TTL-এর মাধ্যমে কনসিস্টেন্সি ও ফ্রেশনেস নিয়ন্ত্রণ করুন।
ক্যাশিং প্রায়শই সস্তা পারফরম্যান্স উন্নতি দেয়, কিন্তু স্টেলনেস ঝুঁকি যোগ করে। নিয়ন্ত্রণের সাধারণ উপায়গুলো হল:
প্রতিটি ডাটার জন্য “পর্যাপ্ততাজনক সদ্যত্ব” কী তা লিখে রাখুন যাতে সঠিকতা দুর্ঘটনাক্রমে না ঘটে।
একটি capability হল একটি অজিপ্ত টোকেন যা নির্দিষ্ট অধিকার প্রদান করে। অ্যাক্সেসকে identity+ACL-ভিত্তিকভাবে বারবার যাচাই করার বদলে capability গুলো আগেই অনুমোদিত ক্ষমতা বহন করে। বাস্তবে প্র্যাকটিসগুলো হল:
আধুনিক সমতুল্য: OAuth টোকেন, স্কোপযুক্ত ক্লাউড ক্রেডেনশিয়াল, সাইনড URLs/JWT (সতর্কভাবে)।