高性能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. Scala中 object 和 class的区别

    object 在scala中没有静态方法和静态字段,所以在scala中可以用object来实现这些功能,直接用对象名调用的方法都是采用这种实现方式,例如Array.toString.对象的构造器在第一 ...

  2. Redis数据过期策略

    1.Redis中key的的过期时间 通过EXPIRE key seconds命令来设置数据的过期时间.返回1表明设置成功,返回0表明key不存在或者不能成功设置过期时间.在key上设置了过期时间后ke ...

  3. 【Django】Web应用开发经由

    [Django开发经由] 本来以为看完网上的入门教程之后就可以看书详细学习一下,没想到手头上的这本书也讲得不是太详细..无奈,不过好在这本书从无到有建立一个网站的流程还算可以,就以这个角度简单记录一下 ...

  4. 【阿里云API】 阿里云API调用的若干说明

    阿里云API 为了监控我们使用的一些阿里云产品,需要些一些脚本,定时调用这些脚本来获得相关阿里云产品的信息. ■ 概述 调用阿里云API大约分成两类方法,一个是直接从HTTP协议开始,自己根据阿里云的 ...

  5. iOS 10.10 10.11 10.12 安装升级CocoPods

    CocoPods简介 CocoaPods是一个用Ruby写的,负责管理iOS以及OSX系统下的一个第三方类库管理工具,通过CocoaPods,我们可以集中,统一的管理第三方开源库.当然这些库徐亚Coc ...

  6. java开源安全框架-------Apache Shiro--第一天

    1.1.简介 Apache Shiro 是Java的一个安全框架.目前使用Apache Shiro 的人越来越多,因为它相当简单,对比Spring Security,可能没有没有Spring Secu ...

  7. KVM之一:安装准备(基于CentOS6.7)

    KVM 虚拟机简介: Kernel-based Virtual Machine的简称,是一个开源的系统虚拟化模块,自Linux 2.6.20之后集成在Linux的各个主要发行版本中.它使用Linux自 ...

  8. Java 多线程并发编程之 Synchronized 关键字

    synchronized 关键字解析 同步锁依赖于对象,每个对象都有一个同步锁. 现有一成员变量 Test,当线程 A 调用 Test 的 synchronized 方法,线程 A 获得 Test 的 ...

  9. 循环while do---while for循环

    一.循环结构 (.^▽^) 1.循环不是无休止进行的,满足一定条件的时候循环才会继续,称为"循环条件",循环条件不满足的时候,循环退出 2.循环结构是反复进行相同的或类似的一系列操 ...

  10. 高级软件工程第三次作业 赵坤&黄亦薇

    0.小组成员 赵坤2017282110261 黄亦薇201728210260 1.项目Github地址  https://github.com/zkself/homework3 PS:建议使用chro ...