paint-brush
স্কেলিং PostgreSQL: কিভাবে আমরা 10 বিলিয়ন দৈনিক রেকর্ড এবং 350 TB+ ডেটা টেমড করেছিদ্বারা@timescale
9,713 পড়া
9,713 পড়া

স্কেলিং PostgreSQL: কিভাবে আমরা 10 বিলিয়ন দৈনিক রেকর্ড এবং 350 TB+ ডেটা টেমড করেছি

দ্বারা Timescale18m2023/11/06
Read on Terminal Reader

অতিদীর্ঘ; পড়তে

কোম্পানি "অন্তর্দৃষ্টি" তৈরি করার জন্য একটি উল্লেখযোগ্য ডগফুডিং প্রচেষ্টা শুরু করেছে, ব্যবহারকারীদের ক্যোয়ারী কর্মক্ষমতা বিশ্লেষণ করার জন্য একটি টুল। তারা সমস্ত গ্রাহক ডাটাবেস থেকে ক্যোয়ারী পরিসংখ্যান সংগ্রহ করেছে, যার মোট 1 ট্রিলিয়ন রেকর্ড রয়েছে স্বতন্ত্র প্রশ্ন সম্পর্কে। প্রতিদিন 10 বিলিয়নেরও বেশি নতুন রেকর্ডের সাথে, একটি একক টাইমস্কেল পরিষেবা দ্বারা পরিবেশিত ডেটাসেট 350 টিবি অতিক্রম করে৷ তারা মূলে TimescaleDB ব্যবহার করে, যা বিশাল ডেটা পরিচালনা করার জন্য একটি PostgreSQL এক্সটেনশন। ডাটাবেস অবজারভেবিলিটি টুল, ইনসাইটস, ব্যবহারকারীদের কম পারফর্মিং কোয়েরি খোঁজার জন্য বিভিন্ন মেট্রিক্সের সাথে সম্পর্কযুক্ত করে। এই বিশাল ডেটাসেটটি পরিচালনা করার জন্য PostgreSQL স্কেল করার জন্য, তারা ক্রমাগত সমষ্টি, হাইপারটেবল এবং ডেটা টিয়ারিং ব্যবহার করেছিল। টাইমস্কেলের কলামার কম্প্রেশন 20x পর্যন্ত কম্প্রেশন হার অর্জন করেছে। তারা নমনীয়তার জন্য আনুমানিক স্কিমা পরিবর্তনযোগ্যতার মতো বৈশিষ্ট্যগুলিও ব্যবহার করেছে। প্রক্রিয়াটি সফল হওয়ার সময়, তারা উন্নত ডাটাবেস পর্যবেক্ষণযোগ্যতা এবং বড় ডেটা আপডেটগুলি পরিচালনা সহ উন্নতির জন্য ক্ষেত্রগুলি চিহ্নিত করেছিল। তারা স্কিমা পরিবর্তন করার সময়, নতুন সূচী যোগ করার বা স্কেলে ক্রমাগত সমষ্টি আপডেট করার সময় মুখোমুখি হওয়া চ্যালেঞ্জগুলিকে হাইলাইট করেছে। তবুও, এই অভিজ্ঞতাটি স্কেল এ টাইমস্কেল ব্যবহার করা গ্রাহকদের জন্য অমূল্য অন্তর্দৃষ্টি এবং সহানুভূতি প্রদান করেছে। সামগ্রিকভাবে, এই নিবন্ধটি "অন্তর্দৃষ্টি" তৈরি করতে TimescaleDB-এর সাথে PostgreSQL স্কেলিং করার ক্ষেত্রে কোম্পানির যাত্রার বিশদ বিবরণ দেয়, প্রযুক্তিগত চ্যালেঞ্জগুলি মোকাবেলা করার সময় এবং ভবিষ্যতের উন্নতির সুযোগগুলিকে স্বীকৃতি দেওয়ার সময় গ্রাহকদের জন্য রিয়েল-টাইম ডাটাবেস পর্যবেক্ষণযোগ্যতা প্রদান করে।
featured image - স্কেলিং PostgreSQL: কিভাবে আমরা 10 বিলিয়ন দৈনিক রেকর্ড এবং 350 TB+ ডেটা টেমড করেছি
Timescale HackerNoon profile picture


এই বছরের শুরুতে, আমরা আমাদের কোম্পানির সবচেয়ে বড় যাত্রা শুরু করেছি ডগফুডিং প্রচেষ্টা কখনও গঠন করা অন্তর্দৃষ্টি , একটি টুল যা আমাদের ব্যবহারকারীদের টাইমস্কেল প্ল্যাটফর্মের মধ্যে তাদের ক্যোয়ারী কর্মক্ষমতা বিশ্লেষণ করতে দেয়, আমরা আমাদের সমস্ত গ্রাহকদের ডেটাবেস জুড়ে ক্যোয়ারী পরিসংখ্যান সংগ্রহ করার চেষ্টা করেছি, যার মধ্যে প্রতিটি প্রশ্নের সাথে সম্পর্কিত সময়, CPU, মেমরি ব্যবহার এবং ডিস্ক I/O। আমাদের এমন একটি ডাটাবেসের প্রয়োজন ছিল যা প্রচুর পরিমাণে ডেটা পরিচালনা করতে পারে, শক্তিশালী বিশ্লেষণাত্মক ক্ষমতা ছিল (বিশেষত সময়ের সাথে বিশ্লেষণের জন্য), এবং একটি অপারেশনাল বোঝা হয়ে উঠবে না।


স্বাভাবিকভাবেই, আমরা টাইমস্কেল বাছাই করেছি, আমাদের পরিপক্ক ক্লাউড প্ল্যাটফর্ম টাইমস্কেলডিবি এর মূল অংশে। আমরা PostgreSQL এর সাথে কাজ করতে অভ্যস্ত, এবং PostgreSQL কে আরও দ্রুত এবং আরও মাপযোগ্য করার জন্য আমরা TimescaleDB তৈরি করেছি—আমাদের নিজের উদাহরণে বেঁচে থাকার চেয়ে ভাল আর কি?


এই ডগফুডিং পরীক্ষাটি বর্ণনা করার সবচেয়ে সহজ উপায় হল সংখ্যাগুলি যা এর স্কেল পরিমাপ করতে সাহায্য করে৷ অন্তর্দৃষ্টি তৈরি করতে, আমাদের ক্রমাগত চলমান উত্পাদন ডেটাবেসগুলির বহরে অনুসন্ধানের তথ্য সংগ্রহ করতে হবে৷ আমরা প্ল্যাটফর্মে ব্যক্তিগত (স্যানিটাইজড) প্রশ্নগুলির বিষয়ে দ্রুত 1 ট্রিলিয়নেরও বেশি রেকর্ড সংগ্রহ করেছি।


এখন যেহেতু অন্তর্দৃষ্টি লাইভ প্রোডাকশনে রয়েছে, আমরা প্রতিদিন 10 বিলিয়নের বেশি নতুন রেকর্ড গ্রহণ করছি৷ একটি একক টাইমস্কেল পরিষেবা দ্বারা পরিবেশিত ডেটাসেট প্রতিদিন প্রায় 3 টিবি বৃদ্ধি পায় এবং বর্তমানে মোট 350 টিবি- র বেশি, এবং একই ডেটাবেস পরিষেবা আমাদের সমস্ত গ্রাহকদের রিয়েল-টাইম ড্যাশবোর্ডগুলিকে ক্ষমতা দেয়৷


এই ব্লগ পোস্টটি অন্তর্দৃষ্টি তৈরির প্রক্রিয়ার মধ্যে একটি পর্দার আড়ালে উঁকি দেয়৷ এই স্কেলে কাজ করার অর্থ হল একটি একক টাইমস্কেল পরিষেবার সীমা ঠেলে দেওয়া, এবং শুধুমাত্র PostgreSQL নয় আমাদের ডেভেলপার সহানুভূতিও স্কেলিং করা। আমরা টাইমস্কেল টাস্কের চেয়ে বেশি খুঁজে পেয়েছি, কিন্তু এমন কিছু ক্ষেত্রও রয়েছে যা আমরা উন্নত করতে চাই!


আমাদের পুরো ফ্লিটের প্রশ্নগুলি বিশ্লেষণ করতে PostgreSQL স্কেলিং

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



ইনসাইটস ক্যোয়ারী লেটেন্সি, CPU, মেমরি, I/O, শেয়ার করা বাফার এবং অন্যান্য মেট্রিক্সের সমস্ত টাইমস্কেল ডাটাবেস জুড়ে তথ্য সংগ্রহ করে, প্রতিদিন কোটি কোটি রেকর্ড ইনজেস্ট করে। এই গ্রাহক-মুখী ড্যাশবোর্ডগুলি টাইমস্কেল প্ল্যাটফর্মে চলমান একটি স্ট্যান্ডার্ড ডাটাবেস পরিষেবা দ্বারা চালিত।



অন্তর্দৃষ্টিগুলি ঘটানোর জন্য, আমাদের ডাটাবেস অ্যাডমিনিস্ট্রেটর হ্যাট লাগাতে হয়েছিল 🤠 এবং PostgreSQL-কে অনেক টেরাবাইট ডেটা স্কেল করার জন্য কয়েকটি প্রযুক্তিগত চ্যালেঞ্জ মোকাবেলা করতে হয়েছিল। আমরা আমাদের কেন্দ্রীয় ডাটাবেস হিসাবে একটি টাইমস্কেল পরিষেবা ব্যবহার করতে চেয়েছিলাম, আমাদের প্ল্যাটফর্মে কোনও "বিশেষ" অবকাঠামো ছাড়াই হোস্ট করা হয়েছে৷ এর অর্থ নিম্নোক্ত:


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


  • আমাদের গ্রাহকদের অন্তর্দৃষ্টি অফার করে এমন সমস্ত বিশ্লেষণকে শক্তি দেওয়ার নমনীয়তার সাথে এই ডাটাবেসটি জিজ্ঞাসা করতে সক্ষম হতে হয়েছিল এবং আমরা তাদের প্রতিক্রিয়ার জন্য মিনিট অপেক্ষা করতে চাইনি!


  • আমাদের একটি একক টাইমস্কেল পরিষেবাতে শত শত টিবি সঞ্চয় করার প্রয়োজন ছিল যেহেতু আমরা প্রতিদিন বেশ কয়েকটি টিবি যুক্ত করছি। পুরানো ডেটা (অর্থাৎ, কয়েক সপ্তাহের বেশি পুরানো) অ্যাক্সেসযোগ্য হওয়া প্রয়োজন, কিন্তু কোয়েরির জন্য দ্রুত নয়।


আমরা কীভাবে এটি তৈরি করেছি: একটি (বিশাল) ডেটাবেসের সাথে রিয়েল-টাইম অ্যানালিটিক্সকে শক্তিশালী করা

প্রচুর ডেটা সংগ্রহ এবং লেখা

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


হ্যান্ড-ওয়েভিনেসকে ক্ষমা করুন যা কিছু নিম্ন-স্তরের রক্তাক্ত বিবরণ এড়িয়ে যায়, কিন্তু বিস্তৃত পরিভাষায়, জিনিসগুলি এইভাবে কাজ করে: ফ্লিট জুড়ে চলমান প্রতিটি ডাটাবেস প্রতিটি প্রশ্নের পরে একটি রেকর্ড (গোপনীয়তা এবং সুরক্ষার জন্য স্যানিটাইজড) তৈরি করার জন্য উপকরণ তৈরি করা হয়, যার মধ্যে রয়েছে প্রশ্ন নিজেই এবং পরিসংখ্যান আমরা যত্ন.


এই রেকর্ডগুলি নোড স্তরে সংগ্রহ করা হয়, লেবেলগুলির সাথে ট্যাগ করা হয় যাতে তারা কোন ডাটাবেস পরিষেবা থেকে এসেছে তার সাথে যুক্ত থাকে এবং আঞ্চলিক লেখকের কাছে পাঠানোর জন্য ব্যাচ করা হয়। আঞ্চলিক লেখক পরিষেবা প্রতিটি অঞ্চলে লোড পরিচালনা করার জন্য প্রয়োজনীয় হিসাবে প্রতিলিপি করা হয়। প্রতিটি লেখক প্রতিটি ক্লাস্টারের নোড থেকে ব্যাচ সংগ্রহ করে এবং আরও বড় ব্যাচ তৈরি করে।


সেই বড় ব্যাচগুলি প্রথমে `COPY` ব্যবহার করে একটি অস্থায়ী টেবিলে লেখা হয় (কোনও লিখতে-আগে লগিং = দ্রুত)। সেই অস্থায়ী টেবিলের এন্ট্রিগুলি প্রয়োজনীয় টেবিল আপডেট করতে ব্যবহার করা হয় (নীচে দেখুন)। অস্থায়ী সারণীটি আমাদের অনুলিপি সম্পর্কে চিন্তা না করেই `COPY` ব্যবহার করার অনুমতি দেয়, যা পরবর্তী ক্রিয়াকলাপগুলি অস্থায়ী টেবিল থেকে রেকর্ডগুলি মুং করে পরিচালনা করে।


সারসংক্ষেপ:


  • আমাদের বিভিন্ন ভৌগোলিক অঞ্চলে k8s ক্লাস্টার রয়েছে। এই অঞ্চলগুলির ভিতরে নোড রয়েছে যা এক বা একাধিক গ্রাহক ডাটাবেস চালায়।
  • গ্রাহক ডাটাবেস থেকে স্যানিটাইজড ক্যোয়ারী পরিসংখ্যান সংগ্রহ করা হয় এবং ব্যাচ করা হয় (অঞ্চলের ভিতরে)।
  • পর্যাপ্ত সংখ্যক ইভেন্ট হয়ে গেলে, সেগুলি আমাদের কেন্দ্রীয় টাইমস্কেল ডাটাবেস পরিষেবাতে পাঠানো হয়।


আসুন ডাটাবেসের মধ্যে জুম করি যা অন্তর্দৃষ্টিকে শক্তিশালী করে। আমরা একটি "অফ-দ্য-শেল্ফ" টাইমস্কেল পরিষেবার সাথে অন্তর্দৃষ্টি চালাচ্ছি উচ্চ প্রাপ্যতা প্রতিরূপ , যা রিড-স্কেলিংয়ের জন্যও ব্যবহার করা হয় (পরে আরও বেশি)। "অফ-দ্য-শেল্ফ" দ্বারা আমরা বলতে চাচ্ছি যে আমরা আমাদের গ্রাহকদের কাছে উপলব্ধ (বা শীঘ্রই উপলব্ধ 😉) একই বৈশিষ্ট্যগুলি ব্যবহার করছি৷ কোনো বিশেষ কালো জাদু নেই কারণ আমরা অবকাঠামো নিয়ন্ত্রণও করি।


ডাটাবেস পাওয়ারিং ইনসাইটের বেশ কয়েকটি অংশ রয়েছে, তবে আমরা সবচেয়ে গুরুত্বপূর্ণগুলি হাইলাইট করার চেষ্টা করব।


প্রথমত, আমাদের দুটি নিয়মিত PostgreSQL টেবিল রয়েছে যা "রেফারেন্স টেবিল" হিসাবে কাজ করে। এই টেবিলে তথ্য ডাটাবেস মেটাডেটা এবং ক্যোয়ারী স্ট্রিং মেটাডেটা রয়েছে। এখানে তাদের (ছদ্ম) স্কিমা রয়েছে:



ডাটাবেস মেটাডেটা


 Table "insights.cloud_db" Column | Type | Collation | Nullable | Default ---------------+--------------------------+-----------+----------+-------------------------------------- id | bigint | | not null | nextval('cloud_db_id_seq'::regclass) service_id | text | | not null | project_id | text | | not null | created | timestamp with time zone | | not null | now() Indexes: "cloud_db_pkey" PRIMARY KEY, btree (id) "cloud_db_project_id_service_id_key" UNIQUE CONSTRAINT, btree (project_id, service_id)



মেটাডেটা জিজ্ঞাসা করুন


 Table "insights.queries" Column | Type | Collation | Nullable | Default ---------------+--------------------------+-----------+----------+-------------------------------------- hash | text | | not null | normalized_query | text | | not null | created | timestamp with time zone | | not null | now() Indexes: "queries_pkey" PRIMARY KEY, btree (hash)



যে কোনো সময় একটি নতুন ডাটাবেসের বিরুদ্ধে প্রশ্ন চালানো শুরু হলে, এটি `insights.cloud_db`-এ যোগ করা হবে। যে কোনো সময় একটি নতুন স্বাভাবিক ক্যোয়ারী চালানো হয়, এটি `insights.queries`-এ যোগ করা হবে।


(একটি স্বাভাবিক প্রশ্ন কী? এটি এমন একটি প্রশ্ন যেখানে সমস্ত ধ্রুবক স্থানধারকগুলির সাথে প্রতিস্থাপিত হয়েছে: প্রথমটির জন্য $1, দ্বিতীয়টির জন্য $2, এবং আরও অনেক কিছু, তাই আমরা কেবলমাত্র ক্যোয়ারীটির "আকৃতি" দেখতে পাই, এর মান নয় .)


এই মুহুর্তে, আমরা কোন টাইমস্কেল গোপন সস ছাড়াই নিয়মিত পোস্টগ্রেস ব্যবহার করছি। কিন্তু ডাটাবেসের অন্যান্য গুরুত্বপূর্ণ বস্তুগুলি TimescaleDB-এর জন্য অনন্য, যা PostgreSQL কে অন্য স্তরে স্কেল করতে সাহায্য করে। এখানেই যাদুটি ঘটে: হাইপারটেবল এবং ক্রমাগত সমষ্টি।


  • হাইপারটেবল হল টাইমস্কেলের স্বয়ংক্রিয়ভাবে বিভাজিত টেবিল। তারা স্বয়ংক্রিয়ভাবে ডেটাকে একটি মাত্রা দ্বারা বিভাজন করে যখন এটি গ্রহণ করা হয়, এটি PostgreSQL টেবিলগুলিকে বড় স্কেল পর্যন্ত স্কেল করা আরও সহজ করে তোলে। হাইপারটেবল হল টাইমস্কেলের বিল্ডিং ব্লক। আমরা আমাদের ক্যোয়ারী পরিসংখ্যান মেট্রিকগুলিকে একটি বিশাল হাইপারটেবলে সংরক্ষণ করছি, যেমনটি আমরা পরে দেখব৷


  • ক্রমাগত সমষ্টি হল PostgreSQL ম্যাটেরিয়ালাইজড ভিউগুলির টাইমস্কেলের উন্নত সংস্করণ, যা ক্রমবর্ধমান এবং স্বয়ংক্রিয় বস্তুগতকরণের অনুমতি দেয়, যা অন্তর্দৃষ্টি তৈরি করার সময় খুব কার্যকর প্রমাণিত হয়েছিল।


আসুন আমরা ব্যবহারকারীদের পক্ষে দ্রুত বিশ্লেষণাত্মক প্রশ্নগুলি সক্ষম করতে এই বৈশিষ্ট্যগুলি কীভাবে ব্যবহার করেছি তা কভার করি।


পাওয়ারিং (দ্রুত) রিয়েল-টাইম বিশ্লেষণ

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


 Table "insights.records" Column | Type | Collation | Nullable | Default -----------------------------+--------------------------+-----------+----------+--------- cloud_db_id | bigint | | not null | query_hash | text | | | created | timestamp with time zone | | not null | total_time | bigint | | | rows | bigint | | | ...


আমরা এই উদাহরণের জন্য একগুচ্ছ পরিসংখ্যান বাদ দিয়েছি, কিন্তু আপনি ধারণা পেয়েছেন।


এখন, আমাদের ব্যবহারকারীর দিক থেকে দ্রুত প্রশ্নের অনুমতি দিতে হবে-কিন্তু এই টেবিলটি বিশাল। জিনিসগুলিকে গতি বাড়ানোর জন্য, আমরা ক্রমাগত সমষ্টির উপর খুব বেশি নির্ভর করেছি (ব্যবহার করে অনুক্রমিক ক্রমাগত সমষ্টি , সঠিক হবে).


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


সুতরাং, আমরা এই সত্যটির সুবিধাও নিতে পারি যে আমরা ব্যবহারকারীদের কাছে কাঁচা পৃথক রেকর্ড দেখাচ্ছি না এবং ফলাফলটি রাখি বস্তুগত দ্রুত প্রতিক্রিয়ার জন্য। গ্রাহকদের জন্য, এর অর্থ অন্তর্দৃষ্টি ব্যবহার করার সময় স্পষ্টতা একটি ছোট ট্রেড-অফ (অর্থাৎ, তারা সেকেন্ড থেকে সঠিক সময়সীমা পেতে পারে না), কিন্তু এটি প্রদান করার জন্য একটি খুব যুক্তিসঙ্গত মূল্য।


আমরা PostgreSQL বস্তুগত দৃষ্টিভঙ্গি ব্যবহার করতে পারতাম, কিন্তু Timescale-এর ক্রমাগত সমষ্টির বেশ কিছু সুবিধা রয়েছে যা আমাদের জন্য বিশেষভাবে উপযোগী ছিল। আমরা ভিউগুলিকে অনেক বেশি রিফ্রেশ করি, এবং ক্রমাগত সমষ্টিতে স্বয়ংক্রিয় রিফ্রেশের জন্য অন্তর্নির্মিত নীতি রয়েছে এবং সেগুলি ক্রমবর্ধমানভাবে রিফ্রেশ করে।


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


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


তারপরও, একটি নির্দিষ্ট সময়ে, ডাটাবেস এই সমস্ত কাঁচা রেকর্ড সন্নিবেশ করার জন্য অনেক কাজ করতে শুরু করে এবং তারপর সেগুলি পরিবেশনের জন্য বাস্তবায়িত করে। আমরা কতটা গ্রহণ করতে পারি এবং বজায় রাখতে পারি তার উপর আমরা কিছু সীমাবদ্ধতাকে আঘাত করছিলাম।


আমাদের প্রয়োজনীয় স্তরে আমাদের ইনজেশন রেট আরও বাড়ানোর জন্য, আমরা ডাটাবেস থেকে অঞ্চল লেখকদের কাছে UDDSketch জেনারেশন অফলোড করেছি। এখন, আমরা এখনও কিছু পরিমাণ রেকর্ড "কাঁচা" রেকর্ড হিসাবে সঞ্চয় করি, তবে আমরা বাকিগুলিকে প্রাক-উত্পন্ন স্কেচগুলিতে পুশ করি যা আমরা ডাটাবেসে সংরক্ষণ করি:



 Table "insights.sketches" Column | Type | Collation | Nullable | Default -----------------------------+--------------------------+-----------+----------+--------- cloud_db_id | bigint | | not null | query_hash | text | | | created | timestamp with time zone | | not null | total_time_dist | uddsketch | | | rows_dist | uddsketch | | | ...



UDDSketchs-এর সবচেয়ে ভালো অংশ হল যে বৃহত্তর সময়সীমাকে সমর্থন করার জন্য স্কেচগুলিকে ক্রমাগত "রোল আপ" করা খুব সহজ। এই ধরনের একটি রোলআপ ব্যবহার করে, যে স্কেচগুলি সংকীর্ণ সময়ের ব্যাপ্তিগুলিকে কভার করে সেগুলিকে একটি স্কেচে একত্রিত করা যেতে পারে যা একটি বিস্তৃত সময় সীমাকে কভার করে, একটি শ্রেণীবদ্ধ ক্রমাগত সমষ্টি তৈরি করার সময় এবং অনুসন্ধানের সময় উভয় ক্ষেত্রেই।


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


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


একটি একক টাইমস্কেল উদাহরণে শত শত টিবি সংরক্ষণ করা

অবশেষে, আমাদের একক টাইমস্কেল পরিষেবাতে শত শত টিবিকে আরামদায়কভাবে ফিট করতে হবে। ইনসাইটস ডাটাবেস দ্রুত স্কেল হচ্ছে: যখন আমরা শুরু করেছিলাম তখন এটি 100 টিবি অর্ডারে ছিল এবং এটি এখন 350 টিবি (এবং গণনা) এর বেশি।


এত ডেটা দক্ষতার সাথে সংরক্ষণ করার জন্য, আমরা সক্ষম করেছি টাইমস্কেল এর কলামার কম্প্রেশন আমাদের হাইপারটেবিলে এবং আমাদের সমস্ত ক্রমাগত সমষ্টিতে (হ্যাঁ, আপনি ক্রমাগত সমষ্টিগুলিকেও সংকুচিত করতে পারেন কারণ সেগুলি মূলত চাইল্ড হাইপারটেবল!) আমরা আমাদের কম্প্রেশন রেটগুলিকেও ডায়াল করেছি—দলটি সর্বোপরি, কম্প্রেশন অপ্টিমাইজ করার বিষয়ে বেশ কিছু জিনিস জানে৷


আমরা আমাদের প্রধান হাইপারটেবিলে 20x কম্প্রেশন হারের উপরে প্রত্যক্ষ করছি।


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


আমরা টাইমস্কেলের ডেটা টাইয়ারিংয়ের ভারী ব্যবহারকারী। এই বৈশিষ্ট্যটি এই বছরের শুরুর দিকে প্রবেশ করানো হয়েছে (শীঘ্রই GA সংবাদের জন্য অপেক্ষা করুন 🔥) এবং আমাদের টাইমস্কেল ডাটাবেসের মাধ্যমে শত শত টিবি অ্যাক্সেসযোগ্য রাখার অনুমতি দেয়। ডেটা টিয়ারিংও অত্যন্ত দক্ষ প্রমাণিত হয়েছে: আমরা এখানেও আশ্চর্যজনক কম্প্রেশন রেট দেখতে পাচ্ছি, 130 টিবি একটি অত্যন্ত সম্পদ-দক্ষ 5 টিবিতে সঙ্কুচিত হচ্ছে।


টাইমস্কেল ব্যবহার করে একটি 350 TB+ PostgreSQL ডেটাবেস স্কেল করা: পাঠ শিখেছি

অন্তর্দৃষ্টি তৈরির প্রক্রিয়াটি আমাদের দেখিয়েছিল যে আমাদের পণ্য আসলে কতদূর যেতে পারে, কিন্তু সবচেয়ে ভাল জিনিসটি ছিল আমাদের গ্রাহকদের জুতাতে কয়েক মাইল হাঁটা। আমরা Timescale এর সাথে PostgreSQL স্কেলিং করার ব্যবহারকারীর অভিজ্ঞতা সম্পর্কে অনেক কিছু শিখেছি, এবং পণ্যটির পিছনে প্রকৌশলী হিসাবে আমরা আমাদের করণীয় তালিকায় কিছু জিনিস যোগ করেছি।


আসুন এটির মধ্য দিয়ে যাই: ভাল এবং তাই।

টাইমস্কেল হাইলাইট

  • আমাদের অশালীনতা ক্ষমা করুন, কিন্তু আমরা মাঝে মাঝে আমাদের পণ্যের জন্য বেশ গর্বিত বোধ করেছি। ইতিমধ্যে শত শত টিবি সহ একটি একক PostgreSQL ডাটাবেসে প্রতিদিন কয়েক বিলিয়ন রেকর্ড গ্রহণ করা হাঁচি দেওয়ার মতো কিছু নয়৷ ডাটাবেসটি র‍্যাম্পিং শুরু করার সময় আমরা কয়েক সপ্তাহ টিউনিং করেছি, কিন্তু এখন এটি বেবিসিটিং বা অবিরাম পর্যবেক্ষণ ছাড়াই কাজ করে । (মনে রাখবেন যে এটি নিরীক্ষণ করা থেকে আলাদা, এটি অবশ্যই পর্যবেক্ষণ করা হয়!)


  • আমাদের অনুসন্ধানকারী ভিউ এই প্রক্রিয়ায় গুরুত্বপূর্ণ ছিল, মূল্যবান অন্তর্দৃষ্টি প্রদান করে এবং কর্মক্ষমতা অপ্টিমাইজ করার জন্য সহজ কনফিগারেশন পরিবর্তনের অনুমতি দেয়, উদাহরণস্বরূপ, যখন খণ্ড (পার্টিশন) আকার অপ্টিমাইজ করা হয়।


  • কম্প্রেশন আমাদের জন্য খুব ভাল কাজ করেছে. যেমন আমরা পূর্ববর্তী বিভাগে শেয়ার করেছি, আমরা একটি সাধারণ একক `সেগমেন্টবাই` বিকল্প ব্যবহার করে চিত্তাকর্ষক কম্প্রেশন রেট (20x!) পেয়েছি। আমাদের জন্য, নীতি সেট আপ এবং সামঞ্জস্য করার অভিজ্ঞতা কঠিন ছিল না—যদিও, অবশ্যই, আমরা এই বৈশিষ্ট্যটি তৈরি করেছি...কেউ বলতে পারে আমাদের সামান্য প্রান্ত আছে। 🙂 এছাড়াও, সংকুচিত ডেটাতে নির্বিঘ্নে নতুন কলাম যুক্ত করার ক্ষমতা আমাদের ডাটাবেসের নমনীয়তা এবং অভিযোজনযোগ্যতাকে আরও উন্নত করেছে। আমরা জটিলতা ছাড়াই এই ক্ষমতা ব্যবহার করেছি।


  • ক্রমাগত সমষ্টি বিভিন্ন সময়কাল নির্মাণ, তথ্য বিশ্লেষণ এবং প্রক্রিয়াকরণ স্ট্রিমলাইন করার যুক্তিকে সরলীকৃত করে। আমরা টন শ্রেণীবদ্ধ ক্রমাগত সমষ্টি ব্যবহার করেছি।


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


  • একটি টাইমস্কেল ডাটাবেস ডেটা টায়ারের মাধ্যমে যে "অসীম" উষ্ণ সঞ্চয়স্থানে রয়েছে তা 100 টিবিতে স্কেল করার জন্য গুরুত্বপূর্ণ ছিল, যেখানে প্রচুর হেডরুম রয়েছে। আমাদের বর্তমান __ ডেটা টিয়ারিং নীতি __ হট স্টোরেজে তিন সপ্তাহের রেকর্ড ধরে রাখে।


অবশেষে, আমরা পর্যবেক্ষণযোগ্যতা বাড়ানোর জন্য কাস্টম কাজ তৈরি করার ক্ষমতা ব্যবহার করেছি (যেমন চাকরির ইতিহাস পর্যবেক্ষণ) এবং পরীক্ষামূলক রিফ্রেশ কৌশলগুলি বাস্তবায়ন করেছি।


উন্নতির সুযোগ (আমরা নোট করেছি)

আপনাকে সমস্ত দুর্দান্ত জিনিসগুলি বলার পরে, এত-মহান জিনিসগুলিকে স্বীকার করার সময় এসেছে। টাইমস্কেল সহ কিছুই নিখুঁত নয়। আমাদের পাইপলাইন বাস্তবায়নের সময় আমরা কয়েকটি চ্যালেঞ্জের সম্মুখীন হয়েছি, এবং আমরা এগুলোকে অভিযোগ বলতে চাই না:


টাইমস্কেল প্ল্যাটফর্মে ডেটাবেস পর্যবেক্ষণযোগ্যতা উন্নত করা যেতে পারে, বিশেষ করে চাকরির আশেপাশে এবং ক্রমাগত সমষ্টির বস্তুগতকরণের কর্মক্ষমতা।


TimescaleDB বেশিরভাগ স্ন্যাপশট-ভিত্তিক ভিউ প্রদান করে, যা সময়ের সাথে পারফরম্যান্স এবং প্রবণতা বোঝা চ্যালেঞ্জিং করে তোলে। উদাহরণ স্বরূপ, কোন আউট-অফ-দ্য-বক্স "চাকরীর ইতিহাস" টেবিল উপলব্ধ নেই। প্রথম দিকে, আমরা লক্ষ্য করেছি যে আমাদের ক্রমাগত সমষ্টির ক্রমবর্ধমান বস্তুগতীকরণ আপাতদৃষ্টিতে দীর্ঘ এবং দীর্ঘ সময় নিচ্ছে-অবশেষে একটি বাগ আবিষ্কারের দিকে পরিচালিত করে-কিন্তু আমাদের সুযোগ নিশ্চিত করার বা পরিমাপ করার কোন উপায় ছিল না।


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


যখন অন্তর্নিহিত ডেটা বড় হয় তখন ক্রমাগত সমষ্টিগুলি সঠিক হওয়া কঠিন হতে পারে


ক্রমাগত সমষ্টি তৈরি করার সময় `__ কোনো ডেটা ছাড়া` বিকল্পটি ব্যবহার করা __ একটি জীবন রক্ষাকারী। রিফ্রেশ নীতির জন্য আপনার অফসেটগুলির সাথে বুদ্ধিমান হওয়াও গুরুত্বপূর্ণ, যাতে আপনি যে পরিমাণ ডেটা ক্রমাগতভাবে রিফ্রেশ করছেন তা দুর্ঘটনাক্রমে খুব বড় না হয়ে যায়।


এমনকি আপনি যদি এই পরামর্শটি অনুসরণ করেন, তবুও আপনি একটি ক্রমাগত সমষ্টির সাথে শেষ করতে পারেন যা আপনি যে পরিমাণ ডেটা বাস্তবায়িত করার চেষ্টা করছেন তার থেকে রিফ্রেশ হতে বেশি সময় নেয়, যেমন, 15 মিনিটের ডেটা বাস্তবায়িত করতে 30 মিনিট সময় নেয়। এটি ঘটে কারণ, কখনও কখনও, ক্রমাগত সমষ্টিগত অন্তর্নিহিত কাজটি মেমরিতে ফিট করার জন্য খুব বড় এবং ডিস্কে ছড়িয়ে পড়ে।


আমরা এই সমস্যাটি নিয়েছিলাম, যা আমরা খুঁজে পেয়েছি একটি অফ-বাই-ওয়ান বাগ (এখন ঠিক করা হয়েছে) এর কারণে আরও বেড়ে গিয়েছিল যার ফলে অতিরিক্ত অংশগুলি ক্যোয়ারী প্ল্যানে অন্তর্ভুক্ত করা হয়েছিল এমনকি যখন তারা শেষ পর্যন্ত বাস্তবায়নে কোনও ডেটা অবদান রাখবে না। এই বাগটি খুঁজে পাওয়া আসলে "ডগফুডসেপশন" এর একটি কেস ছিল: ইনসাইট ব্যবহার করার সময় আমরা এটি তৈরি করার সময় এই পারফরম্যান্স সমস্যাটি আবিষ্কার করেছি 🤯৷ আমরা অন্তর্দৃষ্টিতে যে সময়ের তথ্য দেখেছি তা এখানে কিছু ভুল হওয়ার পরামর্শ দিয়েছে এবং আমরা ব্যাখ্যা ব্যবহার করে এবং পরিকল্পনাগুলি দেখে সমস্যাটি উন্মোচন করেছি৷ তাই আমরা আপনাকে বলতে পারি যে এটি কাজ করে!


বস্তুগতকরণকে দ্রুততর করার জন্য, আমরা একটি কাস্টম ইনক্রিমেন্টাল রিফ্রেশ নীতি তৈরি করেছি যা রিফ্রেশ করার জন্য বৃদ্ধির আকার সীমিত করে। আমরা টাইমস্কেলডিবিতে সঠিকভাবে সাধারণীকরণ করতে পারি কিনা তা দেখার জন্য আমরা কাজ করছি।


পরিবর্তন স্কেল এ কঠিন .


একবার আপনার ডেটা একটি নির্দিষ্ট আকারে পৌঁছে গেলে, TimescaleDB-তে কিছু DDL (স্কিমা পরিবর্তন) অপারেশন আদর্শের চেয়ে বেশি সময় নিতে পারে। আমরা ইতিমধ্যে এটি কয়েকটি উপায়ে অনুভব করেছি।


উদাহরণস্বরূপ, বড় হাইপারটেবিলগুলিতে নতুন সূচী যোগ করা সময়ের মধ্যে একটি অনুশীলন হয়ে ওঠে। যেহেতু TimescaleDB বর্তমানে `CREATE INDEX`-এর সাথে `conCURRENTLY` ব্যবহার করাকে সমর্থন করে না, তাই পরবর্তী সর্বোত্তম বিকল্পটি হল এর অন্তর্নির্মিত পদ্ধতি ব্যবহার করে একবারে এক খণ্ড সূচক তৈরি করা। আমাদের ক্ষেত্রে, একটি নতুন খণ্ড তৈরি হওয়ার পরপরই আমাদের এটি বন্ধ করতে হবে, তাই "সক্রিয়" খণ্ডটিতে লক করা ন্যূনতম। অর্থাৎ, একটি খণ্ড নতুন হলে একটি সূচক তৈরি করার অর্থ হল এটি (প্রায়) খালি এবং তাই, দ্রুত সম্পূর্ণ করতে পারে এবং নতুন সন্নিবেশগুলিকে ব্লক করতে পারে না।


নতুন মেট্রিক্স (কলাম) যোগ করার জন্য ক্রমাগত সমষ্টি আপডেট করার সময় আরেকটি উপায় পরিবর্তন করা কঠিন। ক্রমাগত সমষ্টি বর্তমানে `ALTER` সমর্থন করে না। সুতরাং, যখন আমরা ব্যবহারকারীদের কাছে একটি নতুন মেট্রিক প্রকাশ করতে চাই, তখন আমরা ক্রমাগত সমষ্টির একটি সম্পূর্ণ নতুন "সংস্করণ" তৈরি করি, অর্থাৎ, ক্রমাগত সমষ্টিগত "foo" এর জন্য তখন আমাদের থাকবে "foo_v2", "foo_v3", ইত্যাদি। আদর্শের চেয়ে কম কিন্তু বর্তমানে কাজ করছে।


অবশেষে, কম্প্রেশন সেটিংস পরিবর্তন করা স্কেলে বেশ কঠিন। প্রকৃতপক্ষে, এটি এখনই আমাদের পক্ষে কার্যকরভাবে সম্ভব নয়, কারণ এটির জন্য সমস্ত সংকুচিত অংশগুলিকে ডিকম্প্রেস করতে হবে, সেটিংস পরিবর্তন করতে হবে এবং তারপরে তাদের পুনরায় সংকোচন করতে হবে, যা আমাদের বর্তমান স্কেলে সম্ভব নয়।


আমরা এই সব বিষয়ের কার্যকর সমাধান পেতে আমাদের সহকর্মীদের সাথে ব্রেনস্টর্ম চালিয়ে যাচ্ছি। শুধু আমাদের জন্য নয়, সমস্ত টাইমস্কেল ব্যবহারকারীদের জন্য।


শেষ করি

এটি একটি পোস্টে সমস্ত ড্রপ করার জন্য বেশ কিছুটা তথ্য ছিল। কিন্তু যদি আপনি একটি প্রয়োজন কুকুরের ব্যাগ পরে এটা উপভোগ করতে, এটাও ঠিক আছে!


বিল্ডিং অন্তর্দৃষ্টি আমাদের দলের জন্য একটি গভীর অভিজ্ঞতা ছিল. আমরা টাইমস্কেলকে কতটা দূরে নিয়ে যেতে পারি, সেটাকে চিত্তাকর্ষক স্কেল নম্বরে নিয়ে যেতে আমরা প্রথমেই দেখেছি। প্রক্রিয়া চলাকালীন আমরা যে ব্যথার পয়েন্টগুলির সম্মুখীন হয়েছি তা আমাদের গ্রাহকদের সহানুভূতি দিয়েছে—এটাই ডগফুডিংয়ের সৌন্দর্য।


পরের বছর, আমি আরও একটি ব্লগ পোস্ট লিখতে আশা করি যে কীভাবে আমরা আরও ডেটাবেসের মাত্রার আরও একটি অর্ডার নিরীক্ষণ করছি এবং কীভাবে আমরা টাইমস্কেলের সাথে কাজ করার অভিজ্ঞতার উন্নতি অব্যাহত রেখেছি।


দেখা হবে তাহলে! 👋