美图GeoIP服务实践

网友投稿 666 2022-05-29

业务背景

为什么需要获取用户的地理位置?

1.算法推荐类需求:例如需要用户的地区信息、美拍热门推荐、美拍同城直播列表等;

2.统计类需求:获取用户地区维度做相应的统计指标报表 (新增、活跃、留存等);

3.用户画像及其他在线业务类:如美拍账号经济体系需要检测校验用户的常用登陆地信息。

怎么获取用户的地理位置?

1.***服务(需要用户授权)

通过经纬度获取用户的位置信息,有以下几种方式:

/ GPS:根据系统 GPS 模块获取经纬度,精度 10-100 米左右,限制是容易受环境影响,在室内几乎不起作用;

/ 基站(移动网络):根据运营商基站位置计算经纬度,精度 1000-3000 米左右,限制是定位较慢,精度差;

/ WIFI:根据周围 WIFI 路由器位置计算经纬度,精度 100-200 米左右,限制是受周围 WIFI 数量和分布影响,需要打开手机 WIFI 开关;

2.用户属性(需要用户主动设置)

系统设置的地区,如 iOS 系统需要设置语言与地区;

用户属性设置,如手机 QQ 设置的所在地。

3.IP(不需要用户参与)

传输层 TCP 协议直连,可以直接获取 Remote_Addr;

HTTP 应用层,通过 HTTP Header (X-Forwarded-For,X-Real-Ip);

获取了用户请求的来源 IP,通过 IP 库查找对应的地区信息。

总体来说,需要用户参与的能定位到唯一的设备和用户,但是需要用户主动上传位置信息或相关信息;不需要用户参与的定位方式不需要硬件支持,普适性更强。

Tips

IP 地址属于运营商的资产,运营商很容易将属于自己的 IP 资产与地理位置绑定起来,运营商可以将一段段的 IP 地址绑定到某台物理设备上,于是就生成了 IP 地理信息库(GeoIP),当把全球的 IP 地理信息库融合为一体,就可以根据用户的 IP 来粗略获得用户的位置信息。

IP 的应用场景

全球 IPV4 全库约有 43 亿 IP 地址数据,根据不同的属性可以将 IP 地址分成 9 种不同的应用场景,分别是住宅用户、企业专线、学校机构、移动网络(3G/4G)、WLAN 热点、基础设施、数据中心、交换中心、卫星通信等。这 9 种应用场景可分为非人类使用的场景和有真人使用的场景:

非人类使用的场景:例如交换中心、数据中心和基础设施,这三类场景下的IP地址会定位到其所在机房,能定位到街道级别,但此类 IP 地址一般不用于普通用户访问互联网;

真人使用的场景:例如企业专线和学校机构,IP 地址使用人群出现的位置相对固定,能定位到街道级别;

住宅用户、WLAN热点、移动网络(3G/4G)和卫星通讯,IP地址使用人群出现的位置覆盖相对较广,能定位到一定的区域。

住宅用户这类场景下的IP地址可以覆盖一个行政区的部分区域,能定位到街道级别或者区县级别;

WLAN热点可定位到区县级别或者城市级别;

移动网络(3G/4G)可定位到省级别;

卫星通讯可定位到国家级别。

IP 库从何而来

IP 库按照精度可以分为城市级数据库、区县级数据库、街级数据库,如图所示国内外也有不同类型的常用 IP 库:

其中 IPIP.NET 受到多数知名企业的青睐,如今日头条、滴滴、快手、小米、GrowingIO、诸葛 IO 等。

架构设计与实现原理

##使用场景

1.IP 与地区的映射关系每天都在变更,IP 库需要定期更新,以保证 IP 转地区的准确性、时效性;

2.用户不关心具体的 IP 库格式以及背后复杂的查询算法,并且用户希望使用当前最新的 IP 库,因此需要封装一层供用户使用;

3.一些业务方不希望强耦合于 IP 库,调用的频次比较低,比较适合访问 HTTP API 就能获取 IP 与地区的映射,如线上 API 服务;

4.一些服务性能要求场景比较高,并且调用频次比较高,适合将 IP 库加载到内存缓存在程序内调用,如 collector-server(SDK 用户行为上报收集服务);

5.离线统计场景需要访问 IP 库,如 Hive IP 地区相关的 udf 方法。

整体架构及模块功能介绍

economy-api :检测账号是否安全的 api 接口服务

根据不同业务场景美图搭建的 GeoIP 整体架构图如上所示,接下来具体介绍各个模块的功能。

Geo Lib Server

Geo Lib Server 是基于 Netty 搭建 IP 库的 HTTP File Server 服务,提供 IP 库下载接口,服务内部实现 IP 库定期更新、IP 库校验、IP 库多版本管理等功能。它的架构如上图所示,其中包含 6 个模块:

IPFileDownloader:负责从 IPIP.NET 下载 IP 数据到本地磁盘,并对校验文件大小与 Content-Length;

IPFileHandler:解析 IP 数据,根据地区映射 Location 表,生成公司内部的 IP 库格式;

IPFileVerifier:对应生成的 IP 库数据做检验,如:对应 IP 库的大小、IP 库的变化情况等;

IPFileCompressor:对生成的 IP 库进行压缩,便于后面的 IP 库的传输(gzip);

IPFileUploader:把新版的 IP 库上传一份到 HDFS,供 Kafka-ETL 与 Hive Job 统计使用;

** Tips**

1.IP 库只有在所有流程处理完后,才能对外提供下载;IP 库上传HDFS,只有上传成功并且完整,才能对外提供;那如何保证呢? Linux 内核给我们提供了原子的 rename,而 HDFS DistributedFileSystem 提供了原子的 rename。

2.IP 库下载接口从本地磁盘加载,如何减少网络传输性能开销? 使用 Netty FileRegion 内部封装 Java NIO 的 FileChannel.transferTo()方法,transferTo()方法将数据从一个文件 channel 传输到一个可写 channel,在内部它依赖于操作系统对 Zero-copy 的支持。使用 Netty FileRegion 内部封装 Java NIO 的 FileChannel.transferTo()方法,transferTo()方法将数据从一个文件 channel 传输到一个可写 channel,在内部它依赖于操作系统对 Zero-copy 的支持。

GeoIP HTTP

GeoIP HTTP 是一个无状态的 HTTP 服务,提供一个 IP 与地区相关的 REST API。 每天定时从 Geo Lib Server 下载最新的 IP 库到本地磁盘,并更新内存的 IP 库,保证了 IP 数据的时效性。GeoIP HTTP 提供 HTTP REST API 供第三方调用,主要是 IP 转地区,地区 id 与地区名称的映射等接口,它提供的功能如下: - 通过 IP,可查找到 IP 对应的国家、省份、城市 - id 获取对应的地区名 - 获取中国的所有省份列表(包括直辖市、自治区、港澳台) - 查询中国省份下的城市信息 - 获取所有地区列表 - 判断 IP 是否属于欧盟国家 - ......

Geo Client

Geo Client 封装的 IP 库使用客户端,主要供 IP 查询地区信息的功能,内部兼容多种 IP 库格式,支持 IP 库定期更新。

IP 库格式演进

信息组成

在 IP 库内地区名称往往会与地区 ID 做成映射,其目的主要是为了节省存储、避免城市名称重复,例如城市名伯明翰在美国、英国都有,甚至一个国家不止一个;二来也可以避免一些直辖市等特殊情况。

地区信息 Location 表,其形式如下:

IP 库的文本格式如下:

基于 IP 库查询数据

IP 库的 IP 是连续并且有序的,每个IP 段对应的一个地区。

若要查询一个 IP 所属的地区,需要遍历所有的 IP 段,寻找查询的 IP 是落在哪个 IP 段之间,例如:要查询 1.0.1.10,通过上面这张图,我们很容易知道这个 IP 是中国福建的。其遍历方式主要有三种:顺序遍历、二分法和红黑树。

将每一个 IP 段看作一个节点元素,每个节点元素之间是连续有序的。 基于 JDK 自带的 TreeSet,以 end_ip 实现比较算法,符合 ip_start =< ip <= end_ip 即可实现快速查询。

遇到哪些问题?

随着时间的增长, IP 库越来越大,需要消耗越来越多的内存空间以及加载时间。并且考虑到 IP 定期更新,每次更新完有大量对象晋升老年代引发 Minor GC 停顿时间过长;另外, ETL 与 Hive 统计任务通过 DistributeCache 分发 IP 库至各个结算节点,也会占用更多的网络带宽资源。

如何设计新版 IP 库格式?

IP 库格式直接影响了它的查询性能,首先梳理它存在以下问题:

地区信息重复,同一个地区存在多个 IP 段

27.148.160.0 27.148.195.255 10184:中国 10262:福建 10550:厦门 27.148.219.0 27.148.219.255 10184:中国 10262:福建 10550:厦门 27.148.224.0 27.148.224.255 10184:中国 10262:福建 10550:厦门 ....

每个 IP 段对应一个对象, 占用较大堆空间

根据以上问题提出的优化方案如下:

1.很多 IP 段表示同一地区——将地区信息进行去重操作;

2.红黑二叉树的 TreeSet 是基于占用空间较大的 Java 对象做的——通过较为紧凑有序的字节数据代表 IP 库,并基于二分查找。

据此,我们的 IP 库经历了三次迭代:

/ 第一版

其中第一块数据是有序紧凑排列的 IP 段信息,包括开始 IP、结束 IP、地区信息位置偏移量及地区信息长度;第二块数据是地区信息,每一行代表一个完整的地区信息(country → province/area → city )。其中 12 字节的 IP segment 组成如下所示:

美图GeoIP服务实践

该版本的查询方式是通过二分法遍历 IP 找出所在 IP 段,并根据其偏移量获取地区信息,由于每次查询都要二分所有 IP 段,较低效。

/ 第二版

根据第一版的问题我们参考早期的「HashMap 数组+链表」的实现,对所有 IP 地址第一部分进行分组并建立索引。

分组后查询可先进行分组查找再进行二分法查找,提高部分查询性能。但由于每个 IP 开头不同对应的 IP 段个数不一样,IP 段个数较多的部分依然需要较长的查询时间。

/ 第三版

在第三版我们继续细化,对 IP 的前两段进行分组构建快速查询。

迭代至此,美图 IP 库组成如下所示:

IP 库由字节组成,首先 header 包含 4 个字节,它代表整个索引区的长度;接着是分组索引,它包含 2562564 字节长度;IP 段如上文所述包括开始 IP、结束 IP、地区偏移量及地区信息长度;最后的地理信息由于字符不确定,它的字节长度无法预计。

当一个 IP 传输过来时,我们取其前两段找到分组,得到它对应的 IP 段范围,再对分组内的 IP 段进行二分法查找对应的 IP 段,通过地区信息的偏移量及其长度确认其地理信息进行解析。

后续 IP 库设计

目前我们的 IP 库包含两个 IP 信息:开始 IP 及结束 IP,在 IP 段是有序连续的情况下,后续我们只需保留结束 IP 即可。

实践经验

IP 库体积

基于上文所述迭代演化,IP 库从原来文本格式的 200+ M 压缩至如今的数据格式 30+ M。

查询性能耗时(查询 2800w 线上 IP 数据)

未来展望

美图 IP 库接下来的优化主要分为三个方向:

1.争取通过优化格式使 IP 库体积越来越小,查询性能得到更大的提升;

2.扩展更多海外 IP 数据及经纬度信息;

3.IP 库监控方面提高识别率,调整监控幅度。

附:

参考文献

什么是高精准IP地址定位?

http://www.ipplus360.com/tech/baike/ip/102.html

ipip.net

https://www.ipip.net/

IP 库之手机基站数据篇

https://mp.weixin.qq.com/s/jv-EOCz52jrx-GQisFMIFA

为什么根据 IP 地址查询物理所在地,而不是 mac 地址?

https://www.zhihu.com/question/281516341/answer/421084557

本文转载自异步社区

网络 API

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:OpenGL之常见的专业名词解析
下一篇:云脉纸质文档管理工具教你如何快速查找文件!
相关文章