כל עיכוב בהצגת ציטוטי מניות יכול לעלות ללקוח בסכום גדול. בעורך מרובה משתמשים, חוסר סנכרון מצב מוביל לאובדן עריכות. Ably מבטיחה זמן אחזור מתחת ל-50 אלפיות השנייה ומשלוח מובטח עם SLA של 99.999% לתוכניות ארגוניות. השלמנו למעלה מ-50 אינטגרציות של Ably למוצרי פינטק, אדטק ושיתוף פעולה, כולל פרויקטים עם מיליוני משתמשים בו-זמנית. במאמר זה, אנו מפרקים כיצד להגדיר pub/sub, אימות אסימונים (token auth), ולהימנע מטעויות נפוצות, בהתבסס על ניסיון אמיתי.
למה Ably?
Ably היא פלטפורמת זמן אמת מנוהלת עם תשתית גלובלית (180+ PoP), תמיכה ב-pub/sub, נוכחות (presence), והיסטוריית הודעות. בניגוד ל-Pusher, Ably מספקת זרמי WebSocket מובנים ושמירת היסטוריה עד 30 ימים. WebSocket הוא פרוטוקול תקשורת דו-כיווני מלא מעל TCP. אנו בוחרים ב-Ably לפרויקטים שבהם זמינות של 99.999% וקנה מידה למיליון חיבורים בו-זמנית הם קריטיים. בהשוואה ל-Socket.IO, Ably מציעה זמן אחזור נמוך פי 10 למשלוח גלובלי וזמינות גבוהה פי 5 מ-Pusher.
| תכונה | Ably | Pusher | Socket.IO (באירוח עצמי) |
|---|---|---|---|
| זמן אחזור (P95) | <50 אלפיות השנייה | <100 אלפיות השנייה | תלוי בשרת |
| שמירת היסטוריה | עד 30 ימים | 24 שעות | אין מובנה |
| תשתית גלובלית | 180+ PoP | ~10 PoP | אין |
| אימות אסימונים עם הרשאות | מובנה | דרך פרוקסי | דורש הטמעה |
| SLA | 99.999% | 99.95% | אין |
כיצד לאבטח ערוצי זמן אמת?
האבטחה מבוססת על שלוש רמות: תעבורה (TLS 1.3), אימות (אימות אסימונים), והרשאות (capability). Ably תומכת ברשימות IP מורשות. אנו תמיד משתמשים באימות אסימונים בצד הלקוח — מפתח ה-API לעולם אינו מועבר. עבור כל clientId, אנו מגדירים הרשאות: subscribe, publish, presence. ראו את הדוגמה להלן.
דוגמה ליצירת אסימון עם הרשאות
const tokenParams = {
clientId: req.user.id,
capability: {
[`prices:*`]: ['subscribe'],
[`notifications:${req.user.id}`]: ['subscribe'],
[`user-actions:${req.user.id}`]: ['publish', 'subscribe'],
},
ttl: 60 * 60 * 1000,
};
const tokenRequest = await ably.auth.createTokenRequest(tokenParams);
איך אנחנו עושים את זה
אנו משתמשים בלקוח Ably REST בצד השרת לפרסום נתונים ובלקוח Realtime בצד הלקוח עם אימות אסימונים בחזית. להלן קוד טיפוסי לפרסום והרשמה.
שרת — פרסום נתונים
import Ably from 'ably';
const ably = new Ably.Rest({ key: process.env.ABLY_API_KEY });
// Публикация обновления цены (например, биржевой котировки)
async function publishPriceUpdate(symbol: string, price: number) {
const channel = ably.channels.get(`prices:${symbol}`);
await channel.publish('price-update', { symbol, price, timestamp: Date.now(), change: calculateChange(symbol, price) });
}
// Bulk publish для нескольких символов
async function publishBatch(updates: PriceUpdate[]) {
await Promise.all(
updates.map(u => publishPriceUpdate(u.symbol, u.price))
);
} אסימוני הרשאה (Ably Token Auth)
לעולם אל תעבירו את מפתח ה-API ללקוח — השתמשו באימות אסימונים:
// Сервер генерирует токен для клиента
app.get('/ably/token', authenticate, async (req, res) => {
const tokenParams = {
clientId: req.user.id,
capability: {
// Что может делать этот клиент
[`prices:*`]: ['subscribe'],
[`notifications:${req.user.id}`]: ['subscribe'],
[`user-actions:${req.user.id}`]: ['publish', 'subscribe']
},
ttl: 60 * 60 * 1000 // 1 час
};
const tokenRequest = await ably.auth.createTokenRequest(tokenParams);
res.json(tokenRequest);
});
לקוח (React)
import Ably from 'ably';
import { useEffect, useState } from 'react';
function usePriceUpdates(symbols: string[]) {
const [prices, setPrices] = useState<Record<string, number>>({});
useEffect(() => {
const client = new Ably.Realtime({
authUrl: '/ably/token',
authHeaders: {
Authorization: `Bearer ${getToken()}`
}
});
const channels = symbols.map(symbol => {
const channel = client.channels.get(`prices:${symbol}`);
channel.subscribe('price-update', (message) => {
setPrices(prev => ({ ...prev, [message.data.symbol]: message.data.price }));
});
return channel;
});
return () => {
channels.forEach(ch => ch.unsubscribe());
client.close();
};
}, [symbols.join(',')]);
return prices;
} היסטוריית הודעות
Ably מאחסנת היסטוריה — מנוי חדש יכול לאחזר הודעות שהוחמצו:
// Получить последние 100 сообщений из канала
const channel = client.channels.get('notifications');
const history = await channel.history({ limit: 100, direction: 'backwards' });
for (const item of history.items) {
console.log(item.data, item.timestamp);
} טעויות נפוצות באינטגרציה של Ably
- פרסום ללא היסטוריה. אם persisted מושבת, לא ניתן לשחזר נתונים שהוחמצו. תמיד הפעילו שמירת היסטוריה עבור ערוצים.
- חוסר בלוגיקת ניסיון חוזר. בשגיאות חולפות, הלקוח צריך להתחבר מחדש אוטומטית — Ably SDK עושה זאת כברירת מחדל.
- הרשאות רחבות מדי. הגבילו הרשאות ערוץ: לקוח לא צריך לפרסם לערוצים של לקוחות אחרים.
| תרחיש | ערוץ מומלץ |
|---|---|
| ציטוטי מניות | const tokenParams = { clientId: req.user.id, capability: { [`prices:*`]: ['subscribe'], [`notifications:${req.user.id}`]: ['subscribe'], [`user-actions:${req.user.id}`]: ['publish', 'subscribe'] }, ttl: 60 * 60 * 1000 }; const tokenRequest = await ably.auth.createTokenRequest(tokenParams); עם persisted=true |
| צ'אט | import Ably from 'ably'; const ably = new Ably.Rest({ key: process.env.ABLY_API_KEY }); // Публикация обновления цены (например, биржевой котировки) async function publishPriceUpdate(symbol: string, price: number) { const channel = ably.channels.get(`prices:${symbol}`); await channel.publish('price-update', { symbol, price, timestamp: Date.now(), change: calculateChange(symbol, price) }); } // Bulk publish для нескольких символов async function publishBatch(updates: PriceUpdate[]) { await Promise.all( updates.map(u => publishPriceUpdate(u.symbol, u.price)) ); } עם היסטוריה של 24 שעות |
| עריכה שיתופית | // Сервер генерирует токен для клиента app.get('/ably/token', authenticate, async (req, res) => { const tokenParams = { clientId: req.user.id, capability: { // Что может делать этот клиент [`prices:*`]: ['subscribe'], [`notifications:${req.user.id}`]: ['subscribe'], [`user-actions:${req.user.id}`]: ['publish', 'subscribe'] }, ttl: 60 * 60 * 1000 // 1 час }; const tokenRequest = await ably.auth.createTokenRequest(tokenParams); res.json(tokenRequest); }); עם נוכחות והרשאות |
| התראות | import Ably from 'ably'; import { useEffect, useState } from 'react'; function usePriceUpdates(symbols: string[]) { const [prices, setPrices] = useState<Record<string, number>>({}); useEffect(() => { const client = new Ably.Realtime({ authUrl: '/ably/token', authHeaders: { Authorization: `Bearer ${getToken()}` } }); const channels = symbols.map(symbol => { const channel = client.channels.get(`prices:${symbol}`); channel.subscribe('price-update', (message) => { setPrices(prev => ({ ...prev, [message.data.symbol]: message.data.price })); }); return channel; }); return () => { channels.forEach(ch => ch.unsubscribe()); client.close(); }; }, [symbols.join(',')]); return prices; } עם push |
כיצד Ably מבטיחה משלוח הודעות בזמן כשלים?
Ably משתמשת בפרוטוקול משלוח אמין עם אישור קבלה וניסיונות חוזרים אוטומטיים במקרה של כשל. הודעות נכנסות לתור עד שהלקוח מאשר קבלה. הודות לרשת ה-PoP הגלובלית, אם צומת אחד נכשל, התעבורה מועברת אוטומטית לצומת הקרוב ביותר שפועל. זה מבטיח משלוח ללא אובדן גם במהלך תקלות רשת קצרות.
מה כוללת האינטגרציה במפתח מוכן
- ארכיטקטורת ערוצים ואירועים — אנו מתכננים את המבנה עבור התרחיש העסקי שלכם.
- אימות אסימונים — יצירת אסימונים עם הרשאות מינימליות.
- הרשמת לקוח — hooks של React/Vue/Angular להרשמה לערוצים.
- ניטור ורישום — הגדרת לוחות מחוונים של Ably למעקב אחר מדדים.
- תיעוד — תיאור סכמת הערוצים, אירועים ודוגמאות קוד.
- הדרכת צוות — מפגש של שעתיים על עבודה עם Ably.
- תמיכה טכנית — חודש אחד לאחר ההשקה.
העלות הכוללת של בעלות על אינטגרציה כזו משתלמת בזכות קיצור זמן הפיתוח בשבועיים והפחתת עלויות התשתית ב-30%.
תהליך
- אנליטיקה — ניתוח תרחישי זמן אמת: ציטוטים, צ'אט, עריכה שיתופית.
- עיצוב — הגדרת ערוצים, אירועים, זכויות גישה.
- הטמעה — הגדרת פרסום בצד השרת והרשמה בצד הלקוח.
- בדיקות — בדיקות עומס עם הדמיה של אלפי חיבורים בו-זמנית.
- השקה — פריסה לייצור עם ניטור.
לוחות זמנים
- אינטגרציית pub/sub בסיסית עם אימות אסימונים — 1–2 ימים.
- הטמעה מלאה עם היסטוריה, נוכחות וניטור — 5–7 ימים.
העלות מחושבת באופן אישי. צרו קשר לייעוץ — נעריך את הפרויקט שלכם תוך יום אחד. הזמינו אינטגרציית Ably במפתח מוכן.







