ডিবাগিং busy প্রক্রিয়া
কখনো কখনো আমরা php start.php status কমান্ডের মাধ্যমে busy অবস্থার প্রক্রিয়া দেখতে পাই, যা নির্দেশ করে যে সংশ্লিষ্ট প্রক্রিয়া ব্যবসায়িক কাজ সম্পন্ন করছে, স্বাভাবিক পরিস্থিতিতে ব্যবসায়িক কাজ সম্পন্ন হলে সংশ্লিষ্ট প্রক্রিয়া idle অবস্থায় ফিরে আসবে। সাধারণভাবে এতে কোনও সমস্যা থাকে না। কিন্তু যদি এটি সবসময় busy অবস্থায় থাকে এবং কখনোই idle অবস্থায় ফিরে না আসে, তাহলে এর অর্থ হলো প্রক্রিয়ার ভিতরে ব্যবসায়িক কাজ ব্লক হয়েছে বা অসীম লুপে রয়েছে। এটি চিহ্নিত করার জন্য নিম্নলিখিত পদক্ষেপ গ্রহণ করা যেতে পারে।
strace+lsof কমান্ডের মাধ্যমে চিহ্নিত করা
1. status-এ busy প্রক্রিয়ার pid খুঁজে বের করা
php start.php status চালানোর পর নিচের মত একটি আউটপুট দেখাবে

ছবিতে busy প্রক্রিয়ার pid হলো 11725 এবং 11748
2. strace দিয়ে প্রক্রিয়া ট্রেস করা
একটি প্রক্রিয়ার pid (এখানে 11725 চয়ন করা হয়েছে) নির্বাচন করে চলান strace -ttp 11725 নিচে দেখানো আউটপুট পাবেন

এটি দেখায় যে প্রক্রিয়াটি অবিরাম poll([{fd=16, events=.... সিস্টেম কলের মধ্যে রয়েছে, এটি fd=16 এর বর্ণনাকারীর জন্য পাঠ্য ইভেন্টগুলির অপেক্ষায় রয়েছে, অর্থাৎ এটি এই বর্ণনাকারী থেকে ডেটা ফেরত আসার জন্য অপেক্ষা করছে।
যদি কোনও সিস্টেম কল প্রদর্শিত না হয়, তাহলে বর্তমানে টার্মিনালটি রেখে অন্য একটি টার্মিনাল খুলুন এবং kill -SIGALRM 11725 (প্রক্রিয়াটিকে একটি এলার্ম সিগন্যাল পাঠান) চালান, এরপর strace টার্মিনালে কোনো প্রতিক্রিয়া আসছে কি না দেখুন, এবং এটি কি কোনও সিস্টেম কলের উপরে ব্লকড হয়েছে। যদি এখনও কোনো সিস্টেম কল প্রদর্শিত না হয়, তাহলে প্রোগ্রাম সম্ভবত ব্যবসায়িক মৃত লুপে রয়েছে, নিচে প্রদত্ত পৃষ্ঠায় প্রক্রিয়ার দীর্ঘ সময় ধরে busy থাকার অন্যান্য কারণগুলোর ২য় পয়েন্ট বাস্তবায়ন করুন।
যদি সিস্টেম epoll_wait বা select সিস্টেম কলের উপর ব্লকড হয় তবে এটি স্বাভাবিক অবস্থায় পরিণত হয়, এটি উল্লেখ করে যে প্রক্রিয়াটি ইতিমধ্যে idle অবস্থায় রয়েছে।
3. lsof দিয়ে প্রক্রিয়ার বর্ণনাকারী দেখা
চালান lsof -nPp 11725 নিচে দেখানো আউটপুট পাবেন

বর্ণনাকারী 16 হল 16u রেকর্ড (শেষ সারি), দেখতে পাচ্ছেন fd=16 এর বর্ণনাকারী একটি tcp সংযোগ, দূরবর্তী ঠিকানা হচ্ছে 101.37.136.135:80। এটি নির্দেশ করে যে প্রক্রিয়াটি একটি http উৎসে অ্যাক্সেস করছে, অবিরাম poll([{fd=16, events=.... হচ্ছে http সার্ভার থেকে ডেটা ফেরত আসার জন্য অপেক্ষা করছে, এটি কেন এই প্রক্রিয়া busy অবস্থায় রয়েছে তা ব্যাখ্যা করে।
সমাধান:
জেনে গেলাম প্রক্রিয়াটি কোথায় ব্লক হয়েছে, এখন এটি সমাধান করা সহজ, যেমন উপরে চিহ্নিত করা হয়েছে এটি curl কে কল করার সময় ব্লক হয়েছে, এবং সংশ্লিষ্ট url দীর্ঘ সময় ধরে ডেটা ফেরত দেয়নি, যার ফলে প্রক্রিয়াটি সমান্তরাল অপেক্ষা করছে। এই সময়ে url প্রদানকারীর কাছে গিয়ে url ফিরে আসার ধীরগতির কারণ চিহ্নিত করা যেতে পারে, একই সাথে curl কল করার সময় সময়সীমা প্যারামিটার যোগ করা উচিত, যেমন ২ সেকেন্ডে ডেটা ফেরত না এলে টাইমআউট করুন, দীর্ঘ সময়ের জন্য ব্লকড হয়ে পড়া এড়াতে (এতে প্রক্রিয়াটি প্রায় ২ সেকেন্ডের মতো busy অবস্থায় থাকতে পারে)।
দীর্ঘ সময় ধরে busy অবস্থায় থাকবার অন্যান্য কারণ
প্রক্রিয়ার ব্লকড হওয়া ছাড়া অন্যান্য কারণও রয়েছে যা প্রক্রিয়াকে busy অবস্থায় রাখতে পারে।
1. ব্যবসায়িক ক্ষেত্রে মারাত্মক ত্রুটি ঘটানো
প্রতিক্রিয়া: এ অবস্থায় সিস্টেম লোড সাধারণত অনেক উচ্চ থাকে, status এ load average ১ অথবা তার বেশি। প্রক্রিয়ার exit_count সংখ্যা দেখতে পাবেন খুব বেশি এবং এভাবে বৃদ্ধি পাচ্ছে।
সমাধান: php start.php start (-d ছাড়া) ডিবাগ মোডে চালান, কাজের ত্রুটি দেখুন এবং ত্রুটিগুলি সমাধান করুন।
2. কোডে অসীম মৃত লুপ
প্রতিক্রিয়া: top কমান্ডে busy প্রক্রিয়া CPU অনেক বেশি ব্যবহার করতে দেখা যায়, strace -ttp pid কমান্ড কোন সিস্টেম কলের তথ্য প্রদর্শন করে না।
সমাধান: নীচের gdb এবং php সোর্স কোড ব্যবহার করে চিহ্নিত করা নিবন্ধটি পড়ে সমস্যার সমাধান করুন, পদক্ষেপগুলি সাধারণভাবে নিচে সঙ্গৃহীত হয়:
php -vব্যবহার করে সংস্করণ পরীক্ষা করুন।- সংশ্লিষ্ট php সংস্করণটির সোর্স কোড ডাউনলোড করুন।
gdb --pid=busy প্রক্রিয়ার pidচালান।source php সোর্স কোডের পথ/.gdbinitচালান।zbacktraceব্যবহার করে কল স্ট্যাক মুদ্রণ করুন।
শেষ পদক্ষেপে আপনি php কোডের বর্তমান কার্যকর কল স্ট্যাক দেখতে পাবেন, এটা নির্দেশ করে php কোডে কোন স্থানে মৃত্যুর লুপ হয়েছে।
দ্রষ্টব্য: যদিzbacktraceকল স্ট্যাক মুদ্রণ না করে, তাহলে হতে পারে আপনার php নির্মাণের সময়-gপ্যারামিটার যুক্ত হয়নি, php পুনরায় নির্মাণ করতে হবে এবং পরে workerman পুনরায় চালু করতে হবে।
3. অসীম সময়সীমা নির্ধারণকারী যোগ করা
ব্যবসায়িক কোডগুলি নিত্য নতুন সময়সীমা সংযোজন করছে এবং তা মুছে ফেলছে না, ফলে প্রক্রিয়ার ভিতরে সময়সীমা সংখ্যা বাড়তে থাকে, এইভাবে প্রক্রিয়া একটি অসীম সময়সীমার মধ্যে রয়ে যায়। যেমন নীচের কোড:
$worker = new Worker;
$worker->onConnect = function($con){
Timer::add(10, function(){});
};
Worker::runAll();
এই কোডটি ক্লায়েন্ট সংযোগ পাওয়ার পর একটি সময়সীমা যুক্ত করবে, কিন্তু সমগ্র ব্যবসায়িক কোডে সময়সীমা মুছে ফেলার কোনও যুক্তি নেই, তাই সময় অতিবাহিত হওয়ার সাথে সাথে প্রক্রিয়ার ভিতর সময়সীমার সংখ্যা ক্রমাগত বাড়তে থাকে, যা প্রক্রিয়াকে অসীম সময়সীমা চালাতে নিয়ে যায় এবং busy অবস্থায় রাখে। সঠিক কোড হলো:
$worker = new Worker;
$worker->onConnect = function($con){
$con->timer_id = Timer::add(10, function(){});
};
$worker->onClose = function($con){
Timer::del($con->timer_id);
};
Worker::runAll();