高性能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

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

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

    public class IPSearch3Fast
{
private static readonly Lazy<IPSearch3Fast> lazy = new Lazy<IPSearch3Fast>(() => new IPSearch3Fast());
public static IPSearch3Fast Instance { get { return lazy.Value; } }
private IPSearch3Fast()
{
LoadDat();
Watch();
} private string datPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"qqzeng-ip-ultimate.dat");
private DateTime lastRead = DateTime.MinValue; private long[,] prefmap = new long[, ];
private uint[] endArr;
private string[] addrArr;
private byte[] data; /// <summary>
/// 初始化二进制 qqzeng-ip-ultimate.dat 数据
/// </summary> private void LoadDat()
{
data = File.ReadAllBytes(datPath); for (int k = ; k < ; k++)
{
int i = k * + ;
int prefix = k;
long startIndex = ReadLittleEndian32(data[i], data[i + ], data[i + ], data[i + ]);
long endIndex = ReadLittleEndian32(data[i + ], data[i + ], data[i + ], data[i + ]);
prefmap[k, ] = startIndex; prefmap[k, ] = endIndex;
} uint RecordSize = ReadLittleEndian32(data[], data[], data[], data[]);
endArr = new uint[RecordSize];
addrArr = new string[RecordSize];
for (int i = ; i < RecordSize; i++)
{
long p = + (i * );
uint endipnum = ReadLittleEndian32(data[p], data[ + p], data[ + p], data[ + p]); int offset = data[ + p] + ((data[ + p]) << ) + ((data[ + p]) << );
int length = data[ + p]; endArr[i] = endipnum;
addrArr[i] = Encoding.UTF8.GetString(data, offset, length);
}
}
private void Watch()
{
FileInfo fi = new FileInfo(datPath);
FileSystemWatcher watcher = new FileSystemWatcher(fi.DirectoryName)
{
IncludeSubdirectories = false,
NotifyFilter = NotifyFilters.LastWrite,
Filter = "qqzeng-ip-ultimate.dat",
}; watcher.Changed += (s, e) =>
{ var lastWriteTime = File.GetLastWriteTime(datPath); if (lastWriteTime > lastRead)
{
//延时 解决 正由另一进程使用,因此该进程无法访问此文件
Thread.Sleep(); LoadDat();
lastRead = lastWriteTime;
}
};
watcher.EnableRaisingEvents = true;
} /// <summary>
/// ip快速查询方法
/// </summary>
/// <param name="ip">1.1.1.1</param>
/// <returns></returns>
public string Find(string ip)
{
long val = IpToInt(ip, out long pref);
long low = prefmap[pref, ], high = prefmap[pref, ];
long cur = low == high ? low : BinarySearch(low, high, val);
return addrArr[cur];
} // 二分逼近 O(logN)
private long BinarySearch(long low, long high, long k)
{
long M = , mid = ;
while (low <= high)
{
mid = (low + high) / ;
uint endipnum = endArr[mid];
if (endipnum >= k)
{
M = mid;
if (mid == )
{
break; //防止溢出
}
high = mid - ;
}
else
low = mid + ;
}
return M;
} private long IpToInt(string ipString, out long prefix)
{
//高性能
int end = ipString.Length;
unsafe
{
fixed (char* name = ipString)
{ int numberBase = ;
char ch;
long[] parts = new long[];
long currentValue = ;
int dotCount = ;
int current = ;
for (; current < end; current++)
{
ch = name[current];
currentValue = ; numberBase = ;
if (ch == '')
{
numberBase = ;
current++; if (current < end)
{
ch = name[current];
if (ch == 'x' || ch == 'X')
{
numberBase = ;
current++;
}
}
} for (; current < end; current++)
{
ch = name[current];
int digitValue; if ((numberBase == || numberBase == ) && '' <= ch && ch <= '')
{
digitValue = ch - '';
}
else if (numberBase == && '' <= ch && ch <= '')
{
digitValue = ch - '';
}
else if (numberBase == && 'a' <= ch && ch <= 'f')
{
digitValue = ch + - 'a';
}
else if (numberBase == && 'A' <= ch && ch <= 'F')
{
digitValue = ch + - 'A';
}
else
{
break;
} currentValue = (currentValue * numberBase) + digitValue; } if (current < end && name[current] == '.')
{
parts[dotCount] = currentValue;
dotCount++;
continue;
}
break;
}
parts[dotCount] = currentValue;
prefix = parts[];
return (parts[] << ) | ((parts[] & 0xff) << ) | ((parts[] & 0xff) << ) | (parts[] & 0xff);
}
} //简洁的 普通 //byte[] b = IPAddress.Parse(ip).GetAddressBytes();
//prefix = b[0];
// return ReadBigEndian32(b[0], b[1], b[2], b[3]);
} private uint ReadBigEndian32(byte a, byte b, byte c, byte d)
{
return (uint)((a << ) | (b << ) | (c << ) | d);
} private uint ReadLittleEndian32(byte a, byte b, byte c, byte d)
{
return (uint)(a | (b << ) | (c << ) | (d << ));
}
} /*
(调用例子):
string result = IPSearch3Fast.Instance.Find("1.2.3.4");
--> result="亚洲|中国|香港|九龙|油尖旺|新世界电讯|810200|Hong Kong|HK|114.17495|22.327115"
*/

开发代码: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. 以太坊挖矿源码:ethash算法

    本文具体分析以太坊的共识算法之一:实现了POW的以太坊共识引擎ethash. 关键字:ethash,共识算法,pow,Dagger Hashimoto,ASIC,struct{},nonce,FNV ...

  2. javascript中的null,对象系统还是非对象系统?

    1.一直以来的认知 在我学习js的过程中,爱民老师的绿皮书里将js的类型系统分成了两类: 其一是元类型系统:由typeof运算来检测 其二是对象类型系统:是元类型的object的一个分支 而null这 ...

  3. POJ-1256 next_permutation函数应用

    字典序列: 在字典序中蕴含着一个点,就是大小的问题,谁先出现,谁后出现的问题.譬如a<b<c,出现顺序就是a,b,c. 本题中字符集是所有大小写字母,而题目中规定的谁大谁小已经不是按asc ...

  4. Redis单例、主从模式、sentinel以及集群的配置方式及优缺点对比

    https://my.oschina.net/zhangxufeng/blog/905611

  5. 【Linux】 CentOS7 虚拟机配置

    Linux虚拟机配置 从去年开始实习开始,公司电脑换了两个,自己的电脑也换了一个,每换一个新电脑,总免不了要去装一个Linux的虚拟机作为试验用.但是每次新装一个机器总是会遇到各种各样的问题让我用的不 ...

  6. 【Python】 高级文件操作 shutil

    shutil 很多时候,我想要对文件进行重命名,删除,创建等操作的时候的想法就是用subprocess开一个子进程来处理,但是实际上shutil可以更加方便地提供os的文件操作接口,从而可以一条语句搞 ...

  7. Spring事务管理—aop:pointcut expression解析(转)

    本文转载自: http://hane00.blog.163.com/blog/static/160061522011427473965/ 先来看看这个spring的配置文件的配置: <!-- 事 ...

  8. 透析thinkphp5升级版开发框架tpframe

    这里将全面的介绍这个框架给我们开发带来的好处,让你们对它有更深层次的认识,喜欢或不喜欢的,欢迎大家前来留言讨论 一.目录层次结构 现在很多的项目,特别是大一点的项目里面,都会有很多的人参与,要进行程序 ...

  9. java 对象和封装

    软件出现的目的     面向对象设计和开发程序的好处用计算机语言描述现实世界    交流更加流畅用计算机解决现实世界的问题   提高设计和开发效率 面向对象的思想    描述→ 面向对象的世界     ...

  10. MySQL数据库操作类(PHP实现,支持连贯操作)

    <?php /** * Author: suvan * CreateTime: 2018/2/27 * description: 数据库操作类(仅对接MySQL数据库,主要利用MySQLi函数) ...