Serverless架构实现客户端模糊定位

713 阅读8分钟

方案背景

我们经常遇到一类终端设备模糊定位场景,这就是怎么在已知的有限的条件下,尽可能精确的获取终端的地理位置。以下是一些典型的场景:

  1. 在社交领域,在评论区需要显示用户大致的IP属地。
  2. 在IoT领域,大部分的IoT device没有GPS定位模块,我们只能获取到device的一些基础的联网信息,比如设备的公网IP、设备所连接的WiFi和设备附近的WiFi信息,我们需要这些最基本的信息尽量精确的感知设备的位置。
  3. 在安防领域,某个通过蜂窝网络(5G/4G、NB-IoT)连接到云端的环境感知设备(成本有限没有GPS模块);比如森林火灾传感器,野外空气质量检测器等,我们需要获取比较精确的位置来做地图标记。
  4. 在电商领域,需要在保护用户隐私的情况下收集app端在各个地区的匿名埋点数据,然后通过数据分析来大致了解区域性用户的画像和购物习惯。

架构设计

模糊定位功能适用于终端设备没有GPS模块或者用户不能主动提供准确地理位置的情况尽可能到获取位置信息。定位是操作是用户的敏感操作,我们需要在合法并取得用户同意的情况下进行;定位功能的核心是有准确而庞大的地理位置数据库,这对开发者而言是最难的地方,一般的开源/付费地理位置数据库方案往往会有不同程度的数据老旧和数据量不足的问题;面对这类问题我们可以使用AWS IoT Core Device Location功能来完成。AWS IoT Core Device Location通过与Semtech、HERE和MaxMind等AWS合作伙伴提供的解决方案集成,使客户能够使用云辅助GNSS、WiFi 扫描、蜂窝三角测量和IP反向查找技术来确定设备的地理坐标。

接下来我们假设2类典型定位场景:

  • 移动用户所使用的手机没有授权定位权限(只知道IP)无法通过GPS获取准确的位置,实现基于IP模糊定位的功能;
  • 一个硬件设备通过WiFi连接网络但是没有GPS模块(只知道WiFi信息),实现基于WiFi扫描的迷糊定位功能。

希望通过这2种场景帮助大家了解手机/桌面端、低成本硬件设备的模糊定位的可行性和无服务器架构的优势。

详细的架构图如下: 首先终端设备上报自己的可定位的参数(MQTT/HTTP协议均可),然后lambda得到这些参数后调用IoT Core Location Service进行模糊定位,最后得到终端设备的经纬度信息。

以下是被支持的几种定位方式和定位的原理,我们可以使用其中的一种或者多种方式组合来尽可能精确的实现模糊定位。

测量类型第三方求解器支持的设备
Wi-Fi 接入点基于 Wi-Fi 的求解器一般 IoT 设备和 LoRa WAN 设备
蜂窝无线电发射塔:GSM、LTE、CDMA、SCDMA、WCMDA 和 TD-SCDMA 数据基于蜂窝的求解器一般 IoT 设备和 LoRa WAN 设备
IP 地址IP 反向查找求解器一般 IoT 设备
GNSS 扫描数据(导航消息)GNSS 求解器一般 IoT 设备和 LoRa WAN 设备

模糊定位请求的QPS往往不可预测,有明显的时间周期性和突发性。比如网络社交网站上的一个热点新闻引发大量的讨论,评论区的评论需要大量的IP模糊定位、智能制造企业的给某个地域范围内的数万老旧设备进行定向OTA升级,而不影响其他地域的设备等。相比长期预置大量的服务器等待不可预知的事件发生,AWS Lambda作为计算层有明显的优势,首先是它避免了大量资源闲置造成的成本浪费,其次就是它可以由这些不可预知的事件触发执行,并自动的根据事件的规模进行近乎无限的即时扩展,在两位数毫秒的超短时间内做出响应,在数分钟内快速完成这批事件的处理后停止计费,兼顾了弹性和成本。

代码实现和定位测试

相关的代码实现可以参考GitHub location-service

处理HTTPS或者MQTT 定位请求

我们可以使用AWS Lambda运行模糊定位代码,并通过API-gateway暴露RESTFul HTTPS接口或者通过iot core提供mqtt topic

首先我们假设3种接口

  • 通过HTTPS请求根据IP查询查询终端设备的位置
  • 通过HTTPS请求根据WiFi信息查询终端设备的位置
  • 通过MQTT消息根据WiFi信息查询终端设备的位置

首先我们使用AWS SAM编排我们的lambda代码,代码样例如下,如果大家有不熟悉SAM的请看AWS SAM Doc

基于ip的模糊定位(WiFi定位请自行参考github代码)

r"""
This module provides a function to get the geolocation of an IP address.
"""
import boto3

# Create an IoT Wireless client
client = boto3.client('iotwireless')


def lambda_handler(event, context):
    # get ip address from path parameter
    ipv4_address = event["pathParameters"]["ipv4-address"]
    # get the position estimate by the ip address
    response = client.get_position_estimate(
        Ip={
            'IpAddress': ipv4_address
        },
    )
    # get the geojson payload from the response
    ipv4_location = response["GeoJsonPayload"].read().decode('utf-8')
    # return the geojson payload
    return {
        "statusCode": 200,
        "body": ipv4_location,
    }

定位测试

当我们部署好后,会类似的HTTP输出

我们可以用postman进行大致的测试,首先是IP定位测试,对于正确的公网IP都能获取到比较准确的位置(如果是局域网IP则会查询不到)

然后是wifi mac地址定位,我们可以先获取到自己电脑连接到WiFi的mac地址和信号强度,然后再去进行位置解析(注意:只有WiFi的位置已经被收录到数据库,才可以进行位置解析)

先获取设备所连接的WiFi信息,得到BSSID和RSSI

然后通过BSSID和RSSI进行模糊定位

结合模糊定位功能做宠物活动轨迹追踪

当我们获取到某个终端的大致的经纬度信息后,我们可以结合AWS Location服务作更加精细的图形化展示,AWS Location是一种云原生的地图服务,我们可以结合全球地图信息将我们的终端显示在地图上,依靠AWS Location内置的功能实现终端位置展示,位置轨迹追踪,导航,地理围栏等功能。

我们可以结合前面提到的定位方式,以一个智能宠物项圈为例子模拟宠物的活动轨迹,参考amazon-location-samples,先部署好云端的地图服务,然后通过MQTT或者HTTP请求将宠物项圈的经纬度上报到AWS Location的tracker里面,最后在地图上显示终端的位置并追踪终端设备的位置轨迹。在本文中我假设您完成了前面提及的模糊定位功能,能得到了宠物的经纬度信息,并且假设您完成了amazon-location-samples的部署。

架构图如下图:

image

大致流程为:

  1. 设备上报自己的可定位信息到iot core MQTT topic
  2. 消息经过iot core rule转发到lambda,触发lambda执行模糊定位
  3. lambda将设备的经纬度信息异步发送到例外一个定位专用的topic并将消息通过iot core rule转发到aws location tracker里面。这样位置信息被Location追踪起来了
  4. 用户通过网页查看位置信息

完成上述步骤后,在模拟时我们可以将第2步获取的不断变化的经纬度信息,不断的传入到第3步中,并刷新页面得到宠物的活动轨迹

详情可以看视频演示

总结

我们可以看到对于移动/桌面用户我们可以先获取的其IP地址或者通过解析HTTP请求头获取IP,然后通过IP地址反向查找的方式,大致将位置精确到某个国家某个省份下的具体城市;对于低成本的硬件设备我们可以让其自己上报自己周围的WiFi信息,大致将位置定位到某个国家某个省份某个城市下的具体的街道。在这个架构中对开发者而言可以不用担心地理位置数据库的运维问题,也不用担心计算资源的闲置浪费、突发流量冲垮服务的问题。

此外我们也可以后面进一步的完善架构或者功能整合,比如加入ElastiCache缓存,开启API Gateway缓存避免重复请求造成的成本上升并提升服务质量;我们把终端的位置信息保存到DynamoDB等NoSQL数据库,然后进一步结合地图服务,实现用户/设备热力图、环境监控看板、异常感知看板等。

参考