高性能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. Python sort后赋值 操作陷阱

    x=[1,4,2,0] # 错误的方式,因为sort没有返回值 y=x.sort() type (y) #NoneType #正确的方式 x.sort() y=x[:]

  2. EntityFramework Core 运行dotnet ef命令迁移背后本质是什么?(EF Core迁移原理)

    前言 终于踏出第一步探索EF Core原理和本质,过程虽然比较漫长且枯燥乏味还得反复论证,其中滋味自知,EF Core的强大想必不用我再过多废话,有时候我们是否思考过背后到底做了些什么,到底怎么实现的 ...

  3. 用js编解码base64

    以下是编码和解码的方法 function Base64() { // private property _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef ...

  4. Day4----------用户、群组、权限

    一.创建用户 命令:useradd 详细信息: root:x:0:0:root:/root:/bin/bash 总共七位 tom:x:500:500: :/home/tom:/bin/bash 1.r ...

  5. VMware 下快速克隆出多个 Linux 环境

    念念不忘,必有回响 好好工作,好好吃饭,困了倒头就睡:吃你认为好吃的,吃到饱:买贵的,你想买的:去玩去野: 就这样. 为什么要克隆多个 Linux 系统? 因为要玩阿. 其实也不是了,就是为了折腾嘛, ...

  6. 【itchat】用Python玩耍微信

    [itchat] itchat是个基于网页版微信的python微信API.功能目前做到基本可以满足正常的消息收发,信息的获取等等.不过对于红包之类网页版微信不支持的功能,这个模块自然也就无法支持了. ...

  7. ansible自动化运维

    ansible 系统架构 ansible简介 ansible是新出现的自动化运维工具,ansible是一个配置管理和应用部署工具,基于Python开发,集合了众多运维工具(puppet.cfengin ...

  8. oracle中事务处理--事务隔离级别

    概念:隔离级别定义了事务与事务之间的隔离程度. ANSI/ISO SQL92标准定义了一些数据库操作的隔离级别(这是国际标准化组织定义的一个标准而以,不同的数据库在实现时有所不同). 隔离级别 脏读 ...

  9. mysql gtid 主从复制

    基于GTID环境搭建主从复制 1.环境 ----------------------------------------------------------| |mysql版本 | 5.7.14 | ...

  10. 忘记oracle的sys密码该如何重置;附如何修改oracle数据库用户密码

    参考博客:http://blog.itpub.net/26015009/viewspace-717505/ 这里只说一种方法:使用ORAPWD.EXE 工具修改密码 打开命令提示符窗口,输入如下命令: ...