干货 | 基于红黑树的高效IP归属地查询方案

作者简介

邢钦华,携程风控团队高级研发经理。2016年加入携程,是风控大数据平台Chloro的设计和开发的主要参与者。专注于大数据流式处理和用户行为分析在互联网风控领域中的应用。

在实时风控系统中会涉及到非常多的数据衍生和解析,比如IP归属地解析、手机号归属地解析、银行卡卡BIN解析等等。以IP归属地为例,传统的实现IP归属地查询的方法是把IP地址信息存储到关系型数据库中,对于并发量比较少,实时性要求不高的情况下是可行的,但是一旦并发量增大时,会对关系型数据库产生很大的压力,并且访问速度会明显减慢,因此对于高并发、实时性要求高的场合这种查询方法就显得力不从心。

本文我们将以IP归属地为例,介绍一下携程风控是如何实现相对静态数据的高效衍生的。我们会把IP归属地信息保存到内存中,经过一系列的转变,最终形成红黑树,利用红黑树高效的查找性能,实现了高效的IP归属地解析方案,该方案可承担较大的并发访问压力,并拥有极低的响应延时。

实现方案:

图1

如图1所示,首先把IP地址信息录入到数据库中,系统把已经录入好的IP地址信息从数据库中读取到计算机内存,经过一系列的索引形式的转换,把最终的索引以及把IP地址转成long形式的整数后存放到计算机内存中的红黑树中,当有访问请求获取IP的归属地信息时,首先把具体的IP地址转成long形式的整数,根据此证书到红黑树中查询到其对应的结点,获取该结点的索引数据,再根据该索引数据获取到IP归属地信息,并且返回给用户。

图2

如图2所示为IP地址分类图,在TCP/IP协议中,IP地址以二进制数字的形式出现,总共4个字节,即32个bit,由网络编号(N-ID)和主机编号(H-ID)组成。根据网络地址的不同,IP地址可以分为五类: A类地址、B类地址、C类地址、D类地址以及E类地址。

对于同一个物理网络上的计算机主机,其网络编号是相同的,不同的是主机编号。在为各个城市分配IP地址时,通常是把多个连续的IP地址段分配给某一城市,例如:1.12.0.0 到1.12.255.255,1.15.168.0到1.15.191.255等连续的IP地址段都属于北京的IP地址。通常每个城市包含了多个连续的IP地址段,在这些IP地址段中的IP地址都属于该城市的IP地址,由于IP是有4个字节组成的,并且没有负数,可以把IP地址段转成两个8字节的long类型整数,在这两个整数之间的数字都属于该城市的IP地址。

IP地址是由4段组成的,如1.15.168.0,其对应的4字节二进制形式为00000001.00001111.10101000.00000000,根据计算机的计算特性,可以把第一段左移24位、第二段左移16位、第三段左移8位、第四段不移动,得到整数相加就是IP地址转换后的整数值,即16777216 + 983040 + 43008 + 0 =17803264。

图3

图4

红黑树是一种非常成熟的数据结构,是每个结点都带有红色或者黑色的二叉查找树,是比较高效的,可以在O(log n)时间内做查找,插入和删除,这里的n是树中元素的数目。红黑树在满足二叉查找树的要求外,还必须满足一下要求:

1、节点是红色或黑色。

2、根是黑色。

3、所有叶子都是黑色(叶子是NIL节点)。

4、每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路

径上不能有两个连续的红色节点。)

5、从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。

JSON是一中数据格式,主要用于数据交换,易于人阅读和编写,同时也易于计算机解析和生成。

本系统中,IP地址的归属地信息包含了国家(country)、地区(region)、市(city)等属性。

首先把IP地址信息从数据库中以JSON格式读取到计算机内存中,例如:

{"region":"天津","start":"1.15.232.0","end":"1.15.232.255","city":"天津","country":"中国"},

{"region":"辽宁","start":"1.14.33.0","end":"1.14.33.255","city":"大连","country":"中国"},

{"region":"北京","start":"1.15.186.0","end":"1.15.186.255","city":"北京","country":"中国"},

{"region":"北京","start":"1.12.27.0","end":"1.12.27.255","city":"北京","country":"中国"},

其中start为数据该城市连续IP段的起始IP,end为结束IP。

然后把这些IP归属地信息封装成Area类的集合。Area类由type和name字段组成,其中name表示一个国家或者地区或者城市的名称,比如上面的IP地址信息中的中国、天津、北京、辽宁和大连。type是由country、region、city单独或者任意相加组成,其中country、region、city分别用1、2、4表示,这样当type为1时表示一个国家,为2时表示一个省,为4时表示一个城市,为3时表示国家名和地区名相同,为5时表示国家名和城市名相同,为7时表示国家、地区、城市的名称相同。转换后的数据如下所示:

表1

type

name

1

中国

6

天津

2

辽宁

4

大连

6

北京

然后再把上面的Area类的集合数据转成raw-meta数据,其中index位Area类的集合的索引。

表2

type

name

index

1

中国

0

6

天津

1

2

辽宁

2

4

大连

3

6

北京

4

然后再根据IP地址信息和表2中的raw-meta数据转换成fomatted-raw-ip数据,其中国家索引为IP地址信息中country字段对应的表2中index列的相应值,地区索引为region字段对应的表2中index列的相应值,城市索引为city字段对应的表2中index列的相应值。

表3

国家索引

地区索引

城市索引

开始IP

结束IP

0

1

1

1.15.232.0

1.15.232.255

0

2

3

1.14.33.0

1.14.33.255

0

4

4

1.15.186.0

1.15.186.255

0

4

4

1.12.27.0

1.12.27.255

进一步,表3中第3、4行的国家索引、地区索引,城市索引是相同,都是国家为中国,地区为北京,城市为北京,为了消除重复数据,再把fomatted-raw-ip数据转换为segment-regions-ip数据。

表4

国家索引

地区索引

城市索引

fomatted-raw-ip索引

0

1

1

0

0

2

3

1

0

4

4

2

然后再把IP归属地信息和segment-regions-ip数据转为compact-ex-ip-segment数据,其中第一行为segment-regions-ip的索引。

表5

segment-regions-ip的索引

开始IP

结束IP

0

1.15.232.0

1.15.232.255

1

1.14.33.0

1.14.33.255

2

1.12.27.0

1.12.27.255

2

1.15.186.0

1.15.186.255

表5的IP地址转换成long整数。

表6

segment-regions-ip的索引

开始IP

结束IP

0

17819648

17819903

1

17703168

17703423

2

17570560

17570815

2

17807872

17808127

最后把compact-ex-ip-segment转成红黑树保存在计算机内存中,每个红黑树结点由parent,left,right,color,from,end,index组成。parent 为父节点,left为左结点 right为右结点,color 表示该结点为红色或者黑色,from为起始IP转成的long整数,end为结束IP转成的long整数,index为compact-ex-ip-segment数据保存的索引,即表6的第一次列。

由于红黑树中存放的是IP段的起始IP转换后的整数和结束IP转换后的整数,而需要查询的是具体IP地址转换后的整数,因此查询的规则是:先把IP转换为整数,从红黑树的root结点开始查起,当该整数小于结点中的from整数时,继续沿着红黑树该结点的左边查找,当该整数大于结点中的end整数时,继续沿着红黑树中该结点的右边查找,否则,该查找到的结点即为要查找的IP信息对应的结点。

若查找过程中,结点为NIL节点,说明该IP地址不是有效的IP。例如IP地址为1.15.186.10,首先把IP转成long型的整数,即17807882。然后去红黑树中查找该整数对应的红黑树中的结点为2,17807872,17808127,进而取到索引2,即segment-regions-ip的索引,根据表4取到数据0,4,4,2,其中2为fomatted-raw-ip集合的索引,0,4,4为raw-meta数据的最后一列,即为Area类集合的索引,从而找到country为0,即中国,region为4,即北京,city为4即北京。因此该IP对应的国家为中国、地区为北京、城市为北京。

当红黑树形成以后,在具体IP查询过程中,从数据库中读取的IP地址信息的JSON格式数据已经不再需要,可以从内存中删除。最终留在内存中的数据为Area类的集合,segment-regions-ip数据,红黑树,这样就可以减少计算机内存的使用。经统计,本系统中IP地址信息的总条数为719296,经过对系统启动前后,计算机内存的比较,系统启动后共占用了大约20兆(MB)的内存,在现在计算机技术快速发展的时代,一般家用的计算机的内存也有2千兆(GB)或者更多,公司专门的服务器的内存甚至高达几十GB,因此这些数据的内存占用量可以说是微不足道的。

当IP地址信息的条数增加时,只需要以目前的格式添加到数据库中,然后重启应用程序即可,当需要更详细的IP地址信息时,比如经纬度、运营供应商,除了在数据库中添加相应信息外,只需要增加Area类的相应信息的字段,重启应用程序即可,因此,此系统具有良好的扩展性。

该方案不仅适用于IP归属地查询,也适用于其他相对静态的数据的快速解析。

原文发布于微信公众号 - 携程技术中心(ctriptech)

原文发表时间:2018-01-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菩提树下的杨过

AS1.0(2.0)中的XML示例

虽然Flash早就升级为AS3.0,但是FMS的服务端编程依然仅支持AS1.0(2.0),服务端与.net通讯的最简单方式莫过于请求一个RESTful的webS...

2046
来自专栏我的技术专栏

C++ 自由存储区是否等价于堆?

2965
来自专栏happyJared

Elasticsearch地理坐标类型(Geo-point)在Spring Data ES中的常见使用问题整理解答

  下文整理的几个问答,本人在实际应用中亲身经历或解决过的,主要涉及Elasticsearch地理坐标类型(Geo-point)在Java应用中的一些特殊使用场...

3831
来自专栏数据结构与算法

BZOJ1060: [ZJOI2007]时态同步(树形dp 贪心)

Description   小Q在电子工艺实习课上学习焊接电路板。一块电路板由若干个元件组成,我们不妨称之为节点,并将其用数 字1,2,3….进行标号。电路板的...

2956
来自专栏pangguoming

JS生成UUID

一、UUID是什么   UUID就是Universal Unique IDentifier的缩写,它是一个128位,16字节的值,并确保在时间和空间上唯一。 它...

1.1K8
来自专栏北京马哥教育

shell十三问,为linux学习打基础(一)

本文整理并转自CU上的帖子[学习共享] shell 十三問?,此贴是2003年发表的,但却是相当不错的linux基础知识汇集贴,原帖主使用的台湾风格,本文加以简...

3774
来自专栏FreeBuf

Wannacry深度解析:第一阶段tasksche

WannaCry 勒索软件是2017年最热门的勒索软件,它利用微软漏洞在全球范围内发起的攻击令世界上100多个国家的成千上万的用户深受影响。俨然一场全球范围内的...

2896
来自专栏歪先生_自留地

Python test2

1063
来自专栏Java开发者杂谈

分布式改造剧集1

背景介绍 ​ 我所在的项目组,使用的技术一直是接近原始社会的:jdk1.6 + SpringMVC + hessian + Mybatis,当前最火的中间件技术...

2934
来自专栏开发 & 算法杂谈

基于Lockset的数据竞争检测方法汇总(一)

对于搞数据竞争检测方向的人来说,Lockset方法大家肯定不陌生,作为一个刚入门数据竞争检测方向的我来说,就和大家总结一下我近期有关Lockset方法的一些研究...

1904

扫码关注云+社区

领取腾讯云代金券