lbs 存储调研

最近要做 lbs 的业务, 做了下调研。

首先, 我们的 lbs 业务上主要需要解决 查询附近的人的问题。

而附近的概念有很多, 有类似找外卖这种的附近,有类似找附近的共享单车,找附近的陌生人。

对于这种不同的业务, 查询的需求, 精度,都是不同的, 相应的技术选型也应当不同。

业界方案

业界在技术上对这类 经纬度的数据 的存储方案有

  1. geohash / google s2 算法将二维数据降维到一维, 用处理一维数据的方式插入以及查找, 实现的代表为 mongodb, redis
  2. 用 R树 直接存储二维数据, 实现代表为 postgres

关于 geohash 和 s2 原理可以看以下文章

https://halfrost.com/go_spatial_search/

https://www.jianshu.com/p/3dbaf73a09af

简单总结下

  1. geohash 简单, 性能好,但是,边界问题不好处理。
  2. mongo 实现基于 geohash, api 友好,开发简单, 但是随着查询范围不断扩大, 以及数据量则增大, 性能急剧下降。
  3. pg 万金油, 写入速度比mongo 慢, 查询效率 不会随着范围扩大急剧下降
  4. s2 和 geohash 一样,只是个降纬工具, 比起 geohash, 分割的层级比 s2 多得多, 还内置向量计算, 面积计算, 多边形覆盖 距离, 球面计算等功能, 但问题是, 如果仅仅是小范围的分隔的话 还真不需要这么多功能, 所以相对简单的业务用的少, 地图等自定义需求比较多的相关应用, 用的会多一些。

经过网上搜索,找到别的公司的用法

膜拜用 mongo 做他的 搜索附近的车

美团基于 geohash 和 redis 实现附近的xx

陌陌基于 geohash 实现附近的人

探探直接用 pg 做附近的人

pokemon go 用s2 的level 定义各个游戏业务

在总结下:

  1. 摩拜的业务上, 只需要查询附近的车,如果附近没车,也不需要扩大范围, 所以只需要在地理位置上分库,然后用mongo 就行了

  2. 美团业务上与膜拜类似, 所以geohash 也能满足需求

  3. 陌陌由于用户分散, 用geohash 感觉略微牵强, 为了增加查询效率,以及解决边界问题, 采用空间换时间的方案, 每次写入数据, 将写入 中间的格子 以及 周边8格

  4. 探探和陌陌相同的业务, 直接用pg。

  5. pokemongo 用s2 是因为 ingress 的数据用 s2 编码的, 所以也只能继续用 s2。

结论, pg 对于不确定范围的查询无论从开发成本和性能上都更 万金油 一些。

鉴于, 有现成的轮子就用的思想, 这里调研一下 pg 和 mongo 的性能。

pg mongo kw级别 性能测试

1
2
3
4
PgJMH2.testInsert                                    100   thrpt           3191.577           ops/s
PgJMH2.testInsertNear 100 thrpt 1600.714 ops/s
MongoJMH2.testInsert 100 thrpt 72471.125 ops/s
MongoJMH2.testInsertNear 100 thrpt 76836.235 ops/s

pg数据量过千万后性能降低, 而且对于数据密集的地方 速度更慢。

mongo 写入性能一直都很好

1
2
3
4
5
6
PgJMH2.testEarth                                     100   thrpt          35753.083           ops/s
PgJMH2.testNearBy 100 thrpt 34403.323 ops/s
PgJMH2.testSouthEast 100 thrpt 34893.133 ops/s
MongoJMH2.testEarth 100 thrpt 33446.089 ops/s
MongoJMH2.testNearBy 100 thrpt 17.739 ops/s
MongoJMH2.testSouthEast 100 thrpt 264.248 ops/s

mongo 的读,如果扫描的数据量大的话, 性能不堪入目。
pg则比较稳定。

分析

  1. 破千万后速度慢因为索引 R树 的深度高了,
  2. 插入附近的更慢,因为 数据密集的地方 深度更高。

解决方案,

sar 分析后发现是 磁盘io 瓶颈, 减少 io 成本为关键

  1. 考虑减少索引个数
  2. 合并多个 insert 批量提交
  3. 硬件上, 硬盘换支持写缓存的
  4. 配置上去掉fsync, 每一次逻辑上的commit 不会真正写磁盘(断电会数据不一致, 不推荐)

reference

https://s2.sidewalklabs.com/regioncoverer/

http://mysql.taobao.org/monthly/2015/07/04/

https://www.jianshu.com/p/fd80741bb6fd

https://www.ptt.cc/bbs/PokemonGO/M.1515565927.A.21F.html

https://halfrost.com/go_spatial_search/

https://www.jianshu.com/p/3dbaf73a09af

https://www.slideshare.net/meituan/12lbs

https://yq.aliyun.com/articles/73995

https://momjian.us/main/writings/pgsql/hw_performance/

avatar

lelouchcr's blog