From 922c369db4d5cc4169d7bea3412ccd5b67f342ec Mon Sep 17 00:00:00 2001 From: Oskar Thoren Date: Thu, 18 Jul 2019 20:23:30 +0800 Subject: [PATCH] P2P data sync entry --- _config.yml | 9 +- _posts/2019-07-17-p2p-data-sync-for-mobile.md | 108 ++++++++++++++++++ _posts/2019-07-17-welcome-to-jekyll.markdown | 26 ----- assets/img/mvds_batch.png | Bin 0 -> 14443 bytes assets/img/mvds_interactive.png | Bin 0 -> 24910 bytes 5 files changed, 116 insertions(+), 27 deletions(-) create mode 100644 _posts/2019-07-17-p2p-data-sync-for-mobile.md delete mode 100644 _posts/2019-07-17-welcome-to-jekyll.markdown create mode 100644 assets/img/mvds_batch.png create mode 100644 assets/img/mvds_interactive.png diff --git a/_config.yml b/_config.yml index 91834793..0af13f4a 100644 --- a/_config.yml +++ b/_config.yml @@ -17,7 +17,7 @@ title: Vac description: >- # this means to ignore newlines until "baseurl:" Vac is a modular peer-to-peer messaging stack, with a focus on secure messaging. baseurl: "" # the subpath of your site, e.g. /blog -url: "" # the base hostname & protocol for your site, e.g. http://example.com +url: "vac.dev" # the base hostname & protocol for your site, e.g. http://example.com twitter_username: vacp2p github_username: vacp2p @@ -38,3 +38,10 @@ plugins: # - vendor/cache/ # - vendor/gems/ # - vendor/ruby/ + + +defaults: + - scope: + path: "assets/img" + values: + image: true diff --git a/_posts/2019-07-17-p2p-data-sync-for-mobile.md b/_posts/2019-07-17-p2p-data-sync-for-mobile.md new file mode 100644 index 00000000..74acd413 --- /dev/null +++ b/_posts/2019-07-17-p2p-data-sync-for-mobile.md @@ -0,0 +1,108 @@ +--- +layout: post +title: "P2P Data Sync for Mobile" +date: 2019-07-18 12:00:00 +0800 +author: oskarth +published: true +permalink: /p2p-data-sync-for-mobile +categories: research +--- + +Together with decanus, I've been working on the problem of data sync lately. + +In building p2p messaging systems, one problem you quickly come across is the problem of reliably transmitting data. If there's no central server with high availability guarantees, you can't meaningfully guarantee that data has been transmitted. One way of solving this problem is through a synchronization protocol. + +There are many synchronization protocols out there and I won't go into detail of how they differ with our approach here. Some common examples are Git and Bittorrent, but there are also projects like IPFS, Swarm, Dispersy, Matrix, Briar, SSB, etc. + +## Problem motivation + +Why do we want to do p2p sync for mobilephones in the first place? There are three components to that question. One is on the value of decentralization and peer-to-peer, the second is on why we'd want to reliably sync data at all, and finally why mobilephones and other resource restricted devices. + +### Why p2p? +For decentralization and p2p, there are both technical and social/philosophical reasons. Technically, having a user-run network means it can scale with the number of users. Data locality is also improved if you query data that's close to you, similar to distributed CDNs. The throughput is also improved if there are more places to get data from. + +Socially and philosophically, there are several ways to think about it. Open and decentralized networks also relate to the idea of open standards, i.e. compare the longevity of AOL with IRC or Bittorrent. One is run by a company and is shut down as soon as it stops being profitable, the others live on. Additionally increasingly control of data and infrastructure is becoming a liability. By having a network with no one in control, everyone is. It's ultimately a form of democratization, more similar to organic social structures pre Big Internet companies. This leads to properties such as censorship resistance and coercion resistance, where we limit the impact a 3rd party might have a voluntary interaction between individuals or a group of people. Examples of this are plentiful in the world of Facebook, Youtube, Twitter and WeChat. + +### Why reliably sync data? +At risk of stating the obvious, reliably syncing data is a requirement for many problem domains. You don't get this by default in a p2p world, as it is unreliable with nodes permissionslessly join and leave the network. In some cases you can get away with only ephemeral data, but usually you want some kind of guarantees. This is a must for reliable group chat experience, for example, where messages are expected to arrive in a timely fashion and in some reasonable order. The same is true for messages there represent financial transactions, and so on. + +### Why mobilephones? +Most devices people use daily are mobile phones. It's important to provide the same or at least similar guarantees to more traditional p2p nodes that might run on a desktop computer or computer. The alternative is to rely on gateways, which shares many of the drawbacks of centralized control and prone to censorship, control and surveillence. + +More generally, resource restricted devices can differ in their capabilities. One example is smartphones, but others are: desktop, routers, Raspberry PIs, POS systems, and so on. The number and diversity of devices are exploding, and it's useful to be able to leverage this for various types of infrastructure. The alternative is to centralize on big cloud providers, which also lends itself to lack of democratization and censorship, etc. + +## Minimal Requirements + +For requirements or design goals for a solution, here's what we came up with. + +1. MUST sync data reliably between devices. By reliably we mean having the ability to deal with messages being out of order, dropped, duplicated, or delayed. + +2. MUST NOT rely on any centralized services for reliability. By centralized services we mean any single point of failure that isn’t one of the endpoint devices. + +3. MUST allow for mobile-friendly usage. By mobile-friendly we mean devices that are resource restricted, mostly-offline and often changing network. + +4. MAY use helper services in order to be more mobile-friendly. Examples of helper services are decentralized file storage solutions such as IPFS and Swarm. These help with availability and latency of data for mostly-offline devices. + +5. MUST have the ability to provide casual consistency. By casual consistency we mean the commonly accepted definition in distributed systems literature. This means messages that are casually related can achieve a partial ordering. + +6. MUST support ephemeral messages that don’t need replication. That is, allow for messages that don’t need to be reliabily transmitted but still needs to be transmitted between devices. + +7. MUST allow for privacy-preserving messages and extreme data loss. By privacy-preserving we mean things such as exploding messages (self-destructing messages). By extreme data loss we mean the ability for two trusted devices to recover from a, deliberate or accidental, removal of data. + +8. MUST be agnostic to whatever transport it is running on. It should not rely on specific semantics of the transport it is running on, nor be tightly coupled with it. This means a transport can be swapped out without loss of reliability between devices. + +## MVDS - a minimium viable version + +The first minimum viable version is in an alpha stage, and it has a [specification](https://github.com/status-im/bigbrother-specs/blob/master/data_sync/mvds.md), [implementation](https://github.com/status-im/mvds) and we have deployed it in a [console client](https://github.com/status-im/status-console-client) for end to end functionality. It's heavily inspired by [Bramble Sync Protocol](https://code.briarproject.org/briar/briar-spec/blob/master/protocols/BSP.md). + +The spec is fairly minimal. You have nodes that exchange records over some secure transport. These records are of different types, such as `OFFER`, `MESSAGE`, `REQUEST`, and `ACK`. A peer keep tracks of the state of message for each node it is interacting with. There's also logic for message retransmission with exponential delay. The positive ACK and retransmission model is quite similar to how TCP is designed. + +There are two different modes of syncing, interactive and batch mode. See sequence diagrams below. + +Interactive mode: + + +Batch mode: + + +Which mode should you choose? It's a tradeoff of latency and bandwidth. If you want to minimize latency, batch mode is better. If you care about preserving bandwidth interactive mode is better. The choice is up to each node. + +### Basic simulation + +Initial ad hoc bandwidth and latency testing shows some issues with a naive approach. Running with the default simulation settings (https://github.com/status-im/mvds/): + +- communicating nodes: 2 +- nodes using interactive mode: 2 +- interval between messages: 5s +- time node is offine: 90% +- nodes each node is sharing with: 2 + +we notice a [huge overhead](https://notes.status.im/7QYa4b6bTH2wMk3HfAaU0w#). More specifically, we see a ~5 minute latency overhead and a bandwidth multiplier of x100-1000, i.e. 2-3 orders of magnitude just for receiving a message with interactive mode, without acks. + +Now, that seems terrible. A moment of reflection will reveal why that is. If each node is offline uniformly 90% of the time, that means that each record will be lost 90% of the time. Since interactive mode requires offer, request, payload (and then ack), that's three links just for Bob to receive the actual message. + +Each failed attempt implies another retransmission. That means we have `(1/0.1)^3 = 1000` expected overhead to receive a message in interactive mode. The latency follows naturally from that, with the retransmission logic. + +### Mostly-offline devices + +The problem above hints at the requirements 3 and 4 above. While we did get reliable syncing (requirement 1), it came at a big cost. + +There are a few ways of getting around this issue. One is having a *store and forward* model, where some intermediary node picks up (encrypted) messages and forwards them to the recipient. This is what we have in production right now at Status. + +Another, arguably more pure and robust, way is having a *remote log*, where the actual data is spread over some decentralized storage layer, and you have a mutable reference to find the latest messages, similar to DNS. + +What they both have in common is that they act as a sort of highly-available cache to smooth over the non-overlapping connection windows between two endpoints. Neither of them are *required* to get reliable data transmission. + +## Future work + +There are many enhancements that can be made and desirable. Let's outline a few. + +1. Data sync clients. Examples of acutal usage of data sync, with more interesting domain semantics. This also includes usage of sequence numbers and DAGs to know what content is missing and ought to be synced. + +2. Remote log. As alluded to above, this is necessary. It needs a more clear specification and solid proof of concepts. + +3. More efficient ways of syncing with large number of nodes. When the number of nodes goes up, the algorithmic complexity doesn't look great. This also touches on things such as ambient content discovery. + +4. More robust simulations and real-world deployments. Exisiting simulation is ad hoc, and there are many improvements that can be made to gain more confidence and identify issues. + +5. Example usage over multiple transports. Including things like sneakernet and meshnets. The described protocol is designed to work over unstructured, structured and private p2p networks. In some cases it can leverage differences in topology, such as multicast, or direct connections. diff --git a/_posts/2019-07-17-welcome-to-jekyll.markdown b/_posts/2019-07-17-welcome-to-jekyll.markdown deleted file mode 100644 index f3bc0002..00000000 --- a/_posts/2019-07-17-welcome-to-jekyll.markdown +++ /dev/null @@ -1,26 +0,0 @@ ---- -layout: post -title: "Welcome to Jekyll!" -date: 2019-07-17 13:42:32 +0800 -published: false -categories: jekyll update ---- -You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `jekyll serve`, which launches a web server and auto-regenerates your site when a file is updated. - -To add new posts, simply add a file in the `_posts` directory that follows the convention `YYYY-MM-DD-name-of-post.ext` and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works. - -Jekyll also offers powerful support for code snippets: - -{% highlight ruby %} -def print_hi(name) - puts "Hi, #{name}" -end -print_hi('Tom') -#=> prints 'Hi, Tom' to STDOUT. -{% endhighlight %} - -Check out the [Jekyll docs][jekyll-docs] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekyll’s GitHub repo][jekyll-gh]. If you have questions, you can ask them on [Jekyll Talk][jekyll-talk]. - -[jekyll-docs]: https://jekyllrb.com/docs/home -[jekyll-gh]: https://github.com/jekyll/jekyll -[jekyll-talk]: https://talk.jekyllrb.com/ diff --git a/assets/img/mvds_batch.png b/assets/img/mvds_batch.png new file mode 100644 index 0000000000000000000000000000000000000000..aa3449be1ee2b594a5c411cf5c5b0219d9b43338 GIT binary patch literal 14443 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 literal 0 HcmV?d00001 diff --git a/assets/img/mvds_interactive.png b/assets/img/mvds_interactive.png new file mode 100644 index 0000000000000000000000000000000000000000..84e2450104e00aee04bca18717a8706c0c32d438 GIT binary patch literal 24910 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 literal 0 HcmV?d00001