高性能IP数据库格式详解

每秒解析1000多万ip  qqzeng-ip-ultimate.dat 3.0版

编码:UTF8     字节序:Little-Endian

返回规范字段(如:亚洲|中国|香港|九龙|油尖旺|新世界电讯|810200|Hong Kong|HK|114.17495|22.327115)

------------------------ 文件结构  -------------------------
// 文件头 4字节
[IP段数量]

// 前缀区 8字节(4-4) 256*8
[索引区start第几个][索引区end第几个]

// 索引区 8字节(4-3-1) ip段行数x8
[结束IP数字][地区流位置][流长度]

// 内容区 长度无限制
[地区信息][地区信息]……唯一不重复

------------------------ 文件结构 ---------------------------

优势:压缩形式将数据存储在内存中,通过减少将相同数据读取到内存的次数来减少I/O.
          较高的压缩率通过使用更小的内存中空间提高查询性能。
          前缀区为作为缩小查询范围,索引区和内容区长度一样,
          解析出来一次性加载到数组中,查询性能提高3-5倍!

压缩:原版txt为38.5M,生成dat结构为3.68M 。
          和上一版本2.0不同的是索引区去掉了[开始IP数字]4字节,节省多1-2M。
          3.0版本只适用[全球版],条件为ip段区间连续且覆盖所有IPV4。
          2.0版本适用[全球版][国内版][国外版]

性能:每秒解析1000多万ip

创建:qqzeng-ip 于 2018-04-08

性能测试   ( CPU i7-7700K + DDR2400 16G + win10 X64 )

查询【3.0】内存优化版 3414万ip->3.318秒 每秒1028.93309222423万次
查询【3.0】内存优化版 4439万ip->4.199秒 每秒1057.1564658252万次
查询【3.0】内存优化版 4056万ip->3.821秒 每秒1061.50222454855万次
查询【3.0】内存优化版 1781万ip->1.68秒 每秒1060.11904761905万次
查询【3.0】内存优化版 3862万ip->3.66秒 每秒1055.1912568306万次
查询【3.0】内存优化版 3479万ip->3.31秒 每秒1051.05740181269万次
查询【3.0】内存优化版 2892万ip->2.713秒 每秒1065.97862145227万次
查询【3.0】内存优化版 3484万ip->3.263秒 每秒1067.72908366534万次
查询【3.0】内存优化版 2699万ip->2.548秒 每秒1059.26216640502万次
查询【3.0】内存优化版 88万ip->0.087秒 每秒1011.49425287356万次
查询【3.0】内存优化版 161万ip->0.153秒 每秒1052.28758169935万次
查询【3.0】内存优化版 91万ip->0.088秒 每秒1034.09090909091万次
查询【3.0】内存优化版 42万ip->0.041秒 每秒1024.39024390244万次
查询【3.0】内存优化版 159万ip->0.152秒 每秒1046.05263157895万次
查询【3.0】内存优化版 88万ip->0.084秒 每秒1047.61904761905万次
查询【3.0】内存优化版 123万ip->0.118秒 每秒1042.37288135593万次
查询【3.0】内存优化版 106万ip->0.101秒 每秒1049.50495049505万次
查询【3.0】内存优化版 61万ip->0.059秒 每秒1033.89830508475万次
查询【3.0】内存优化版 177万ip->0.169秒 每秒1047.33727810651万次
查询【3.0】内存优化版 106万ip->0.101秒 每秒1049.50495049505万次

查询【3.0】普通优化版 1464万ip->3.408秒 每秒429.577464788732万次
查询【3.0】普通优化版 352万ip->0.803秒 每秒438.356164383562万次
查询【3.0】普通优化版 1357万ip->3.042秒 每秒446.088099934254万次
查询【3.0】普通优化版 184万ip->0.43秒 每秒427.906976744186万次
查询【3.0】普通优化版 752万ip->1.697秒 每秒443.134944018857万次
查询【3.0】普通优化版 1795万ip->4.032秒 每秒445.188492063492万次
查询【3.0】普通优化版 1823万ip->4.076秒 每秒447.252208047105万次
查询【3.0】普通优化版 723万ip->1.622秒 每秒445.745992601726万次
查询【3.0】普通优化版 136万ip->0.319秒 每秒426.332288401254万次
查询【3.0】普通优化版 334万ip->0.756秒 每秒441.798941798942万次
查询【3.0】普通优化版 636万ip->1.435秒 每秒443.205574912892万次
查询【3.0】普通优化版 701万ip->1.578秒 每秒444.233206590621万次
查询【3.0】普通优化版 1807万ip->4.07秒 每秒443.980343980344万次
查询【3.0】普通优化版 489万ip->1.105秒 每秒442.533936651584万次

随机生成 IP

  1. RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
  2. byte[] bytes = new byte[];
  3. rngCsp.GetBytes(bytes);
  4. uint value = ReadBigEndian32(bytes[], bytes[], bytes[], bytes[]);

开发参考 (解析dat以及查询)

  1. public class IPSearch3Fast
  2. {
  3. private static readonly Lazy<IPSearch3Fast> lazy = new Lazy<IPSearch3Fast>(() => new IPSearch3Fast());
  4. public static IPSearch3Fast Instance { get { return lazy.Value; } }
  5. private IPSearch3Fast()
  6. {
  7. LoadDat();
  8. Watch();
  9. }
  10.  
  11. private string datPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"qqzeng-ip-ultimate.dat");
  12. private DateTime lastRead = DateTime.MinValue;
  13.  
  14. private long[,] prefmap = new long[, ];
  15. private uint[] endArr;
  16. private string[] addrArr;
  17. private byte[] data;
  18.  
  19. /// <summary>
  20. /// 初始化二进制 qqzeng-ip-ultimate.dat 数据
  21. /// </summary>
  22.  
  23. private void LoadDat()
  24. {
  25. data = File.ReadAllBytes(datPath);
  26.  
  27. for (int k = ; k < ; k++)
  28. {
  29. int i = k * + ;
  30. int prefix = k;
  31. long startIndex = ReadLittleEndian32(data[i], data[i + ], data[i + ], data[i + ]);
  32. long endIndex = ReadLittleEndian32(data[i + ], data[i + ], data[i + ], data[i + ]);
  33. prefmap[k, ] = startIndex; prefmap[k, ] = endIndex;
  34. }
  35.  
  36. uint RecordSize = ReadLittleEndian32(data[], data[], data[], data[]);
  37. endArr = new uint[RecordSize];
  38. addrArr = new string[RecordSize];
  39. for (int i = ; i < RecordSize; i++)
  40. {
  41. long p = + (i * );
  42. uint endipnum = ReadLittleEndian32(data[p], data[ + p], data[ + p], data[ + p]);
  43.  
  44. int offset = data[ + p] + ((data[ + p]) << ) + ((data[ + p]) << );
  45. int length = data[ + p];
  46.  
  47. endArr[i] = endipnum;
  48. addrArr[i] = Encoding.UTF8.GetString(data, offset, length);
  49. }
  50. }
  51. private void Watch()
  52. {
  53. FileInfo fi = new FileInfo(datPath);
  54. FileSystemWatcher watcher = new FileSystemWatcher(fi.DirectoryName)
  55. {
  56. IncludeSubdirectories = false,
  57. NotifyFilter = NotifyFilters.LastWrite,
  58. Filter = "qqzeng-ip-ultimate.dat",
  59. };
  60.  
  61. watcher.Changed += (s, e) =>
  62. {
  63.  
  64. var lastWriteTime = File.GetLastWriteTime(datPath);
  65.  
  66. if (lastWriteTime > lastRead)
  67. {
  68. //延时 解决 正由另一进程使用,因此该进程无法访问此文件
  69. Thread.Sleep();
  70.  
  71. LoadDat();
  72. lastRead = lastWriteTime;
  73. }
  74. };
  75. watcher.EnableRaisingEvents = true;
  76. }
  77.  
  78. /// <summary>
  79. /// ip快速查询方法
  80. /// </summary>
  81. /// <param name="ip">1.1.1.1</param>
  82. /// <returns></returns>
  83. public string Find(string ip)
  84. {
  85. long val = IpToInt(ip, out long pref);
  86. long low = prefmap[pref, ], high = prefmap[pref, ];
  87. long cur = low == high ? low : BinarySearch(low, high, val);
  88. return addrArr[cur];
  89. }
  90.  
  91. // 二分逼近 O(logN)
  92. private long BinarySearch(long low, long high, long k)
  93. {
  94. long M = , mid = ;
  95. while (low <= high)
  96. {
  97. mid = (low + high) / ;
  98. uint endipnum = endArr[mid];
  99. if (endipnum >= k)
  100. {
  101. M = mid;
  102. if (mid == )
  103. {
  104. break; //防止溢出
  105. }
  106. high = mid - ;
  107. }
  108. else
  109. low = mid + ;
  110. }
  111. return M;
  112. }
  113.  
  114. private long IpToInt(string ipString, out long prefix)
  115. {
  116. //高性能
  117. int end = ipString.Length;
  118. unsafe
  119. {
  120. fixed (char* name = ipString)
  121. {
  122.  
  123. int numberBase = ;
  124. char ch;
  125. long[] parts = new long[];
  126. long currentValue = ;
  127. int dotCount = ;
  128. int current = ;
  129. for (; current < end; current++)
  130. {
  131. ch = name[current];
  132. currentValue = ;
  133.  
  134. numberBase = ;
  135. if (ch == '')
  136. {
  137. numberBase = ;
  138. current++;
  139.  
  140. if (current < end)
  141. {
  142. ch = name[current];
  143. if (ch == 'x' || ch == 'X')
  144. {
  145. numberBase = ;
  146. current++;
  147. }
  148. }
  149. }
  150.  
  151. for (; current < end; current++)
  152. {
  153. ch = name[current];
  154. int digitValue;
  155.  
  156. if ((numberBase == || numberBase == ) && '' <= ch && ch <= '')
  157. {
  158. digitValue = ch - '';
  159. }
  160. else if (numberBase == && '' <= ch && ch <= '')
  161. {
  162. digitValue = ch - '';
  163. }
  164. else if (numberBase == && 'a' <= ch && ch <= 'f')
  165. {
  166. digitValue = ch + - 'a';
  167. }
  168. else if (numberBase == && 'A' <= ch && ch <= 'F')
  169. {
  170. digitValue = ch + - 'A';
  171. }
  172. else
  173. {
  174. break;
  175. }
  176.  
  177. currentValue = (currentValue * numberBase) + digitValue;
  178.  
  179. }
  180.  
  181. if (current < end && name[current] == '.')
  182. {
  183. parts[dotCount] = currentValue;
  184. dotCount++;
  185. continue;
  186. }
  187. break;
  188. }
  189. parts[dotCount] = currentValue;
  190. prefix = parts[];
  191. return (parts[] << ) | ((parts[] & 0xff) << ) | ((parts[] & 0xff) << ) | (parts[] & 0xff);
  192. }
  193. }
  194.  
  195. //简洁的 普通
  196.  
  197. //byte[] b = IPAddress.Parse(ip).GetAddressBytes();
  198. //prefix = b[0];
  199. // return ReadBigEndian32(b[0], b[1], b[2], b[3]);
  200. }
  201.  
  202. private uint ReadBigEndian32(byte a, byte b, byte c, byte d)
  203. {
  204. return (uint)((a << ) | (b << ) | (c << ) | d);
  205. }
  206.  
  207. private uint ReadLittleEndian32(byte a, byte b, byte c, byte d)
  208. {
  209. return (uint)(a | (b << ) | (c << ) | (d << ));
  210. }
  211. }
  212.  
  213. /*
  214. (调用例子):
  215. string result = IPSearch3Fast.Instance.Find("1.2.3.4");
  216. --> result="亚洲|中国|香港|九龙|油尖旺|新世界电讯|810200|Hong Kong|HK|114.17495|22.327115"
  217. */

开发代码:https://github.com/zengzhan/qqzeng-ip

最新IP数据库 存储优化 查询性能优化 每秒解析上千万的更多相关文章

  1. Mysql数据库调优和性能优化的21条最佳实践

    Mysql数据库调优和性能优化的21条最佳实践 1. 简介 在Web应用程序体系架构中,数据持久层(通常是一个关系数据库)是关键的核心部分,它对系统的性能有非常重要的影响.MySQL是目前使用最多的开 ...

  2. 一次使用 Redis 优化查询性能的实践

    因为我的个人网站 restran.net 已经启用,博客园的内容已经不再更新.请访问我的个人网站获取这篇文章的最新内容,一次使用 Redis 优化查询性能的实践 应用背景 有一个应用需要上传一组ID到 ...

  3. SQL SERVER 查询性能优化——分析事务与锁(五)

    SQL SERVER 查询性能优化——分析事务与锁(一) SQL SERVER 查询性能优化——分析事务与锁(二) SQL SERVER 查询性能优化——分析事务与锁(三) 上接SQL SERVER ...

  4. mysql笔记03 查询性能优化

    查询性能优化 1. 为什么查询速度会慢? 1). 如果把查询看作是一个任务,那么它由一系列子任务组成,每个子任务都会消耗一定的时间.如果要优化查询,实际上要优化其子任务,要么消除其中一些子任务,要么减 ...

  5. SQL Server查询性能优化——堆表、碎片与索引(二)

    本文是对 SQL Server查询性能优化——堆表.碎片与索引(一)的一些总结.  第一:先对 SQL Server查询性能优化——堆表.碎片与索引(一)中的例一的SET STATISTICS IO之 ...

  6. SQL Server查询性能优化——覆盖索引(二)

    在SQL Server 查询性能优化——覆盖索引(一)中讲了覆盖索引的一些理论. 本文将具体讲一下使用不同索引对查询性能的影响. 下面通过实例,来查看不同的索引结构,如聚集索引.非聚集索引.组合索引等 ...

  7. Redis 优化查询性能

    一次使用 Redis 优化查询性能的实践   应用背景 有一个应用需要上传一组ID到服务器来查询这些ID所对应的数据,数据库中存储的数据量是7千万,每次上传的ID数量一般都是几百至上千数量级别. 以前 ...

  8. MySQL查询性能优化(精)

    MySQL查询性能优化 MySQL查询性能的优化涉及多个方面,其中包括库表结构.建立合理的索引.设计合理的查询.库表结构包括如何设计表之间的关联.表字段的数据类型等.这需要依据具体的场景进行设计.如下 ...

  9. 高性能mysql 第六章查询性能优化 总结(上)查询的执行过程

    6  查询性能优化 6.1为什么查询会变慢 这里说明了的查询执行周期,从客户端到服务器端,服务器端解析,优化器生成执行计划,执行(可以细分,大体过程可以通过show profile查看),从服务器端返 ...

随机推荐

  1. 笔记:Hibernate 持久化类标注说明

    持久化类标注 标注 @Entity:注解声明该类是一个Hibernate的持久化类 标注 @Table:指定该类映射的表 参数 name:指定映射数据库表的名称 参数 uniqueConstraint ...

  2. Spring Boot 定时任务的使用

    @Configuration @EnableScheduling public class ScheduleConfig { private final Logger logger = LoggerF ...

  3. Docker 网络管理及容器跨主机通信

    1.网络模式 docker支持四种网络模式,使用--net选项指定: host,--net=host,如果指定此模式,容器将不会获得一个独立的network namespace,而是和宿主机共用一个. ...

  4. JWT 简介

    JWT是一种用于双方之间传递安全信息的简洁的.URL安全的表述性声明规范.JWT作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息 ...

  5. Javascript中几个看起来简单,却不一定会做的题

    Javascript作为前端开发必须掌握的一门语言,因为语言的灵活性,有些知识点看起来简单,在真正遇到的时候,却不一定会直接做出来,今天我们就一起来看看几道题目吧 题目1 var val = 'smt ...

  6. apache实现301永久性重定向代码

    301重定向(301 redirect)又叫301代表永久性转移(Permanently Moved),将各种网络请求重新定个方向转到其它位置,是网页更改地址后对搜索引擎友好的最好方法,只要不是暂时搬 ...

  7. Alpha第七天

    Alpha第七天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  8. B-day7

    1.昨天的困难,今天解决的进度,以及明天要做的事情 昨天的困难:美化了登录页面,对导入导出的bug进行相关修改,对用户编辑页面进行相关美化,对第三方逻辑进行相应调整. 今天解决的进度:解决了导入和导出 ...

  9. 201621123050 《Java程序设计》第2周学习总结

    1.本周学习总结 java的数据类型 基本数据类型:介绍了java特有的boolean 引用数据类型 String:不变性:需要频繁修改时使用StringBuilder 包装类:自动拆.装箱 数组 一 ...

  10. 团队作业2:需求分析&原型设计

    Deadline: 2017-11-5  22:00PM,以博客发表日期为准.   评分基准: 按时交 - 有分,检查的项目包括后文的三个方面 需求分析 原型设计 编码规范 晚交 - 0分 迟交两周以 ...