Java - ip2region - 基础篇(你知道ip2region吗?)

本篇主要介绍 ip2regionip2region 支持很多客户端,本次主要以Java来介绍

在进行系统开发时,我们一般会涉及到获取到用户的具体位置信息,一般有两个方法:

  • 根据GPS 定位的信息 (一般用于手机端)
  • 用户的 IP 地址解析

每个手机都不一定会打开 GPS,而且有时并不太需要太精确的位置(到城市这个级别即可),所以根据 IP 地址入手来分析用户位置是个不错的选择。

下面就介绍一个分析 IP 地址一个比较好的东西 ip2region,这篇介绍一些基础的东西,下篇介绍使用与原理

前言

ip2region 是什么?

官方:ip2region - 准确率99.9%的离线IP地址定位库,0.0x毫秒级查询,ip2region.db数据库只有数MB,提供了java,php,c,python,nodejs,golang,c#等查询绑定和Binary,B树,内存三种查询算法

其实就是一个库,用于 IP地址解析定位用的,支持很多客户端,速度很快也不占内存,目前github已经到了10k star 了

特性:

  • 准确率高,数据聚合多个供应商的数据
  • 体积小,空间优化形成了仅仅几兆的 ip2region.db 文件
  • 速度快,内置三种查询算法,支持毫秒级查询
  • 支持多客户端,支持很多客户端,java、C#、php、c、python、nodejs、php扩展(php5和php7)、golang、rust、lua、lua_c, nginx

它的数据聚合了一些知名ip到地名查询提供商的数据,例如:(如果一下开放API或者数据都不给开放数据时ip2region将停止数据的更新服务)

  • 淘宝IP地址库, http://ip.taobao.com/
  • GeoIP, https://geoip.com/
  • 纯真IP库, http://www.cz88.net/

ip地址相关知识

不知道的去百度百科了解一下 ip地址介绍

简短总结:

IPv4使用32位(4字节)地址,如果存储需要有 2^32 = 4294967296 约42.9 亿个地址空间来存储

关于位置信息,一般由 国家|区域|省份|城市|ISP组成,如:

// ip地址|国家|区域|省份|城市|ISP
0.0.0.0|0|0|0|内网IP|内网IP
0.0.0.1|0|0|0|内网IP|内网IP
...
1.0.15.255|中国|0|广东省|广州市|电信
...
255.255.255.255|0|0|0|内网IP|内网IP

那我们需要根据ip地址获取位置信息,那如果想要直接根据ip地址获取到位置信息,即时间复杂度为O(1) 时,我们可以存储这些位置信息入文件中

假如使用 utf-8 进行存储,一条记录最短的情况是 0.0.0.0|0|0|0|0|0,有17位,占用17个字节,那么我们需要的地址空间为:

17 * 2^32 = 73014444032 B = 71303MB = 71GB 显然,不能够直接这样存储,谁会为了O(1)来存储72G的一个文件呀~

那么如何来又让速度快,又存储空间小呢?

空间文件优化

1、第一种 记录合成

因为 相邻 IP 具有相同的位置信息,所以可以其记录合成一条记录。如下文件数据(地址段依次递增):

//起始ip,结束ip,国家,区域,省份,市,运营商。无数据区域默认为0  根据开始ip地址升序排列0.0.0.0|0.255.255.255|0|0|0|内网IP|内网IP
...
1.0.8.0|1.0.15.255|中国|0|广东省|广州市|电信
...
224.0.0.0|255.255.255.255|0|0|0|内网IP|内网IP0.0.0.0|0.255.255.255|0|0|0|内网IP|内网IP
1.0.0.0|1.0.0.255|澳大利亚|0|0|0|0
1.0.1.0|1.0.3.255|中国|0|福建省|福州市|电信
1.0.4.0|1.0.7.255|澳大利亚|0|维多利亚|墨尔本|0
1.0.8.0|1.0.15.255|中国|0|广东省|广州市|电信
1.0.16.0|1.0.31.255|日本|0|0|0|0
1.0.32.0|1.0.63.255|中国|0|广东省|广州市|电信

在ip2region 库中的 ip.merge.txt 就是根据这样的规则来记录所有的IP地址,文件大小仅仅才 39.3 M ,如若根据ip地址查找位置信息,最简单的就是顺序遍历,当该ip在某条记录起始和结束ip之间时,即命中。

2、第一种 存储方式转变

上述的文件存储的ip地址都是以字符串的方式进行存储,比如像最短的字符串 0.0.0.0 占据 7 字节,最长的字符串 111.111.111.111 占据 15 字节

那如果将其转换成整型进行存储便可以大大节省空间,如果转换成整型,0.0.0.0 是 int(0), 111.111.111.111 是 int(1869573999),都仅仅占据 4 字节,可以省略大量的存储空间

3、第三种 位置信息优化

相同的位置信息会对应不同的 IP 段,所以仍有大量的位置信息在 IP 库文件中,我们可以在内存中只保留一份位置信息,并使用指针或者文件偏移量+数据长度来获取对应的位置信息

这个的意思就是也就是如:

|中国|华南|广东省|广州市|电信

其实这样的数据在文件中被重复存储了很多次,可以只存储一次,靠指针或者文件偏移量+数据长度来获取对应的位置信息

在ip2region 库中的 ip2region.db就是在 ip.merge.txt 基础上,为所有数据生成一份索引,并和数据地址组成一个索引项(index block),,然后按起始ip升序排列组成索引,并存储到数据文件的末尾,最终生成的 ip2region.db文件大小只有3.5M,根据索引获取位置信息,也直接将性能提升到0.0x毫秒级别

ip2region.db 结构介绍

ip2region.db 的文件结构图如下:

根据结构图,可以看到其主要分为以下四个部分:

  • SUPER BLOCK:存储 INDEX 的起始位置(前四个字节) 与 INDEX 的结束位置(后四个字节),用于快速获取 INDEX 索引区域的地址
  • HEADER INDEX: INDEX 区的二级索引 ,一个个 header index block 组成, 每个 header index block 对应存储 INDEX 中的 每个 index partion(4k) (前四个字节存储每个4K分区起始位置的index block 的起始ip值,后四个字节指向该index block的地址
  • DATA:数据部分 以 城市ip,国家,区域,省份,城市,运营商 形式存储, 例如:2163|中国|华南|广东省|深圳市|鹏博士
  • INDEX:一个个 index partion 组成,对应 index block 的索引分区,每个index block 对应ip.merge.txt中每一条记录的 起始ip结束ip位置数据(前四个字节存储起始ip,中间四个字节存储结束ip, 后四个字节存储数据信息 ,数据信息的 前三个字节保存数据地址(DATA中),后一个字节保存数据长度。)

查询算法

内置了三种查询算法,单次查询都在0.x毫秒级别:

  1. binary算法:基于二分查找,基于ip2region.db文件,不需要载入内存,单次查询在0.x毫秒级别
  2. b-tree算法:基于btree算法,基于ip2region.db文件,不需要载入内存,单词查询在0.x毫秒级别,比binary算法更快
  3. memory算法:整个数据库全部载入内存,单次查询都在0.1x毫秒内,C语言的客户端单次查询在0.00x毫秒级别。

本质:三种方法都是通过不同的方法先找到 index,然后根据二分查找找到 ip地址 处于的 index bolck(12个字节),根据后四个字节存储的数据信息找到数据,然后根据数据信息中的前三个字节找到对应的数据地址

binary搜索

基于二分查询方法,步骤如下:

  • 把 ip值 通过 ip2long 方法转为长整型
  • 通过 SUPER BLOCK 拿到 INDEX 的起始位置和结束位置
  • 两个位置相减,然后 +1 得出index block 总数
  • 采用二分法直接求解,比较 index block 和当前 ip 的大小,即可找到该ip属于的 index block(经典二分)
  • 拿到该 index block 的后面四个字节(数据信息), 分别得到数据长度和数据地址
  • 从数据地址读取拿到的所得长度的字节,即是搜索结果
b-tree 搜索

b-tree 搜索用到了 HEADER INDEX,第一步先在 HEADER INDEX 中搜索,再定位到 INDEX 中的某个 4k index分区搜索。

步骤:

  • 把 ip值 通过 ip2long 转为长整型
  • 使用二分法在 HEADER INDEX 中搜索,比较得到对应的 header index block
  • header index block 指向 INDEX 中的一个 4K 分区,所以直接把搜索范围降低到 4K
  • 采用二分法在获取到的 4K 分区搜索,得到对应的 index block
  • 拿到该 index block 的后面四个字节(数据信息), 分别得到数据长度和数据地址
  • 从数据地址读取拿到的所得长度的字节,即是搜索结果
memory算法

该方法和 binary搜索 方法类似,区别就是它将 ip2region.db 全部读进内存中再进行查找

相关链接

GitHub ip2region

Java - ip2region - 使用篇

Java - ip2region - 基础篇(你知道ip2region吗?)相关推荐

  1. java实现linkstring,【JAVA SE基础篇】32.String类入门

    [JAVA SE基础篇]32.String类入门 1.字符串 1.String类又称作不可变字符序列 2.String位于java.lang包中,java程序默认导入java.lang包下所有的类 3 ...

  2. java 中间容器 表格_【JAVA SE基础篇】45.迭代器、Collections工具类以及使用容器存储表格...

    本文将要为您介绍的是[JAVA SE基础篇]45.迭代器.Collections工具类以及使用容器存储表格,具体完成步骤: 1.迭代器 迭代器为我们提供了统一遍历容器(List/Map/Set)的方式 ...

  3. JAVA多线程基础篇-关键字synchronized

    1.概述 syncronized是JAVA多线程开发中一个重要的知识点,涉及到多线程开发,多多少少都使用过.那么syncronized底层是如何实现的?为什么加了它就能实现资源串行访问?本文将基于上述 ...

  4. Java面试基础篇之集合

    文章目录 你知道的集合都有哪些? 哪些集合是线程安全的? Collection 集合类和数组有什么不同? Collection和Collections有什么区别? 如何确保一个集合不能被修改? Lis ...

  5. java预科基础篇2021.2.3学习记录

    java预科基础篇2021.2.3学习记录 初识博客 本以为老师会讲是在微博上写博客做记录,没想到会是很多程序员专用的博客 博客为音译,正确翻译结果为网络日记,英文为bog 较为专业的程序员用博客为: ...

  6. java se运算符优先级,【JAVA SE基础篇】10.运算符优先级与类型转换

    [JAVA SE基础篇]10.运算符优先级与类型转换 1.运算符的优先级 运算符的优先级在考试中会考,了解即可,多用就会熟能生巧 实际使用过程中建议用小括号来分优先级 关键就是:逻辑非>逻辑与& ...

  7. JAVA红石_【Mc我的世界红石研究日记】第四期:红石基础元件(四)——JAVA版基础篇...

    Hello,大家好,欢迎来到Mc元气工作室!本期给大家带来Mc我的世界红石研究日记·第四期!版本:JAVA1.14.3. 第三期答题互动答案 以下哪一个选项被红石比较器检测出的红石信号与其他三项不同? ...

  8. java se用哪个eclipse_【JAVA SE基础篇】5.eclipse的使用和运行

    1.eclipse的版本介绍 所有版本的eclipse都按照系统分为32位和64位,如果你的JDK是32位,eclispe必须也是32位,eclipse应与JDK相符合 eclipse分SE和EE等版 ...

  9. 零基础入门 自学 JAVA SE 基础篇(九)instanceof final 开闭原则 多态 抽象(abstract)方法与抽象类 接口(interface)

    JAVA SE自学 基础篇 多态 instanceof final 开闭原则 多态 抽象(abstract)方法与抽象类 接口(interface) 目标 父类型与子类型之间的转换及instanceo ...

最新文章

  1. 对象检测工具包mmdetection简介、安装及测试代码
  2. android UI进阶之布局的优化(二)
  3. Ext Js MVC系列二 利用Application和Viewport进行应用程序初始化和页面布局
  4. 【转载】Few-shot learning(少样本学习)和 Meta-learning(元学习)概述
  5. NodeJS学习笔记(一)——搭建开发框架Express,实现Web网站登录验证
  6. php与rest的关系,PHP与节点REST-API
  7. 关于ajax跨域的问题
  8. 简约大方干净明亮“现代简约细体字体”
  9. android iso系统下载 百度云,Windows 7 SP1官方原版ISO系统镜像所有版本下载集合
  10. 知网文献阅读器android,CAJViewer知网阅读器
  11. 架构师应该具备什么技能
  12. OA系统-部门和员工管理模块
  13. ESP8266 开发之旅 网络篇 无线更新 --OTA 固件更新
  14. 树莓派配置记录——aria2
  15. imatest测试分辨率使用教程
  16. YOLOV4垃圾检测召回率提升
  17. 在一家公司待久了没有目标,没有动力,我该怎么办?
  18. qt助手服务器超时,qt助手安装与使用教程
  19. 我是如何在知乎上赚钱的?真实经验分享,可操作性强
  20. Syzkaller学习笔记---更新syz-manager(二)

热门文章

  1. Redis学习篇3_事务及其监控(锁)、Jedis、SpringBoot整合Redis、RedisTemplate的json序列化、RedisUtil工具类
  2. 高薪程序员Java面试题精讲系列汇总
  3. MySQL 查询、子查询及连接查询
  4. 互联网公司春联大集合,太特么有才了
  5. java父原型,对象及原型丶Java教程网-IT开发者们的技术天堂
  6. JVM06-经典垃圾收集器
  7. Spring Cloud落地之Spring Cloud LoadBalancer 线上优化方案
  8. 有关彩票的python编程教程_python实现彩票系统
  9. GridView中BoundField与TemplateField的区别
  10. python月球地球质量计算_科学网—天文计算PyEphem指南 - 张金龙的博文