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

এই টুলটি আপনার প্রোডাকশন অ্যাপ্লিকেশনগুলো থেকে সিপিইউ ব্যবহার এবং মেমরি-অ্যালোকেশন সংক্রান্ত তথ্য সংগ্রহ করে। এটি সেই তথ্যকে অ্যাপ্লিকেশনটির সোর্স কোডের সাথে সংযুক্ত করে, যা আপনাকে অ্যাপ্লিকেশনটির সবচেয়ে বেশি রিসোর্স ব্যবহারকারী অংশগুলো শনাক্ত করতে সাহায্য করে এবং কোডের পারফরম্যান্স বৈশিষ্ট্যগুলো তুলে ধরে। টুলটির ব্যবহৃত তথ্য সংগ্রহের কৌশলগুলোর ওভারহেড কম হওয়ায় এটি প্রোডাকশন পরিবেশে নিরবচ্ছিন্ন ব্যবহারের জন্য উপযুক্ত।
এই কোডল্যাবে, আপনি একটি Go প্রোগ্রামের জন্য ক্লাউড প্রোফাইলার কীভাবে সেট আপ করতে হয় তা শিখবেন এবং অ্যাপ্লিকেশন পারফরম্যান্স সম্পর্কে এই টুলটি কী ধরনের তথ্য দিতে পারে, সে বিষয়ে পরিচিত হবেন।
আপনি যা শিখবেন
- ক্লাউড প্রোফাইলার দিয়ে প্রোফাইলিং করার জন্য কীভাবে একটি গো প্রোগ্রাম কনফিগার করবেন।
- ক্লাউড প্রোফাইলার ব্যবহার করে কীভাবে পারফরম্যান্স ডেটা সংগ্রহ, দেখা এবং বিশ্লেষণ করবেন।
আপনার যা যা লাগবে
- একটি গুগল ক্লাউড প্ল্যাটফর্ম প্রকল্প
- একটি ব্রাউজার, যেমন ক্রোম বা ফায়ারফক্স
- Vim, EMACs বা Nano-এর মতো প্রচলিত লিনাক্স টেক্সট এডিটরগুলোর সাথে পরিচিতি।
আপনি এই টিউটোরিয়ালটি কীভাবে ব্যবহার করবেন?
গুগল ক্লাউড প্ল্যাটফর্মের সাথে আপনার অভিজ্ঞতাকে আপনি কীভাবে মূল্যায়ন করবেন?
২. সেটআপ এবং প্রয়োজনীয়তা
স্ব-গতিতে পরিবেশ সেটআপ
- ক্লাউড কনসোলে সাইন ইন করুন এবং একটি নতুন প্রজেক্ট তৈরি করুন অথবা বিদ্যমান কোনো প্রজেক্ট পুনরায় ব্যবহার করুন। যদি আপনার আগে থেকে কোনো Gmail বা Google Workspace অ্যাকাউন্ট না থাকে, তবে আপনাকে অবশ্যই একটি তৈরি করতে হবে।



প্রজেক্ট আইডিটি মনে রাখবেন, যা সমস্ত গুগল ক্লাউড প্রজেক্ট জুড়ে একটি অনন্য নাম (উপরের নামটি ইতিমধ্যে ব্যবহৃত হয়েছে এবং আপনার জন্য কাজ করবে না, দুঃখিত!)। এই কোডল্যাবে এটিকে পরবর্তীতে PROJECT_ID হিসাবে উল্লেখ করা হবে।
- এরপরে, গুগল ক্লাউড রিসোর্স ব্যবহার করার জন্য আপনাকে ক্লাউড কনসোলে বিলিং চালু করতে হবে।
এই কোডল্যাবটি চালাতে খুব বেশি খরচ হওয়ার কথা নয়, এমনকি আদৌ কোনো খরচ নাও হতে পারে। "পরিষ্কার-পরিচ্ছন্নতা" (Cleaning up) বিভাগে দেওয়া নির্দেশাবলী অবশ্যই অনুসরণ করবেন, যেখানে রিসোর্স বন্ধ করার পরামর্শ দেওয়া হয়েছে, যাতে এই টিউটোরিয়ালের বাইরে আপনার কোনো বিল না আসে। গুগল ক্লাউডের নতুন ব্যবহারকারীরা ৩০০ মার্কিন ডলারের ফ্রি ট্রায়াল প্রোগ্রামের জন্য যোগ্য।
গুগল ক্লাউড শেল
যদিও গুগল ক্লাউড আপনার ল্যাপটপ থেকে দূরবর্তীভাবে পরিচালনা করা যায়, এই কোডল্যাবে সেটআপ সহজ করার জন্য আমরা গুগল ক্লাউড শেল ব্যবহার করব, যা ক্লাউডে চালিত একটি কমান্ড লাইন এনভায়রনমেন্ট।
ক্লাউড শেল সক্রিয় করুন
- ক্লাউড কনসোল থেকে, Activate Cloud Shell-এ ক্লিক করুন।
.

আপনি যদি আগে কখনো ক্লাউড শেল চালু না করে থাকেন, তাহলে এটি কী তা বর্ণনা করে একটি মধ্যবর্তী স্ক্রিন (নিচে দেওয়া আছে) আপনার সামনে আসবে। যদি তাই হয়, তাহলে 'Continue'-তে ক্লিক করুন (এবং আপনি এটি আর কখনো দেখতে পাবেন না)। একবারের জন্য আসা সেই স্ক্রিনটি দেখতে এইরকম:

ক্লাউড শেল প্রস্তুত করতে এবং এর সাথে সংযোগ স্থাপন করতে মাত্র কয়েক মুহূর্ত সময় লাগা উচিত।

এই ভার্চুয়াল মেশিনটিতে আপনার প্রয়োজনীয় সমস্ত ডেভেলপমেন্ট টুলস লোড করা আছে। এটি একটি স্থায়ী ৫ জিবি হোম ডিরেক্টরি প্রদান করে এবং গুগল ক্লাউডে চলে, যা নেটওয়ার্ক পারফরম্যান্স ও অথেনটিকেশনকে ব্যাপকভাবে উন্নত করে। এই কোডল্যাবে আপনার প্রায় সমস্ত কাজই শুধুমাত্র একটি ব্রাউজার বা আপনার ক্রোমবুক দিয়ে করা সম্ভব।
ক্লাউড শেলে সংযুক্ত হওয়ার পর আপনি দেখতে পাবেন যে, আপনাকে ইতিমধ্যেই প্রমাণীকৃত করা হয়েছে এবং প্রজেক্টটি আপনার প্রজেক্ট আইডিতে সেট করা আছে।
- আপনি প্রমাণীকৃত কিনা তা নিশ্চিত করতে ক্লাউড শেলে নিম্নলিখিত কমান্ডটি চালান:
gcloud auth list
কমান্ড আউটপুট
Credentialed Accounts
ACTIVE ACCOUNT
* <my_account>@<my_domain.com>
To set the active account, run:
$ gcloud config set account `ACCOUNT`
- gcloud কমান্ডটি আপনার প্রজেক্ট সম্পর্কে জানে কিনা তা নিশ্চিত করতে ক্লাউড শেলে নিম্নলিখিত কমান্ডটি চালান:
gcloud config list project
কমান্ড আউটপুট
[core] project = <PROJECT_ID>
যদি তা না থাকে, তবে আপনি এই কমান্ডটি দিয়ে এটি সেট করতে পারেন:
gcloud config set project <PROJECT_ID>
কমান্ড আউটপুট
Updated property [core/project].
৩. ক্লাউড প্রোফাইলার-এ যান
ক্লাউড কনসোলে, বাম দিকের নেভিগেশন বারে 'প্রোফাইলার'-এ ক্লিক করে প্রোফাইলার UI-তে যান:

বিকল্পভাবে, আপনি ক্লাউড কনসোল সার্চ বার ব্যবহার করে প্রোফাইলার UI-তে যেতে পারেন: শুধু "Cloud Profiler" টাইপ করুন এবং খুঁজে পাওয়া আইটেমটি নির্বাচন করুন। উভয় ক্ষেত্রেই, আপনি নীচের মতো "প্রদর্শনের জন্য কোন ডেটা নেই" বার্তা সহ প্রোফাইলার UI দেখতে পাবেন। প্রকল্পটি নতুন, তাই এতে এখনও কোনও প্রোফাইলিং ডেটা সংগ্রহ করা হয়নি।

এখন কোনো কিছুর প্রোফাইল তৈরি করার সময় হয়েছে!
৪. বেঞ্চমার্কের প্রোফাইল তৈরি করুন
আমরা গিটহাবে উপলব্ধ একটি সহজ সিন্থেটিক গো অ্যাপ্লিকেশন ব্যবহার করব। আপনার খোলা থাকা ক্লাউড শেল টার্মিনালে (এবং প্রোফাইলার UI-তে "প্রদর্শনের জন্য কোন ডেটা নেই" বার্তাটি থাকা অবস্থায়), নিম্নলিখিত কমান্ডটি চালান:
$ go get -u github.com/GoogleCloudPlatform/golang-samples/profiler/...
তারপর অ্যাপ্লিকেশন ডিরেক্টরিতে যান:
$ cd ~/gopath/src/github.com/GoogleCloudPlatform/golang-samples/profiler/hotapp
ডিরেক্টরিটিতে 'main.go' ফাইলটি রয়েছে, যেটি একটি সিন্থেটিক অ্যাপ এবং এতে প্রোফাইলিং এজেন্ট সক্রিয় করা আছে:
main.go
...
import (
...
"cloud.google.com/go/profiler"
)
...
func main() {
err := profiler.Start(profiler.Config{
Service: "hotapp-service",
DebugLogging: true,
MutexProfiling: true,
})
if err != nil {
log.Fatalf("failed to start the profiler: %v", err)
}
...
}
প্রোফাইলিং এজেন্ট ডিফল্টরূপে সিপিইউ, হিপ এবং থ্রেড প্রোফাইল সংগ্রহ করে। এখানকার কোডটি মিউটেক্স (যা 'কন্টেনশন' নামেও পরিচিত) প্রোফাইল সংগ্রহ সক্ষম করে।
এখন, প্রোগ্রামটি চালান:
$ go run main.go
প্রোগ্রামটি চলার সময়, প্রোফাইলিং এজেন্ট পর্যায়ক্রমে কনফিগার করা পাঁচটি ধরনের প্রোফাইল সংগ্রহ করবে। এই সংগ্রহ সময়ের সাথে সাথে এলোমেলোভাবে হয় (প্রতিটি ধরনের জন্য প্রতি মিনিটে গড়ে একটি প্রোফাইল হারে), তাই প্রতিটি ধরনের প্রোফাইল সংগ্রহ করতে তিন মিনিট পর্যন্ত সময় লাগতে পারে। প্রোগ্রামটি যখন একটি প্রোফাইল তৈরি করে, তখন আপনাকে জানিয়ে দেয়। উপরের কনফিগারেশনে থাকা DebugLogging ফ্ল্যাগ দ্বারা এই বার্তাগুলো সক্রিয় করা হয়; অন্যথায়, এজেন্টটি নীরবে চলে।
$ go run main.go 2018/03/28 15:10:24 profiler has started 2018/03/28 15:10:57 successfully created profile THREADS 2018/03/28 15:10:57 start uploading profile 2018/03/28 15:11:19 successfully created profile CONTENTION 2018/03/28 15:11:30 start uploading profile 2018/03/28 15:11:40 successfully created profile CPU 2018/03/28 15:11:51 start uploading profile 2018/03/28 15:11:53 successfully created profile CONTENTION 2018/03/28 15:12:03 start uploading profile 2018/03/28 15:12:04 successfully created profile HEAP 2018/03/28 15:12:04 start uploading profile 2018/03/28 15:12:04 successfully created profile THREADS 2018/03/28 15:12:04 start uploading profile 2018/03/28 15:12:25 successfully created profile HEAP 2018/03/28 15:12:25 start uploading profile 2018/03/28 15:12:37 successfully created profile CPU ...
প্রথম প্রোফাইলটি সংগ্রহ করার কিছুক্ষণ পরেই UI নিজে থেকেই আপডেট হয়ে যাবে। এরপর এটি আর স্বয়ংক্রিয়ভাবে আপডেট হবে না, তাই নতুন ডেটা দেখতে হলে আপনাকে ম্যানুয়ালি প্রোফাইলার UI রিফ্রেশ করতে হবে। তা করার জন্য, টাইম ইন্টারভ্যাল পিকারের 'Now' বাটনে দুইবার ক্লিক করুন:

UI রিফ্রেশ হওয়ার পর আপনি এইরকম কিছু দেখতে পাবেন:

প্রোফাইল টাইপ সিলেক্টরটি উপলব্ধ পাঁচটি প্রোফাইল টাইপ দেখায়:

চলুন এখন প্রতিটি প্রোফাইল টাইপ এবং কিছু গুরুত্বপূর্ণ UI বৈশিষ্ট্য পর্যালোচনা করি, এবং তারপর কিছু পরীক্ষা-নিরীক্ষা চালাই। এই পর্যায়ে আপনার আর ক্লাউড শেল টার্মিনালের প্রয়োজন নেই, তাই আপনি CTRL-C চেপে এবং "exit" টাইপ করে এটি থেকে বেরিয়ে যেতে পারেন।
৫. প্রোফাইলার ডেটা বিশ্লেষণ করুন
এখন যেহেতু আমরা কিছু ডেটা সংগ্রহ করেছি, চলুন এটি আরও ঘনিষ্ঠভাবে দেখি। আমরা একটি সিন্থেটিক অ্যাপ ব্যবহার করছি (যার সোর্স গিটহাবে পাওয়া যাবে ) যা প্রোডাকশনে বিভিন্ন ধরণের পারফরম্যান্স সমস্যার সাধারণ আচরণগুলো অনুকরণ করে।
সিপিইউ-নিবিড় কোড
সিপিইউ প্রোফাইল টাইপ নির্বাচন করুন। UI এটি লোড করার পরে, আপনি ফ্লেম গ্রাফে load ফাংশনের জন্য চারটি লিফ ব্লক দেখতে পাবেন, যা সম্মিলিতভাবে সমস্ত সিপিইউ ব্যবহারের হিসাব রাখে:

এই ফাংশনটি একটি টাইট লুপ চালানোর মাধ্যমে প্রচুর সিপিইউ সাইকেল খরচ করার জন্য বিশেষভাবে লেখা হয়েছে:
main.go
func load() {
for i := 0; i < (1 << 20); i++ {
}
}
ফাংশনটি busyloop () থেকে চারটি কল পাথের মাধ্যমে পরোক্ষভাবে কল করা হয়: busyloop → { foo1 , foo2 } → { bar , baz } → load । একটি ফাংশন বক্সের প্রস্থ নির্দিষ্ট কল পাথটির আপেক্ষিক খরচকে নির্দেশ করে। এক্ষেত্রে চারটি পাথেরই খরচ প্রায় একই। একটি বাস্তব প্রোগ্রামে, পারফরম্যান্সের দিক থেকে সবচেয়ে গুরুত্বপূর্ণ কল পাথগুলোকে অপ্টিমাইজ করার দিকে মনোযোগ দেওয়া উচিত। ফ্লেম গ্রাফ, যা বড় বক্সের মাধ্যমে অধিক ব্যয়বহুল পাথগুলোকে দৃশ্যত তুলে ধরে, এই পাথগুলোকে সহজে শনাক্ত করতে সাহায্য করে।
প্রদর্শনকে আরও পরিমার্জিত করতে আপনি প্রোফাইল ডেটা ফিল্টার ব্যবহার করতে পারেন। উদাহরণস্বরূপ, ফিল্টার স্ট্রিং হিসেবে "baz" উল্লেখ করে একটি "Show stacks" ফিল্টার যোগ করার চেষ্টা করুন। আপনি নিচের স্ক্রিনশটের মতো কিছু দেখতে পাবেন, যেখানে load() ফাংশনের চারটি কল পাথের মধ্যে মাত্র দুটি প্রদর্শিত হচ্ছে। এই দুটি পাথই একমাত্র পাথ যা এমন একটি ফাংশনের মধ্য দিয়ে যায় যার নামে "baz" স্ট্রিংটি রয়েছে। এই ধরনের ফিল্টারিং তখন কাজে আসে যখন আপনি একটি বড় প্রোগ্রামের কোনো উপাংশের উপর মনোযোগ দিতে চান (উদাহরণস্বরূপ, কারণ আপনি কেবল এর একটি অংশের মালিক)।

মেমরি-নিবিড় কোড
এখন "হিপ" প্রোফাইল টাইপে পরিবর্তন করুন। আগের পরীক্ষাগুলোতে তৈরি করা যেকোনো ফিল্টার মুছে ফেলতে ভুলবেন না। এখন আপনি একটি ফ্লেম গ্রাফ দেখতে পাবেন যেখানে alloc দ্বারা কল করা allocImpl কে অ্যাপের প্রধান মেমরি ব্যবহারকারী হিসেবে দেখানো হবে:

ফ্লেম গ্রাফের উপরের সারসংক্ষেপ সারণীটি নির্দেশ করে যে অ্যাপটিতে ব্যবহৃত মোট মেমরির পরিমাণ গড়ে প্রায় ৫৭.৪ MiB, যার বেশিরভাগই allocImpl ফাংশন দ্বারা বরাদ্দ করা হয়েছে। এই ফাংশনটির বাস্তবায়ন বিবেচনা করলে এটি আশ্চর্যজনক নয়:
main.go
func allocImpl() {
// Allocate 64 MiB in 64 KiB chunks
for i := 0; i < 64*16; i++ {
mem = append(mem, make([]byte, 64*1024))
}
}
ফাংশনটি একবার চলে এবং ছোট ছোট খণ্ডে ৬৪ MiB মেমরি বরাদ্দ করে। এরপর, গার্বেজ কালেকশন থেকে রক্ষা করার জন্য সেই খণ্ডগুলোর পয়েন্টার একটি গ্লোবাল ভেরিয়েবলে সংরক্ষণ করা হয়। উল্লেখ্য যে, প্রোফাইলার দ্বারা ব্যবহৃত হিসেবে দেখানো মেমরির পরিমাণ ৬৪ MiB থেকে সামান্য ভিন্ন হয়: গো হিপ প্রোফাইলার একটি পরিসংখ্যানগত টুল, তাই এর পরিমাপগুলো লো-ওভারহেড হলেও বাইট-সঠিক নয়। এই ধরনের প্রায় ১০% পার্থক্য দেখলে অবাক হবেন না।
IO-নিবিড় কোড
আপনি যদি প্রোফাইল টাইপ সিলেক্টরে 'থ্রেডস' নির্বাচন করেন, তাহলে ডিসপ্লেটি একটি ফ্লেম গ্রাফে পরিবর্তিত হবে, যার বেশিরভাগ প্রস্থ wait এবং waitImpl ফাংশনগুলো দ্বারা দখল করা থাকবে:

উপরের সারসংক্ষেপ ফ্লেম গ্রাফে আপনি দেখতে পাচ্ছেন যে, ১০০টি গোরুটিন আছে যেগুলো wait ফাংশন থেকে তাদের কল স্ট্যাক বৃদ্ধি করে। এটি একদম সঠিক, কারণ যে কোড এই ওয়েটগুলো শুরু করে তা দেখতে এইরকম:
main.go
func main() {
...
// Simulate some waiting goroutines.
for i := 0; i < 100; i++ {
go wait()
}
প্রোগ্রামটি কোনো অপ্রত্যাশিত সময় অপেক্ষায় (যেমন I/O) ব্যয় করছে কিনা, তা বোঝার জন্য এই প্রোফাইল টাইপটি কার্যকর। এই ধরনের কল স্ট্যাকগুলো সাধারণত সিপিইউ প্রোফাইলার দ্বারা স্যাম্পল করা হয় না, কারণ এগুলো সিপিইউ-এর সময়ের কোনো উল্লেখযোগ্য অংশ ব্যবহার করে না। আপনি প্রায়শই থ্রেডস প্রোফাইলের সাথে "হাইড স্ট্যাকস" ফিল্টার ব্যবহার করতে চাইবেন — উদাহরণস্বরূপ, gopark, কারণ সেগুলো প্রায়শই নিষ্ক্রিয় গোরুটিন এবং I/O-এর জন্য অপেক্ষারতগুলোর চেয়ে কম গুরুত্বপূর্ণ।
থ্রেড প্রোফাইল টাইপটি প্রোগ্রামের সেইসব স্থান শনাক্ত করতেও সাহায্য করতে পারে যেখানে থ্রেডগুলো দীর্ঘ সময়ের জন্য প্রোগ্রামের অন্য কোনো অংশের মালিকানাধীন একটি মিউটেক্সের জন্য অপেক্ষা করছে, কিন্তু সেই কাজের জন্য নিম্নলিখিত প্রোফাইল টাইপটি আরও বেশি উপযোগী।
বিতর্ক-নিবিড় কোড
কনটেনশন প্রোফাইল টাইপটি প্রোগ্রামের সবচেয়ে "চাহিদাসম্পন্ন" লকগুলোকে শনাক্ত করে। এই প্রোফাইল টাইপটি Go প্রোগ্রামের জন্য উপলব্ধ, কিন্তু এজেন্ট কনফিগারেশন কোডে " MutexProfiling: true " উল্লেখ করে এটিকে অবশ্যই স্পষ্টভাবে সক্রিয় করতে হবে। এই সংগ্রহটি "Contentions" মেট্রিকের অধীনে রেকর্ড করে যে, কতবার একটি নির্দিষ্ট লক, যখন একটি গোরুটিন A দ্বারা আনলক করা হচ্ছিল, তখন অন্য একটি গোরুটিন B সেই লকটি আনলক হওয়ার জন্য অপেক্ষা করছিল। এটি "Delay" মেট্রিকের অধীনে আরও রেকর্ড করে যে, ব্লক হয়ে থাকা গোরুটিনটি লকটির জন্য কতক্ষণ অপেক্ষা করেছিল। এই উদাহরণে, একটিমাত্র কনটেনশন স্ট্যাক রয়েছে এবং লকটির জন্য মোট অপেক্ষার সময় ছিল ১০.৫ সেকেন্ড।

যে কোডটি এই প্রোফাইলটি তৈরি করে, তাতে ৪টি গোরুটিন একটি মিউটেক্স নিয়ে নিজেদের মধ্যে লড়াই করে:
main.go
func contention(d time.Duration) {
contentionImpl(d)
}
func contentionImpl(d time.Duration) {
for {
mu.Lock()
time.Sleep(d)
mu.Unlock()
}
}
...
func main() {
...
for i := 0; i < 4; i++ {
go contention(time.Duration(i) * 50 * time.Millisecond)
}
}
৬. সারসংক্ষেপ
এই ল্যাবে, আপনি শিখেছেন কিভাবে ক্লাউড প্রোফাইলারের সাথে ব্যবহারের জন্য একটি গো প্রোগ্রাম কনফিগার করা যায়। আপনি আরও শিখেছেন কিভাবে এই টুলটি দিয়ে পারফরম্যান্স ডেটা সংগ্রহ, দেখা এবং বিশ্লেষণ করতে হয়। এখন আপনি আপনার এই নতুন দক্ষতা গুগল ক্লাউড প্ল্যাটফর্মে চালানো বাস্তব পরিষেবাগুলিতে প্রয়োগ করতে পারেন।
৭. অভিনন্দন!
আপনি ক্লাউড প্রোফাইলার কনফিগার এবং ব্যবহার করতে শিখেছেন!
আরও জানুন
- ক্লাউড প্রোফাইলার: https://cloud.google.com/profiler/
- ক্লাউড প্রোফাইলার যে গো রানটাইম/পিপ্রফ প্যাকেজটি ব্যবহার করে: https://golang.org/pkg/runtime/pprof/
লাইসেন্স
এই কাজটি ক্রিয়েটিভ কমন্স অ্যাট্রিবিউশন ২.০ জেনেরিক লাইসেন্সের অধীনে রয়েছে।