2.17 কনকারেন্সি ও প্যারালেলিজম
পরিচিতি ও প্রেরণা
কনকারেন্সি হলো একটি প্রোগ্রামকে স্বাধীন কর্মের এমন কাঠামোয় সাজানোর শিল্প, যারা একে অন্যের জন্য অপেক্ষা না করে এগোতে পারে। প্যারালেলিজম হলো সেই কর্মগুলো একাধিক প্রসেসরে একই মুহূর্তে আসলে চালানো। পার্থক্যটি পাণ্ডিত্য নয়। কনকারেন্সি হলো কোড সাজানোর একটি উপায়, যাতে একটি ধীর নেটওয়ার্ক কল পুরো প্রোগ্রামকে থামিয়ে না দেয়; প্যারালেলিজম হলো একটি বড় গণনাকে কোর জুড়ে ছড়িয়ে দ্রুত শেষ করার উপায়। দুটি গুলিয়ে ফেললে দল গতির আশায় থ্রেড যোগ করে এবং পায় কেবল ত্রুটি।
বড় দলের জন্য এই বিষয় গুরুত্বপূর্ণ কারণ কনকারেন্সিতেই সঠিকতা নিঃশব্দে মরে। একক-থ্রেডে কোড লেখা একজন রচয়িতা লাইন ধরে ধরে তা নিয়ে যুক্তি করতে পারেন, কিন্তু যে মুহূর্তে অনেক রচয়িতা থ্রেড জুড়ে মেমরি ভাগ করেন, সম্ভাব্য ইন্টারলিভিংয়ের সংখ্যা বিস্ফোরিত হয়, এবং প্রতিটি টেস্টে উত্তীর্ণ একটি প্রোগ্রাম প্রোডাকশন লোডে দশ লক্ষে একবার ব্যর্থ হতে পারে, জোরালো ক্র্যাশে নয়, বরং নষ্ট ডেটা, আটকে থাকা অনুরোধ এবং কেউ পুনরুৎপাদন করতে পারে না এমন ঘটনায়। এই অধ্যায় অধ্যায় 2.16 (পারফরম্যান্স প্রকৌশল)-এর কোড-স্তরের মনোযোগ ও অধ্যায় 2.13-এর কম্পিউটিং ভিত্তির ওপর দাঁড়িয়ে, এবং অধ্যায় 3.3 (বিতরিত সিস্টেম)-এর সমন্বয় সমস্যায় জোগান দেয়, যা মেশিন জুড়ে কনকারেন্সি, সঙ্গে অনির্ভরযোগ্য নেটওয়ার্কের বাড়তি নিষ্ঠুরতা।
এন্টারপ্রাইজের জন্য কনকারেন্সি ত্রুটি মানে থ্রুপুট ত্রুটি। উচ্চ-ট্রাফিক সার্ভিস বাঁচে-মরে ভাগ করা অবস্থায় রেস না করে হাজারো একযোগ অনুরোধ সামলানোর সামর্থ্যে, এবং একটিমাত্র অসমন্বিত কাউন্টার লোডে একটি খতিয়ান নষ্ট করতে পারে। সরকারের জন্য ঝুঁকি হলো দশকের পর দশক চলা, নিরাপত্তা, সুবিধা বা সরকারি নথি ছোঁয়া সিস্টেমে সঠিকতা ও নিরীক্ষণযোগ্যতা। কর বা স্বাস্থ্য সিস্টেমে একটি রেস অসুবিধা নয়; এটি একটি ভুল উত্তর যা পরে কাউকে তদারকি সংস্থাকে ব্যাখ্যা করতে হবে। দুই ক্ষেত্রেই লক্ষ্য এক: নিরাপদ পথকে ডিফল্ট করা, যাতে কোড ছোঁয়া অনেক মানুষের প্রত্যেককে কনকারেন্সি বিশেষজ্ঞ হতে না হয়।
মূল নীতিসমূহ
- কনকারেন্সি কাঠামো; প্যারালেলিজম এক্সিকিউশন। থ্রেড ধরার আগে ঠিক করুন আপনার আসলে কোনটি দরকার।
- ভাগ করা পরিবর্তনযোগ্য অবস্থা শত্রু। প্রায় প্রতিটি কনকারেন্সি ত্রুটি দুটি কর্মের একই পরিবর্তনশীল ডেটা ছোঁয়ায় ফিরে যায়।
- অপরিবর্তনীয়তা ও বার্তা-আদানপ্রদান পছন্দ করুন। যে ডেটা বদলায় না তাতে রেস হয় না, আর নিরাপত্তায় বার্তা ভাগ করা মেমরিকে হারায়।
- অনির্ধারিততা মূল কঠিনতা। হাজার রানে একবার দেখা দেওয়া ত্রুটিই পুরো সমস্যা, প্রান্তিক কেস নয়।
- সবকিছুকে সীমাবদ্ধ করুন। সীমাহীন কিউ, থ্রেড সংখ্যা ও চলমান কাজ একটি স্পাইককে বিভ্রাটে পরিণত করে।
- উচ্চ-স্তরের মডেল কাঁচা লককে হারায়। অ্যাক্টর, চ্যানেল ও কাঠামোবদ্ধ কনকারেন্সি অনেক রচয়িতাকে নিরাপদ ডিফল্ট দেয়, আর প্রতিটি লকের খরচ আছে।
- কেবল সুখী পথ নয়, ইন্টারলিভিং পরীক্ষা করুন। নির্ধারিত টেস্ট এমন ত্রুটি ধরতে পারে না যা কেবল বিরল ক্রমে প্রকাশ পায়।
সুপারিশ
কনকারেন্সি নাকি প্যারালেলিজম দরকার তা ঠিক করুন
সমস্যার নাম দিয়ে শুরু করুন। আপনার সার্ভিস বেশিরভাগ সময় অপেক্ষায় কাটালে (ডেটাবেস, নেটওয়ার্ক কল বা ডিস্কে), এটি I/O-বাউন্ড ওয়ার্কলোড, এবং কনকারেন্সিই উত্তর: কোড এমনভাবে কাঠামো করুন যাতে একটি অনুরোধ অপেক্ষা করার সময় অন্যগুলো এগোয়। async/await সহ একটি একক থ্রেড বা ছোট পুল হাজার হাজার অপেক্ষমাণ অনুরোধ সামলাতে পারে। বরং আপনার প্রোগ্রাম CPU-বাউন্ড হলে, অল্প অপেক্ষায় গণনা পিষে চললে, কোর জুড়ে প্যারালেলিজমই গতি কেনে, এবং এখানে সীমা ঠিক হয় অ্যামডালের সূত্রে (অধ্যায় 2.16 দেখুন): আপনি যত কোরই যোগ করুন, ক্রমিক ভগ্নাংশ আপনার গতিবৃদ্ধি সীমিত করে। নকশার আগে মাপুন আপনি কোন অবস্থায়।
ভাগ করা পরিবর্তনযোগ্য অবস্থাকে শত্রু গণ্য করুন
প্রায় প্রতিটি কনকারেন্সি ত্রুটি একই আকারে নামে: দুটি কর্ম ক্রমে একমত না হয়ে একই পরিবর্তনশীল ডেটা পড়ে ও লেখে। এটি একটি রেস কন্ডিশন, যা হারানো আপডেট, অর্ধেক-লেখা অবজেক্ট, এবং কোড নিরাপদ ধরে নেওয়া ইনভ্যারিয়ান্ট ভঙ্গকারী মান তৈরি করে। সবচেয়ে নির্ভরযোগ্য প্রতিরক্ষা হলো কম ভাগ করা পরিবর্তনযোগ্য অবস্থা রাখা। প্রতিটি কর্মকে তার নিজস্ব ডেটা দিন, রেফারেন্সের বদলে কপি পাঠান, এবং পরিবর্তনযোগ্য অবস্থাকে একক মালিকে সীমাবদ্ধ করুন যাঁর কাছে অন্যরা বার্তার মাধ্যমে পৌঁছায়। সত্যিই ভাগ করতে হলে ভাগাভাগি সুস্পষ্ট ও ছোট রাখুন, যাতে একজন পর্যালোচক অবস্থা ছোঁয়ার প্রতিটি জায়গা দেখতে পান।
অপরিবর্তনীয়তা ও বার্তা-আদানপ্রদানকে ডিফল্ট করুন
সবচেয়ে নিরাপদ ভাগ করা ডেটা সেটি, যা বদলাতে পারে না। একটি অপরিবর্তনীয় অবজেক্ট একবার তৈরি হলে যেকোনো সংখ্যক থ্রেড শূন্য সমন্বয়ে পড়তে পারে, কারণ রেস করার কিছু নেই। অপরিবর্তনীয়তাকে ডিফল্ট এবং পরিবর্তনীয়তাকে সুচিন্তিত ব্যতিক্রম করুন। কর্মগুলোকে সমন্বয় করতে হলে ভাগ করা মেমরির বদলে বার্তা-আদানপ্রদান পছন্দ করুন: একটি সাধারণ চলক ভাগ করার বদলে একটি কর্ম মানটি অন্যটির কাছে পাঠাক, যা Go প্রবাদ “মেমরি ভাগ করে যোগাযোগ করো না; যোগাযোগ করে মেমরি ভাগ করো”-র দর্শন। বার্তা-আদানপ্রদান অদৃশ্য, ক্রম-নির্ভর ত্রুটিকে সুস্পষ্ট, পরিদর্শনযোগ্য ডেটা প্রবাহে বদলায়, এবং অনেক মানুষ রক্ষণাবেক্ষণ করে এমন কোডে সেই স্পষ্টতা প্রায় সবসময় প্রতি-বার্তা খরচের যোগ্য।
কাঁচা লকের আগে উচ্চ-স্তরের মডেলের কাছে যান
হাতে-লেখা লকিং নীতিগতভাবে সঠিক কিন্তু বাস্তবে বিপর্যয়কর, কারণ মানুষ প্রতিটি ইন্টারলিভিং নিয়ে যুক্তি করায় খারাপ। যে মডেল নিরাপদ কনকারেন্সিকে ডিফল্ট করে তা পছন্দ করুন। অ্যাক্টর মডেল প্রতিটি অ্যাক্টরকে ব্যক্তিগত অবস্থা ও একটি মেইলবক্স দেয়: অ্যাক্টর কখনো মেমরি ভাগ করে না, কেবল বার্তা পাঠায়, তাই রেসের পুরো শ্রেণি উধাও হয়। কমিউনিকেটিং সিকোয়েনশিয়াল প্রসেসেস (CSP), Go-র মতো ভাষায় চ্যানেলের পেছনের মডেল, স্বাধীন প্রসেসকে টাইপ করা চ্যানেলে মান পাঠাতে দেয়। কাঠামোবদ্ধ কনকারেন্সি কনকারেন্ট কর্মের জীবনকাল একটি লেক্সিক্যাল স্কোপে বাঁধে, ফলে কর্ম তাদের সৃষ্টিকারী ব্লককে ছাড়িয়ে বাঁচতে পারে না এবং ত্রুটি হারিয়ে না গিয়ে ছড়ায়। async/await আপনাকে কনকারেন্ট, I/O-বাউন্ড কোড ক্রমিক শৈলীতে লিখতে দেয়। এর প্রতিটি গড় রচয়িতার মেঝে উঁচু করে, যা একটি বড় দলের দরকার।
আপনার মেমরি মডেল, পারমাণবিকতা ও দৃশ্যমানতা বুঝুন
মেমরি ভাগ করলে দুটি বৈশিষ্ট্য কামড়ায়। পারমাণবিকতা মানে একটি অপারেশন হয় সম্পূর্ণ একবারে ঘটে, নয়তো একেবারেই নয়; একটি সাধারণ ইনক্রিমেন্ট (x = x + 1) পারমাণবিক নয়, কারণ তা পড়ে, যোগ করে ও লেখে তিন ধাপে যা অন্য থ্রেড বিঘ্নিত করতে পারে, এভাবেই কাউন্টার আপডেট হারায়। দৃশ্যমানতা মানে একটি থ্রেডের লেখা অন্যের কাছে পর্যবেক্ষণযোগ্য হওয়া; যথাযথ সমন্বয় ছাড়া একটি কোরে লেখা মান ক্যাশে বসে থাকতে পারে অন্যটির অদেখা, ফলে একটি থ্রেড ইতিমধ্যে সেট হওয়া ফ্ল্যাগে অনন্তকাল লুপ করতে পারে। আপনার ভাষার মেমরি মডেল সংজ্ঞায়িত করে কখন লেখা দৃশ্যমান হয় এবং কম্পাইলার ও CPU কোন ক্রম পুনর্বিন্যাস করতে পারে, তাই আপনি ধরে নিতে পারেন না কোড আপনার লেখা ক্রমে চলে। নিজস্ব লক-মুক্ত পরিকল্পনা আবিষ্কার না করে ভাষার পারমাণবিক টাইপ ও সমন্বয় আদিম ব্যবহার করুন।
সমন্বয় আদিম সচেতনভাবে ব্যবহার করুন এবং ডেডলকের বিরুদ্ধে নকশা করুন
ভাগ করা অনিবার্য হলে সঠিক আদিম ধরুন এবং তার দাম সম্মান করুন। একটি লক বা মিউটেক্স (পারস্পরিক বর্জন) একবারে একটি থ্রেডকে ক্রিটিক্যাল সেকশনে ঢুকতে দেয়, কিন্তু প্রবেশ ক্রমিক করে, ফলে একটি গরম লক এমন বাধা হয় যা অনেক কোরের সুবিধা মুছে দেয়। একটি সেমাফোর একসঙ্গে কতটি কর্ম এগোতে পারবে তা সীমিত করে, যেভাবে আপনি পুল বাউন্ড করেন। পারমাণবিক অপারেশন কাউন্টারের মতো সরল মানের জন্য লক-মুক্ত আপডেট দেয়, লকের চেয়ে সস্তা কিন্তু যৌগিক কিছুর জন্য ভুল ব্যবহার করা সহজ। লক তিনটি ক্লাসিক ব্যর্থতার ধরন আনে। একটি ডেডলক হলো যখন কর্মগুলো চক্রে একে অন্যের জন্য অপেক্ষা করে এবং কেউ এগোতে পারে না, পাঠ্যবইয়ের উদাহরণ দুটি থ্রেড যার প্রতিটি একটি লক ধরে আছে এবং অন্যটি চায়। একটি লাইভলক হলো যখন কর্মগুলো একে অন্যের প্রতি প্রতিক্রিয়া দেখাতে থাকে কিন্তু অগ্রগতি হয় না। স্টারভেশন হলো যখন একটি কর্ম কখনো সম্পদ পায় না কারণ অন্যরা সামনে লাফিয়ে যেতে থাকে। এগুলো ঠেকানোর শৃঙ্খলা সুনির্দিষ্ট: একটি বৈশ্বিক লক ক্রম চাপান, লক সংক্ষিপ্ত সময় ধরে রাখুন, টাইমআউট যোগ করুন যাতে আটকে যাওয়া কর্ম জোরে ব্যর্থ হয়, লক ধরে থাকা অবস্থায় অজানা কোড কখনো ডাকবেন না, এবং যেখানে স্টারভেশন ঝুঁকি সেখানে ন্যায্য শিডিউলিং ব্যবহার করুন। এই নিয়মগুলো লিখে রাখুন, কারণ একজন নতুন রচয়িতা কেবল কোড থেকে এগুলো পুনরাবিষ্কার করতে পারেন না।
ব্যাকপ্রেশার দিয়ে আপনার কিউ, পুল ও চলমান কাজ সীমাবদ্ধ করুন
একটি সীমাহীন কিউ একটি টাইম বোমা। ট্রাফিক স্পাইকে কাজ নিষ্কাশনের চেয়ে দ্রুত আসে, কিউ সীমাহীনভাবে বাড়ে, মেমরি ভরে, এবং সার্ভিস এমনভাবে মরে যা ওভারলোডের বদলে রহস্যময় মেমরি-শেষ ক্র্যাশের মতো দেখায়। প্রতিটি কিউ সীমাবদ্ধ করুন, প্রতিটি থ্রেড পুল সীমিত করুন এবং ব্যাকপ্রেশার প্রয়োগ করুন: সিস্টেম ভরে গেলে আপস্ট্রিমকে ধীর হতে সংকেত দিন বা দ্রুত কাজ প্রত্যাখ্যান করুন, শেষ করতে পারবেন না এমন অসীম কাজ গ্রহণ না করে। পুলের আকার ওয়ার্কলোড অনুযায়ী ঠিক করুন (CPU-বাউন্ড কাজে মোটামুটি কোর সংখ্যা, I/O-বাউন্ড কাজে বেশি যেখানে থ্রেড বেশিরভাগ অপেক্ষা করে), এবং বাউন্ডকে সুচিন্তিত সক্ষমতা সিদ্ধান্ত ভাবুন। এটি অধ্যায় 3.3-এর স্থিতিস্থাপকতা ধরনের সঙ্গে যুক্ত।
যেখানে কাজ লজ্জাজনকভাবে সমান্তরাল সেখানে ডেটা প্যারালেলিজম ব্যবহার করুন
কিছু সমস্যা পরিচ্ছন্নভাবে ভাগ হয়: একটি বড় ডেটাসেটের প্রতিটি উপাদানে একই অপারেশন প্রয়োগ, কোনো উপাদান অন্যের ওপর নির্ভর না করে। এই ডেটা প্যারালেলিজম সবচেয়ে বন্ধুত্বপূর্ণ ধরন, কারণ রেস করার মতো ভাগ করা অবস্থা কম এবং গতিবৃদ্ধি কোর সংখ্যার কাছাকাছি পৌঁছাতে পারে, যা ম্যাপ-রিডিউস পাইপলাইন, সমান্তরাল অ্যারে অপারেশন ও ভেক্টরাইজড সংখ্যাসূচক কোড সবই দেখায়। এখানেও অ্যামডালের সূত্র সম্মান করুন: মার্জ বা রিডিউস ধাপ প্রায়ই ক্রমিক এবং আপনার লাভ সীমিত করে, আর ছোট ইনপুটে ভাগ করার বাড়তি বোঝা প্রাধান্য পেতে পারে। এটি ধরুন যখন প্রতি-উপাদান কাজ যথেষ্ট এবং উপাদানগুলো সত্যিই স্বাধীন; নইলে সরলতম ক্রমিক সংস্করণ প্রায়ই যথেষ্ট দ্রুত এবং সঠিক রাখা অনেক সহজ, যা অধ্যায় 2.9-এর নির্মাণ চর্চা আরও দৃঢ় করে।
অনির্ধারিত কোড ইচ্ছাকৃতভাবে পরীক্ষা ও ডিবাগ করুন
কনকারেন্সি ত্রুটি অনির্ধারিত, তাই সাধারণ টেস্ট, যা একটি ইন্টারলিভিং চালায়, বেশিরভাগ তা মিস করে। বিরল ক্রম ঝেড়ে ফেলতে এলোমেলো সময়ে অনেক কর্ম চালানো স্ট্রেস ও ফাজ টেস্ট দিয়ে সমস্যাকে সুচিন্তিতভাবে আক্রমণ করুন। রেস ডিটেক্টর ও থ্রেড স্যানিটাইজার ধরুন, এমন টুলিং যা মেমরি অ্যাক্সেস যন্ত্রসজ্জা করে ডেটা রেস ধরে, ত্রুটিপূর্ণ ইন্টারলিভিং এই রানে না ঘটলেও। আপনার প্ল্যাটফর্ম দিলে নির্ধারিত সিমুলেশন বা নিয়ন্ত্রিত শিডিউলার ব্যবহার করুন যা নির্দিষ্ট ইন্টারলিভিং পুনরায় চালায়, একটি হাইজেনবাগকে পুনরুৎপাদনযোগ্য করে, এবং এমনভাবে নকশা করুন যাতে প্রোডাকশন হ্যাং আপনাকে থ্রেড অবস্থা ও লক মালিকানা ধরতে দেয়, যা অধ্যায় 2.15-এর ডিবাগিং শৃঙ্খলার সঙ্গে যুক্ত। সবচেয়ে বড় কথা, এমন নকশা (অপরিবর্তনীয়তা, বার্তা-আদানপ্রদান, একক মালিকানা) পছন্দ করুন যা এই ত্রুটির পুরো শ্রেণি অসম্ভব করে, কারণ যে ত্রুটি আপনি তৈরিই করতে পারেন না তা কখনো ডিবাগ করতে হয় না।
ট্রেড-অফ: সুবিধা ও অসুবিধা
| পদ্ধতি | সুবিধা | অসুবিধা |
|---|---|---|
| লকসহ ভাগ করা মেমরি | প্রতি অপারেশনে দ্রুত; পরিচিত | রেস, ডেডলক ও দৃশ্যমানতা ত্রুটি; অনেক রচয়িতার পক্ষে সঠিক রাখা কঠিন |
| অপরিবর্তনীয়তা | সমন্বয় লাগে না; তুচ্ছভাবে থ্রেড-নিরাপদ পাঠ | কপি করার খরচ; বড় পরিবর্তনযোগ্য কাঠামোর জন্য বেখাপ্পা |
| বার্তা-আদানপ্রদান (অ্যাক্টর, চ্যানেল) | সুস্পষ্ট ডেটা প্রবাহ; ত্রুটির পুরো শ্রেণি উধাও | প্রতি-বার্তা বাড়তি বোঝা; কিউ সীমাহীন হলে ব্যাকপ্রেশার লুকাতে পারে |
| Async/await | I/O-বাউন্ড কাজে সস্তা কনকারেন্সি; ক্রমিক-দেখতে কোড | CPU কাজে প্যারালেলিজম নেই; একটি কর্ম ব্লক হলে অন্যগুলো থামে |
| কাঠামোবদ্ধ কনকারেন্সি | স্পষ্ট কর্মজীবন; ত্রুটি ছড়ায়; কর্ম ফাঁস হয় না | নতুনতর, কিছু ইকোসিস্টেমে কম পাওয়া যায় |
| ডেটা প্যারালেলিজম | স্বাধীন কাজে প্রায়-রৈখিক গতিবৃদ্ধি | অ্যামডালের সীমা; ছোট ইনপুটে বাড়তি বোঝা প্রাধান্য পায় |
| পারমাণবিক / লক-মুক্ত | সরল মানে লক কনটেনশন নেই | সূক্ষ্মভাবে ভুল করা অত্যন্ত সহজ; পর্যালোচনা কঠিন |
কেন্দ্রীয় টানাপোড়েন নিরাপত্তা বনাম কাঁচা গতি, এবং সমাধান হলো আগে সঠিকতা কেনা এবং কেবল সেখানে পারফরম্যান্স ব্যয় করা যেখানে পরিমাপ প্রমাণ করে আপনাকে করতেই হবে। কাঁচা ভাগ করা-মেমরি লকিং প্রতি অপারেশনে দ্রুততম এবং প্রতি লাইন কোডে সবচেয়ে বিপজ্জনক; উচ্চ-স্তরের মডেল সামান্য থ্রুপুট খরচ করে এবং প্রচুর নিরাপত্তা ও স্পষ্টতা ফেরত দেয়, আর অনেক হাতে রক্ষণাবেক্ষণ করা কোডের জন্য সেই বিনিময় নিঃসন্দেহে সার্থক। হাতে-টিউন করা লক-মুক্ত কনকারেন্সি সংরক্ষণ করুন সেই ছোট হট স্পটের জন্য, যেখানে একটি প্রোফাইলার (অধ্যায় 2.16) প্রমাণ করে সমন্বয়ের বাড়তি বোঝা গুরুত্বপূর্ণ, এবং সেগুলোকেও সুপরীক্ষিত সীমানার পেছনে রাখুন।
আপনার দলের সঙ্গে আলোচনার প্রশ্ন
আপনার ব্যস্ততম সার্ভিসের ওয়ার্কলোড কি I/O-বাউন্ড নাকি CPU-বাউন্ড, এবং আপনার কনকারেন্সি নকশা কি মেলে? দলগুলো নিয়মিত তাদের ৯৫% সময় ডেটাবেসের অপেক্ষায় কাটানো সার্ভিসে থ্রেড পুল যোগ করে, থ্রুপুট ছাড়া কনটেনশন পায়, অথবা এমন গণনা সমান্তরাল করতে চায় যার ক্রমিক ভগ্নাংশ যেকোনো গতিবৃদ্ধি সীমিত করে। সঠিক নকশা অবস্থা থেকে আসে: অপেক্ষা-ভারী কাজের জন্য async বা ছোট পুল, গণনা-ভারী কাজের জন্য কোর জুড়ে প্রকৃত প্যারালেলিজম। সময় আসলে কোথায় যায় তা দেখানো একটি প্রোফাইল আনুন, কোনো অনুমান নয়, এবং বেশিরভাগ সময় গণনায় গেলে ক্রমিক ভগ্নাংশ মাপুন এবং অ্যামডালের সূত্রকে সীমা বলতে দিন। উত্তর ঠিক করে আপনি async, বাউন্ডেড পুল নাকি ডেটা প্যারালেলিজম ধরবেন।
কর্ম জুড়ে অবস্থা ভাগ করার জন্য আপনার দলের ডিফল্ট কী, এবং তা কি নকশায় নিরাপদ? বড় দলে ব্যতিক্রমের চেয়ে ডিফল্ট বেশি গুরুত্বপূর্ণ, কারণ বেশিরভাগ কোড লেখেন যাঁরা কনকারেন্সি বিশেষজ্ঞ নন এবং যা ইতিমধ্যে আছে তার নকল করেন। ডিফল্ট যদি অ্যাড হক লক দিয়ে পাহারা দেওয়া ভাগ করা পরিবর্তনযোগ্য অবজেক্ট হয়, আপনি একটি ভুলে যাওয়া লক দূরে এমন রেস থেকে, যা মাসের পরে প্রোডাকশনে ওঠে। ডিফল্ট অপরিবর্তনীয়তা ও বার্তা-আদানপ্রদান হলে ত্রুটির পুরো শ্রেণি কখনো ঘটে না, এবং যে বিরল জায়গায় সত্যিই ভাগ করা মেমরি দরকার তা যত্নশীল পর্যালোচনার জন্য আলাদা হয়ে ওঠে। আলোচনা করুন একজন নতুন ইঞ্জিনিয়ার আজ কী ধরবেন, আপনার পর্যালোচনা কি একটি অসমন্বিত লেখা ধরত, এবং নিরাপদ পথকে সহজ পথ কীভাবে করবেন।
প্রোডাকশনে দশ লক্ষ অনুরোধে একবার ঘটা কনকারেন্সি ত্রুটি আপনি কীভাবে খুঁজবেন, পুনরুৎপাদন করবেন ও সারাবেন? অনেক দলের সৎ উত্তর হলো পারবেন না, কারণ তাঁরা দেখতে গেলে ত্রুটি উধাও হয় এবং তাঁদের টেস্ট সবসময় একটিমাত্র নিরীহ ইন্টারলিভিং চালায়। এটি আপনাকে উদ্বিগ্ন করা উচিত, কারণ এই ত্রুটি নিঃশব্দে ডেটা নষ্ট করে এবং বিশ্বাস ক্ষয় করে। আলোচনা করুন আপনি কন্টিনিউয়াস ইন্টিগ্রেশনে রেস ডিটেক্টর ও থ্রেড স্যানিটাইজার চালান কি না, এলোমেলো সময়ে স্ট্রেস টেস্ট করেন কি না, এবং আপনার প্রোডাকশন অবজার্ভেবিলিটি হ্যাংয়ের মুহূর্তে থ্রেড ও লকের অবস্থা ধরে কি না। সেরা দলগুলো মডেল বাছাই দিয়ে এই ত্রুটির বেশিরভাগ অসম্ভব করে উত্তর দেয়, ফলে অবশিষ্ট অল্প ক’টি বিরল ও সীমাবদ্ধ।
আপনার সিস্টেমের কোথায় এখনো একটি সীমাহীন কিউ বা সীমাহীন থ্রেড পুল আছে, এবং হঠাৎ দশ গুণ স্পাইকে তার কী হয়? এটি গুরুত্বপূর্ণ কারণ চলমান সীমাহীন কাজ সেই ব্যর্থতা যা রহস্যময় মেমরি-শেষ ক্র্যাশের ছদ্মবেশ ধরে: কাজ নিষ্কাশনের চেয়ে দ্রুত আসে, মেমরি ভরে, এবং সার্ভিস ওভারলোডের বদলে হার্ডওয়্যার ত্রুটির মতো দেখিয়ে মরে। প্রতিদ্বন্দ্বী বিবেচনা প্রকৃত, কারণ খুব কম বাউন্ড বৈধ ট্রাফিক প্রত্যাখ্যান করে আর খুব বেশি বাউন্ড ক্র্যাশ ঠেকানোর বদলে পিছিয়ে দেয়, তাই সংখ্যাটি সক্ষমতার সিদ্ধান্ত, অনুমান নয়। প্রতিটি কিউ ও পুলের একটি তালিকা আনুন, তার বর্তমান বাউন্ড (বা বাউন্ড নেই তার স্বীকারোক্তি), ভরে গেলে ব্যাকপ্রেশারের আচরণ, এবং প্রান্তে সিস্টেম কীভাবে নিম্নমুখী হয় তার লোড-টেস্ট প্রমাণ। একটি এন্টারপ্রাইজ বহরে একটিমাত্র সীমাহীন কিউ বহর-জোড়া বিভ্রাটে গড়াতে পারে, আর নাগরিকদের কাছে সদা উপলব্ধ থাকতে হওয়া সরকারি প্ল্যাটফর্মে স্পষ্ট ত্রুটিসহ মার্জিত প্রত্যাখ্যান একটি সেবা-বাধ্যবাধকতা, তাই বাউন্ড ও তার প্রত্যাখ্যান পথ একজন ইঞ্জিনিয়ারের স্মৃতিতে নয়, সক্ষমতা পরিকল্পনা ও রানবুকে থাকা উচিত।
কাঁচা লকের তুলনায় উচ্চ-স্তরের কনকারেন্সি মডেল ব্যবহারে আপনার দলের নীতি কী, এবং কোথায় ব্যতিক্রম অনুমোদন করেছেন? ডিফল্ট মডেল ঠিক করে গড় পরিবর্তন কতটা নিরাপদ, কারণ বেশিরভাগ রচয়িতা কনকারেন্সি বিশেষজ্ঞ নন এবং বিদ্যমান ধরন নকল করবেন: অ্যাক্টর, চ্যানেল ও কাঠামোবদ্ধ কনকারেন্সি সবার মেঝে উঁচু করে, অথচ কাঁচা লকিং তত্ত্বে সঠিক ও বাস্তবে ডেডলকের উৎস। টানাপোড়েন হলো উচ্চ-স্তরের মডেল সামান্য প্রতি-বার্তা বা প্রতি-কর্ম বাড়তি বোঝা খরচ করে, আর একটি প্রোফাইলার মাঝেমধ্যে প্রমাণ করবে যে একটি হট পথে হাতে-টিউন করা লক-মুক্ত কোড দরকার, তাই সর্বাত্মক নিষেধ স্বেচ্ছাচারের মতোই ভুল। আপনি যেসব জায়গায় নিরাপদ ডিফল্টের নিচে নেমেছেন তার তালিকা আনুন, প্রতিটিকে যুক্তিযুক্ত করা প্রোফাইলিং প্রমাণ, এবং প্রতিটি ব্যতিক্রম কীভাবে একটি পরীক্ষিত সীমানা ও নথিবদ্ধ লক ক্রমের পেছনে বেড়া দেওয়া। একটি বড় এন্টারপ্রাইজে এই নীতিই হাজার হাজার অবদানকারীকে প্রত্যেকের একটি অনিরাপদ পরিকল্পনা পুনরাবিষ্কার থেকে ঠেকায়, আর দীর্ঘজীবী সরকারি সিস্টেমে এটিই বছর পরে একজন পর্যালোচককে বুঝতে দেয় কেন একটি বিপজ্জনক ধরন অনুমোদিত হয়েছিল এবং তা এখনো যথার্থ কি না নিশ্চিত করতে দেয়।
একটি গণনা সমান্তরাল করার সিদ্ধান্ত নিলে ক্রমিক ভগ্নাংশ কীভাবে মাপেন, এবং গতিবৃদ্ধি বাস্তব তা নিশ্চিত করার দায় কার? দলগুলো নিয়মিত একটি গণনা কোর জুড়ে ছড়ায় এবং এমন একটি সংখ্যা উদ্যাপন করে যা প্রোফাইলার কখনো নিশ্চিত করত না, কারণ অ্যামডালের সূত্র আপনি যত কোরই যোগ করুন, লাভ ক্রমিক ভগ্নাংশের গুণফল-বিপরীতে সীমিত করে, এবং ছোট ইনপুটে ভাগ-ও-মার্জের বাড়তি বোঝা সুবিধা পুরোপুরি মুছে দিতে পারে। প্রতিদ্বন্দ্বী টান হলো প্যারালেলিজম প্রকৃত জটিলতা ও নতুন রেস-পৃষ্ঠ যোগ করে, তাই প্রশ্ন হলো মাপা গতিবৃদ্ধি আপনার নেওয়া সঠিকতার ঝুঁকিকে যথার্থ করে কি না। ক্রমিক অংশ আলাদা করা একটি প্রোফাইল, ইনপুটের যেসব আকারে প্যারালেলিজম সত্যিই জেতে, এবং আশাবাদী অনুমানের বদলে প্রতিনিধিত্বমূলক হার্ডওয়্যারে আগে-ও-পরের বেঞ্চমার্ক আনুন। বড় কম্পিউট বহরের জন্য অর্থ দেওয়া এন্টারপ্রাইজের জন্য সৎ ক্রমিক-ভগ্নাংশ বিশ্লেষণ বাঁচানো বা অপচয় হওয়া হার্ডওয়্যার ব্যয়ে রূপ নেয়, আর একটি সরকারি সিস্টেমের খরচের জবাবদিহিযোগ্য সংস্থার জন্য সমান্তরাল নকশা অনুমোদনকারী ব্যক্তি নিরীক্ষায় তা যথার্থ করা পরিমাপ দেখাতে সক্ষম হওয়া উচিত।
খাতভেদে দৃষ্টিভঙ্গি
স্টার্টআপ। ছোট দল ও বাড়তি রানওয়ে ছাড়া, যে কনকারেন্সি বিশেষজ্ঞ নিয়োগ করতে পারবেন না তাঁর বদলে কাঠামো দিয়ে সঠিকতা কিনুন। আপনার ভাষার দেওয়া একক নিরাপদ ডিফল্ট ধরুন, I/O-বাউন্ড কাজের জন্য async/await, যেকোনো ভাগ করা অবস্থার জন্য একটি মালিক কর্ম বা অ্যাক্টর, এবং হাতে-টিউন করা লকিং পুরোপুরি এড়িয়ে যান। পেমেন্ট পথে একটি হারানো-আপডেট রেস একটি মিস হওয়া ফিচারের চেয়ে দ্রুত আপনাকে ডোবাতে পারে, তাই সেই শ্রেণির ত্রুটি অসম্ভব করতে সামান্য বাড়তি কোড খরচ করুন এবং এগিয়ে যান।
ছোট ব্যবসা। কনকারেন্সি আপনার কারও কাজ নয়, তাই যেসব প্ল্যাটফর্ম ও ম্যানেজড সেবা তা আপনার জন্য সামলায় সেগুলো পছন্দ করুন: ডেটাবেস ট্রানজ্যাকশন, হোস্টেড কিউ, বা ফ্রেমওয়ার্কের অনুরোধ মডেল আপনি হাতে রক্ষণাবেক্ষণ করা থ্রেডের চেয়ে ভালো। কোনো টুল মূল্যায়নের সময় “এটি কি কনকারেন্সিকে ডিফল্টে নিরাপদ করে” প্রশ্নটিকে কেনা-বনাম-বানানোর প্রশ্ন ভাবুন, এবং সেই বিকল্প পছন্দ করুন যেখানে ভুল ইন্টারলিভিং একজন গ্রাহকের রেকর্ড নিঃশব্দে নষ্ট করতে পারে না। যেখানে একটি বাউন্ডেড, ম্যানেজড সেবা ধরে রাখতে পারে সেখানে ভাগ করা পরিবর্তনযোগ্য অবস্থা আপনার নিজের কোড থেকে দূরে রাখুন।
এন্টারপ্রাইজ। অনেক দল জুড়ে লক্ষ্য হলো একটি হাউস ডিফল্ট যা হাজার হাজার অবদানকারীকে নিরাপদ রাখে: নিয়ম হিসেবে অপরিবর্তনীয়তা ও বার্তা-আদানপ্রদান, কাঁচা লকের চেয়ে উচ্চ-স্তরের মডেল, ব্যাকপ্রেশারসহ বাউন্ডেড কিউ ও পুল, এবং নথিবদ্ধ বৈশ্বিক লক ক্রম। এগুলো প্রকৌশল মানে কোডবদ্ধ করুন, CI-তে রেস ডিটেক্টর ও স্ট্রেস টেস্ট দিয়ে প্রয়োগ করুন, এবং যেখানে প্রোফাইলার লক-মুক্ত কোডকে যথার্থ করেছে সেই ব্যতিক্রম নিয়ন্ত্রণ করুন যাতে প্রতিটি পরীক্ষিত, পর্যালোচিত সীমানার পেছনে থাকে। কনকারেন্সি সক্ষমতা বহর-জোড়া উদ্বেগ হিসেবে পরিচালনা করুন, মাপা লোডের সঙ্গে বাঁধা কিউ বাউন্ড ও পুল আকারসহ।
সরকার। দশকের পর দশক চলা সিস্টেমে সঠিকতা ও নিরীক্ষণযোগ্যতা কাঁচা থ্রুপুটের চেয়ে এগিয়ে। দাবি করুন প্রতিটি অবস্থা পরিবর্তন লিপিবদ্ধ ও পুনরায় চালানো যায়, যাতে একটি সন্দেহজনক রেস পুনরুৎপাদন এবং সমাধান তদারকি সংস্থার কাছে প্রমাণ করা যায়, এবং সুবিধা, নিরাপত্তা বা সরকারি নথি ছোঁয়া সিদ্ধান্তের জন্য AI-মুক্ত নির্ধারিত পথ রাখুন। ক্রয়ে বিক্রেতাদের তাদের কনকারেন্সি মডেল এবং রেস-ডিটেক্টর ও স্ট্রেস-টেস্ট কভারেজের প্রমাণ প্রকাশ করতে বলুন, কারণ একটি সরকারি সিস্টেমে লোডে ভুল উত্তর অসুবিধা নয়, এটি এমন কিছু যা একজন জবাবদিহিযোগ্য কর্মকর্তাকে পরে ব্যাখ্যা করতে হবে।
উদাহরণ
স্টার্টআপ। একটি ছোট দল একটি পেমেন্ট ফিচার পাঠায় এবং লক্ষ্য করে লোডে অ্যাকাউন্ট ব্যালেন্স মাঝেমধ্যে কয়েক সেন্ট সরে যায়। কারণ একযোগ অনুরোধ হ্যান্ডলার থেকে একটি ব্যালেন্স ফিল্ডে সাধারণ রিড-মডিফাই-রাইট, একটি হারানো-আপডেট রেস। লক ছিটানোর বদলে তারা প্রতিটি অ্যাকাউন্টের ব্যালেন্স একটি একক মালিক কর্মের পেছনে সরায়, যে ডেবিট ও ক্রেডিট বার্তা হিসেবে একটি একটি করে প্রক্রিয়া করে। সরণ উধাও হয়, কোড নিয়ে যুক্তি করা সহজ হয়, এবং তারা সমাধান পাহারা দিতে হাজার হাজার একযোগ স্থানান্তর চালানো একটি স্ট্রেস টেস্ট যোগ করে। একটি কাঠামোগত পরিবর্তন, ত্রুটির একটি পুরো শ্রেণি অবসরে।
এন্টারপ্রাইজ। প্রতি সেকেন্ডে হাজার হাজার অনুরোধ সামলানো একটি উচ্চ-থ্রুপুট অর্ডার সার্ভিস ট্রাফিক বৃদ্ধির সময় পর্যায়ক্রমিক লেটেন্সি স্পাইক ও মাঝেমধ্যে মেমরি-শেষ ক্র্যাশে ভোগে। তদন্তে একটি থ্রেড পুলের পেছনে একটি সীমাহীন কাজের কিউ মেলে যা চাহিদা সক্ষমতা ছাড়ালে সীমাহীনভাবে বাড়ে। দল কিউ বাউন্ড করে, পুলকে কোর সংখ্যার সঙ্গে বাঁধা আকারে সীমিত করে, এবং ব্যাকপ্রেশার যোগ করে যা অতিরিক্ত লোড দ্রুত স্পষ্ট ত্রুটিসহ প্রত্যাখ্যান করে। থ্রুপুট পূর্বানুমেয় হয়, ক্র্যাশ থামে, এবং একটি ভাগ করা ক্যাশের গরম লক লক-মুক্ত কাঠামো দিয়ে প্রতিস্থাপিত হয় কেবল প্রোফাইলার কনটেনশন প্রকৃত প্রমাণ করার পর। অনেক রচয়িতার জন্য নিরাপদ ডিফল্ট, কেবল যেখানে মাপা সেখানে টিউন করা কনকারেন্সি।
সরকার। একটি জাতীয় সুবিধা প্ল্যাটফর্ম দশকের পর দশক চলে এবং একযোগ কেস আপডেটেও নিরীক্ষণযোগ্য, সঠিক ফল দিতে হয়। দল অপরিবর্তনীয়তা ও বার্তা-আদানপ্রদানকে হাউস ডিফল্ট বাছে, প্রতিটি পরিবর্তনযোগ্য অবস্থা একক মালিকে সীমাবদ্ধ করে, এবং যেখানে লক থাকে সেখানে বৈশ্বিক লক ক্রম চাপায়, সবই প্রকৌশল মানে লিখিত। তারা পাইপলাইনে থ্রেড স্যানিটাইজার ও এলোমেলো স্ট্রেস টেস্ট চালায়, এবং এমনভাবে নকশা করে যাতে প্রতিটি অবস্থা পরিবর্তন তদারকির জন্য লিপিবদ্ধ ও পুনরায় চালানো যায়, যা একটি বিরল ইন্টারলিভিং সন্দেহ হলে তাদের সমাধান পুনরুৎপাদন ও প্রমাণ করতে দেয়। সঠিকতা ও নিরীক্ষণযোগ্যতা প্রথম-শ্রেণির প্রয়োজন হিসেবে গণ্য, পারফরম্যান্সের পরবর্তী ভাবনা নয়।
ব্যবসায়িক যুক্তি: প্রেরণা, ROI ও TCO
সুশৃঙ্খল কনকারেন্সির প্রতিদান দেখা দেয় যে ঘটনা কখনো ঘটে না তার রূপে। একটি প্রোডাকশন রেস হাজার হাজার রেকর্ডে ডেটা নষ্ট করতে পারে, এবং খরচে থাকে পর্যবেক্ষণে লুকিয়ে যাওয়া ত্রুটি খুঁজতে প্রকৌশল ঘণ্টা, এবং খারাপ ডেটা মেলানো, ক্ষতিগ্রস্ত ব্যবহারকারীদের জানানো ও বিশ্বাস পুনর্গঠনের বহুগুণ বড় খরচ। এগুলো নির্ণয়ে সবচেয়ে ব্যয়বহুল ত্রুটির মধ্যে, ঠিক কারণ তারা অনির্ধারিত, তাই একটি হাইজেনবাগের পেছনে ছোটা আগেভাগে নিরাপদ মডেল বাছার পরিশ্রমকে বামন করতে পারে।
সুবিধা দেখা দেয় থ্রুপুট ও খরচেও। কনকারেন্সির সঠিক মাপ একটি সার্ভিসকে একই হার্ডওয়্যারে অনেক বেশি লোড সামলাতে দেয়, একটি বড় বহরের জন্য পুনরাবৃত্ত সঞ্চয়, আর ব্যাকপ্রেশার ও বাউন্ডেড কিউ সেই ধাপে ধাপে বিভ্রাট ঠেকায় যা ট্রাফিক স্পাইককে প্রকাশ্য ঘটনায় পরিণত করে। মালিকানার মোট খরচ মাঝারি এবং বেশিরভাগ সাংস্কৃতিক: আপনি বিনিয়োগ করেন একটি হাউস শৈলীতে (অপরিবর্তনীয়তা, বার্তা-আদানপ্রদান, কাঠামোবদ্ধ কনকারেন্সি), টুলিংয়ে (CI-তে রেস ডিটেক্টর, থ্রেড স্যানিটাইজার, স্ট্রেস হার্নেস), এবং লক ক্রম ও বাউন্ডিং কোডবদ্ধ করা মানে। বিকল্প হলো এমন কোডবেস যেখানে সঠিকতা নির্ভর করে প্রতিটি রচয়িতা চিরকাল বিশেষজ্ঞ থাকার ওপর, যা কোনো বর্ধমান দল টিকিয়ে রাখতে পারে না। নেতৃত্বকে তাঁদের এককে যুক্তি দিন: একটি প্রতিরোধ করা রেসকে এড়ানো ডেটা-নষ্ট ঘটনায়, ব্যাকপ্রেশারকে প্রতিরোধ করা বিভ্রাটে, এবং একটি নিরাপদ ডিফল্টকে বাঁচানো অনবোর্ডিং সময়ে অনুবাদ করুন।
অ্যান্টি-প্যাটার্ন ও ফাঁদ
- I/O-বাউন্ড কাজে গতির জন্য থ্রেড যোগ। অপেক্ষা-ভারী সার্ভিসে আরও থ্রেড থ্রুপুট নয়, কনটেনশন কেনে।
- সর্বত্র ভাগ করা পরিবর্তনযোগ্য অবস্থা। যেকোনো থ্রেড যেকোনো অবজেক্ট বদলালে সঠিকতা ভাগ্যের ব্যাপার হয়, যা কোনো পর্যালোচক যাচাই করতে পারেন না।
- সীমাহীন কিউ ও পুল। একটি স্পাইক কিউ বাড়ায় যতক্ষণ না মেমরি মরে; ক্র্যাশ রহস্যময় দেখায় কিন্তু তা সাধারণ ওভারলোড।
- বৈশ্বিক ক্রম ছাড়া অ্যাড হক লকিং। কোডবেস জুড়ে ভিন্ন ক্রমে ধরা লক লোডে ডেডলক করে।
- কোড লেখা ক্রমেই চলে ধরে নেওয়া। মেমরি মডেল উপেক্ষা, ফলে দৃশ্যমানতা ত্রুটি একটি থ্রেডকে সেকেলে মানে ঘুরতে রাখে।
- হাতে-গড়া লক-মুক্ত চতুরতা। কাস্টম লক-মুক্ত পরিকল্পনা প্রায় সবসময় সূক্ষ্মভাবে ভুল এবং পর্যালোচনা প্রায় অসম্ভব।
- কেবল সুখী ইন্টারলিভিং পরীক্ষা। নির্ধারিত টেস্ট পাস করে যখন দশ লক্ষে একবারের ক্রম প্রোডাকশন নষ্ট করে।
- লক ধরে রেখে অজানা কোড ডাকা। একটি কলব্যাক যা ব্লক করে বা পুনরায় ঢোকে তা ক্রিটিক্যাল সেকশনকে ডেডলকে পরিণত করে।
পরিপক্বতা মডেল
- স্তর ১, সূচনা: কনকারেন্সি অ্যাড হক ও প্রতিক্রিয়াশীল। থ্রেড ও লক সহজাত বোধে যোগ হয়, ভাগ করা পরিবর্তনযোগ্য অবস্থা সর্বত্র, এবং কিউ সীমাহীন। রেস কন্ডিশন অপুনরুৎপাদনযোগ্য প্রোডাকশন ঘটনা হিসেবে দেখা দেয় যা কেউ নির্ণয় করতে পারে না, এবং তা ধরার কোনো টুলিং নেই।
- স্তর ২, বিকাশ: কিছু দল মৌলিক চর্চা শিখেছে: তারা আরও যত্নে লক ব্যবহার করে এবং সবচেয়ে স্পষ্ট কিউ বাউন্ড করে। রেস ও ডেডলক সম্পর্কে অনানুষ্ঠানিক সচেতনতা আছে, এবং কয়েকটি গুরুত্বপূর্ণ পথ বাড়তি নজর পায়। দল জুড়ে চর্চা অসঙ্গত, টেস্টিং এখনো বেশিরভাগ একক-ইন্টারলিভিং, এবং নিরাপদ ধরন লিখিত নয়, ব্যক্তিদের মধ্যে বাস করে।
- স্তর ৩, মানসম্মতকরণ: প্রতিষ্ঠানের একটি নথিবদ্ধ হাউস শৈলী আছে যা সর্বত্র প্রয়োগ হয়: ডিফল্ট হিসেবে অপরিবর্তনীয়তা ও বার্তা-আদানপ্রদান, কাঁচা লকের চেয়ে উচ্চ-স্তরের মডেল, ব্যাকপ্রেশারসহ বাউন্ডেড কিউ ও পুল, এবং নথিবদ্ধ বৈশ্বিক লক ক্রম। CI-তে রেস ডিটেক্টর ও স্ট্রেস টেস্ট চলে, এবং কনকারেন্সি পছন্দ কাজ I/O-বাউন্ড নাকি CPU-বাউন্ড তা থেকে আসে।
- স্তর ৪, ব্যবস্থাপনা: প্রতিষ্ঠান ভিত্তিরেখার বিপরীতে তার কনকারেন্সি অবস্থান মাপে ও নিয়ন্ত্রণ করে। এটি সার্ভিস জুড়ে রেস-ডিটেক্টর ও থ্রেড-স্যানিটাইজার কভারেজ অনুসরণ করে, কিউ গভীরতা, লক-অপেক্ষা সময়, পুল সম্পৃক্ততা ও প্রত্যাখ্যান হার পর্যবেক্ষিত মেট্রিক হিসেবে লিপিবদ্ধ করে, এবং অবনতি রেখা লোড-টেস্ট করে যাতে প্রতিটি বাউন্ড একটি তথ্য-সমর্থিত সক্ষমতা সিদ্ধান্ত হয়। কনকারেন্সি ঘটনা গোনা ও প্রবণতা বিশ্লেষণ করা হয়, সমান্তরাল ওয়ার্কলোডের ক্রমিক ভগ্নাংশ প্রকৃতপক্ষে অর্জিত গতিবৃদ্ধির বিপরীতে মাপা হয়, এবং নতুন নকশায় যাওয়া-বা-না-যাওয়ার সিদ্ধান্ত সহজাত বোধের বদলে সেই প্রমাণে দাঁড়ায়।
- স্তর ৫, সমন্বয়: নিরাপদ কনকারেন্সি প্রতিটি রচয়িতার জন্য ন্যূনতম-প্রতিরোধের পথ, এবং চর্চা নিরন্তর উন্নত ও প্রতিষ্ঠান জুড়ে একীভূত। ত্রুটির পুরো শ্রেণি নকশায় অসম্ভব, হট স্পট কেবল সেখানে টিউন হয় যেখানে প্রোফাইলিং প্রমাণ করে, এবং নির্ধারিত পুনঃচালনা বিরল অবশিষ্ট ত্রুটিকে পুনরুৎপাদনযোগ্য করে। সঠিকতা ও নিরীক্ষণযোগ্যতা নিরন্তর রক্ষিত বৈশিষ্ট্য, সক্ষমতা বাউন্ড পর্যবেক্ষিত লোডের সঙ্গে খাপ খায়, এবং প্ল্যাটফর্ম ও ওয়ার্কলোড সরলে মান বিবর্তিত হয়।
আলোচনার ভাবনা
- আজ আপনার ব্যস্ততম সার্ভিস নিরীক্ষা করলে তার কতটা অবস্থা ভাগ করা ও পরিবর্তনযোগ্য, এবং সেই ভাগাভাগির কতটা সত্যিই প্রয়োজনীয়?
- দুটি কর্মকে সমন্বয় করতে হলে আপনার দলের ডিফল্ট উত্তর কী, এবং আপনি কি চাইবেন তা অপরিবর্তনীয়তা বা বার্তা-আদানপ্রদান হোক?
- আপনার সিস্টেমে সীমাহীন কিউ বা সীমাহীন পুল এখনো কোথায় লুকিয়ে, এবং হঠাৎ দশ গুণ ট্রাফিক স্পাইকে তাদের কী হবে?
- আপনার কন্টিনিউয়াস ইন্টিগ্রেশন রানে কি রেস ডিটেক্টর বা থ্রেড স্যানিটাইজার আছে, এবং প্রোডাকশনের আগে শেষবার কখন একটি কিছু ধরেছিল?
- আপনার সবচেয়ে সমান্তরাল ওয়ার্কলোডের ক্রমিক ভগ্নাংশ কত, এবং অ্যামডালের সূত্র কি আপনি যে গতিবৃদ্ধির পেছনে ছুটছেন তা সীমিত করে?
- আপনার দল কি চাহিদামতো দশ লক্ষে একবারের ইন্টারলিভিং ত্রুটি পুনরুৎপাদন করতে পারত, এবং সেখানে পৌঁছাতে কী লাগবে?
প্রধান শিক্ষা
- কনকারেন্সি একটি প্রোগ্রামকে স্বাধীন কর্ম হিসেবে কাঠামো দেয়; প্যারালেলিজম সেগুলো একসঙ্গে চালায়। থ্রেড যোগের আগে ঠিক করুন আপনার কোনটি দরকার।
- ভাগ করা পরিবর্তনযোগ্য অবস্থা প্রায় প্রতিটি কনকারেন্সি ত্রুটির মূল; অনেক রচয়িতার জন্য নিরাপদ ডিফল্ট হিসেবে অপরিবর্তনীয়তা ও বার্তা-আদানপ্রদান পছন্দ করুন।
- হাতে-লেখা লকের আগে উচ্চ-স্তরের মডেল (অ্যাক্টর, চ্যানেল, কাঠামোবদ্ধ কনকারেন্সি, async/await) ধরুন, যা তত্ত্বে সঠিক ও চর্চায় বিপজ্জনক।
- পারমাণবিকতা, দৃশ্যমানতা ও আপনার মেমরি মডেল বুঝুন; সঠিক আদিম ব্যবহার করুন, লক সংক্ষিপ্ত ধরুন, এবং ডেডলক, লাইভলক ও স্টারভেশন এড়াতে বৈশ্বিক লক ক্রম চাপান।
- প্রতিটি কিউ ও পুল সীমাবদ্ধ করুন এবং ব্যাকপ্রেশার প্রয়োগ করুন, যাতে স্পাইক ক্র্যাশের বদলে মার্জিতভাবে নিম্নমুখী হয় (অধ্যায় 3.3)।
- রেস ডিটেক্টর, স্ট্রেস টেস্ট ও পুনঃচালনা দিয়ে ইন্টারলিভিং ইচ্ছাকৃতভাবে পরীক্ষা করুন (অধ্যায় 2.15), এবং সমান্তরাল করার সময় অ্যামডালের সূত্র সম্মান করুন (অধ্যায় 2.16)।
- এন্টারপ্রাইজের জন্য এটি থ্রুপুট ও প্রতিরোধ করা ঘটনা; সরকারের জন্য এটি দীর্ঘজীবী সিস্টেমে সঠিকতা ও নিরীক্ষণযোগ্যতা।
তথ্যসূত্র ও আরও পড়ার জন্য
- Brian Goetz et al., Java Concurrency in Practice (পারমাণবিকতা, দৃশ্যমানতা, মেমরি মডেল ও নিরাপদ প্রকাশনা)।
- Herb Sutter, “The Free Lunch Is Over” (ক্লক গতি স্থির হলে কেন সফটওয়্যারকে কনকারেন্সি গ্রহণ করতে হবে)।
- Leslie Lamport, “Time, Clocks, and the Ordering of Events in a Distributed System” (ক্রম ও কনকারেন্ট যুক্তির ভিত্তি)।
- C. A. R. Hoare, “Communicating Sequential Processes” (Communications of the ACM, 1978): চ্যানেলের পেছনের CSP মডেল।
- Carl Hewitt, Peter Bishop ও Richard Steiger, “A Universal Modular Actor Formalism for Artificial Intelligence” (অ্যাক্টর মডেলের উৎস)।
- Edsger W. Dijkstra, “Cooperating Sequential Processes” (সেমাফোর, পারস্পরিক বর্জন ও ডেডলক সমস্যা)।
- Maurice Herlihy ও Nir Shavit, The Art of Multiprocessor Programming (লক, পারমাণবিক ও লক-মুক্ত ডেটা স্ট্রাকচার)।
- Nathaniel J. Smith, “Notes on Structured Concurrency, or: Go Statement Considered Harmful” (কাঠামোবদ্ধ কনকারেন্সির পক্ষে যুক্তি)।
- Martin Kleppmann, Designing Data-Intensive Applications (যেখানে মেমরি বিতরিত সিস্টেমের সঙ্গে মেলে সেখানে কনকারেন্সি ও সামঞ্জস্য)।
- Gene M. Amdahl, “Validity of the Single Processor Approach to Achieving Large-Scale Computing Capabilities” (1967): অ্যামডালের সূত্রের উৎস।