When you use Ditto in your app, you don’t have to think about how your devices will connect in the peer-to-peer mesh network.
A device like an iPhone will build an interconnected mesh all on its own. As soon as you call startSync(), it fires up Bluetooth Low Energy (LE), scans for peers on the Wi-Fi, and activates Apple Wireless Direct Link (AWDL) to create high-speed connections with nearby Apple devices — using only one line of code.
The mesh is an underlay for data sync. It operates independently of your queries and subscriptions. Data updates will propagate through the mesh automatically, provided your subscriptions match.
Ditto contains several algorithms to maintain an optimal mesh automatically, whether you have two devices or two thousand.
Many applications need to sync data with the Big Peer or an on-premises server. The Ditto SDK uses peer-to-peer and Big Peer connections simultaneously, turning your mesh global. This is as easy as setting your server’s URL.
Types of Transports
Ditto uses as many technologies as possible to communicate with other devices running your app. These different modes, such as Bluetooth LE and Local Area Network (LAN), are called transports.
Where possible Ditto will create a mesh using a mixture of transports. They offer different advantages and disadvantages. For example, Bluetooth LE generally has a longer range but much lower bandwidth than Wi-Fi. Therefore Ditto uses Wi-Fi when available and falls back to Bluetooth LE when it is not. For an overview of performance and limitation by transport type, see Transports.
Which transports are supported depends on what kind of device or SDK you are using. Some examples:
- A mobile phone can use Bluetooth LE, LAN, Wi-Fi Direct, or a WebSocket connection to a Big Peer server.
- A web application running in a browser can use WebSocket.
- A Raspberry Pi can use Bluetooth LE, LAN, or WebSocket.
Many transports will work automatically. Others like WebSocket require configuration. For instructions, see Configuring Transports.
When Ditto starts syncing it advertises itself on all enabled peer-to-peer transports. This advertisement is transmitted in different ways depending on the transport but it always involves two small pieces of information.
- App ID Hash
All devices running the same app will have the same App ID Hash so they know they should connect to each other. In the rare event of a hash collision, Ditto may try to connect to a different app, but verification will fail and the connection will be cancelled immediately.
If you are monitoring network traffic you might come across a Ditto Announce. This is a Ditto-specific advertisement format which contains basic information about the device. This provides hints to Ditto so that it can construct a good mesh quickly and efficiently.
The Network ID is randomized each time Ditto starts up. It enables peers to identify each other with high probability across all transports. If Peer A connects to Peer B over Wi-Fi they know each other’s Network IDs, so Peer B can avoid creating a duplicate connection in the reverse direction.
When a user opens your app the first thing they will see is how quickly it syncs the latest information. Ditto understands this. When sync begins it uses all the transports aggressively to locate and connect to multiple potential peers concurrently. At the same time, the existing peers will notice the newcomer’s arrival. If they have capacity they will also establish connections to the new device. Together, these processes ensure that a new peer is integrated into the mesh as quickly as possible.
After this initial burst Ditto must become more efficient. A mobile phone has a finite battery. Each extra LAN connection consumes more CPU time and more radio energy. Bluetooth is particularly constrained: devices can manage only a handful of concurrent connections and each connection can take several seconds to initiate. Therefore in larger meshes, Ditto must limit the number of interconnections, and choose wisely.
At the same time, Ditto must not have too few connections: otherwise islanding can occur, where different groups of devices in the same room are connected in individual clusters. If there is no connection between those groups they will not sync data with each other.
Ditto avoids islanding using two techniques, neither of which require central coordination. First, a reasonably dense mesh is preferred so that islanding is improbable. Second, a random churn means that devices will slowly change which peers they are connected to. This ensures that even if an island did form, it would likely only last a few seconds.
Next, certain optimizations are possible. Imagine there are two candidate peers for a Bluetooth connection but you only have the capacity for one. If you are already connected to one of those peers via WiFi, then we should spend our Bluetooth connection on the other peer, to improve the diversity of the mesh.
Now, imagine the same scenario except we have capacity for two Bluetooth connections. This time we should connect to both of them. The Bluetooth connection where we have WiFi will sit idle for now, but if that WiFi connection goes away in the future then we can immediately failover to the pre-established Bluetooth connection. The user won't even notice that anything happened.
Sounds complicated? Don’t worry about it. Everything described here is built into Ditto and your app will do this completely automatically. All you need to do is enable your transports and Ditto will make the best possible use of them.
Using Bandwidth Intelligently
In smaller meshes, Ditto will often create multiple connections to the same peer using different transports. This might look wasteful but it provides important performance benefits.
- The transports race against each other to establish a connection. As soon as we get the first one, data sync can begin. This means lower latency for initial sync.
- The fastest connection is preferred to transfer data, so large updates sync as quickly as possible.
- Unneeded slower connections like Bluetooth are left idle, which means the limited radio bandwidth is reserved for those peers that really need it.
- If the fastest connection is lost, the next-best option is ready to go, reducing or eliminating the gap when no sync is possible.
The seamless switching between transports relies on a Ditto component called the Multiplexer, which is described in detail in a blog post.
The Multiplexer uses one transport at a time with failover. In future versions, this feature will enable more complex scenarios such as load-balancing across multiple routes and lossy transports.
Servers and the Big Peer
In addition to peer-to-peer transports like Bluetooth, a cloud or on-prem server can be configured by specifying its URL. At Ditto, we call a server like this a Big Peer, while regular SDKs are Small Peers.
An SDK can sync directly with a Big Peer, or locally with Small Peers, or with both at the same time, acting as a bridge for devices that don’t have an internet connection.
Configuring the Mesh
Every Ditto SDK has a configuration structure called TransportConfig, which lives in the main Ditto object. If you don’t change the default configuration Ditto will enable all available peer-to-peer transports.
If you create a new TransportConfig it has three main sections:
Most apps will only need to configure the peerToPeer and WebSocket settings.
The listen parameters provide support for unusual scenarios such as web browser clients on fully offline networks. Please use these only as directed by Ditto. If misconfigured, the listener features could circumvent Ditto’s usual encryption and access control.
For more information, see Configuring Transports.