最新IP数据库 存储优化 查询性能优化 每秒解析上千万

高性能IP数据库格式详解

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

编码:UTF8     字节序:Little-Endian

返回规范字段(如:亚洲|中国|香港|九龙|油尖旺|新世界电讯|810200|*|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|*|HK|114.17495|22.327115"
*/

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

上一篇:[AWS S3] Hosting a Static Website on Amazon S3


下一篇:Struts2笔记——初次框架配置