Skip to content

Commit

Permalink
BC-7905 - refine technical details
Browse files Browse the repository at this point in the history
  • Loading branch information
bergatco committed Dec 4, 2024
1 parent a16f60d commit dd3e1fc
Showing 1 changed file with 73 additions and 4 deletions.
77 changes: 73 additions & 4 deletions docs/tldraw-server/Technical details.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,77 @@
# Technical details

## Introduction

In tldraw, **Y-Redis** and **S3 storage** are integrated to support collaborative drawing features, data synchronization, and persistent storage in a scalable and efficient manner. The combination of **Yjs** (used for collaborative editing), **Y-Redis** (for real-time data synchronization), and **S3** (for file storage) enables the platform to handle complex collaborative interactions and large-scale, persistent storage of drawing data.

### How tldraw Uses Y-Redis and S3 Storage:

1. **Real-time Collaboration with Yjs:**
- **Yjs** is the backbone of real-time collaboration in tldraw. It provides a **CRDT-based (Conflict-free Replicated Data Type)** framework for handling shared documents where changes made by one user are automatically and consistently synchronized across all other users in the same session.
- In tldraw, the **drawing canvas** or **document** is represented as a **Yjs document**. Users can draw shapes, lines, text, or modify the canvas in real time.
- The **Yjs document** tracks all changes in the form of small, incremental edits. These edits could be changes to the position of objects, the creation of new objects (e.g., shapes or lines), or modification of existing elements.

2. **Y-Redis for Real-Time Data Synchronization:**
- **Y-Redis** is used to store and synchronize these Yjs documents across multiple users in real time.
- Redis, being a fast in-memory key-value store, provides low-latency updates that are crucial for real-time collaboration. It is used for:
- **Broadcasting updates**: When one user makes a change, Yjs sends that change to the Redis server, which then distributes the change to all other connected users.
- **Data persistence**: Changes are stored in Redis and can be fetched by other users at any time to maintain consistency.
- The use of **Redis Pub/Sub** allows different instances of the tldraw application to subscribe to channels. When one user makes a change, the Redis system publishes the change, and other users (who are subscribed to that document) get updated immediately.

3. **S3 Storage for Persistent and Large-Scale File Storage:**
- While Y-Redis ensures real-time synchronization and collaboration, **S3** (Amazon Simple Storage Service) is used for **persistent storage** of larger files or data that need to be saved across sessions.
- **S3** is highly scalable and can store large amounts of data. For tldraw, S3 is primarily used for:
- **Storing canvases and drawings**: While **Y-Redis** handles real-time data synchronization and storage of changes, the worker service is responsible for **periodically persisting** the state of the collaborative canvas to **S3 storage**.
- **S3 as a file store**: Unlike Redis, which is an in-memory store designed for fast access and transient data, S3 is optimized for storing larger data in a persistent manner. This makes it suitable for storing media files, large canvas snapshots, and other assets that don't need to be constantly updated in real-time.

4. **Integration Between Y-Redis and S3:**
- **Y-Redis** and **S3** serve different but complementary purposes:
- **Y-Redis** handles **real-time synchronization** of drawing changes and interactions, ensuring that users see each other's edits in near real-time.
- **S3** handles **long-term storage** and **backup** of the drawings or canvases themselves. For example, when a user closes the app or saves their session, the drawing data is saved to S3.
- The worker service will save snapshots of the collaborative document or canvas to S3 periodically, ensuring that the state of the canvas is preserved even if a user disconnects or the server restarts.

5. **How tldraw's Workflow Would Look Using Y-Redis and S3:**
- **Step 1: Collaborative Drawing Session**
- Users interact with the tldraw canvas, making real-time changes (drawing shapes, text, etc.).
- The changes are immediately propagated through **Yjs** and **Y-Redis**. Y-Redis stores these changes in memory and broadcasts them to other users.
- Each user's drawing operations are synchronized, so everyone sees the same live canvas.

- **Step 2: Saving the Canvas**
- On a regular basis the worker service will send a **snapshot of the canvas** (or the entire Yjs document) to **S3**. This can include data about the shapes, their positions, colors, and any other relevant canvas data.
- The snapshot can be stored as a **JSON object**, an image, or another format, depending on how tldraw chooses to serialize the data.

- **Step 3: Retrieving Saved Data**
- When a user returns to the drawing session or opens the application at a later time, the application queries **S3** for the last saved canvas snapshot.
- Once retrieved, the snapshot is loaded back into the application, allowing users to continue editing from where they left off.
- Y-Redis can be used in the background to ensure that any new changes made by users are synchronized in real time while they are working on the canvas.

6. **Scalability and Fault Tolerance:**
- **Redis Scaling**: As more users join the session, Redis allows scaling horizontally, ensuring that updates are propagated quickly to all connected clients.
- **S3 Scaling**: S3 is designed to scale automatically and handle large amounts of storage without performance degradation. This makes it ideal for storing large or numerous drawing assets, like high-resolution images or full snapshots of large canvases.

### Benefits of Using Y-Redis and S3 Together:

- **Real-time Collaboration**: Y-Redis ensures that changes made by users are immediately reflected for all participants, enabling fluid collaboration on the canvas.
- **Persistence**: S3 provides long-term storage for the canvas and drawing data, allowing for version control, backups, and recovery in case of unexpected disruptions.
- **Scalability**: Redis handles real-time data synchronization efficiently, even with a large number of concurrent users. S3 handles large files and assets without requiring custom infrastructure management.
- **Separation of Concerns**: Redis is optimized for fast, real-time data synchronization, while S3 handles large-scale, persistent storage, allowing tldraw to leverage both for different aspects of the application.

### Example Scenario:

- **User A** and **User B** start a collaborative session in tldraw, and they can see each other's updates in real time (thanks to Y-Redis).
- After some time, the worker service saves the drawing to S3, and now the drawing is stored in S3 as a persistent snapshot.
- **User B**, who was not connected when the session ended, can later load the canvas from S3, where the most recent version is stored.
- Meanwhile, as new users join the session, **Y-Redis** continues to handle the real-time synchronization of the drawing, ensuring smooth interaction.

### Conclusion:

In **tldraw**, **Y-Redis** and **S3** are integrated to deliver a collaborative and scalable experience. Y-Redis ensures real-time synchronization of drawing changes among multiple users, while S3 provides persistent and scalable storage for canvas data. This combination allows tldraw to offer seamless collaboration, persistent storage, and fault-tolerant handling of large-scale data.

## Backend
We are using pure Web Sockets implementation to establish connection between client and server. The reason why we used pure websockets is because tldraw-client is using y-websockets from Yjs library, that does not connect with socket.io web sockets. We also have to implement broadcasting mechanism to provide stateless solution. To achive that goal we decided to use Redis. We used ioredis library to connect to our Redis instance. Everytime user make some changes at first it is handled to the server instance that he is connected to an then this change is send to the channel with the name of the board and servers that also operate that board are listening on this channel so they can recive messages from other servers and provide those changes to users that are connected to this pod. We added the same mechanism for awareness channel so every user from every pod can see other users cursors.

Tldraw is deployed as a separate application from schoulcloud-server. On the backend side we have added couple new resources:
### Deployments

Tldraw is deployed as a separate application from schoulcloud-server and consists of the following deployments :

- tldraw-server-deployment - deployment for tldraw-server's instances.
- tldraw-worker-deployment - deployment for worker's instances.
Expand All @@ -17,7 +85,7 @@ Tldraw is deployed as a separate application from schoulcloud-server. On the bac
- redis.service.ts - encapsulates the logic for creating and managing Redis instances, supporting both standalone and sentinel configurations, and integrates seamlessly with the NestJS framework.
- ioredis.adapter.ts - encapsulates the logic for interacting with Redis, including defining custom commands and subscribing to channels. It leverages the ioredis library and integrates with the application's configuration and logging systems to provide a robust and flexible Redis adapter.
- api.service.ts - API service for y-redis.
- ws.service.ts - main service responsible for establishing web socket connection as well as saving data to database. Responsibe for Redis communication.
- ws.service.ts - Responsibe for Redis communication.
- metrics.service.ts - service resonsible for storing application-level metrics.
- worker.service.ts - responsible for persisting the current state of changed tldraw documents into the file storage.

Expand All @@ -26,6 +94,7 @@ On the backend side we are also using Yjs library to store tldraw board in memor
## Frontend

### Key Files

- stores/setup.ts – this file provides a real-time collaboration environment for a drawing application using the WebSocket and Yjs libraries.
- hooks/useMultiplayerState.ts – custom hook for managing multiplayer state.
- App.tsx – main application component integrating Tldraw and multiplayer state.
Expand All @@ -48,6 +117,7 @@ The frontend of the project is built using React and leverages various libraries
- File system operations like opening and saving projects.

#### useTldrawUiSanitizer.ts

This hook is designed to observe changes in the DOM, specifically targeting certain buttons and a horizontal rule (< hr>), and hides them if they match a specific ID pattern. We hide this elements and left just only Language and Keyboard shortcuts.

#### Event Handling
Expand Down Expand Up @@ -81,4 +151,3 @@ This hook is designed to observe changes in the DOM, specifically targeting cert
- https://teamchat.dbildungscloud.de/channel/G9hJWv92zXEESKK3X - rocketchat discussion "tldraw syncronisation for release again"

- https://teamchat.dbildungscloud.de/group/SagK4sCyujhu6yZr8 - rocketchat discussion "Tldraw deployment"s

0 comments on commit dd3e1fc

Please sign in to comment.