简单地说,我们现在是Redis
正如你所料,实时车辆跟踪不是儿戏。从开始到结束,在实现实时车辆跟踪的好处之前,你必须考虑一系列变量。可以说,最重要的因素是速度。任何通信延迟都会产生陈旧的数据,数据越陈旧,它的价值就越低。
这是一个复杂的操作这是Redis Launchpad应用将Redis和Golang结合起来,使其能够高效和准确地提取数据.这确保了用户从车辆跟踪中获得最大的价值。
让我们来看看是怎么做到的。(我们还想指出各种各样的令人兴奋的应用在我们的复述,发射台为您开始,不管您喜欢的框架和语言。)
让我们看看如何使用Redis创建一个可靠和强大的实时车辆跟踪系统。我们将揭示如何使用Redis在赫尔辛基创建一个实时跟踪系统,在web UI上发布公共汽车的实时位置。
考虑到HSL每天发布约5000万次更新,Redis是首选工具,因为它的健壮性RedisTimeSeries模块。它能够快速聚合数万个数据点。
使用此应用程序,用户能够收集关于每个总线的实时信息,包括其位置、历史位置和当前速度。
让我们分析每个组件,分解其功能及其实现所需的步骤。下面是你需要的系统组件的概述:
为了将所有内容联系在一起,并让您清楚地了解每个特性是如何实现的,下面是对所有内容按时间顺序流动的快速总结。
在我们研究架构的细节之前,有一点很重要,那就是所有组件都托管在一个AWS t3上。介质与GP3 EBS卷。尽管t3。medium之所以吸引人,是因为它具有可突发的CPU,更小的实例可以处理当前状态下的应用程序。
GoLang broker被用来处理从赫尔辛基传入Redis的消息。经过GoLang处理后,这些信息会被发送到多个不同的地点:
发送到Redis Streams的事件数据会被一个RedisGears函数处理并写入持久化存储(PostgreSQL)。
事件数据由GoLang发布并发送到Redis PubSub,然后通过Web套接字发送到每个连接的客户端。这在实时位置层上提供了浏览器中位置的实时更新。
通过RedisTimeSeries记录每辆公交车的当前速度和位置。时间序列数据根据每次预定行程的位置(GeoHash)和速度分为不同的序列。每隔15秒,这些记录就会使用压缩规则进行标准化,以避免在任何给定行程中存储不同的数据间隔。
先决条件:
克隆存储库:
构建应用程序:
系统的一个功能性版本可以通过docker-compose在本地启动。
上面的命令将启动(几乎)所有在它们自己的独立环境中运行本地演示所需的服务。
打开浏览器并使用http://localhost:8080/.
如果您对接收流量速度/邻里层的定期更新感兴趣,可以运行以下命令。这并不是绝对必要的,因为收集足够的数据可能需要几个小时才能获得合理数量的数据(您仍然需要等待tilegen工作来重新填充层)。
Redis PubSub频道用于现场直播。它相对简单:代理向Redis PubSub频道发布一个事件,然后实时位置API订阅相同的消息。当客户端连接时,他们通过web套接字接收相同的数据。MQTT代理使用Golang作为Redis客户端,并使用下面的代码:
传入的事件被推送到Redis Streams。然后,通过RedisGears运行的代码清除并处理它。以下是使用Redis Go客户端编写的:
在RedisTimeSeries中记录每辆巴士的当前速度和位置。为每个“trip”创建一个惟一标识符(一个JourneyHash),哈希事件的某些属性。为了澄清,代理为每个JourneyHash创建一个时间序列,包括速度和位置。
需要注意的是,位置和速度序列的保留时间较短,并被压缩为次级时间序列。这个紧凑的系列具有更长的保留时间(约2小时),并被API用于向用户显示旅行历史层。通过能够有效地聚合单个事件,这种模式允许我们减少内存使用。
命令
这些命令是通过Golang执行的。首先,检查是否还没有看到JourneyHash。您可以通过检查它在集合(journeyID)中的包含来实现这一点。如果下列结果返回1,则继续创建序列和规则,或者只是TS.ADD数据。
使用以下命令创建第一个系列。为了简化,我将这些称为时间序列。
聚合系列由“主”时间系列提供,并使用下面的命令创建。同样,为了简化,我将这些称为时间序列B。
为统治的规则时间序列的->时间序列B,可以使用如下命令:
如果需要向TimeSeries A添加数据,请使用以下方法:
redislabs/redismod是一个Docker镜像,包含了所有的Redis模块。这被用作这个项目的基础图像。从流中,该函数每5秒/10,000个事件向PostgreSQL/PostGIS写入数据。尽管Gears运行在主线程之外,但这个组件的设计目的是做最小的数据处理。
它的主要目的是将MQTT数据转储到PostGIS中,并允许PostGIS和TileGen进程将这些事件转换为MBtiles。
你还应该知道RedisGears函数是用Python编写的,不会调用任何Redis命令。
PostGIS和TileGen容器是服务GTFS和当前流量层的基础。强调一下,PostGIS是一个支持地理空间操作的PostgreSQL扩展。
TileGen是一个Alpine容器,它包含两个用于地理空间处理的常用工具,GDAL和tippecanoe(以及PostgreSQL客户端psql)。该容器用于:
TilesAPI是一个简单的Golang API,用于从磁盘获取这些tiles并将它们发送到前端。
在位置API中有两个端点:/ Locations /和/histlocations/。
命令
/locations/端点从MQTT代理部分中定义的PUB/SUB通道订阅/读取数据。当用Go编写时,用于此的redis-cli命令是:
/histlocations/端点需要从多个时间序列中收集数据,以便为客户机创建组合响应。这意味着发出TS.MRANGE呼叫。因为每个Timeseries B被标记为JourneyHash, TS.MRANGE通过一个呼叫收集位置和速度数据,并对JourneyHash进行过滤。
前端(OpenLayers)
前端使用一个JS库OpenLayers.这用于创建映射并显示前面描述的服务创建的层。在生产中,这是使用Nginx而不是包裹的发展模式。
前端也调用公开的API基础图图像。
技术附件
数据吞吐量
需要强调的是,这个系统并不是专门创建来处理大量数据的。尽管如此,在给定这个(相对较小的规模)任务时,它执行得很出色。
根据传闻,当订阅与所有总线位置更新相对应的MQTT主题时,系统每天处理大约15GB的消息。下面我们有一些图表来说明从周日上午到下午和晚上发生的事件吞吐量的上升。
如果你仔细观察,你会注意到在一天的中午,事件/秒达到了500/秒的最高水平。这是在早晨从<10个事件逐渐增长之后。
然而,在工作日的早上8点,我们可以看到系统轻松处理大约1600+事件/秒。以下是2021年5月14日早上5分钟窗口期的一些数据。
内存、CPU和磁盘使用率
在本地测试中,最初怀疑CPU是系统中压力最大的部分。事实证明,它实际上是圆盘。下面是2021年5月14日早上8点的码头统计数据。
通过从AWS标准gp2 EBS升级到gp3,我们可以免费获得3000 IOPs和125MB/s吞吐量,这使得在容器中托管PostgreSQL实例变得可行。尽管没有一个健壮的磁盘,该网站仍然可以运行,但这是一个成本相当低的生成,可能滞后10分钟以上。
由于团队喜欢扩展这个组件,以支持30分钟、1小时、2小时和6小时的流量层,因此能够有效地访问磁盘上的历史位置是至关重要的。
在升级之前,由于齿轮(写入磁盘)的write-behind和tile(从磁盘)的生成,系统负载非常高。即使在高峰时间和瓷砖再生,%iowait保持低,系统负载保持<1。
下面是瓷砖再生过程中的sar结果:
这款应用的核心是需要一个能够精确和快速传输数据的数据库。每个Redis组件都是一个至关重要的器官,它们彼此协调工作,形成了一个高效的实时跟踪系统。
但通过将Redis和Golang合并,你就有能力以极高的效率和准确性提取数据。你可以在复述,发射台一定要去看看其他伟大的应用程序我们有可用的。
达斯汀·威尔逊
Dustin是一名后台工程师,目前在Numina工作。为了在GitHub上了解更多关于他的工作和活动,你可以在这里查看他的资料.