ব্যর্থ OpenVPN স্টার্ট প্রায়ই আসে একটি রিসোর্স-অভিযোগ আর একটি সীমা বাড়ানোর সদাশয় পরামর্শ নিয়ে, আর সেই পরামর্শ কাজ করে মাত্র অর্ধেক ক্ষেত্রে। এই ব্যর্থতার পেছনে আছে দুটি সম্পর্কহীন কাউন্টার। একটি হলো কার্নেলের সীমা—একটি প্রকৃত ইউজার আইডির মালিকানাধীন টাস্কের সংখ্যা, যা প্রসেস চালু হওয়ার সময় উত্তরাধিকারসূত্রে পাওয়া যায়। অন্যটি হলো cgroup বাজেট, যা সার্ভিস ম্যানেজার একটি ইউনিট এবং তার থেকে ফোর্ক হওয়া সবকিছুর ওপর প্রয়োগ করে। যে ইউনিটটি সত্যিই চলে, তার জন্য প্রতিটির কার্যকর মান পড়তে একটি অনুমানের চেয়ে কম খরচ হয়।

দুই কাউন্টার, দুই প্রশ্ন

LimitNPROC হলো systemd নামের অধীনে RLIMIT_NPROC, আর এর হিসাব-একক প্রকৃত ইউজার আইডি। সেই ব্যবহারকারীর মালিকানাধীন প্রতিটি প্রসেস একই মোটে গণনা হয়, যার মধ্যে অন্য ইউনিট, লগইন সেশন বা শিডিউলার জবের শুরু করা কাজও রয়েছে। তাই এই সীমাটি প্রতিটি সার্ভিসের জন্য আলাদা ক্যাপ নয়, এমনকি সেটি কোনো সার্ভিস ইউনিটের ভেতরেও নির্ধারিত হলেও; আর যে সার্ভিস প্রতিটি ক্লায়েন্টের জন্য একটি হেল্পার ফোর্ক করে, সে ওই অ্যাকাউন্টে চলা বাকি সবকিছুর সঙ্গে প্রতিযোগিতা করে। একই ব্যবহারকারীর অধীনে ব্যস্ত একটি ক্রন জব VPN ইউনিটকে এমন রেখার ওপারে ঠেলে দিতে পারে যা এটি নিজে কখনো পেরোয়নি।

TasksMax-এর মালিক আলাদা: ইউনিটের cgroup-এর ওপর pids কন্ট্রোলার, যা প্রসেস নয়, টাস্ক গণনা করে। থ্রেডগুলো টাস্ক, তাই এক থ্রেডের মতো দেখতে কিন্তু ওয়ার্কার পুলযুক্ত একটি ডিমন এমন বাজেট খরচ করতে পারে যা প্রথম দেখায় তার প্রসেস সংখ্যার চেয়ে অনেক বড়। EffectiveTasksMax জানায়, অভিভাবক স্লাইসগুলো তাদের কথা বলার পর cgroup অনুক্রমটি আসলে কী অনুমতি দেয়।

কেন রুট ব্যতিক্রম উত্তরটি বদলে দেয়

কার্নেল CAP_SYS_RESOURCE বা CAP_SYS_ADMIN বহনকারী প্রসেসে RLIMIT_NPROC প্রয়োগ করে না, এজন্য বিশেষাধিকার না ছেড়ে রুট হিসেবে চলা ইউনিটটি ওই সেটিং দ্বারা কার্যত অসীম। এই একক ব্যতিক্রমই মানুষদের বিনিময় করা পরস্পরবিরোধী পরামর্শের ব্যাখ্যা দেয়: LimitNPROC বাড়ালে বিশেষাধিকার ছেড়ে দেওয়া ডিপ্লয়মেন্ট সার হয় এবং বিশেষাধিকার ধরে রাখা ডিপ্লয়মেন্টের জন্য মোটেও কিছু করে না। ওই সেটিংকে কৃতিত্ব বা দোষ দেওয়ার আগে User= এবং ডিমনটি চালু হওয়ার পর পরিচয় বদলায় কি না দেখুন। যে ইউনিট বিশেষাধিকার নিয়ে চলে কিন্তু পরে বিশেষাধিকারহীন অ্যাকাউন্টে বদলে যায়, সেটি বদলের মুহূর্তেই সীমার নিচে নেমে আসে, ফলে ব্যর্থতার সময়রেখাটিও পড়ার মতো।

ব্যর্থতার ধাপটি বিষয়টিকে আরও সংকুচিত করে। এক্সিকিউশন সেটআপের সময় প্রত্যাখ্যান, ডিমন নিজেই জানানো একটি ফোর্ক ত্রুটি, এবং cgroup-এর ভেতরে প্রত্যাখ্যাত টাস্ক তৈরি—এগুলো আলাদা জার্নাল লাইন দেয়, আর তাদের একটিরই উত্তর দেয় বড় বাজেট।

কার্যকর মান পড়ুন, শেলের নয়

একটি ইন্টারঅ্যাকটিভ শেলের ulimit -u সেই শেলটিকেই বর্ণনা করে। সার্ভিস ম্যানেজার ডিমনকে কী দিয়েছে তা এটি বর্ণনা করে না, আর cgroup হিসাব নিয়ে কিছুই বলে না। বরং ইউনিটটিকে জিজ্ঞাসা করুন, কোনো গাইডের উদাহরণ নয়—হোস্টে বিদ্যমান ইনস্ট্যান্স নাম ব্যবহার করে।

systemctl show [email protected] -p User -p LimitNPROC -p TasksCurrent -p TasksMax -p EffectiveTasksMax
cat /proc/$(systemctl show -p MainPID --value [email protected])/limits | grep -i processes

কনটেইনারের ভেতরে উত্তরের জন্য আরও দুটি পাঠ দরকার, কারণ infinity-এর মতো ভেতরের মান কেবল অতিথির দৃষ্টিভঙ্গি বর্ণনা করে। হোস্টের মালিকের কাছে কনটেইনারের নিজস্ব pids সিলিং জানতে চান, এবং ভেতরের সার্ভিস ম্যানেজার ওই কন্ট্রোলার আদৌ ডেলিগেট করতে পারে কি না তা নিশ্চিত করুন। একটি নেস্টেড ইউনিট এমন বাজেট ধরে রাখতে পারে না যা তার অভিভাবক cgroup কখনো দেয়নি।

সমাধানের মাত্রা নির্ধারণ করুন এবং লোডের মধ্যে তা প্রমাণ করুন

ত্রুটির লেখা থেকে নয়, ওয়ার্কলোড থেকে একটি সংখ্যা নিন। ডিমন প্রতি সংযুক্ত ক্লায়েন্ট বা প্রতি হেল্পার আহ্বানে কতগুলো প্রসেস চালু করে তা গণনা করুন, ডিপ্লয়মেন্টকে যে সমবর্তিতা বহন করতে হবে তা দিয়ে গুণ করুন, প্রশাসনিক সেশনের জন্য কিছু মার্জিন যোগ করুন, তারপর সেই সংখ্যাটি দুটি কার্যকর মানের সঙ্গে তুলনা করুন। স্থানীয় drop-in ওভাররাইড পরিবর্তনটিকে পর্যালোচনযোগ্য রাখে এবং প্যাকেজ আপগ্রেডের পরও টিকে থাকে, অথচ শিপ করা ইউনিট ফাইল সম্পাদনা করলে পরিবর্তনটি পরবর্তী আপডেট তা প্রতিস্থাপন করার আগ পর্যন্ত লুকিয়ে থাকে। ওভাররাইডের পাশে হিসাবটি লিখে রাখুন, কারণ পরবর্তী যে ব্যক্তি এটি বাড়াবে বা কমাবে তার চূড়ান্ত সংখ্যা নয়, অনুমিতিগুলোই দরকার।

বাজেটের পরিবর্তন এক্সিকিউশনের সময় প্রয়োগ হয়, তাই কেবল রিলোড করলে ইতিমধ্যে চলা প্রসেসের আকার বদলায় না। স্বাভাবিক জীবনচক্রের মধ্য দিয়ে ইউনিটটি পুনরায় চালু করুন, সেশনের বিঘ্ন মেনে নিন, এবং নতুন ইনস্ট্যান্সে কাউন্টারগুলো আবার পড়ুন।

sudo systemctl daemon-reload
sudo systemctl restart [email protected]
systemctl show [email protected] -p TasksCurrent -p EffectiveTasksMax
sudo journalctl -u [email protected] -b --no-pager | tail -n 20

সমাধান প্রমাণ করে পুনরায় চালু করা একটি ইউনিট, যার টাস্ক সংখ্যা অভীষ্ট লোড বহন করার সময়ও দুটি সিলিংয়ের নিচে থাকে, সাথে এমন জার্নাল যা একই ধাপে আর টাস্ক বা ফোর্ক নিঃশেষের কথা জানায় না। পরিবর্তনের সঙ্গে আগের-পরের সংখ্যাগুলো রাখুন, যাতে পরবর্তী তদন্ত একই পরামর্শ নয়, একটি মাপ থেকে শুরু হয়। যদি সংখ্যাটি এখনো সিলিংয়ে পৌঁছায়, তবে হিসাবটাই ভুল ছিল, সীমাটি দৈবক্রমে খুব ছোট ছিল না—এবং পরবর্তী রিস্টার্টের আগে এই পার্থক্যটি জানা দরকার।

সম্পর্কিত নিবন্ধ