Go在Grab地理服务中的实践

本文分享了Grab在地理服务中使用Golang的实践经验,详细介绍了从R-Tree到Astrolabe再到Sextant的演进过程,以解决高并发写入和查询的性能挑战。通过引入Geohash、自定义的空间索引引擎和去中心化的服务治理,实现了高可用和可扩展性,确保在业务快速增长下的稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我叫张志印,来自 Grab,这次主要跟大家分享一下我们在地理服务中的 Golang 实践。本次分享大纲:

  • What's Grab

  • 一个典型的派单流程

  • 一个核心地理服务系统演进历程

  • Why go

  • 压测与调优

  • QA

    Grab 是东南亚最大的出行平台,我们不只是做出行,还在做支付以及送餐业务。能做出行的一定能做送餐,做送餐的也可以做出行,这是很自然的一个选择。出行就是连接供需,一个是需求端,一个是供给端,这两端连接起来出行生意就做起来了。


一个典型的派单流程

640?wx_fmt=png&wxfrom=5&wx_lazy=1

   从派单流程说起,一个典型的派单流程是什么。首先会查找附近的司机,然后我们有过滤和分配策略,包括 ETA 和 ETD 的计算,以及各种 Allocation 策略, 我们基本上也是很复杂的 RPC 调用,然后锁定司机,通知司机,司机收到并确认就成单了。对于地理服务来说,就是如何找到附近的司机,大家可以看到,这是一个关键路径,如果这个 Nearby 服务 down 了,整个派单流程就全部 down 了。


如何构建一个高可用的 Nearby 服务呢?

这个看起来很简单,就是找附近的司机。那么,首先来看要解决什么问题?第一个就是我们有大量的司机做秒级的实时上传,并且司机的坐标是不断动态变化,如从A区到B区。找附近的司机,坐标是有时效性的,你不能找到一个小时之前的司机。可用性也说了,要求就是不能宕机,还有性能要好。


 简单聊一下 Nearby 服务演进的过程

我们的目标是做一个类似于特斯拉一样的系统,性能好,续航时间又长。

但是实际上一开始不可能造出特斯拉,从0到1,最开始做的时候都比较简陋。跟大家一样,如果你做 Nearby 的服务要用什么呢?要成熟的东西,比如 PostGIS、MongoDB 等这些都可以用,但是这个场景其实不适合。我们有大量的并发写,这里使用的是 PostGIS,而 PostGIS 是基于 R-Tree,那 R-Tree 在这个场景下有什么问题呢?我们看R-Tree的结构图:

640?wx_fmt=jpeg

当写入一个新结点,从根结点遍历直到查找到相应的叶子结点, 如果有可写空间就写进去,如果已满, 就回溯,不断地向上分裂, 直到根结点。这个时间复杂度比较高,想一下,把整个地理空间搞到一个  R-Tree 里面,而且要加锁,这个时候写性能会非常差。另一个问题是流量高峰时,造成服务经常崩掉,这样的可用性是完全不可接受的。

有节操的程序猿都是在不断地造轮子,如果当前系统不好用,我们造一个新的轮子好了。在我们内部一次 Hackathon 的时候,一个澳洲大哥说我们造个轮子吧,就是 Astrolabe,中文名称是星盘。

640?wx_fmt=jpeg

Astrolabe 完全是用 Golang 实现的 Nearby 服务。


引擎方面,我们把空间索引从 R-Tree 换 Geohash,Geohash 有一个特点,就是地理位置相近的地方,前缀是相似的,另外就是把二字符串维坐标转成一维数据,点击上图链接大家会看到返回的坐标是小南国花园酒店。因为前缀相似的一维字符串表示的地理空间是相近的,我们可以把二维空间的搜索转成 Range 查询,相对来讲,Nearby 的邻近搜索写性能会好一些。  

640?wx_fmt=jpeg

 我们看到"写"就非常简单了,先计算 Geohash,然后把 Geohash 值存储到zset 中,"读"也比较简单,先找到查询半径的最小外界矩形的左下、右上两个点,这个时候可以基于 range 查询粗略筛选一批司机,对这些司机再计算一下距目标点的距离,就可以精确的找到附近的司机。

最后解决了哪些问题呢?写性能确实提高了,可用性也更好了,主要是什么原因? 一个是 Redis 很少宕机;另外就是我们用 Golang 写的,做出来的系统也很稳定,实际上在当时那个时间结点, Golang 逐渐成为 Grab 后端首选语言。



但 Astrolabe 也有一些问题,主要是 Geohash 会有跨纬度前缀跳变问题。

640?wx_fmt=jpeg

国内还好,中国大部是在130、132,不是那么明显,但是东南亚是132、310,在赤道附近会产生突变。

Astrolabe-主要问题

  • 准确度低。赤道附近会查找到司机不全,准确度有一些问题。

  • 还有一个问题就是 CPU 和 IO 比较高,内存非常低。IO 比较高一个很大原因是有大量的网络 IO 在 Astrolabe 与 Redis 之间。

  • 很难做横向扩展。你要做 Range 查询,必须把一个城市的所有司机分配在一个 SortedSet 里面,但司机人数在不断快速增长,势必会成为一个瓶颈。

现在的问题就是发现不能横向扩展了,但是业务增长非常快速,如果我们不做更新换代,只有死路一条。我们内部就说那再造一个轮子吧,我们又搞了一个更高级的定位系统,叫 Sextant,中文名称是六分仪, 这个也是航海用的定位系统,接下来分享一下Sextant 这个系统。



回顾一下我们要解决的问题

640?wx_fmt=png

业务高速增长,上百万的司机在做秒级实时地理位置上传,都会打到你空间引擎里面。可用性要求越来越高,如果因为不能查找到附近司机而导致订单不能完成,这是绝对不可接受的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值