Skip to content
← লোড ব্যালান্সিং · মধ্যবর্তী · 10 মিনিট · 06 / 07 EN

Advanced Load Balancing Pattern

Blue-green deployment, circuit breaker, global load balancing, আর anycast — যেসব deployment ভুল হওয়া চলে না তার pattern।

blue-greencanarycircuit breakerglobal load balancinganycastGeoDNS

গল্পে বুঝি

ইবনে সিনার একটা রেস্তোরাঁ চেইন, শহরের নানা এলাকায় শাখা। এবার তিনি একদম নতুন একটা মেনু নামাচ্ছেন। কিন্তু পুরো শহরের সব টেবিলে একসাথে নতুন রান্না পরিবেশন করার ঝুঁকি তিনি নেন না — প্রথমে শুধু একটা টেবিলে নতুন ডিশগুলো দেন, তারপর চুপচাপ দেখেন খদ্দের খুশি না অভিযোগ করছে। এক টেবিলে সব ঠিক থাকলে ধীরে ধীরে আরও টেবিলে ছড়ান। একেই বলে ছোট একটা অংশ দিয়ে যাচাই।

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

এই গল্পটাই আসলে advanced load balancing। শুধু এক টেবিলে নতুন ডিশ দিয়ে যাচাই করাটা হলো canary release — নতুন version-এ অল্প একটু traffic পাঠিয়ে আগে দেখা। দুটো সমান রান্নাঘর রেখে এক পলকে সব অর্ডার এদিক-ওদিক ঘোরানোটা হলো blue-green deployment — দুটো identical environment, atomically switch, দরকারে instant rollback। আর প্রতিটা খদ্দেরকে কাছের শাখায় বসানোটা হলো geo / global load balancing — user-কে তার নিকটতম region-এ route করা। বাস্তবে এভাবেই বড় সাইটগুলো ঝুঁকি না নিয়ে deploy করে: canary দিয়ে অল্প traffic-এ যাচাই, blue-green দিয়ে নিরাপদ switch, আর GeoDNS/Anycast দিয়ে সবাইকে কাছের datacenter-এ পাঠানো।

বাস্তব জীবনের উদাহরণ

একটা রেল ট্র্যাক switchover: আপনি track বদলাতে ট্রেন থামান না — আপনি একটা সমান্তরাল track বানান, সেটা test করেন, তারপর সঙ্গে সঙ্গে switch flip করেন। Blue-green deployment ঠিক এই কাজটাই করে: একটা user request hit করার আগেই নতুন version চলছে আর প্রস্তুত। switch তাৎক্ষণিক; rollback মানে শুধু এটা আবার ফিরিয়ে দেওয়া।

Blue-Green Deployment

Blue live। Green নতুন version। Traffic atomically switch হয়।

Runtime API দিয়ে HAProxy blue-green:

#!/bin/bash
# deploy-green.sh
HAPROXY_SOCK="/run/haproxy/admin.sock"

# 1. Deploy new version to green servers (separate process)
# 2. Add green servers to a "staging" backend, verify health
# 3. When verified, flip traffic:

haproxy_cmd() {
    echo "$1" | socat stdio $HAPROXY_SOCK
}

# Drain blue servers
haproxy_cmd "set server api_blue/s1 state drain"
haproxy_cmd "set server api_blue/s2 state drain"

# Activate green servers
haproxy_cmd "set server api_green/s1 state ready"
haproxy_cmd "set server api_green/s2 state ready"

echo "Traffic shifted to green"

দুটো backend নিয়ে config:

backend api_blue
    server s1 10.0.0.10:3000 check
    server s2 10.0.0.11:3000 check

backend api_green
    server s1 10.0.0.20:3000 check
    server s2 10.0.0.21:3000 check

frontend https_in
    # Default to blue; switch by changing state via runtime API
    use_backend api_green if { nbsrv(api_green) ge 1 } { nbsrv(api_blue) eq 0 }
    default_backend api_blue

nbsrv(api_blue) eq 0 condition-এর মানে “blue-তে কোনো active server না থাকলে green ব্যবহার করো” — সব blue server drain হলে স্বাভাবিকভাবে green-এ fallback।

LB-তে Circuit Breaking

HAProxy বারবার failure শনাক্ত করে সাময়িকভাবে একটা backend সরাতে পারে:

backend api_servers
    option httpchk GET /health

    # After 3 failed checks, server marked down
    server s1 10.0.0.10:3000 check fall 3 rise 2 inter 5s
    server s2 10.0.0.11:3000 check fall 3 rise 2 inter 5s

    # If all servers are down, return a custom error instead of 502
    errorfile 503 /etc/haproxy/errors/maintenance.http

application-level circuit breaking-এর জন্য (যেমন downstream service error), application layer-এ implement করুন (Opossum, Resilience4j) — HAProxy শুধু upstream HTTP response দেখে।

Slow Backend Detection

ধীর server-দের deprioritize করতে HAProxy-র timeout tuning আর server weight ব্যবহার করুন:

# Script to watch response times and lower weight for slow servers
#!/bin/bash
SOCK="/run/haproxy/admin.sock"

check_response_time() {
    local server=$1
    local host=$2
    local time_ms
    time_ms=$(curl -o /dev/null -s -w "%{time_total}" "http://$host/health" | awk '{print $1 * 1000}')
    echo $time_ms
}

for server in s1 s2; do
    host=$(echo "show servers state api_servers" | socat stdio $SOCK | grep $server | awk '{print $4}')
    time_ms=$(check_response_time $server $host)

    if (( $(echo "$time_ms > 500" | bc -l) )); then
        echo "set server api_servers/$server weight 10" | socat stdio $SOCK
        echo "$server slow ($time_ms ms) — weight lowered"
    fi
done

Global Load Balancing

user-দের নিকটতম বা সবচেয়ে সুস্থ datacenter-এ route করা:

GeoDNS: DNS client-এর ভৌগোলিক অবস্থানের ভিত্তিতে ভিন্ন IP দিয়ে সাড়া দেয়।

  • AWS Route 53 Geolocation routing
  • Cloudflare Load Balancing
  • EU client-এর জন্য EU IP, US client-এর জন্য US IP ফেরত দেয়
# Route 53 Geolocation example (via AWS CLI)
aws route53 change-resource-record-sets --hosted-zone-id Z123 --change-batch '{
  "Changes": [{
    "Action": "CREATE",
    "ResourceRecordSet": {
      "Name": "api.example.com",
      "Type": "A",
      "GeoLocation": {"ContinentCode": "EU"},
      "TTL": 60,
      "ResourceRecords": [{"Value": "18.185.0.1"}]
    }
  }, {
    "Action": "CREATE",
    "ResourceRecordSet": {
      "Name": "api.example.com",
      "Type": "A",
      "GeoLocation": {"CountryCode": "*"},
      "TTL": 60,
      "ResourceRecords": [{"Value": "52.204.0.1"}]
    }
  }]
}'

Latency-based routing: যে datacenter দ্রুততম সাড়া দেয় তাতে route করুন:

aws route53 change-resource-record-sets --hosted-zone-id Z123 --change-batch '{
  "Changes": [{
    "Action": "CREATE",
    "ResourceRecordSet": {
      "Name": "api.example.com",
      "Type": "A",
      "Region": "us-east-1",
      "SetIdentifier": "us-east-1",
      "TTL": 60,
      "ResourceRecords": [{"Value": "52.204.0.1"}]
    }
  }]
}'

Anycast

একটা IP address একসাথে একাধিক location থেকে বিজ্ঞাপিত হয়। BGP routing প্রতিটা client-কে সেই IP announce করা topographically নিকটতম server-এ পাঠায়। Cloudflare তাদের পুরো network-এর জন্য এটা ব্যবহার করে।

নিজে anycast implement করতে আপনার BGP peering সক্ষমতা লাগে (colocation বা BGP-capable cloud)। বেশিরভাগ team-এর জন্য: এর বদলে Cloudflare বা AWS Global Accelerator ব্যবহার করুন।

AWS Global Accelerator কার্যত anycast-as-a-service:

aws globalaccelerator create-accelerator \
  --name my-api \
  --ip-address-type IPV4 \
  --enabled

aws globalaccelerator create-listener \
  --accelerator-arn arn:aws:globalaccelerator::123:accelerator/abc \
  --protocol TCP \
  --port-ranges "[{\"FromPort\":443,\"ToPort\":443}]"

Traffic নিকটতম edge PoP-এ AWS-এর network-এ ঢোকে, তারপর AWS-এর private backbone দিয়ে region-এ যায় — public internet-এর চেয়ে দ্রুত আর বেশি নির্ভরযোগ্য।

Global LB-র জন্য Health Check Aggregation

একটা datacenter degraded হলে (পুরোপুরি down নয়), আপনি traffic সরাতে চান — সব-অথবা-কিছুই-না নয়:

#!/bin/bash
# health-reporter.sh — runs on each datacenter, updates Route 53
REGION="us-east-1"
HOSTED_ZONE="Z123"
WEIGHT=100

# Check local LB health
HEALTHY_SERVERS=$(echo "show servers state api_servers" | \
  socat stdio /run/haproxy/admin.sock | \
  awk '$6 == "2" {count++} END {print count}')

TOTAL_SERVERS=4

# Reduce weight proportionally to healthy servers
WEIGHT=$((HEALTHY_SERVERS * 100 / TOTAL_SERVERS))

# Update Route 53 weighted record
aws route53 change-resource-record-sets \
  --hosted-zone-id $HOSTED_ZONE \
  --change-batch "{
    \"Changes\": [{
      \"Action\": \"UPSERT\",
      \"ResourceRecordSet\": {
        \"Name\": \"api.example.com\",
        \"Type\": \"A\",
        \"SetIdentifier\": \"$REGION\",
        \"Weight\": $WEIGHT,
        \"TTL\": 30,
        \"ResourceRecords\": [{\"Value\": \"$MY_IP\"}]
      }
    }]
  }"

0 healthy server-এ, weight 0-তে নেমে যায় — Route 53 স্বয়ংক্রিয়ভাবে এই datacenter-এ routing বন্ধ করে দেয়।

Request Hedging

একই request একসাথে দুটো backend-এ পাঠান, যেটা আগে সাড়া দেয় সেটা ফেরত দিন। দ্বিগুণ backend load-এর বিনিময়ে tail latency কমায়:

# nginx Plus: proxy_next_upstream with timeout
location / {
    proxy_pass http://notes;
    proxy_next_upstream error timeout http_503;
    proxy_next_upstream_timeout 100ms;   # try next server if first takes > 100ms
    proxy_next_upstream_tries 2;
}

এটা সত্যিকারের hedging নয় (parallel request) — এটা একটা timeout সহ sequential fallback। সত্যিকারের hedging-এর জন্য application-level implementation লাগে।

Observability

সবসময় LB layer-এ এগুলো measure করুন:

# HAProxy stats via CSV — good for dashboards
curl -s 'http://admin:pass@localhost:8404/stats;csv' | \
  python3 -c "
import csv, sys
reader = csv.DictReader(sys.stdin)
for row in reader:
    if row['svname'] not in ('FRONTEND', 'BACKEND'):
        print(f\"{row['pxname']}/{row['svname']}: {row['req_tot']} req, {row['hrsp_5xx']} 5xx, {row['qtime']}ms queue\")
"

haproxy_exporter দিয়ে Prometheus-এ push করুন:

# docker-compose.yml
haproxy-exporter:
  image: prom/haproxy-exporter
  command: '--haproxy.scrape-uri=http://admin:pass@haproxy:8404/stats;csv'
  ports:
    - '9101:9101'

গুরুত্বপূর্ণ metric:

  • haproxy_backend_requests_total — per backend request rate
  • haproxy_backend_response_errors_total — 5xx rate
  • haproxy_backend_queue_average_time_seconds — queuing latency
  • haproxy_server_status — 1=UP, 0=DOWN