שני מפתחים עורכים בו-זמנית את אותו קובץ תצורת JSON. תוך דקה—דה-סנכרון, אובדן עריכות. תרחיש זה מוכר לכל מי שעובד עם גישה מקבילית. שידור אירועים פשוט דרך WebSocket נשבר תחת שינויים בו-זמניים. ללא מודל נתונים פורמלי, קונפליקטים הם בלתי נמנעים. הצוות שלנו, עם ניסיון של 10 שנים, מיישם CRDT ו-OT לסנכרון ללא קונפליקטים. הפתרון מקצר את זמן הפיתוח ב-30% ומחזיר את עצמו תוך 3–4 חודשים, וחוסך עד 40% מתקציב הפיתוח.
בעיות ש-CRDT פותר
גישה מקבילית — כאשר שני משתמשים משנים את אותו אובייקט, ללא מודל מיוחד עריכות אובדות או נדרסות. CRDT מבטיח שכל העותקים מתכנסים למצב אחד. מצב לא מקוון — משתמש מבצע שינויים ללא אינטרנט, ועם החיבור מחדש הם מסתנכרנים אוטומטית. OT דורש חיבור קבוע. מורכבות יישום — כתיבת OT משלך ליותר משני לקוחות כרוכה בעשרות מקרי קצה. CRDT עם ספריות מוכנות (Yjs, Automerge) נותן פתרון עובד תוך ימים.
איך CRDT ו-OT עובדים: ההבדל היסודי
OT (טרנספורמציה אופרטיבית) הופך פעולות תוך התחשבות בשינויים מקביליים. השיטה שמאחורי Google Docs, עובדת רק עם שרת-בורר מרכזי. עבור >2 לקוחות, היישום הופך למורכב אקספוננציאלית. CRDT (סוגי נתונים משוכפלים ללא קונפליקטים) הם מבני נתונים שמבטיחים מתמטית עקביות ללא תיאום. הפעולות הן קומוטטיביות ואידמפוטנטיות. מידע נוסף בויקיפדיה.
| קריטריון | OT | CRDT |
|---|---|---|
| שרת מרכזי | חובה | אופציונלי (P2P) |
| תמיכה במצב לא מקוון | קשה | מובנית |
| ביצועים | גבוהים | תלוי |
| יישום | מורכב, מקרי קצה רבים | פשוט יותר עם ספריות מוכנות |
| טקסט עשיר | Google Docs, Quill | Yjs, Automerge |
למה CRDT רלוונטי לאפליקציות מודרניות?
CRDT מנצח בתרחישים של מצב לא מקוון, P2P ונקודת כשל יחידה. Yjs מקצר את זמן הפיתוח פי 2–3 בהשוואה ל-OT מותאם אישית—אינטגרציות מוכנות ללא לוגיקת טרנספורמציה. OT נשאר רלוונטי לעורכי טקסט בעומס גבוה, אבל עבור רוב אפליקציות ה-web CRDT הוא מעשי יותר. עלות האינטגרציה מופחתת ב-30% על ידי ביטול פתרונות מותאמים אישית. עבור לקוח שבונה לוח שיתופי, שילבנו את Yjs עם אחסון WebSocket. התוצאה: אפס קונפליקטי סנכרון, תמיכה בעריכה לא מקוונת, והפחתה של 40% בזמן הפיתוח בהשוואה לבניית OT מותאם אישית.
איך ליישם CRDT תוך 3–5 ימים?
- בחרו ספרייה: Yjs לטקסט, Automerge ל-JSON מורכב.
- החליפו מצבים מקומיים בסוגים משותפים (Y.Doc, Y.Text, Y.Map).
- פרסו שרת WebSocket (y-websocket או Hocuspocus) עם אחסון.
- בדקו גישה מקבילית.
- הוסיפו מודעות לסמנים.
להלן תצורה עובדת.
דוגמת אינטגרציה עם Yjs ו-WebSocket
npm install yjs y-websocket y-protocols שרת (y-websocket):
// server.js
const { WebSocketServer } = require('ws');
const { setupWSConnection } = require('y-websocket/bin/utils');
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200);
res.end('ok');
});
const wss = new WebSocketServer({ server });
wss.on('connection', (ws, req) => {
setupWSConnection(ws, req, {
docName: req.url.slice(1),
gc: true,
});
});
server.listen(1234);
לקוח עם Quill:
import * as Y from 'yjs';
import { WebsocketProvider } from 'y-websocket';
import { QuillBinding } from 'y-quill';
import Quill from 'quill';
const ydoc = new Y.Doc();
const provider = new WebsocketProvider(
'ws://localhost:1234',
'my-document-room',
ydoc,
{ connect: true }
);
provider.on('status', ({ status }) => {
console.log('WS status:', status);
});
provider.on('sync', (isSynced: boolean) => {
if (isSynced) {
console.log('Document synced from server');
}
});
const ytext = ydoc.getText('quill-content');
const quill = new Quill('#editor', {
theme: 'snow'
});
const binding = new QuillBinding(ytext, quill, provider.awareness);
provider.awareness.setLocalStateField('user', {
name: 'Иван Петров',
color: '#4a9eff',
});
אחסון נתונים: התמדה
y-websocket ארעי מאבד את המסמך בעת אתחול מחדש. עבור סביבת ייצור, אנו משתמשים ב-Hocuspocus עם PostgreSQL. תצורה לדוגמה
import { Server } from '@hocuspocus/server';
import { Database } from '@hocuspocus/extension-database';
import { Pool } from 'pg';
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const server = Server.configure({
port: 1234,
extensions: [
new Database({
fetch: async ({ documentName }) => {
const { rows } = await pool.query(
'SELECT data FROM documents WHERE name = $1',
[documentName]
);
return rows[0]?.data ?? null;
},
store: async ({ documentName, state }) => {
await pool.query(
`INSERT INTO documents (name, data, updated_at) VALUES ($1, $2, NOW()) ON CONFLICT (name) DO UPDATE SET data = $2, updated_at = NOW()`,
[documentName, Buffer.from(state)]
);
},
}),
],
});
server.listen();
השוואה בין Yjs ו-Automerge
| קריטריון | Yjs | Automerge 2.x |
|---|---|---|
| ביצועים | גבוהים לטקסט | טובים יותר ל-JSON גדול |
| גודל | ~30 KB gzip | ~50 KB gzip (WASM) |
| טקסט עשיר | Quill, ProseMirror | מניפולציית JSON ישירה |
| P2P | דרך y-websocket | רשת מובנית |
| תיעוד | נרחב | טוב |
פתרון קונפליקטים: איך CRDT בוחר מנצח
CRDT אינו מבטל קונפליקטים—הוא קובע מנצח דטרמיניסטי. Yjs משתמש באלגוריתם YATA: מיקום ההוספה נקבע על ידי אלמנטים שכנים, לא אינדקס, מה שהופך אותו לעמיד בפני הוספות מקביליות. עבור מפת Last-Write-Wins, הפעולה עם חותמת הזמן המאוחרת יותר מנצחת. מקרה קצה: שני משתמשים מוחקים ועורכים את אותו אלמנט בו-זמנית—CRDT שומר tombstone כדי להחיל שינויים בצורה נכונה.
קנה מידה וסנכרון מרובה-צמתים
שרת WebSocket יחיד אינו מתרחב אופקית. פתרונות: Sticky sessions (nginx), Pub/Sub דרך Redis (Hocuspocus תומך בכך באופן מובנה), שירותים מנוהלים (Liveblocks, PartyKit). חיסכון נוסף בתשתית: סנכרון CRDT אינו דורש שרת מרכזי יקר. הצוות שלנו מגדיר קלאסטר עם זמינות של 99.9%.
מה אנו מספקים ולוחות זמנים
- ביקורת ארכיטקטורה וניתוח מודל נתונים.
- בחירת ספרייה (Yjs, Automerge).
- אינטגרציית backend (Node.js, PostgreSQL/Redis).
- פיתוח סוגים משותפים מותאמים אישית (לוחות, טפסים).
- הגדרת התמדה וריבוי-תהליכים.
- בדיקת עומסים ב-5000 פעולות/שנייה.
- תיעוד והדרכת צוות.
לוחות זמנים: אינטגרציה בסיסית 3–5 ימים, עם התמדה +2–3 ימים, מרובה-צמתים +שבוע. צרו קשר לייעוץ חינמי והערכת פרויקט. הזמינו יישום—המהנדסים שלנו עם ניסיון של 10+ שנים סיפקו עשרות פרויקטים מוצלחים.







