移动互联网络的飞速发展,导致移动应用类服务层出不穷,其中很重要一类就是LBS(Location Based Services)——位置定位服务,在此基础上出现了很多面向生活服务类的热门App应用,如:快的打车,陌陌等。如何能根据你现在的地理位置,找到离你最近的商店等需求,已经成为每个智能终端(如手机)的必备功能。
LBS类应用,除了前端的App,后台主要通过数据库进行数据支撑,除却网络因素外,数据库性能和对空间数据的支持程度,直接影响用户请求响应时间,波及用户体验。所以选择一个正确而合适的数据服务应用,对LBS类服务来说是至关重要的。
如何选择合适的数据服务,跟许多因素有关,需要考虑预估数据量规模、并发请求数量和预期投入成本等等因素。而本文档的主要目的,就是通过比较几种常用的LBS数据服务产品,找出在哪种场景下,采用哪种数据服务产品,给具体不同的业务,提供LBS数据服务产品选型。
目前能提供空间数据存储的数据服务产品比较多,如:Oracle Spatial、MySQL Spatial、PostGIS、MongoDB、Lucene Spatial等等。上述产品中,除了Oracle Spatial外,其余4中都是开源的数据库产品,我们本次对比的范围,正是基于这4种能够提供空间数据存储的产品。
MySQL本身就自带空间类型数据,如Point,Polygon,LineString等等,MySQL 5.6开始MyISAM储存引擎开始支持空间索引(Spatial Index),MySQL 5.7.5开始,InnoDB存储引擎也开始支持Spatial Index索引。
MySQL对空间数据支持
MySQL Spatial只支持了OpenGIS的一个子集,实现了其中基本功能如GeoFromText等等。MySQL InnoDB在使用Spatial Index时,需要使用自带的函数如MBRContains等。还有就是MySQL Spatial计算距离的时候计算的是欧式空间距离(直线距离),而一般LBS应用中计算的距离是球面距离。
InnoDB Spatial Index采用R树建立索引,由于R树的特殊性,计算距离的时候是计算外接矩形的距离,所以在精确度上可能有所偏差。
R树结构图
R树的叶子节点为具体的坐标点,而父节点则为所有子节点的外接矩形
InnoDB建立包含空间索引信息通过关键字SPATIAL进行指定,如下:
CREATE TABLE Person(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(64),
sex ENUM(‘M’, ‘F’),
age INT,
address VARCHAR(256) NOT NULL,
address_loc POINT NOT NULL,
SPATIAL KEY(address_loc))ENGINE=INNODB;
MySQL支持Master-Slave等复制方式,通过Master-Slave来保证数据的高可靠性和系统的高可用性
MySQL对空间数据类型本来就支持,所以在数据备份时,可以利用MySQL数据备份工具进行,如:xtrabackup、mydumper、mysqldump等等
MySQL本身支持分库分表,但不支持负载均衡,需要通过中间件如MySQL-Proxy、MySQL Fabric、DDB等提供支持
基于MySQL数据库,MySQL本身产品的关注度和社区成熟度比较高
支持Spatial Index
支持事务操作
对于空间扩展支持偏弱
对空间支持部分刚起步,正式的应用不多
Scale out比较困难,需要中间件支持
PostGIS是基于PostgreSQL上面的一个扩展,与MySQL不同的是PostgreSQL本身不支持空间数据类型,需要在PostgreSQL基础上安装PostGIS扩展后才能存储空间数据。
PostGIS单从功能上来讲,是除了Oracle Spatial外对空间数据支持最好的一个产品,基本上支持OpenGIS的规范实施的,当然其支持的数据类型和函数也比MySQL spatial丰富得多。
PostGIS支持几乎所有的空间数据类型,包括:POINT、LINESTRING、POLYGON、MULTIPOLYGON等等,当然PostGIS还提供大量以ST开头的空间处理函数,如ST_AsBinary、ST_GeoFromText等。
除了上面这些基本功能外,PostGIS还提供:
PostGIS空间索引实现有两种不同的选择:R树和GIST(Generalized Search Tree),一般建立索引的时候选用GIST,GIST本身就是一种R树的变种,在R树基础上进行了改进
PostgreSQL中,GIST相比R树的优点:
GiST indexes have two advantages over R-Tree indexes in PostgreSQL. Firstly, GiST indexes are "null safe", meaning they can index columns which include null values. Secondly, GiST indexes support the concept of "lossiness" which is important when dealing with GIS objects larger than the PostgreSQL 8K page size. Lossiness allows PostgreSQL to store only the "important" part of an object in an index -- in the case of GIS objects, just the bounding box. GIS objects larger than 8K will cause R-Tree indexes to fail in the process of being built.
CREATE INDEX index_name ON TABLE table_name USING GIST (geometryfield)
可以通过pg_dump和pg_restore等工具进行备份和恢复
PostgreSQL-9.1.2后支持Streaming Replication复制,可以配置Primary和Standby节点
PostGIS可以通过PostgreSQL的中间件pgpoll-II实现分库分表
对空间数据类型支持丰富(更多类型、函数,坐标变换等等)
PostgreSQL本身布支持地理信息,需要部署PostgreSQL和PostGIS两部分
Scale out比较困难,需要部署pgpool-II中间件,操作起来也比较复杂
MongoDB区别于MySQL和PostGIS,MongoDB不支持SQL查询,MongoDB是介于关系型数据库和NoSQL之间的一种文档型数据库。相对于MySQL和PostGIS而言,MongoDB使用简单,而且内嵌了很多对Spatial的支持。
MongoDB采用journal日志保证数据不会被大面积丢失(相当于MySQL的redo log),采用oplog实现主从节点的数据同步(相当于MySQL的binlog)
MongoDB从3.0版本开始集成了WiredTiger存储引擎,全面支持数据压缩和基于Doc级别的锁,极大的增大了系统的可用性和并发性能。
MongoDB插入带有地理位置信息的数据:
db.person.insert(
{
‘name’:’john’,
‘sex’:’M’,
‘age’:18,
‘address’:’London’,
‘address_loc’:{‘lat’:40.12345, ‘long’:120.34567}
})
MongoDB基于地理位置创建索引
db.person.ensureIndex(‘address_loc’, ‘2d’)
根据给定的[long,lat]点,查找附近的数据
db.person.find({“address_loc” : {$near : [long, lat]]}})
MongoDB采用Geohash方式建立空间索引,Geohash即把二维的空间坐标转换成一维字符串
Geohash示例图
Geohash的主要原理就是把一张图切成若干等分,其中每一块用一个字符串表示,比如上左图中,00、01、10、11分别代表一块,按照这种方法,只要切分的够细(误差在允许范围之内),每个坐标点就可以用一块来表示,即把二维坐标转化成了一维字符串。Geohash可以根据字符串的精确度不同来分别搜索距离目标点不同距离的点。
MongoDB内部自带Spatial extensions,数据备份等都采用MongoDB自身工具(mongodump、mongorestore、mongoexport、mongoimport)
MongoDB支持基于Master-Slave的主从复制,和基于Replica Pairs的副本集复制,Master-Slave复制与MySQL类似,Replica Pairs复制可以在Master宕机的情况下,自动选取一个节点作为主机对外提供服务。
MongoDB支持自动和手动的sharding功能,利用Replica Pairs和sharding功能,很容易在不停服的情况下,为数据库集群实现scale out扩展。
MongoDB面向文档存储,记录为BSON形式,没有严格数据格式
支持Master-Slave复制和Replica Pairs,实现自动故障转移
支持手动和自动sharding切片,实现数据水平扩展
支持动态查询
支持全文索引
支持地理空间信息和空间索引,内嵌空间计算函数
单个文档大小限制16M
不支持SQL和事务操作
不支持多个collection上join操作
MongoDB采用mmap形式映射全部数据到内存空间,对内存占用比较高
本文来自网易实践者社区,经作者蒋鸿翔授权发布。