সেশন ১৪

Service Discovery - নাম জানলেই ঠিকানা মেলে

এই সেশনের লক্ষ্য: Machine এর IP যখন প্রতি কয়েক মিনিটে বদলায়, তখন একটা service কীভাবে আরেকটা service কে খুঁজে পায়, সেটা বোঝা। Service registry, register আর deregister, health check, client-side আর server-side discovery, DNS এর TTL সমস্যা, Kubernetes Service, আর registry নিজে fail করলে কী হয়।

০০ যে প্রশ্নগুলোর উত্তর খুঁজবো

সেশন ১১ তে আমরা একটা বড় application কে কয়েকটা ছোট service এ ভাগ করেছি। এখন order service কে payment service এর কাছে request পাঠাতে হয়। কিন্তু পাঠাবে কোন ঠিকানায়? এক machine এর জগতে উত্তরটা সহজ ছিলো: ঠিকানা একবার লিখে রাখলেই হতো।

Cloud এ machine আসে আর যায়। আজ যে IP তে payment service আছে, এক ঘণ্টা পরে সেখানে হয়তো কিছুই নেই। এই সেশনে আমরা দেখবো, ঠিকানা প্রতিনিয়ত বদলালেও service গুলো কীভাবে একে অপরকে খুঁজে পায়।

  • ১ Config এ hard-coded IP রাখলে autoscaling আর restart এর পর কী ভাঙে?
  • ২ IP মুখস্থ না রেখে নাম দিয়ে খুঁজলে কেমন হয়? (service registry)
  • ৩ Registry তে নাম ওঠে আর নামে কীভাবে? (self-registration, deregistration)
  • ৪ Registry কীভাবে বোঝে কোন instance সত্যিই চালু আছে? (heartbeat, health check)
  • ৫ Instance বাছাই করবে কে: caller নিজে, নাকি load balancer? (client-side বনাম server-side discovery)
  • ৬ DNS দিয়েই discovery করলে সমস্যা কোথায়? (DNS TTL)
  • ৭ Kubernetes এই কাজটা কীভাবে করে? (Kubernetes Service)
  • ৮ Registry তে stale entry থাকলে, বা registry নিজেই down হলে কী হয়?

০১ Config এ hard-coded IP রাখলে autoscaling আর restart এর পর কী ভাঙে?

রাত দুইটা সাত মিনিট। আরিফের ফোন বেজে উঠলো। আরিফ একটা অনলাইন shopping site এর DevOps engineer, আর আজ রাতে on call এ আছে। Alert বলছে, শেষ চার মিনিটে একটা order ও সফল হয়নি। অথচ আজ রাত বারোটা থেকে midnight sale চলছে, মিনিটে প্রায় ১,২০০টা order আসছে। চোখ কচলাতে কচলাতে আরিফ laptop খুললো। Dashboard এ payment service এর ৮টা instance সবুজ, সবগুলো চালু। তাহলে payment হচ্ছে না কেন?

আধা ঘণ্টা খোঁজার পর আরিফ order service এর config file টা খুললো। সেখানে payment service এর তিনটা IP লেখা আছে, মাস ছয়েক আগে কেউ হাতে লিখেছিলো:

# order-service/application.properties
payment.hosts=10.0.1.11:8080,10.0.1.12:8080,10.0.1.13:8080
payment.timeout=3s

# রাত ২:০৩ এর log
02:03:11 ERROR PaymentClient: connect timed out (10.0.1.12:8080)
02:03:11 ERROR PaymentClient: connect timed out (10.0.1.11:8080)
02:03:12 ERROR OrderController: payment failed, order #58213 cancelled
02:03:12 ERROR PaymentClient: connect timed out (10.0.1.13:8080)

রাত দুইটায় কী হয়েছিলো, এবার পরিষ্কার। পুরোনো তিনটা payment machine এর memory প্রায় শেষ হয়ে আসছিলো। Autoscaling group ওদের অসুস্থ ধরে বন্ধ করে দিলো। Sale এর ভিড় সামলাতে সে একসাথে ৮টা নতুন machine চালু করলো। নতুন machine গুলো নতুন IP পেলো। Order service এর config কেউ বদলায়নি:

রাত ১:০০ রাত ২:০০ (autoscaling এর পরে) Payment service (৩টা instance) Order service config: ৩টা IP 10.0.1.11 10.0.1.12 10.0.1.13 পুরোনো ৩টা IP নতুন ৮টা instance Order service config: সেই ৩টা IP 10.0.1.11 · নেই 10.0.1.12 · নেই 10.0.1.13 · নেই 10.0.2.21 10.0.2.22 10.0.2.23 10.0.2.24 10.0.2.25 10.0.2.26 10.0.2.27 10.0.2.28 প্রতিটা payment call ৩s অপেক্ষা করে fail করে, নতুন ৮টা machine idle থাকে
রাত ১টায় config এর ৩টা IP আর আসল ৩টা machine মিলে যাচ্ছিলো। রাত ২টায় autoscaling পুরোনো ৩টা machine বন্ধ করে নতুন ৮টা চালু করলো। Order service এর config কেউ বদলায়নি, তাই সে এখনো এমন ৩টা IP তে call করছে যেগুলোর পেছনে আর কোনো machine নেই।

প্রতিটা payment call ৩ সেকেন্ড অপেক্ষা করে timeout হলো, আর order টা বাতিল হলো। আরিফ রাত দুইটা একচল্লিশে config ঠিক করে order service restart করলো। ততক্ষণে ৩৮ মিনিট পার হয়ে গেছে। মিনিটে ১,২০০টা করে ধরলে প্রায় ৪৫ হাজার order বাতিল হয়েছে। গড়ে ১,২০০ টাকার order ধরলে ক্ষতি সাড়ে পাঁচ কোটি টাকার মতো।

IP কেন এত বদলায়

আগের দিনে একটা server বছরের পর বছর একই IP তে চলতো। এখন একটা instance এর IP অনেক কারণে বদলায়:

একটু হিসাব করে দেখুন। ধরুন আপনার company তে মোট ৪০০টা instance চলে, আর প্রতিটা গড়ে এক দিন টেকে। তাহলে দিনে প্রায় ৪০০ বার কোনো না কোনো IP বদলায়, মানে গড়ে প্রতি চার মিনিটে একবার। এত ঘন ঘন বদলানো ঠিকানা কোনো মানুষ হাতে config এ লিখে রাখতে পারবে না।

আসল সমস্যা

Order service এর জানা দরকার “payment service এখন কোথায় আছে”, কিন্তু config file জানে শুধু “ছয় মাস আগে কোথায় ছিলো”। একটা service যেভাবে আরেকটা service এর এখনকার ঠিকানা খুঁজে পায়, সেই ব্যবস্থার নাম service discovery।

০২ IP মুখস্থ না রেখে নাম দিয়ে খুঁজলে কেমন হয়?

হাসপাতালের reception desk

বড় একটা হাসপাতালের কথা ভাবুন। ডাক্তার রহমান সোমবার বসেন ৩০৪ নম্বর রুমে, বুধবার ৫১২ নম্বরে। ছুটিতে থাকলে তাঁর জায়গায় অন্য কেউ বসেন। রোগীরা কিন্তু রুম নম্বর মুখস্থ রাখেন না। তাঁরা reception desk এ গিয়ে জিজ্ঞেস করেন, “ডাক্তার রহমান আজ কোথায় বসেছেন?” Reception এর খাতায় সবসময় আজকের হিসাব থাকে, কারণ ডাক্তাররা এসেই সেখানে নিজের রুম নম্বর জানিয়ে যান।

Service এর জগতে এই reception desk এর নাম service registry। এটা একটা ছোট database, যেখানে লেখা থাকে কোন service এর কোন কোন instance এখন কোন IP আর port এ চালু আছে।

১. register ২. lookup ৩. IP list ৪. সরাসরি call (registry মাঝখানে থাকে না) Payment 1 10.0.2.21:8080 Payment 2 10.0.2.22:8080 Payment 8 10.0.2.28:8080 SERVICE REGISTRY payment 10.0.2.21:8080 · UP 10.0.2.22:8080 · UP ... মোট ৮টা inventory 10.0.3.5:9000 · UP Order service "payment কোথায়?"
প্রতিটা payment instance চালু হয়েই registry তে নিজের নাম আর ঠিকানা লিখে দেয়। Order service IP মুখস্থ রাখে না; সে registry কে শুধু নাম দিয়ে জিজ্ঞেস করে: "payment কোথায়?" Registry তখনকার জীবিত instance গুলোর list ফেরত দেয়। আসল payment call টা তারপর সরাসরি instance এ যায়।

পুরো কাজটা চার ধাপে হয়। প্রতিটা payment instance চালু হয়েই registry তে নিজের নাম আর ঠিকানা লিখে দেয়। Order service এর payment দরকার হলে সে registry কে নাম দিয়ে জিজ্ঞেস করে। Registry তখন চালু থাকা instance গুলোর list ফেরত দেয়। শেষে order service সেই list থেকে একটা বেছে নিয়ে সরাসরি call করে।

খেয়াল করুন, registry শুধু ঠিকানা বলে দেয়। আসল payment request টা registry এর ভেতর দিয়ে যায় না। আর order service প্রতিটা request এর আগে registry কে জিজ্ঞেস ও করে না। সে list টা কিছুক্ষণ নিজের কাছে রেখে দেয়, তারপর মাঝে মাঝে নতুন করে আনে। এই ছোট্ট সিদ্ধান্তটা সেশনের শেষে খুব কাজে লাগবে।

নাম বনাম ঠিকানা

Config এ এখন আর IP থাকে না, থাকে শুধু একটা নাম: payment। নাম কখনো বদলায় না। নামের পেছনের ঠিকানা যতবার খুশি বদলাক, registry সবসময় এখনকার ঠিকানা জানে।

০৩ Registry তে নাম ওঠে আর নামে কীভাবে?

Registry এর list ঠিক থাকলে তবেই পুরো ব্যবস্থাটা কাজ করে। তাই দুটো মুহূর্ত খুব জরুরি: instance চালু হওয়ার মুহূর্ত, আর বন্ধ হওয়ার মুহূর্ত।

Payment 3 চালু হলো (10.0.2.23) app ready, DB connection তৈরি ১ Register: "payment, 10.0.2.23:8080" registry তে নিজের ঠিকানা লেখে, TTL 30s ২ প্রতি 10s এ heartbeat "আমি আছি", প্রতিবার TTL আবার 30s হয় ৩ স্বাভাবিক বন্ধ (deploy, scale-in) হঠাৎ crash ৪ক. Deregister করে যায় সাথে সাথে list থেকে বাদ ৪খ. কিছু বলার সুযোগ নেই heartbeat বন্ধ, TTL শেষে বাদ
Instance চালু হয়ে নিজেই register করে, তারপর নিয়ম করে heartbeat পাঠায়। স্বাভাবিকভাবে বন্ধ হলে সে যাওয়ার আগে নিজেই deregister করে, তাই list সাথে সাথে ঠিক হয়ে যায়। Crash করলে বলার সুযোগ থাকে না; registry তখন heartbeat না পেয়ে TTL শেষ হলে instance টাকে বাদ দেয়।

নাম তোলা: registration

Instance চালু হয়ে নিজেই registry কে জানায়: “আমি payment, আমার ঠিকানা 10.0.2.23:8080।” এই কাজের নাম registration। Instance নিজের নাম নিজে তোলে বলে এই পদ্ধতিকে বলে self-registration। Netflix এর Eureka আর HashiCorp এর Consul এ এটাই প্রচলিত পদ্ধতি।

একটা জিনিস মনে রাখবেন: register করতে হয় instance পুরোপুরি ready হওয়ার পরে। Database connection তৈরি হয়নি, অথচ নাম উঠে গেছে, এমন হলে প্রথম কয়েক সেকেন্ডের request গুলো fail করবে।

আরেকটা পদ্ধতিও আছে। সেখানে instance নিজে কিছু বলে না। আলাদা একটা component সব machine এর উপর নজর রাখে, আর নতুন instance দেখলে তার হয়ে registry তে নাম তুলে দেয়। এর নাম third-party registration। সেশনের ০৭ নম্বর অংশে দেখবো, Kubernetes ঠিক এই কাজটাই করে।

নাম নামানো: deregistration

Instance বন্ধ হওয়ার আগে registry থেকে নিজের নাম সরিয়ে নেয়। এর নাম deregistration। স্বাভাবিকভাবে বন্ধ হওয়ার (graceful shutdown) সময় ভালো instance এই ক্রমে কাজ করে:

  1. নাম সরায়: Registry কে বলে, “আমাকে list থেকে বাদ দিন।”
  2. কয়েক সেকেন্ড অপেক্ষা করে: Caller দের cache এ পুরোনো list থাকতে পারে, তাই তাদের নতুন list আনার সময় দেয়।
  3. হাতের কাজ শেষ করে: যে request গুলো এর মধ্যেই এসে গেছে, সেগুলোর উত্তর দেয়।
  4. তারপর বন্ধ হয়।

কিন্তু crash এর সময় এসবের সুযোগ থাকে না। Power চলে গেলে বা process হঠাৎ থেমে গেলে instance কাউকে কিছু বলে যেতে পারে না। Registry এর খাতায় তখনো তার নাম লেখা থাকে। এই ফাঁকটা ধরার জন্যই দরকার health check।

০৪ Registry কীভাবে বোঝে কোন instance সত্যিই চালু আছে?

Registry একটা instance এর খবর দুইভাবে নিতে পারে। দুটো পদ্ধতিকে একসাথে বলে health check।

পদ্ধতিকে কাকে খবর দেয়উদাহরণ
HeartbeatInstance নিজে প্রতি কয়েক সেকেন্ডে registry কে বলে “আমি আছি”Eureka, Consul এর TTL check
Active health checkRegistry নিজে প্রতি কয়েক সেকেন্ডে instance এর /health এ request পাঠায়Consul এর HTTP check, load balancer এর health check

Heartbeat এর ধারণাটা আপনি সেশন ০২ এ দেখেছেন, যেখানে দুটো load balancer একে অপরের খবর রাখতো। এখানেও একই কৌশল। প্রতিটা registration এর সাথে একটা মেয়াদ থাকে, যাকে বলে TTL (সেশন ০৪ এর cache এর TTL এর মতোই)। প্রতিটা heartbeat মেয়াদটা আবার নতুন করে শুরু করে দেয়। মেয়াদ শেষ হওয়ার আগে heartbeat না এলে registry instance টাকে list থেকে বাদ দেয়।

উদাহরণ: Payment 3 এর crash

আরিফের নতুন setup এ heartbeat যায় প্রতি ১০ সেকেন্ডে, আর TTL ৩০ সেকেন্ড। Payment 3 এর শেষ heartbeat এসেছিলো t=20s এ। তারপর t=25s এ machine টা crash করলো:

INSTANCE 10.0.2.23 · TTL 30s crash (t=25s) registry থেকে বাদ (t=50s) heartbeat heartbeat heartbeat আসেনি আসেনি 0s 10s 20s 30s 40s 60s সব ঠিক: list এ আছে, সত্যিই আছে stale window: 25s
শেষ heartbeat এসেছিলো t=20s এ, তাই registry t=50s পর্যন্ত (20 + 30) instance টাকে জীবিত ধরে রাখে। Machine টা কিন্তু t=25s এই crash করেছে। মাঝের 25s registry একটা dead IP দিয়ে যায়; এই সময়টাকে বলে stale window।

Registry জানেই না যে crash হয়েছে। সে শুধু জানে, t=20s এর পর আর কোনো heartbeat আসেনি। তাই সে t=50s পর্যন্ত অপেক্ষা করে। মাঝের ২৫ সেকেন্ড registry একটা dead IP কে জীবিত বলে দেখায়। এই সময়টাকে বলে stale window, আর list এর ঐ ভুল লাইনটাকে বলে stale entry।

এই ২৫ সেকেন্ডে কতগুলো request বিপদে পড়ে, হিসাব করে দেখা যাক:

traffic        : 1,200 order/min = 20 request/s
instance       : 8টা, round robin, প্রতিটা পায় 20 ÷ 8 = 2.5 request/s
stale window   : 25s (crash থেকে registry থেকে বাদ পড়া পর্যন্ত)

dead IP তে যাওয়া request = 2.5 × 25 ≈ 62টা

retry নেই            : 62টা payment fail
অন্য instance এ retry : 0টা fail, শুধু ওই 62 জন ~1s বেশি অপেক্ষা করে
                       (connect timeout 1s ধরে)

Interval ছোট করলেই কি সমাধান?

Heartbeat প্রতি সেকেন্ডে পাঠালে stale window ছোট হয়, কিন্তু দুটো নতুন সমস্যা আসে। প্রথমত, ৪০০টা instance প্রতি সেকেন্ডে heartbeat পাঠালে registry কে সেকেন্ডে ৪০০টা request সামলাতে হয়। দ্বিতীয়ত, network এ এক সেকেন্ডের ছোট একটা ঝাঁকুনিতেই সুস্থ instance বাদ পড়ে যায়। তাই বেশিরভাগ team কয়েক সেকেন্ডের interval রাখে, আর stale window এর বাকি ঝুঁকিটা retry দিয়ে সামলায়।

Health check আসলে কী দেখবে

Process চালু থাকা আর request নিতে পারা এক জিনিস নয়। একটা instance চালু থাকতে পারে, কিন্তু তার cache এখনো খালি, বা database connection এখনো তৈরি হয়নি। তাই ভালো /health endpoint দেখে instance টা সত্যিই কাজ নিতে প্রস্তুত কিনা। তবে health check এ অন্য service এর উপর বেশি নির্ভর করবেন না। Database একটু ধীর হলেই সব instance একসাথে “অসুস্থ” হয়ে list থেকে বাদ পড়তে পারে।

০৫ Instance বাছাই করবে কে: caller নিজে, নাকি load balancer?

Registry এর কাছে ৮টা payment instance এর list আছে। কিন্তু কোন request কোন instance এ যাবে, সেই সিদ্ধান্তটা কেউ একজনকে নিতে হবে। এখানে দুটো পথ আছে:

CLIENT-SIDE SERVER-SIDE lookup, list cache করে Order service + discovery library নিজেই instance বাছে Registry Payment Payment Payment উদাহরণ: Netflix Eureka Order service শুধু LB কে চেনে Load balancer registry দেখে বাছে Registry Payment Payment Payment উদাহরণ: AWS ALB, Kubernetes Service
বাঁ দিকে client-side discovery: order service এর ভেতরের library নিজে registry থেকে list আনে আর একটা instance বেছে সরাসরি call করে। ডান দিকে server-side discovery: order service শুধু একটা load balancer এর ঠিকানা জানে; কোন instance এ যাবে, সেটা load balancer registry দেখে ঠিক করে।

Client-side discovery

এই পদ্ধতিতে caller নিজেই সব করে। Order service এর ভেতরে একটা ছোট library থাকে। Library টা registry থেকে list আনে, cache করে রাখে, আর প্রতিটা request এর জন্য একটা instance বেছে নেয় (যেমন round robin এ, মানে পালা করে একটার পর একটা)। এর নাম client-side discovery। Netflix অনেক বছর Eureka আর Ribbon library দিয়ে এভাবেই চালিয়েছে।

Server-side discovery

এই পদ্ধতিতে caller শুধু একটা ঠিকানা চেনে: একটা load balancer এর। সেশন ০২ এর load balancer এর কথা মনে করুন, যে request গুলো কয়েকটা server এর মধ্যে ভাগ করে দিতো। এখানে load balancer নিজে registry দেখে জানে কোন কোন instance চালু আছে, আর সে-ই একটা বেছে নেয়। এর নাম server-side discovery। AWS এর load balancer (ALB) আর Kubernetes Service এভাবে কাজ করে।

Client-side discoveryServer-side discovery
সুবিধামাঝে বাড়তি কোনো hop নেই, তাই latency কম। Caller নিজের মতো করে instance বাছতে পারে, যেমন একই data center এর instance আগে।Caller একদম সহজ থাকে, শুধু একটা ঠিকানা জানলেই হয়। যেকোনো language এর service কোনো library ছাড়াই কাজ করে।
Downsideপ্রতিটা language এর জন্য আলাদা library লাগে: Java, Go, Node, সবার জন্য। Library এর bug সব service এ ছড়িয়ে যায়।প্রতিটা request এ বাড়তি একটা hop (সাধারণত ১ms এর কম)। Load balancer নিজেও একটা বাড়তি system, তাই তাকেও redundant রাখতে হয় (সেশন ০২)।
দুটোই আসলে একই কাজ করে

দুই পদ্ধতিতেই কাউকে না কাউকে registry দেখে একটা instance বাছতে হয়। পার্থক্য শুধু কাজটা কোথায় হয়: caller এর ভেতরে, নাকি মাঝখানের একটা load balancer এ। আজকাল অনেক company একটা মাঝামাঝি পথ নেয়। প্রতিটা service এর পাশে একটা ছোট proxy বসানো থাকে, যে caller এর হয়ে discovery করে দেয়। এর নাম service mesh, সেশন ১২ তে এর কথা আছে।

০৬ DNS দিয়েই discovery করলে সমস্যা কোথায়?

একটা প্রশ্ন মাথায় আসা স্বাভাবিক। নাম থেকে ঠিকানা বের করার জন্য তো আগে থেকেই একটা system আছে: DNS। সেশন ০৬ এ দেখেছি, DNS হলো ইন্টারনেটের phonebook, নাম দিলে IP ফেরত দেয়। তাহলে payment.internal নামে একটা DNS record বানিয়ে তাতে সব instance এর IP রাখলেই তো হয়?

এটা সত্যিই করা যায়, আর একে বলে DNS-based discovery। Consul এর মতো registry গুলো নিজেই একটা DNS interface দেয়, যাতে payment.service.consul নামে খুঁজলে চালু instance গুলোর IP পাওয়া যায়। সমস্যাটা অন্য জায়গায়: DNS এর উত্তর cache হয়।

প্রতিটা DNS উত্তরের সাথে একটা TTL থাকে। TTL শেষ না হওয়া পর্যন্ত caller আর DNS কে জিজ্ঞেস করে না, নিজের cache থেকেই IP নেয়। ধরুন TTL ৬০ সেকেন্ড:

t=15s: .22 crash DNS .21 .22 .23 t=20s থেকে নতুন record: .21 .23 (ঠিক) CACHE .21 .22 .23 45s ধরে পুরোনো list, dead .22 তে request যায় 0s 10s 20s 30s 40s 50s 60s t=60s: TTL শেষ, তবেই আবার DNS জিজ্ঞেস করে
Order service t=0s এ DNS থেকে ৩টা IP পেয়েছে, সাথে TTL 60s। t=15s এ .22 crash করলো, t=20s এ DNS record ঠিক হয়ে গেলো। কিন্তু order service এর cache এই খবর জানে না। TTL শেষ হওয়ার আগে সে DNS কে আর জিজ্ঞেস করবে না। তাই crash এর পর মোট 45s সে dead .22 তে request পাঠায়।

DNS server নিজে মাত্র ৫ সেকেন্ডে ঠিক হয়ে গেছে। তবু order service আরো ৪০ সেকেন্ড dead IP তে request পাঠিয়েছে, কারণ উত্তরটা তার cache এ আটকে ছিলো। তার উপর আরো কয়েকটা সমস্যা আছে:

DNS কখন চলে

যে ঠিকানা কালেভদ্রে বদলায় (যেমন একটা database cluster এর ঠিকানা, বা একটা load balancer এর ঠিকানা), সেখানে DNS চমৎকার কাজ করে। যে ঠিকানা প্রতি কয়েক মিনিটে বদলায়, সেখানে DNS এর cache ই বিপদ ডেকে আনে।

০৭ Kubernetes এই কাজটা কীভাবে করে?

আজ অনেক company তার service গুলো Kubernetes এ চালায়। Kubernetes এ প্রতিটা চালু instance কে বলে pod। Pod খুব ঘন ঘন বদলায়: restart হয়, অন্য machine এ সরে যায়, আর প্রতিবার নতুন IP পায়। তাই Kubernetes এর ভেতরেই service discovery তৈরি করা আছে। এর নাম Kubernetes Service।

Order pod call করে http://payment:8080 Kubernetes নিজে আপডেট করে Service: payment ClusterIP 10.96.0.20 (বদলায় না) Endpoints ready pod এর IP list pod · ready 10.244.1.7 pod · ready 10.244.2.4 pod · ready 10.244.3.9 pod · not ready এখনো warm up হচ্ছে pod বদলায়, pod এর IP বদলায়; Service এর নাম আর IP একই থাকে
Order pod শুধু একটা নাম চেনে: payment। এই নামের পেছনে একটা স্থির IP থাকে (ClusterIP)। Kubernetes প্রতিনিয়ত দেখে কোন payment pod ready, আর সেই list (Endpoints) আপডেট করে। Ready না হওয়া pod এ কোনো traffic যায় না।

একটা Kubernetes Service এর একটা নাম থাকে (payment) আর একটা স্থির IP থাকে, যাকে বলে ClusterIP। এই IP টা Service যতদিন আছে ততদিন বদলায় না। Order pod শুধু http://payment:8080 এ call করে। এর পেছনের কাজ Kubernetes নিজেই করে:

Service বানানোর জন্য শুধু এটুকু লিখতে হয়:

apiVersion: v1
kind: Service
metadata:
  name: payment            # এই নামটাই order service ব্যবহার করবে
spec:
  selector:
    app: payment           # এই label যে pod গুলোর আছে, তারাই এর পেছনে থাকবে
  ports:
    - port: 8080           # Service এর port
      targetPort: 8080     # pod এর ভেতরের port

# order service এর config এ এখন IP নেই, শুধু নাম:
payment.url=http://payment:8080

খেয়াল করুন, Kubernetes এখানে আগের দুটো ধারণাই একসাথে ব্যবহার করছে। Pod নিজে register করে না; Kubernetes তার হয়ে list বানায়, তাই এটা third-party registration। আর order pod নিজে instance বাছে না; Service এর পেছনের ব্যবস্থা বাছে, তাই এটা server-side discovery। নাম থেকে ClusterIP বের করতে Kubernetes DNS ও ব্যবহার করে। কিন্তু ClusterIP কখনো বদলায় না বলে DNS এর TTL সমস্যা এখানে আর ঝামেলা করে না।

Kubernetes এ থাকলে

Kubernetes এ থাকলে সাধারণত আলাদা registry বসানোর দরকার হয় না। আপনার কাজ শুধু দুটো: একটা ভালো readiness probe লেখা, আর pod বন্ধ হওয়ার সময় হাতের request গুলো শেষ করার সুযোগ দেওয়া।

০৮ Registry তে stale entry থাকলে, বা registry নিজেই down হলে কী হয়?

Stale entry দুই রকমের

Registry এর list দুই দিক থেকে ভুল হতে পারে।

Registry নিজেই down হলে

এবার সবচেয়ে ভয়ের প্রশ্ন। সব service ই registry এর উপর নির্ভর করে। Registry এর একটা মাত্র machine থাকলে সেটাই হয়ে যায় পুরো system এর SPOF (single point of failure, সেশন ০১)। তাই registry দুইভাবে নিজেকে রক্ষা করে:

REGISTRY CLUSTER node 1 leader node 2 copy node 3 · down ৩টার ২টা চালু থাকলেই চলে প্রতি 30s এ list refresh Order service local cache: payment এর শেষ জানা ৮টা IP call চলে Payment (৮টা) আগের মতোই চলছে পুরো cluster down হলেও শেষ জানা list দিয়ে call চলে; শুধু নতুন instance এর খবর আসে না
Registry একটা machine এ চলে না; তিন বা পাঁচটা node এ একই data এর copy থাকে। বেশিরভাগ node চালু থাকলে registry কাজ করে যায়। তার উপর order service প্রতিটা request এ registry কে জিজ্ঞেস করে না, নিজের কাছে শেষ জানা list রাখে। তাই registry পুরোপুরি down হলেও payment call থেমে যায় না।

প্রথম রক্ষা, cluster: Registry তিন বা পাঁচটা node এ চলে, আর প্রতিটা node এ একই data এর copy থাকে। বেশিরভাগ node চালু থাকলেই registry কাজ করে। তিনটার মধ্যে একটা down হলে কেউ টেরও পায় না। Node গুলো কীভাবে একমত হয় কোন list টা সঠিক, সেই কৌশলের নাম consensus। Consul আর etcd দুটোই Raft নামের consensus algorithm ব্যবহার করে। এর ভেতরের কথা সেশন ১৬ তে।

দ্বিতীয় রক্ষা, caller এর cache: ০২ নম্বর অংশে দেখেছি, order service প্রতিটা request এ registry কে জিজ্ঞেস করে না। সে শেষ জানা list নিজের কাছে রাখে, আর প্রতি ৩০ সেকেন্ডে নতুন করে আনে। তাই পুরো registry cluster down হলেও payment call থামে না। শুধু এই সময়ে নতুন instance এর খবর আসে না, আর কোনো instance crash করলে সেটা list এ রয়ে যায়। কাজ চলতে থাকে, যদিও একটু অন্ধভাবে।

Registry কে request এর পথে রাখবেন না

প্রতিটা request এর আগে registry কে জিজ্ঞেস করলে registry এর প্রতিটা ঝাঁকুনি সরাসরি user এর কাছে পৌঁছায়। শেষ জানা list cache করে রাখুন। Registry down হলে নতুন list পাওয়া বন্ধ হয়, কিন্তু চালু থাকা কাজ বন্ধ হয় না।

আরিফের পরের sale

তিন সপ্তাহ পরে আবার midnight sale। এর মধ্যে আরিফের team order service এর config থেকে সব IP মুছে দিয়েছে। Payment instance গুলো এখন চালু হয়েই Consul এ register করে, প্রতি ১০ সেকেন্ডে heartbeat পাঠায়। Order service শুধু “payment” নামটা চেনে, আর fail হলে অন্য instance এ একবার retry করে।

রাত দুইটা দশে autoscaling আবার কয়েকটা পুরোনো machine বদলে দিলো, আর ৬টা নতুন machine যোগ করলো। নতুন machine গুলো ১৫ সেকেন্ডের মধ্যে traffic পেতে শুরু করলো। একটা order ও বাতিল হলো না। আরিফের ফোন সেই রাতে একবারও বাজেনি। সে ঘুমিয়ে ছিলো।

Service discovery যা দিলো

  • IP আর কারো মুখস্থ রাখতে হয় না: Order service শুধু নাম চেনে, আর registry তখনকার ঠিকানা বলে দেয়।
  • Autoscaling সত্যিই কাজে লাগে: নতুন instance চালু হয়ে register করলেই কয়েক সেকেন্ডের মধ্যে traffic পায়।
  • Crash করা instance নিজে থেকেই বাদ পড়ে: Health check না মিললে registry সেটাকে list থেকে সরিয়ে দেয়।
  • Deploy এ কেউ config বদলায় না: রাত ২টায় কাউকে ঘুম থেকে উঠে IP লিখতে হয় না।

Downside গুলো

  • আরেকটা জরুরি system চালাতে হয়: Registry কে নিজেই cluster বানিয়ে রাখতে হয়, monitor করতে হয়।
  • Stale window কখনো শূন্য হয় না: Crash থেকে বাদ পড়া পর্যন্ত কয়েক সেকেন্ড ভুল IP যায়, তাই retry লাগবেই।
  • Debug করা কঠিন হয়: "Request টা কোন machine এ গেলো" সেটা আর config দেখে বলা যায় না।
  • সব service কে নিয়ম মানতে হয়: Register, heartbeat আর graceful shutdown ঠিকমতো না করলে list ভুল থাকে।

০৯ মগজে প্রেশার দিন

আগে নিজে ভাবুন। তারপর দেখুন: সবাই যেভাবে ভাবে, কেন সেটা অসম্পূর্ণ, আর আসল কথাটা কোথায়।

প্রশ্ন ১: আমাদের তো load balancer আছেই। তাহলে আলাদা করে service discovery লাগবে কেন?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“Load balancer request গুলো instance দের মধ্যে ভাগ করে দেয়। Caller শুধু load balancer এর ঠিকানা জানলেই হলো। তাই service discovery এর আলাদা কোনো দরকার নেই।”

কথাটা অর্ধেক সত্যি। Caller এর দিক থেকে সমস্যাটা সত্যিই মিটে যায়।

যে জায়গাটা যোগ করা দরকার

কিন্তু load balancer নিজে কীভাবে জানে পেছনে কোন কোন instance আছে? তার config এ IP হাতে লিখে রাখলে আরিফের রাত দুইটার সমস্যাটা শুধু order service থেকে load balancer এ সরে যায়। Load balancer কে নিজেই কোনো registry থেকে চালু instance এর list পেতে হয়, আর health check করতে হয়। অর্থাৎ load balancer service discovery এর বিকল্প নয়। Load balancer আর registry মিলে যা হয়, সেটাই server-side discovery।

মনে রাখুন

প্রশ্নটা “load balancer আছে কিনা” নয়। প্রশ্নটা হলো, instance এর বদলে যাওয়া list টা কে জানে, আর কীভাবে জানে।

প্রশ্ন ২: DNS এর TTL ১ সেকেন্ড করে দিলেই তো stale entry এর সমস্যা শেষ। Registry লাগবে কেন?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“সমস্যাটা তো cache এর মেয়াদ নিয়ে। TTL ১ সেকেন্ড করলে caller প্রতি সেকেন্ডে নতুন উত্তর আনবে, তাই dead IP বড়জোর ১ সেকেন্ড থাকবে।”

TTL ছোট করা ঠিক দিকেই একটা পদক্ষেপ। কিন্তু এতে তিনটা জিনিস ধরা পড়ে না।

যে জায়গাটা যোগ করা দরকার

প্রথমত, TTL একটা অনুরোধ মাত্র, আদেশ নয়। অনেক runtime আর library নিজের মতো করে উত্তর আরো বেশি সময় রেখে দেয়। দ্বিতীয়ত, আগে খোলা connection গুলো DNS কে আর জিজ্ঞেস ই করে না, পুরোনো IP তে লেগে থাকে। তৃতীয়ত, DNS record কে ঠিক রাখতে হলে কাউকে না কাউকে জানতে হবে কোন instance চালু আছে। সেই কাজটা heartbeat আর health check দিয়েই হয়, মানে একটা registry লাগবেই। DNS এখানে শুধু registry এর উত্তর পৌঁছে দেওয়ার একটা পথ, registry এর বিকল্প নয়।

মনে রাখুন

DNS দিয়ে discovery করা যায়, কিন্তু DNS নিজে health check করে না। আর TTL ছোট করলেও সব caller সেটা মানবে, এমন নিশ্চয়তা নেই।

প্রশ্ন ৩: Interview তে জিজ্ঞেস করলো: সব service registry এর উপর নির্ভর করে, তাহলে registry ই কি নতুন SPOF না?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“হ্যাঁ, তাই registry এর দুইটা copy রাখবো। একটা down হলে আরেকটা কাজ চালাবে।”

Redundancy এর চিন্তাটা ঠিক আছে। কিন্তু উত্তরটা এখানে থেমে গেলে interviewer এর পরের প্রশ্নেই আটকে যাবেন।

যে জায়গাটা যোগ করা দরকার

দুইটা copy থাকলে দুজনের মধ্যে network কেটে গেলে কে সঠিক, সেটা বলার উপায় থাকে না। দুজনেই নিজেকে সঠিক ভাবতে পারে (সেশন ০৩ এর split brain)। তাই registry চলে তিন বা পাঁচটা node এ, আর বেশিরভাগ node একমত হলে তবেই list বদলায় (সেশন ১৬)। এর চেয়েও বড় কথা হলো, registry কে request এর পথে রাখা হয় না। Caller শেষ জানা list cache করে রাখে, তাই পুরো registry কিছুক্ষণ down থাকলেও চালু call গুলো চলতে থাকে। শুধু নতুন instance এর খবর আসা বন্ধ থাকে।

মনে রাখুন

ভালো উত্তরের দুটো অংশ: registry কে consensus সহ cluster এ চালানো, আর caller এর cache দিয়ে registry কে request এর পথ থেকে সরিয়ে রাখা।

১০ যে টার্মগুলো শিখলাম

টার্মমানে
Service discoveryএকটা service যেভাবে আরেকটা service এর এখনকার ঠিকানা খুঁজে পায়।
Service registryযে database এ লেখা থাকে কোন service এর কোন instance এখন কোন IP আর port এ চালু আছে।
RegistrationInstance এর নাম আর ঠিকানা registry তে তোলা।
Deregistrationবন্ধ হওয়ার আগে registry থেকে নিজের নাম সরিয়ে নেওয়া।
Self-registrationInstance নিজেই চালু হয়ে নিজের নাম registry তে তোলে।
Third-party registrationআলাদা একটা component instance দের উপর নজর রাখে আর তাদের হয়ে নাম তোলে (যেমন Kubernetes)।
Graceful shutdownবন্ধ হওয়ার আগে নাম সরানো, একটু অপেক্ষা করা, আর হাতের request গুলো শেষ করা।
Health checkRegistry যেভাবে নিশ্চিত হয় যে একটা instance সত্যিই কাজ নিতে পারছে।
HeartbeatInstance এর নিয়মিত “আমি আছি” বার্তা (সেশন ০২)।
Active health checkRegistry নিজে নিয়মিত instance এর /health এ request পাঠিয়ে খবর নেয়।
Stale entry / stale windowRegistry তে রয়ে যাওয়া dead instance এর লাইন, আর যতক্ষণ সেটা রয়ে যায় সেই সময়টুকু।
Client-side discoveryCaller নিজেই registry থেকে list এনে একটা instance বেছে নেয়।
Server-side discoveryCaller একটা load balancer কে call করে, আর load balancer registry দেখে instance বাছে।
DNS-based discoveryDNS record এ instance গুলোর IP রেখে নাম দিয়ে খোঁজা। TTL এর cache এর কারণে বদল দেরিতে পৌঁছায়।
Kubernetes ServiceKubernetes এর ভেতরের discovery: একটা স্থির নাম আর ClusterIP, যার পেছনে ready pod গুলো থাকে।
Readiness probeKubernetes এর নিয়মিত প্রশ্ন, pod টা request নিতে প্রস্তুত কিনা। প্রস্তুত না হলে traffic পায় না।
Eureka / Consul / etcdপ্রচলিত registry। Consul আর etcd Raft consensus দিয়ে cluster এ চলে (সেশন ১৬)।

১১ শর্ট সামারি

  1. Cloud এ instance এর IP প্রতিনিয়ত বদলায় (autoscaling, crash, deploy, restart), তাই config এ hard-coded IP একদিন না একদিন এমন জায়গায় request পাঠাবে যেখানে কোনো machine নেই।
  2. Service registry প্রতিটা service এর চালু instance এর list রাখে। Instance নিজে register আর deregister করে; crash করলে heartbeat না পেয়ে registry তাকে TTL শেষে বাদ দেয়, আর মাঝের stale window টুকু retry দিয়ে সামলাতে হয়।
  3. Client-side discovery তে caller নিজে instance বাছে, server-side discovery তে load balancer বাছে। DNS দিয়েও discovery হয়, কিন্তু TTL এর cache এর কারণে বদল দেরিতে পৌঁছায়; Kubernetes Service একটা স্থির নামের পেছনে ready pod গুলো রেখে এই কাজটা নিজেই করে।
  4. Registry কে তিন বা পাঁচ node এর cluster এ চালাতে হয়, আর caller কে শেষ জানা list cache করতে হয়, যাতে registry down হলেও চালু কাজ থেমে না যায়।

১২ মনে রাখুন