6

我的问题涉及以下用例:

用例参与者

  • 用户A:设置广播区域并查看带直播帖子的流的用户。
  • 用户 B:在用户 A 设置的广播区域内第一个发送广播消息的用户。
  • 用户 C:在用户 A 设置的广播区域内发送广播消息的第二个用户。

在此处输入图像描述

用例描述

  • 用户A选择一个广播区域,在其边界(半径)内他想要接收直播消息。
  • 用户 A 打开 livefeed 并请求一组初始 livefeed 项目。
  • 用户 B 从用户 A 的广播区域内广播一条消息,而用户 A 的 livefeed 仍处于打开状态。用户 A 的实时源打开时,带有 1 个新实时源项目的标签会显示在其顶部。
  • 当用户 C 从用户 A 的选定广播区域内发布另一个实时馈送帖子时,标签计数器会增加。

用户 A 收到类似于以下 Facebook 示例的通知: 在此处输入图像描述

我想应用的解决方案(我认为 Pubnub 使用)是为每个 geohash 创建一个主题。
在我的情况下,这意味着对于广播消息的每个用户,它都需要发布到 geohash-topic,如果它落在范围内,客户端(应用程序/网站用户)将通过 websocket 使用 geohash-topic定义的区域(半径)。Ably 似乎使用 Web 套接字提供这种可扩展的服务。

我想它会简化成这样:

在此处输入图像描述

因此,这意味着需要从发送广播消息的当前位置提取 geohash。这个 geohash 应该具有足够小的粒度,以便接收用户可以设置或多或少准确的广播区域。(即,如果我们希望允许用户定义接收实时消息的广播区域,geohash 应该具有足够的准确性,这意味着如果我们决定扩展,人们应该期望有相当多的主题)。

选项 2 是为粒度较小(覆盖较大区域)的 geohash 创建主题,并让客户端根据与消息一起发送的 latlng 值来处理准确性。
然后客户端将决定是否丢弃消息。但是,这意味着发送更多消息(更多开销)和更高成本。

我没有这种架构的经验,并且质疑这种方法的可行性/可扩展性。
您能否想到这个问题的替代解决方案以达到预期的结果或提供更多关于如何整体解决此类问题的见解?(我也考虑过使用常规的 req-res 流,但这意味着向服务器发送垃圾邮件,这似乎也不是一个很好的解决方案)。

我确实查过了。
给定一个 161.4 平方公里的区域(如布鲁塞尔区域),geohashes 按字符串长度划分如下:

1   ≤ 5,000km   ×   5,000km
2   ≤ 1,250km   ×   625km
3   ≤ 156km     ×   156km
4   ≤ 39.1km    ×   19.5km
5   ≤ 4.89km    ×   4.89km
6   ≤ 1.22km    ×   0.61km
7   ≤ 153m      ×   153m
8   ≤ 38.2m     ×   19.1m
9   ≤ 4.77m     ×   4.77m
10  ≤ 1.19m     ×   0.596m
11  ≤ 149mm     ×   149mm
12  ≤ 37.2mm    ×   18.6mm

鉴于我们将允许用户可能有高达 153m 的不准确性(在用户可能希望订阅以接收本地广播消息的区域),这将需要大量的主题,这些主题肯定已经太大,甚至无法仅涵盖布鲁塞尔的整个地区。
所以我目前仍然有点卡在这个水平上。

4

2 回答 2

2

1. 酒吧小酒馆

PubNub 是目前唯一通过 websockets 提供开箱即用 geohash pub-sub 解决方案的服务,但它们的价格非常高(500 个连接设备的成本约为 49 美元,20k 设备的成本为 799 美元)更新:PubNub 现已更新价格无限设备。网站更新即将推出。

Pubnub 正在研究他们的定价模型,因为他们的一些客户为意外的流量高峰付出了很多。

但是,对于一个面向所有人开放的通用广播消息应用程序来说,这将不是一个可行的解决方案,因此流量非常不可预测。

很遗憾,否则这项服务对我们来说是完美的解决方案。

2.干练

Ably 提供了一个 pubsub 系统,用于通过 websocket 将数据流式传输到客户端以用于自定义通道。当客户端附加自己以发布或订阅该频道时,频道是动态创建的。

这里的主要问题是:

  • 如果我们想要高 geohash 精度,我们需要大量的通道,因此我们必须付出更多;
  • 如果我们使用低 geohash 精度,将会有很多冗余消息:假设我们采用一个由 4 个字符的 geohash 表示的频道,跨越 39.1 x 19.5 公里的地理区域。

发送到该频道的任何帖子都将被多路复用给该区域内当前正在收听的每个人。

但是,假设我们的应用程序允许最大半径为 10 公里,并且一半的连接用户将其设置为 1 公里半径。

这意味着 2 公里半径之外的所有帖子都将不必要地多路复用给这些用户,并且将被丢弃而不再使用。

我们还应该考虑这种方法的可扩展性。对于生产者或消费者需要的每个 geohash,将创建另一个通道。

拥有一个需要基于全球地理哈希主题的应用程序肯定比只需要基于主题的主题的应用程序更昂贵。

也就是说,在全球范围内采用时,主题的数量会急剧增加,因此价格也会增加。

另一个考虑因素是我们的应用程序需要额外数量的通道:

  • 通过 geohash 和组:我们的应用程序允许创建基于地理位置的组(这相当于 Twitter,如 #hashtags)。
  • 按地点
  • 被关注的用户(高级功能)

这种方法有一些乐观的考虑,尽管:

  • 仅当新闻源处于活动状态时才需要流式传输:当用户在我们的网站上打开浏览器窗口时 + 当用户在移动设备上并主动打开相关的源时
  • 可以进行进一步优化,例如仅在刷新提要后 10 到 20 秒开始流式传输
  • 根据当前活动,按地点/关注的用户进行流式传输可能具有高流量,但许多地点频道也将处于空闲状态

在这方面一个非常重要的说明是 Ably 如何向其消费者收费,这可以充分利用我们的优势:

当以下任何一种情况发生时,通道就会打开:

  • 通过 REST 在通道上发布消息
  • 实时客户端连接到通道。该通道在客户端连接到该通道的整个过程中保持活动状态,因此如果您连接到 Ably,连接到通道并发布消息但从不分离通道,只要该连接保持,通道将保持活动状态打开。

当满足以下所有条件时,打开的通道将自动关闭:

没有更多的实时客户端连接到该通道自最后一条消息发布以来至少已经过去了两分钟。我们将通道保持活动状态两分钟,以确保我们可以在通道上提供连续性,作为连接状态恢复的一部分。

例如,如果您有 10,000 个用户,并且在您每月最忙的时间有一个峰值,即 500 个客户与 Ably 建立实时连接,并且每个客户都连接到一个唯一频道和一个全球共享频道,那么频道的峰值数量将是每个客户端 500 个唯一频道和一个全球共享频道(即 501 个峰值频道)的总和。如果在整个月中,这 10,000 个用户中的每一个都连接并附加到他们自己的唯一频道,但不一定同时,那么这不会影响您的峰值频道数,因为峰值频道是在任何时间点同时打开的频道数在那一个月里。

乐观的结论

最重要的结论是,我们应该考虑到这个功能可能并不像人们认为它对于应用程序的第一个版本那么重要。

尽管 Twitter、Facebook 等提供了接收实时更新的功能(并且用户已经开始期待它),但我们应用程序的有限规模的初始测试版可以在没有的情况下运行,即用户必须刷新才能接收新的更新。

在应用程序首次启动期间,可以收集统计数据以更深入地了解详细的用户行为。这将使我们能够基于事实数据建立更可靠的基础设施和财务反思。

于 2018-06-09T14:25:08.257 回答
1

抛开 Ably、Pubnub 和 DIY 解决方案的问题,问题的核心是这样的:

消息过滤发生在哪里?

有三种可能的解决方案:

  1. Pub/Sub 服务。

  2. 服务器(WebSocket 连接处理程序)。

  3. 客户端(客户端的设备)。

由于这显然是一种面向移动设备的方法,因此客户端消息过滤非常粗鲁,因为它增加了客户端的数据消耗,而大部分数据可能无关紧要。

客户端过滤也会增加电池消耗,并可能导致客户接受率降低。

这留下了发布/订阅过滤(频道名称/模式匹配)和服务器端过滤。

Pub/Sub 频道名称过滤

单个 pub/sub 服务服务于许多服务器(如果不是全部),使其成为非常昂贵的资源(相对于我们手头的资源)。

使用通道名称过滤消息将是理想的 - 只要过滤成本低(使用与通道名称哈希映射完全匹配)。

但是,与精确模式匹配相比,模式匹配(当订阅名称不准确的通道时,例如"users.*")非常广泛。

这意味着 Pub/Sub 频道名称过滤不能用于过滤所有消息而不会使 pub/sub 系统过载。

服务器端过滤

由于服务器接受 WebSocket 连接并在 WebSocket 和 pub/sub 服务之间建立桥梁,因此它处于过滤消息的理想位置。

但是,我们不希望服务器为每个连接处理所有客户端的所有消息,因为这是一种极端的重复工作。

混合解决方案

一个经典的解决方案是将地球划分为可管理的部分(每部分 1 平方公里将需要 5.101 亿个独特的频道名称才能完全覆盖......但我建议应该忽略 70% 的海洋空间)。

繁忙的路段可能会被细分(纽约市可能需要每 250 平方米而不是 1 平方公里的路段)。

这允许发布者发布到确切的频道名称,而订阅者可以订阅确切的频道名称。

发布者可能需要发布到多个频道,订阅者可能需要订阅多个频道,具体取决于他们的确切位置和网格的边界。

这种过滤方案将过滤很多,但不是全部。

服务器节点将需要查看消息,查看其确切的地理位置并过滤消息,然后再决定是否应通过 WebSocket 连接将它们发送到客户端。

为什么选择混合解决方案?

这允许系统相对容易地扩展。

由于服务器节点(按设计)比 pub/sub 服务便宜,因此它们可用于处理精确的位置过滤(繁重的工作)。

同时,可以利用发布/订阅系统的力量来最小化服务器的工作量,过滤掉明显的不匹配。

Pubnub vs. Ably?

我不知道。我没有使用它们中的任何一个。我使用 Redis 并实现了我自己的 pub/sub 解决方案。

我认为它们都很棒,这完全取决于您的需求。

当涉及到定制或复杂的情况时,我个人更喜欢 DIY 方法。恕我直言,如果我要实现它,这似乎属于 DIY 类别。

于 2018-06-12T21:25:15.403 回答