הרחבת תשתית בלוקצ'יין: מצומת ל-WebSocket

הרחבת תשתית בלוקצ'יין: מצומת ל-WebSocket תשתית שעבדה היטב עם 100 משתמשים מתחילה להתפורר ב-10,000. מחסנית הבלוקצ'יין היא ספציפית: צוואר הבקבוק הוא לעתים קרובות לא במקום שבו מצפים – לא במסד הנתונים, לא ב-CPU – אלא בצומת RPC שלא יכול לעמוד בקצב של `eth_getLogs

שירותי פיתוח בלוקצ'יין

שאלות נפוצות

העבודות האחרונות

  • image_website-b2b-advance_0.webp
    פיתוח אתר חברה B2B ADVANCE
    1451
  • image_web-applications_feedme_466_0.webp
    פיתוח אפליקציית ווב עבור FEEDME
    1309
  • image_websites_belfingroup_462_0.webp
    פיתוח אתר עבור BELFINGROUP
    1005
  • image_ecommerce_furnoro_435_0.webp
    פיתוח חנות מקוונת לחברת FURNORO
    1270
  • image_logo-advance_0.webp
    עיצוב לוגו לחברת B2B Advance
    719
  • image_crm_enviok_479_0.webp
    פיתוח אפליקציית ווב עבור Enviok
    1011

הרחבת תשתית בלוקצ'יין: מצומת ל-WebSocket

תשתית שעבדה היטב עם 100 משתמשים מתחילה להתפורר ב-10,000. מחסנית הבלוקצ'יין היא ספציפית: צוואר הבקבוק לרוב אינו במקום שבו מצפים – לא במסד הנתונים, לא במעבד – אלא בצומת RPC שלא יכול לעמוד בקצב של eth_getLogs, או באינדקסר שמפגר ב-50 בלוקים, או במטפל WebSocket שמפיל חיבורים תחת עומס. הרחבת תשתית בלוקצ'יין היא דיסציפלינה נפרדת עם דפוסים לא קונבנציונליים. אנחנו עושים זאת כבר למעלה מ-5 שנים ומבטיחים שהתשתית שלכם תוכל לעמוד בכל עומס – צרו קשר, נבחן את הפרויקט שלכם ללא עלות.

למה הרחבת תשתית בלוקצ'יין היא דיסציפלינה נפרדת

בניגוד ל-web קלאסי, ישנן נקודות כשל שלא ניתן לתקן על ידי הוספת שרתים פשוטה: מצב השרשרת, מגבלות WebSocket, נתונים בלתי ניתנים לשינוי בצמתים. כל שכבה דורשת גישה משלה – ממאגר צמתים ועד אינדוקס מונחה אירועים.

אבחון: היכן צוואר הבקבוק האמיתי

לפני שמרחיבים כל דבר – מדדו. צווארי בקבוק טיפוסיים: זמן השהיה לכל שיטת RPC, עומק תור האינדקסר, פער בין ראש הצומת לראש מסד הנתונים, תפוקת חיבורי WebSocket. אנו משתמשים ב-Prometheus ובדשבורדים מוכנים לאיסוף מדדים – כלול בהיקף העבודה.

// Инструментация RPC вызовов class InstrumentedProvider { private metrics: Map<string, number[]> = new Map(); async call(method: string, params: any[]): Promise<any> { const start = performance.now(); try { const result = await this.provider.send(method, params); this.record(method, performance.now() - start); return result; } catch (err) { this.recordError(method); throw err; } } getPercentiles(method: string) { const samples = (this.metrics.get(method) || []).sort((a, b) => a - b); return { p50: samples[Math.floor(samples.length * 0.5)], p95: samples[Math.floor(samples.length * 0.95)], p99: samples[Math.floor(samples.length * 0.99)], count: samples.length, }; } } 

איך להרחיב את שכבת RPC

מאגר צמתים עם איזון עומסים

צומת יחיד הוא נקודת כשל יחידה וצוואר בקבוק. תצורת ייצור מינימלית: שלושה צמתים עם בדיקות בריאות ו-round-robin שמדלג על צמתים לא בריאים. לפעולות stateful (מנויים, עסקאות ממתינות) – ניתוב דביק (sticky routing). קוד הדוגמה למטה – אנו משתמשים בו בכל פרויקט.

class NodePool { private nodes: RpcNode[]; private currentIndex = 0; private healthStatus: Map<string, boolean> = new Map(); async sendRequest(method: string, params: any[]): Promise<any> { for (let i = 0; i < this.nodes.length; i++) { const node = this.nodes[this.currentIndex % this.nodes.length]; this.currentIndex++; if (!this.healthStatus.get(node.url)) continue; try { return await node.send(method, params); } catch (err) { this.healthStatus.set(node.url, false); setTimeout(() => this.healthStatus.set(node.url, true), 30_000); } } throw new Error('All nodes unhealthy'); } } 

שמירת תגובות RPC במטמון

בקשות רבות זהות וניתנות לשמירה במטמון: // Инструментация RPC вызовов class InstrumentedProvider { private metrics: Map<string, number[]> = new Map(); async call(method: string, params: any[]): Promise<any> { const start = performance.now(); try { const result = await this.provider.send(method, params); this.record(method, performance.now() - start); return result; } catch (err) { this.recordError(method); throw err; } } getPercentiles(method: string) { const samples = (this.metrics.get(method) || []).sort((a, b) => a - b); return { p50: samples[Math.floor(samples.length * 0.5)], p95: samples[Math.floor(samples.length * 0.95)], p99: samples[Math.floor(samples.length * 0.99)], count: samples.length, }; } } (24 שעות), class NodePool { private nodes: RpcNode[]; private currentIndex = 0; private healthStatus: Map<string, boolean> = new Map(); async sendRequest(method: string, params: any[]): Promise<any> { for (let i = 0; i < this.nodes.length; i++) { const node = this.nodes[this.currentIndex % this.nodes.length]; this.currentIndex++; if (!this.healthStatus.get(node.url)) continue; try { return await node.send(method, params); } catch (err) { this.healthStatus.set(node.url, false); setTimeout(() => this.healthStatus.set(node.url, true), 30_000); } } throw new Error('All nodes unhealthy'); } } (שעה – קוד החוזה לא משתנה), eth_chainId עבור גרסאות שאינן האחרונות (דקה), eth_getCode (5 דקות לאחר סופיות). לעולם אל תשמרו במטמון eth_getBlockByNumber או eth_getTransactionReceipt. השתמשו ב-Redis – זה מפחית בקשות לצומת ב-80%.

const CACHEABLE_METHODS: Record<string, number> = { 'eth_chainId': 86400, 'eth_getCode': 3600, 'eth_getBlockByNumber': 60, 'eth_getTransactionReceipt': 300, }; class CachingRpcProxy { async send(method: string, params: any[]): Promise<any> { const ttl = CACHEABLE_METHODS[method]; if (!ttl) return this.upstream.send(method, params); if (params.includes('latest') || params.includes('pending')) { return this.upstream.send(method, params); } const cacheKey = `rpc:${method}:${JSON.stringify(params)}`; const cached = await this.redis.get(cacheKey); if (cached) return JSON.parse(cached); const result = await this.upstream.send(method, params); await this.redis.setex(cacheKey, ttl, JSON.stringify(result)); return result; } } 

אינדוקס: מסקירה תקופתית למונחה אירועים

בעיית הסקירה התקופתית

סקירה כל 5 שניות עבור 10,000 כתובות – 2,000 בקשות בשנייה. הצומת מוצף. עברו למודל מונחה אירועים באמצעות יומני EVM: latest אחד עבור טווח בלוקים מחליף אלפי בקשות בודדות. חיסכון – עד 90% מעומס RPC.

The Graph לאינדוקס מורכב

לצבירות לפי משתמש, נתונים היסטוריים – The Graph subgraph. Graph Node באירוח עצמי על PostgreSQL 14+ עם קלט/פלט מספק. כלול בהיקף עבודה טיפוסי: הגדרת subgraph, פריסה, ניטור.

WebSocket: הרחבת מנויים

WebSocket הוא stateful – round-robin של nginx לא עובד. השתמשו ב-Redis pub/sub: שירות נפרד מפרסם אירועים (בלוק חדש, עסקה) ל-Redis, ושרתי WS נרשמים ומפיצים ללקוחותיהם. הוספת שרת WS נוסף – הדבר היחיד הנדרש להרחבה אופקית.

ניהול עומס הצומת

מיזוג בקשות – אם 100 בקשות מבקשות בו-זמנית את אותו משאב, שלבו אותן לקריאת RPC אחת. Multicall – בקשת HTTP אחת במקום 100 עבור pending. שני הדפוסים מפחיתים את עומס הצומת עשרות מונים.

בעיה פתרון מורכבות חיסכון בעומס RPC
צוואר בקבוק בצומת RPC מאגר צמתים + איזון נמוכה 50%+
בקשות זהות חוזרות מיזוג בקשות + מטמון Redis נמוכה 80%+
ניטור יתרות של 100+ כתובות Multicall + אינדוקס אירועים בינונית 90%+
WS מפיל חיבורים תחת עומס תשתית Redis pub/sub בינונית
שאילתות היסטוריות איטיות ארכיון Erigon/Reth + אופטימיזציית שאילתות בינונית 70%+
אנליטיקה מורכבת של נתוני on-chain The Graph subgraph גבוהה

מה כלול בעבודה שלנו

  • ביקורת של הארכיטקטורה הנוכחית עם מדידת זמן השהיה, תפוקה ופיגור;
  • תכנון פתרון למחסנית שלכם (Ethereum, Polygon, Arbitrum, Solana);
  • יישום: מאגר צמתים, מטמון, אינדוקס מונחה אירועים, שער WebSocket;
  • שילוב ניטור (Grafana, Prometheus, התראות);
  • תיעוד והעברת גישה;
  • הכשרת צוות על התשתית החדשה;
  • חודש תמיכה לאחר ההשקה.

תהליך

  1. אנליטיקה – פרופיל התשתית הנוכחית, זיהוי צווארי בקבוק.
  2. עיצוב – בחירת דפוסים, הכנת סכמה.
  3. יישום – כתיבת קוד, הגדרת שירותים.
  4. בדיקות – מבחני עומס על התרחישים שלכם.
  5. פריסה וניטור – השקה עם תצפית בימים הראשונים.

לוחות זמנים משוערים

מ-2 עד 6 שבועות תלוי במורכבות ובמספר הרשתות. העלות מחושבת באופן אישי לאחר הביקורת – צרו קשר, נעריך תוך 1-2 ימים.

אנו עובדים עם Ethereum, Polygon, Arbitrum, Optimism, BNB Chain, Solana. ניסיון – 10+ פרויקטים, למעלה מ-5 שנים בשוק. איכות מובטחת: כל הפתרונות עוברים בדיקה וסקירה.