رفتن به محتوا
LoopX

آزمون بخش ۳: عملکرد و مقیاس

این آزمون پنج درس بخش «عملکرد و مقیاس» را می‌سنجد: عملکرد: gzip و کش، load balancing، محدودسازی درخواست‌ها، Nginx در داکر و Compose و پروژه: استقرار کامل. جواب هر سؤال همان لحظه با توضیح نشان داده می‌شود و نتیجه‌ات در همین مرورگر ذخیره می‌شود (پیشرفت من).

؟ آزمون بخش ۳
  1. روی Ubuntu با gzip on، صفحه‌ی HTML فشرده می‌آید ولی CSS نه. چرا؟

  2. کدام نوع فایل را نباید در gzip_types گذاشت؟

  3. gzip_vary on چه فایده‌ای دارد؟

  4. سیاست کش درست برای HTML و برای /_astro/style.3fa9c1.css کدام است؟

  5. gzip_static on دقیقاً چه می‌کند؟

  6. در upstream بدون zone، ۹ درخواست پشت‌سرهم به سه سرور نامتوازن پخش شد. چرا؟

  7. گزارش‌گیری‌ها چند ثانیه طول می‌کشند و بقیه‌ی درخواست‌ها کوتاه‌اند. کدام روش پخش؟

  8. کاربرها از پشت یک اپراتور با IP های 5.6.7.x می‌آیند و ip_hash داری. نتیجه؟

  9. یکی از سه سرور خاموش شد و max_fails=2 fail_timeout=10s داری. کاربر چه می‌بیند؟

  10. اپ وسط پردازش یک POST اتصال را بست. Nginx آن را به سرور دیگر می‌فرستد؟

  11. برای دیپلوی یکی‌یکی سرورهای upstream بدون خطا، چه می‌کنی؟

  12. با rate=2r/s و بدون burst، دو درخواست با فاصله‌ی ۱۰۰ میلی‌ثانیه. دومی؟

  13. تفاوت burst=5 با burst=5 nodelay؟

  14. location /x { return 200 "ok"; limit_req zone=z; } چرا محدود نمی‌شود؟

  15. کلید یک limit_req_zone را عوض کردی و اسمش را نه. nginx -t موفق و systemctl reload هم کد ۰ داد. چه شده؟

  16. چطور IP دفتر را از محدودیت معاف می‌کنی؟

  17. در Compose نوشته‌ای proxy_pass http://localhost:3000 و اپ سرویس app است. نتیجه؟

  18. بعد از دیپلوی API در Compose، سایت ۵۰۲ می‌دهد تا nginx -s reload. علت و راه‌حل دائمی؟

  19. فایل default.conf را تنها mount کرده‌ای و با sed -i ویرایشش کردی؛ reload هم زدی ولی تغییر اعمال نشد. چرا؟

  20. در استقرار اتمی، چرا ln -sfn new current.new و بعد mv -T current.new current؟

  21. certbot renew --dry-run موفق بود. آیا deploy hook (systemctl reload nginx) هم آزمایش شد؟

🏁 چالش: آماده‌سازی فروشگاه برای روز حراجسخت

فردا حراج است. روی سرور، این‌ها را بساز و با یک اسکریپت ثابت کن:

۱. دو نسخه از یک API (روی 127.0.0.1:9431 و 9432) که در پاسخ بگوید کدام نسخه است و مسیر /api/search را جواب بدهد. ۲. Nginx برای sale.test: upstream با zone، روش least_conn، max_fails=1 fail_timeout=5s. ۳. /api/search محدود به 2r/s برای هر IP با burst=4 nodelay و کد 429؛ بقیه‌ی /api/ بدون این محدودیت. ۴. پاسخ‌های JSON API فشرده (gzip) شوند. ۵. اسکریپت آزمایش: پخش بین دو نسخه، ادامه‌ی کار وقتی یکی خاموش است، تعداد 200 و 429 در ۱۰ جستجوی همزمان، و Content-Encoding: gzip روی JSON.

راهنمایی

برای API همان الگوی درس load balancing: یک اسکریپت Node و یک unit قالبی systemd (lx-sale@9431). JSON را کمی بزرگ کن (مثلاً ۱۰۰ نتیجه) تا از gzip_min_length بیشتر شود. برای /api/search یک location = /api/search جدا با limit_req. یادت باشد پاسخ پشت proxy با gzip_proxied any فشرده می‌شود. برای درخواست‌های همزمان: seq 10 | xargs -P 10 -I{} curl ....

راه‌حل
Terminal window
systemctl stop 'lx-sale@*' 2>/dev/null
rm -rf /srv/lx-sale && mkdir -p /srv/lx-sale
grep -v '\.test$' /etc/hosts > /tmp/hosts.lx; cat /tmp/hosts.lx > /etc/hosts
echo '127.0.0.1 sale.test' >> /etc/hosts
cat > /srv/lx-sale/app.js <<'EOF'
// sale API: /api/search returns 100 fake results
const http = require('http');
const port = Number(process.env.PORT);
http.createServer((req, res) => {
const results = Array.from({ length: 100 }, (_, i) => ({ id: i, title: `book ${i}`, price: 100000 + i * 500 }));
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ instance: port, path: req.url, results }));
}).listen(port, '127.0.0.1');
EOF
cat > /etc/systemd/system/lx-sale@.service <<'EOF'
[Unit]
Description=sale API on port %i
[Service]
Environment=PORT=%i
ExecStart=/usr/bin/node /srv/lx-sale/app.js
Restart=on-failure
EOF
systemctl daemon-reload
systemctl start lx-sale@9431 lx-sale@9432
cat > /etc/nginx/sites-available/sale.test <<'EOF'
upstream sale_api {
zone sale_api 64k;
least_conn;
server 127.0.0.1:9431 max_fails=1 fail_timeout=5s;
server 127.0.0.1:9432 max_fails=1 fail_timeout=5s;
}
limit_req_zone $binary_remote_addr zone=sale_search:10m rate=2r/s;
server {
listen 80;
server_name sale.test;
gzip on;
gzip_proxied any;
gzip_types application/json;
location /api/ {
proxy_pass http://sale_api;
include proxy_params;
}
location = /api/search {
limit_req zone=sale_search burst=4 nodelay;
limit_req_status 429;
proxy_pass http://sale_api;
include proxy_params;
}
}
EOF
ln -sf /etc/nginx/sites-available/sale.test /etc/nginx/sites-enabled/
sleep 1
nginx -t 2>&1 | tail -n 1 && systemctl reload nginx
sleep 1
inst() { curl -s "$@" | grep -o '"instance":[0-9]*' | cut -d: -f2; }
echo "1) spread: $(for i in 1 2 3 4 5 6; do inst http://sale.test/api/items; done | sort | uniq -c | tr -s ' ' | tr '\n' ' ')"
systemctl stop lx-sale@9431
echo "2) 9431 off: $(for i in 1 2 3 4; do curl -s -o /dev/null -w '%{http_code} ' http://sale.test/api/items; done)-> $(inst http://sale.test/api/items)"
systemctl start lx-sale@9431
sleep 1
echo "3) search: $(seq 10 | xargs -P 10 -I{} curl -s -o /dev/null -w '%{http_code}\n' 'http://sale.test/api/search?q=x' | sort | uniq -c | tr -s ' ' | tr '\n' ' ')"
echo " items: $(seq 10 | xargs -P 10 -I{} curl -s -o /dev/null -w '%{http_code}\n' http://sale.test/api/items | sort | uniq -c | tr -s ' ' | tr '\n' ' ')"
echo "4) gzip: $(curl -s -D - -o /dev/null -H 'Accept-Encoding: gzip' http://sale.test/api/items | grep -i '^content-encoding' | tr -d '\r'), $(curl -s -o /dev/null -w '%{size_download}' http://sale.test/api/items) -> $(curl -s -o /dev/null -w '%{size_download}' -H 'Accept-Encoding: gzip' http://sale.test/api/items) bytes"
خروجی
nginx: configuration file /etc/nginx/nginx.conf test is successful
1) spread: 3 9431 3 9432
2) 9431 off: 200 200 200 200 -> 9432
3) search: 5 200 5 429
items: 10 200
4) gzip: Content-Encoding: gzip, 4329 -> 759 bytes

هر بخش ثابت شد:

  1. پخش: ۶ درخواست، ۳ به هر نسخه (least_conn وقتی همه بیکارند مثل round robin رفتار می‌کند).
  2. خرابی: با ۹۴۳۱ خاموش، هر ۴ درخواست 200 گرفتند و همه را ۹۴۳۲ جواب داد.
  3. محدودیت: از ۱۰ جستجوی همزمان، ۵ تا قبول (۱ + burst=4) و ۵ تا 429؛ ولی ۱۰ درخواست همزمان به /api/items همه 200، چون location = /api/search (تطابق دقیق) محدودیت جدای خودش را دارد و بقیه‌ی /api/ نه.
  4. gzip: JSON اپ (از پشت proxy، با gzip_proxied any) فشرده شد: ۴۳۲۹ بایت به ۷۵۹ بایت.