# `ip2region xdb rust` 查询客户端实现
# 实现效果
得益于`xdb`数据存储格式设计以及`rust`编译器的高度代码优化
- 实现单核`CPU`下接近每秒千万级别的查询,如果是4核8线这样的`CPU`,采用`tokio`异步运行时,可以达到接近每秒4千万查询速度,查询速度取决于`CPU`物理核睿频频率
- 达到查询稳定在`100-150ns/op`
- `ip2region.xdb`文件会直接加载到内存,整个程序运行时候占用内存`13M`左右,即使是多线程或者异步运行时下面的高并发查询也是稳定在这个内存大小
- 只会加载一次数据,多线程安全,可以自由使用`tokio`异步运行时或者标准库的多线程`std::thread`
# 缓存方式说明
由于基于文件的查询以及缓存`VectorIndex`索引在并发较高(比如每秒上百并发)的情况下,每次查询都会从磁盘加载`ip2region.xdb`文件进入内存,由此会产生很高的磁盘`IO`以及极大的内存占用,所以决定做一次减法,不对这两种缓存进行开发,只提供缓存整个`xdb`文件的方式,以此实现最小的并发查询内存开销以及极限`CPU`性能压榨
# 使用方式
使用`cargo`新建一个项目,比如`cargo new ip-test`
同时把`ip2region.xdb`文件也移动到该项目根路径下,或者不移动,下面示例编译的时候注意调整`xdb_filepath`的参数值
配置`Cargo.toml`的`[dependencies]`如下
```toml
[dependencies]
xdb = { git = "https://github.com/lionsoul2014/ip2region.git", branch = "master" }
# 用于生成随机数
rand = "0.8"
# 用于初始化日志打印
tracing = "0.1"
tracing-subscriber = "0.3.14"
# 异步运行时
tokio = { version = "1", features = ["full"]}
```
### 基本使用示例
编写`main.rs`
```rust
use std::net::Ipv4Addr;
use std::thread;
use std::time::{Duration, Instant};
use xdb::{search_by_ip, searcher_init};
fn main() {
// 配置输出日志信息
tracing_subscriber::fmt::init();
// 初始化加载xdb文件
let xdb_filepath = "./ip2region.xdb";
searcher_init(Some(xdb_filepath.to_owned()));
// 如果../data或者../../data或者../../../data下面有对应的ip2region.xdb文件
// 初始化函数可以直接调用如下
// searcher_init(None);
println!("\n测试多类型查询");
println!("{}", search_by_ip("9999999").unwrap());
println!("{}", search_by_ip("1.0.1.0").unwrap());
println!("{}", search_by_ip(9999999).unwrap());
println!("{:?}", search_by_ip(Ipv4Addr::from(3333333)));
println!("\n测试多线程初始化以及多线程查询");
for i in 1..5 {
thread::spawn(move || {
// 再次初始化是没什么效果的
searcher_init(Some(xdb_filepath.to_owned()));
println!("in thread {i} {:?}", search_by_ip(rand::random::<u32>()));
});
}
// 等待多线程执行结束
thread::sleep(Duration::from_secs(1));
let count = 10_000_000;
print!("\n计算千万数据总共耗时: ");
let now = Instant::now();
for _ in 0..count {
search_by_ip(rand::random::<u32>()).unwrap();
}
println!("{:?}, ave: {:?}", now.elapsed(), now.elapsed()/count);
print!("\n计算千万数据,每次迭代都统计耗时的总共耗时: ");
let mut total = Duration::from_secs(0);
for _ in 0..count {
let current = Instant::now();
search_by_ip(rand::random::<u32>()).unwrap();
total += current.elapsed();
}
println!("{:?}, ave: {:?}", total, total/count);
print!("\n计算空迭代耗时: ");
let now = Instant::now();
for _ in 0..count {}
println!("{:?}", now.elapsed());
}
```
进行测试如下,需要指定`RUST_LOG`参数打印日志
```shell
➜ RUST_LOG=debug cargo run -r
Compiling ip-test v0.1.0 (/home/gong/rust-work/ip-test)
Finished release [optimized] target(s) in 0.27s
Running `target/release/ip-test`
2022-12-24T03:31:22.921958Z DEBUG xdb::searcher: load xdb searcher file at ./ip2region.xdb
测试多类型查询
0|0|0|内网IP|内网IP
中国|0|福建省|福州市|电信
0|0|0|内网IP|内网IP
Ok("0|0|0|内网IP|内网IP")
测试多线程初始化以及多线程查询
in thread 1 Ok("美国|0|新墨西哥|0|康卡斯特")
in thread 3 Ok("0|0|0|内网IP|内网IP")
in thread 2 Ok("土耳其|0|Ankara|0|0")
in thread 4 Ok("爱尔兰|0|Cork|0|0")
计算千万数据总共耗时: 1.176241972s, ave: 117ns
计算千万数据,每次迭代都统计耗时的总共耗时: 1.407956755s, ave: 140ns
计算空迭代耗时: 40ns
```
### `tokio`使用示例
```rust
use std::time::Instant;
use tokio::sync::mpsc;
use xdb::{search_by_ip, searcher_init};
#[tokio::main]
async fn main() {
// 配置输出debug 信息
tracing_subscriber::fmt::init();
searcher_init(Some("./ip2region.xdb".to_owned()));
let main_now = Instant::now();
let (tx, mut rx) = mpsc::channel(10);
for i in 0..6 {
let tx = tx.clone();
tokio::spawn(async move {
let now = Instant::now();
let count = 10_000_000;
for _ in 0..count {
search_by_ip(rand::random::<u32>()).unwrap();
}
let message = format!(
"tokio spawn {i} over cost: {:?}, ave: {:?}",
now.elapsed(),
now.elapsed() / count
);
tx.send(message).await.unwrap();
});
}
drop(tx);
while let Some(message) = rx.recv().await {
println!("{}", message);
}
println!("总共耗时: {:?}", main_now.elapsed());
}
```
开始执行测试
```shell
$ RUST_LOG=debug cargo run -r
Compiling ip-test v0.1.0 (/home/gong/rust-work/ip-test)
Finished release [optimized] target(s) in 0.51s
Running `target/release/ip-test`
2022-12-24T04:05:32.876664Z DEBUG xdb::searcher: load xdb searcher file at ./ip2region.xdb
tokio spawn 4 over cost: 1.133448675s, ave: 113ns
tokio spawn 2 over cost: 1.133938619s, ave: 113ns
tokio spawn 1 over cost: 1.136872027s, ave: 113ns
tokio spawn 5 over cost: 1.173464286s, ave: 117ns
tokio spawn 0 over cost: 1.197527014s, ave: 119ns
tokio spawn 3 over cost: 1.26446099s, ave: 126ns
总共耗时: 1.264631935s
```
# `binding/rust`路径下面的结构说明
`xdb`
- 封装了`ip`到`region`的函数
- 里面包含单元测试和`benchmark`测试
`example`
- 包含了命令行可执行文件生成的源码程序
- 作为一个用于`rust`的开发集成例子
开始编译之后会生成如下
`target`
- 文件夹存放编译之后的文件以及编译产生的临时文件与缓存
`Cargo.lock`
- 固定`rust`第三方库的版本
编译生成的文件全部在`.gitignore`中有标识,不会被提交
# 编译程序
切换到 `ip2region/binding/rust` 路径,执行如下命令
```bash
$ cargo build -r
```
生成的二进制文件会在`./target/release/rust-example`位置
# 查询测试
切换到 `ip2region/binding/rust` 路径,执行如下命令
`help`输出如下
```shell
$ ./target/release/rust-example query --help
query test
Usage: rust-example query [OPTIONS]
Options:
--db <db> the xdb filepath, you can set this field like ../data/ip2region.xdb,if you dont set,if will detect xdb file on ../data/ip2region.xdb, ../../data/ip2region.xdb, ../../../data/ip2region.xdb if exists
-h, --help Print help information
```
执行测试,使用默认`data/ip2region.txt`
```shell
$ ./target/release/rust-example query --db=../../data/ip2region.xdb
ip2region xdb searcher test program, type `quit` or `Ctrl + c` to exit
ip2region>> 123123123
region: Ok("美国|0|0|0|0"), took: 4.94µs
ip2region>> 1.1.1.1
region: Ok("澳大利亚|0|0|0|0"), took: 2.057µs
ip2region>> 2.2.2.2
region: Ok("法国|0|0|0|橘子电信"), took: 4.294µs
ip2region>>
```
这边发现每次查询的消耗时间都超过`1µs`,和开头所说的纳秒级查询不一致啊,这个是由于`rust`的标准库封装的`use std::time::Instant`对
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
ip2region - 是一个离线IP地址定位库和IP定位数据管理框架,10微秒级别的查询效率,提供了众多主流编程语言的 xdb 数据生成和查询客户端实现。 支持亿级别的 IP 数据段行数,默认的 region 信息都固定了格式:国家|区域|省份|城市|ISP,缺省的地域信息默认是0。 region 信息支持完全自定义,例如:你可以在 region 中追加特定业务需求的数据,例如:GPS信息/国际统一地域信息编码/邮编等。也就是你完全可以使用 ip2region 来管理你自己的 IP 定位数据。
资源推荐
资源详情
资源评论
收起资源包目录
一个离线IP地址定位库和IP定位数据管理框架,10微秒级别的查询效率,提供了众多主流编程语言的 xdb数据生成和查询客户端实现 (154个子文件)
make.bat 231B
github-issue-287.bug 396B
xdb_searcher.c 15KB
xdb_searcher.c 11KB
ngx_http_ip2region_module.c 11KB
main.c 10KB
util_test.c 3KB
config 765B
rebar.config 395B
Maker.cs 9KB
SearcherTest.cs 2KB
Searcher.cs 2KB
Segment.cs 2KB
Util.cs 2KB
AbstractCacheStrategy.cs 2KB
Program.cs 2KB
Program.cs 1KB
UtilTest.cs 1KB
ContentCacheStrategy.cs 971B
CacheStrategyFactory.cs 929B
VectorIndexCacheStrategy.cs 847B
FileCacheStrategy.cs 635B
Util.cs 574B
ISearcher.cs 459B
CachePolicy.cs 341B
UtilTest.cs 285B
IndexPolicy.cs 255B
Usings.cs 29B
Usings.cs 29B
IP2Region.Net.csproj 2KB
IP2Region.Net.Test.csproj 1KB
IP2Region.Net.BenchMark.csproj 774B
IP2RegionMaker.Test.csproj 716B
IP2RegionMaker.csproj 239B
global_region.csv 84KB
dummy 0B
ip2region_worker.erl 6KB
xdb_benchmark.erl 2KB
ip2region_sup.erl 2KB
xdb.erl 1KB
ip2region_util.erl 758B
ip2region_app.erl 529B
xdb_test.erl 489B
github-issue-243.fix 10KB
github-issue-196.fix 3KB
github-issue-200.fix 2KB
.gitignore 6KB
.gitignore 1KB
.gitignore 340B
main.go 10KB
maker.go 9KB
main.go 6KB
searcher.go 6KB
editor.go 6KB
searcher.go 5KB
util.go 4KB
util.go 3KB
segment.go 2KB
util_test.go 2KB
util_test.go 2KB
index.go 588B
xdb_searcher.h 4KB
ngx_http_ip2region_module.h 493B
ip2region.hrl 622B
Maker.java 11KB
Searcher.java 9KB
SearchTest.java 8KB
Log.java 3KB
MakerTest.java 3KB
Segment.java 3KB
UtilTest.java 2KB
Util.java 2KB
Header.java 1KB
UtilTest.java 1KB
IndexPolicy.java 761B
index.js 5KB
bench.app.js 4KB
test.app.js 2KB
benchmark.js 1KB
function.test.js 1KB
.eslintrc.js 224B
package.json 813B
.nycrc.json 80B
.mocharc.json 60B
rebar.lock 280B
xdb_searcher.lua 8KB
bench_test.lua 5KB
bench_test.lua 5KB
search_test.lua 4KB
search_test.lua 4KB
util_test.lua 3KB
util_test.lua 3KB
Makefile 664B
Makefile 469B
Makefile 165B
Makefile 158B
LICENSE.md 12KB
ReadMe.md 11KB
ReadMe.md 7KB
ReadMe.md 7KB
共 154 条
- 1
- 2
资源评论
Java程序员-张凯
- 粉丝: 1w+
- 资源: 7361
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功