בריכות חיבור ואיחור
בריכות חיבור ו latency
1) מדוע יש צורך בבריכות
חיבורים הם יקרים (לחיצות ידיים TCP/TLS, אימות, חימום). הבריכה מאפשרת:- שימוש מחדש בחיבורים מוכנים (לשמור-בחיים) = מתחת ל-TTFB.
- שולט בו זמנית ונותן תרמיל גב במקום מפולת שלגים של נסיגות.
- הפחתת זנבות p95/p99 בשל גודל ופסקי זמן נכונים.
סיכונים מרכזיים: המתנה בתור בבריכה, חסימת ראש הקו, תוכן לחיבורים וסערה של נסיגות.
2) בסיס מתמטיקה: כיצד לספור את גודל הבריכה
אנחנו משתמשים בחוק של ליטל: ”L = עבירי xW”. עבור בריכה, זה אומר:- ”Divership” הוא זרם הבקשה הממוצע (RPS).
- 'W' הוא חיבור ממוצע עסוק לכל בקשה (זמן שירות, כולל latency רשת ופעולת שירות מרחוק).
- גודל הבריכה המינימלי הוא N _ min industribution xW.
- הוסף מרווח עבור וריאציות ו-p99: חדר ראש 20-50%.
- דוגמה: 300 RPS, ממוצע hold-time 40 ms 'N _ min = 300 × 0. 04 = 12`. עם מרווח של 50%, 18 חיבורים הם.
אם הזנבות גדולים: חשוב על ”W _ p95” או ”W _ p99” עבור מסלולים קריטיים - בריכות גדלות.
3) עקרונות עיצוב כלליים
1. נתיב נתונים קצר: שימוש חוזר (לשמור-בחיים, HTTP/2/3 multiplexing).
2. מגבלת המקביליות: עדיף לסרב במהירות (429/503) מאשר לטגן את החלק האחורי.
3. פסקי זמן> נסיגות: קבע פסקי זמן קטנים ונופש ריחות נדירים.
4. תורים ללקוח קצרים יותר מתור השרת (מהר אל-כשל).
5. תרגיל גב: כאשר הבריכה מלאה - מייד NACK/שגיאה/קולבק ”מאוחר יותר”.
6. בידוד בריכות על ידי מטרות: DB, מטמון, PSP חיצוני - הגבולות שלהם.
4) HTTP/1. 1 נגד HTTP/2/3, לשמור-בחיים
HTTP/1. 1: בקשת חיבור אחת בכל פעם (כמעט); צריך בריכה עם קשרים מרובים לכל מארח.
HTTP/2: ריבוי זרם בTCP אחד; פחות קשרים, אבל חסימת HOL על TCP אפשרית כאשר חבילות אבודות.
HTTP/3 עצמאות על פני UDP - פחות בעיות HOL, ביטים ראשונים מהירים יותר.
- לשמור על זמן חיים 30-90 (על ידי פרופיל), הגבלת בקשות לחיבור (מיחזור חינני).
- חימום מראש (connect) בתחילת העבודה.
- הגבל את הזרימות המקסימליות לכל HTTP/2 (למשל: 100-200).
nginx upstream backend {
server app-1:8080;
server app-2:8080;
keepalive 512;
keepalive_requests 1000;
keepalive_timeout 60s;
}
proxy_http_version 1. 1;
proxy_set_header Connection "";
שליח (בריכת HTTP/2):
yaml http2_protocol_options:
max_concurrent_streams: 200 common_http_protocol_options:
idle_timeout: 60s max_connection_duration: 3600s
5) בריכות DB: סדרן, היקריקפ, נהגים
המטרה היא להגביל עסקאות תחרותיות ולשמור על חיבור קצר.
5. 1 סדרן (PostGreSQL)
מצבים: ”הפעלה ”/” העברה ”/” הצהרה”. עבור API - לעתים קרובות יותר עסקה.
פרמטרים חשובים הם ”pool _ size”, ”min _ pool _ size”, ”reserve _ pool _ size”, ”server _ idle _ timeout',” query _ wait _ timeout'.
ini
[databases]
appdb = host=pg-primary port=5432 dbname=appdb
[pgbouncer]
pool_mode = transaction max_client_conn = 5000 default_pool_size = 100 min_pool_size = 20 reserve_pool_size = 20 query_wait_timeout = 500ms server_idle_timeout = 60 server_reset_query = DISCARD ALL
5. 2 HikariCP (ג 'אווה)
קשרים קטנים ומהירים, פסקי זמן קשים.
properties dataSourceClassName=org. postgresql. ds. PGSimpleDataSource maximumPoolSize=30 minimumIdle=5 connectionTimeout=250 validationTimeout=200 idleTimeout=30000 maxLifetime=1800000 leakDetectionThreshold=5000
כללים:
- 'מידת סימולטנית' RPS × W × חדר הראש.
- 'Timeout' underdows של אלפיות שנייה, לא שניות.
- אפשר זיהוי דליפה.
5. 3 Go/Node/Python - דוגמאות
עבור http. לקוח (שימוש חוזר + פסקי זמן):go tr:= &http. Transport{
MaxIdleConns: 512,
MaxIdleConnsPerHost: 128,
IdleConnTimeout: 60 time. Second,
TLSHandshakeTimeout: 2 time. Second,
}
c:= &http. Client{
Transport: tr,
Timeout: 2 time. Second ,//general
}
צומת. js לשמור על סוכן בחיים:
js const http = require('http');
const agent = new http. Agent({ keepAlive: true, maxSockets: 200, maxFreeSockets: 64, timeout: 60000 });
Psycopg/SQLAchemy (פייתון):
python engine = create_engine(
url, pool_size=30, max_overflow=10, pool_recycle=1800, pool_pre_ping=True, pool_timeout=0. 25
)
6) תורים ממתינים וזנב-לילי
זנבות מתרחשים כאשר:- הבריכה קטנה יותר מ- ”trough × W”. תור החיבור גדל.
- טעינה פריקות (התפרצויות) ללא חוצץ ומגבלות.
- בקשות ארוכות לקחת את החיבור וליצור HOL.
- בריכות נפרדות לפי סוג הבקשה (מהיר/איטי).
- ליישם פסק זמן בצד לקוח. אם פג תוקפו - נאק מהיר.
- זיהוי חריג ושבירת מעגלים על נתיבים (שליח, HAPROXY).
- מכסות לנתיבים ”כבדים”, בריכה נפרדת לדיווחים/יצוא.
yaml circuit_breakers:
thresholds:
- priority: DEFAULT max_connections: 200 max_pending_requests: 100 max_requests: 1000 max_retries: 2
7) פסקי זמן ונסיגות (סדר נכון)
1. חיבור זמן (קצר: 50-250 ms בתוך DC).
2. זמן לחיצת יד TLS (500-1000 MS MESLANY DC).
3. בקש/קרא פסק זמן (קרוב יותר לתוואי SLO).
4. ריטרי: זמן מקסימלי 1, רק לשיטות אידמפוטנטיות; ג 'יטר + אחורה.
5. תקציב מגש: הגבלה גלובלית כאחוז RPS (לדוגמה, 10%).
8) לשמור-בחיים, נייגל, פרוטוקולים
בטל את Nagle (TCP_NODELAY) למסר קטן של RPC.
אפשר שמירה של HTTP בכל מקום אפשרי.
צפה TIME_WAIT - מנגינה ”להשתמש מחדש ”/” למחזר” רק אם אתה מבין את ההשלכות; טוב יותר - להשתמש מחדש קשרים, לא כוונון גרעין.
TLS - השתמש בחידוש הפעלה ו ־ ALPN.
9) כוונון מערכת ההפעלה של קרנל (בזהירות)
'net. ליבה. סומקסון, רשת. ipv4. ip_local_port_range', "נטו. ipv4. tcp_fin_timeout'.
תיאורים: 'nofile' N64k לתהליך פרוקסי.
איזון IRQ, GRO/LRO - על ידי פרופיל תנועה.
עדיפות - פרופיל; כוונון ללא מדדים הוא לעתים קרובות מזיק.
10) יכולת תצפית: מה למדוד
ניצול בריכה: עמוס/סך הכל, חיבור p50/p95 תלוי ועומד.
בקשות לטיסה ושעת ההמתנה שלהם (פרוסות מסלול).
תקציב שגיאת מגש מחדש: פרופורציה של חזרות.
חיבור נוצר/סגור לשנייה.
TCP/TLS: SYN RTT, לחיצות ידיים, שימוש חוזר.
חיבורים פעילים, המתנה, עסקאות ארוכות, מנעולים.
”RPS נגד ביליארד המתנה”, ”Hold-time distribution”, ”reuse ratio”, ”circuit tributes”.
11) מתכוני מקרה
11. 1 API pateway # backend
HTTP/2 לגבות, ”max _ concurrent _ streams = 200”.
מאגר של 20-40 חיבורים לשירות לכל צומת שער.
פסקי זמן: לחבר 100 מ ”מ, לכל ניסיון 300-500 מ” מ, משותף 1-2, 1 ריטרי עם ג 'יטר.
11. 2 שירות PostGreSQL # באמצעות PegreServer
'Pool _ mode = transaction', 'ברירת מחדל _ pool _ side' על ידי formula _ (RPS × W × 1. 3).
ב ” Timeout”, עסקאות קצרות (<100ms).
בקשות דיווח כבדות - בריכה/העתק נפרד.
11. 3 GRPC פנימי
ערוץ אחד (HTTP/2) לכל מארח מטרה עם גבול חוט של 100-200.
תאריך יעד על RPC במסלול SLO, מגש רק אידמפוטנטי.
איתור ארוך של אר-פי-סי ומדדי זמן האחיזה.
12) רשימת מימושים (0-30 יום)
0-7 ימים
מדידה 'W' (hold-time) על מסלולי מפתח/לקוחות.
חישוב של N _ min = grough × W והוספת 30-50% ראש.
אפשר זמן שמירת חיים ופסקי זמן חיבור קצרים.
8-20 ימים
בריכות נפרדות (מהיר/איטי/חיצוני).
להקליד מפסקים מחדש ומגש תקציבים.
הוסף לוחות מחוונים: המתנת בריכה p95, יחס שימוש חוזר, במעוף.
21-30 ימים
עומס פועל עם פרצים, מבחן כאוס ”נפילה של גב”.
אופטימיזציה זנב: בידוד של נתיבים כבדים, מטמונים מקומיים.
מסמכי נוסחאות ומגבלות ב-runbook 'ax.
13) אנטי דפוסים
מידת בריכה ”באקראי” ואין חדר ראש.
חיבור גדול בזמן המתנה = זנבות ארוכים במקום כשלים מהירים.
נסיגות רבות ללא עצבנות ואידמפוטנציה = סערה.
בריכה משותפת לכל סוגי הבקשות.
עסקאות ארוכות לשמור על החיבור (DB) = הרעבה של השאר.
נכים נשארים בחיים, או קטנים מדי.
14) מדדי בגרות
בריכה להמתין p95 בדרבן <10% של מסלול p95 הכולל.
יחס שימוש חוזר (> 90% עבור HTTP פנימי;> 80% עבור חיצוני).
DB time p95 <100-200 ms; אחוז העסקאות הארוכות <1%.
שיעור החזרה <5% (ותקציב), שגיאות הנובעות מפסקי זמן הן יציבות וצפויות.
יישוב בריכה מתועד לכל הלקוחות הקריטיים.
15) מסקנה
איסוף חיבור יעיל הוא תור הנדסה + טיים-אאוט. למדוד 'W', לחשב את הבריכה 'xW עם מרווח, להדליק keep-alive/HTTP2 +, נתיבים איטיים נפרדים, לשמור על פסקי זמן קצרים ו Retras מינימלי עם ג' יטר. הוסף את יכולת התצפית של בריכת המתנה נגד latency ואת מפסקי המעגל, ותקבל TTFB נמוך,