2025-10-21 13:31:01 +08:00

200 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ip2region xdb golang 查询客户端实现
# 使用方式
### package 获取
```bash
go get github.com/lionsoul2014/ip2region/binding/golang
```
### 关于查询 API
定位信息查询 API 原型为:
```golang
SearchByStr(string) (string, error)
Search([]byte) (string, error)
```
查询出错则 error 会包含具体的错误信息,查询成功会返回字符串的 `region` 信息,如果指定的 IP 查询不到则会返回空字符串 `""`
### 关于 IPv4 / IPv6
该 xdb 查询客户端实现同时支持对 IPv4 和 IPv6 的查询,使用方式如下:
```golang
// 如果是 IPv4: 设置 xdb 路径为 v4 的 xdb 文件IP版本指定为 xdb.IPv4
dbPath := "../../data/ip2region_v4.xdb" // 或者你的 ipv4 xdb 的路径
version := xdb.IPv4
// 如果是 IPv6: 设置 xdb 路径为 v6 的 xdb 文件IP版本指定为 xdb.IPv6
dbPath = "../../data/ip2region_v6.xdb" // 或者你的 ipv6 xdb 路径
version = xdb.IPv6
// dbPath 指定的 xdb 的 IP 版本必须和 version 指定的一致,不然查询执行的时候会报错
// 备注:以下演示直接使用 dbPath 和 version 变量
```
### 文件验证
建议您主动去验证 xdb 文件的适用性,因为后期的一些新功能可能会导致目前的 Searcher 版本无法适用你使用的 xdb 文件,验证可以避免运行过程中的一些不可预测的错误。
你不需要每次都去验证,例如在服务启动的时候,或者手动调用命令验证确认版本匹配即可,不要在每次创建的 Searcher 的时候运行验证,这样会影响查询的响应速度,尤其是高并发的使用场景。
```golang
err := xdb.VerifyFromFile(dbPath)
if err != nil {
// err 包含的验证的错误
return fmt.Errorf("xdb file verify: %w", err)
}
// 当前使用的 Searcher 可以安全的用于对 dbPath 指向的 xdb 的查询操作
```
### 完全基于文件的查询
```golang
import (
"fmt"
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
"time"
)
func main() {
// 通过 version 和 dbPath 创建完全基于文件的查询对象
searcher, err := xdb.NewWithFileOnly(version, dbPath)
if err != nil {
fmt.Printf("failed to create searcher: %s\n", err.Error())
return
}
defer searcher.Close()
// 定位信息查询IPv4 或者 IPv6 的地址都支持
var ip = "1.2.3.4" // IPv4
// ip = "2001:4:112:ffff:ffff:ffff:ffff:ffff" // IPv6
var tStart = time.Now()
region, err := searcher.SearchByStr(ip)
if err != nil {
fmt.Printf("failed to SearchIP(%s): %s\n", ip, err)
return
}
// IPv4 或者 IPv6 的定位信息
fmt.Printf("{region: %s, took: %s}\n", region, time.Since(tStart))
// 备注:并发使用,每个 goroutine 需要创建一个独立的 searcher 对象。
}
```
### 缓存 `VectorIndex` 索引
可以预先加载 `vectorIndex` 缓存,然后做成全局变量,每次创建 searcher 的时候使用全局的 `vectorIndex`,可以减少一次固定的 IO 操作从而加速查询,减少系统 io 压力。
```golang
// 1、从 dbPath 加载 VectorIndex 缓存,把下述 vIndex 变量全局到内存里面。
vIndex, err := xdb.LoadVectorIndexFromFile(dbPath)
if err != nil {
fmt.Printf("failed to load vector index from `%s`: %s\n", dbPath, err)
return
}
// 2、用全局的 vIndex 创建带 VectorIndex 缓存的查询对象。
searcher, err := xdb.NewWithVectorIndex(version, dbPath, vIndex)
if err != nil {
fmt.Printf("failed to create searcher with vector index: %s\n", err)
return
}
// 备注:并发使用,全部 goroutine 共享全局的只读 vIndex 缓存,每个 goroutine 创建一个独立的 searcher 对象
```
### 缓存整个 `xdb` 数据
可以预先加载整个 ip2region.xdb 到内存,完全基于内存查询,类似于之前的 memory search 查询。
```golang
// 1、从 dbPath 加载整个 xdb 到内存
cBuff, err := xdb.LoadContentFromFile(dbPath)
if err != nil {
fmt.Printf("failed to load content from `%s`: %s\n", dbPath, err)
return
}
// 2、用全局的 cBuff 创建完全基于内存的查询对象。
searcher, err := xdb.NewWithBuffer(version, cBuff)
if err != nil {
fmt.Printf("failed to create searcher with content: %s\n", err)
return
}
// 备注:并发使用,用整个 xdb 缓存创建的 searcher 对象可以安全用于并发。
```
# 编译测试程序
通过如下方式编译得到 xdb_searcher 可执行程序:
```bash
# 切换到 golang binding 根目录
make
```
# 查询测试
通过 `xdb_searcher search` 命令来测试 xdb 的查询:
```bash
➜ golang git:(fr_xdb_ipv6) ✗ ./xdb_searcher search
./xdb_searcher search [command options]
options:
--db string ip2region binary xdb file path
--cache-policy string cache policy: file/vectorIndex/content
```
例如:使用默认的 data/ip2region_v4.xdb 进行 IPv4 的查询测试
```bash
➜ golang git:(master) ./xdb_searcher search --db=../../data/ip2region_v4.xdb
ip2region xdb searcher test program
source xdb: ../../data/ip2region_v4.xdb (IPv4, vectorIndex)
type 'quit' to exit
ip2region>> 219.133.111.87
{region: 中国|广东省|深圳市|电信, ioCount: 2, took: 19.005µs}
ip2region>>
```
例如:使用默认的 data/ip2region_v6.xdb 进行 IPv6 的查询:
```bash
➜ golang git:(master) ✗ ./xdb_searcher search --db=../../data/ip2region_v6.xdb
ip2region xdb searcher test program
source xdb: ../../data/ip2region_v6.xdb (IPv6, vectorIndex)
type 'quit' to exit
ip2region>> ::
{region: , ioCount: 1, took: 42.157µs}
ip2region>> 240e:87c:892:ffff:ffff:ffff:ffff:ffff
{region: 中国|北京市|北京市|专线用户, ioCount: 10, took: 88.769µs}
```
输入对应版本的 ip 地址进行查询即可,输入 quit 退出测试程序。可以设置 `cache-policy` 为 file/vectorIndex/content 来测试不同的查询缓存机制。
# bench 测试
通过 `xdb_searcher bench` 命令来进行自动 bench 测试,一方面确保程序和 `xdb` 文件都没有错误,另一方面通过大量的查询得到平均查询性能:
```bash
➜ golang git:(fr_xdb_ipv6) ./xdb_searcher bench
./xdb_searcher bench [command options]
options:
--db string ip2region binary xdb file path
--src string source ip text file path
--cache-policy string cache policy: file/vectorIndex/content
```
例如:通过 data/ip2region_v4.xdb 和 data/ipv4_source.txt 进行 ipv4 的 bench 测试:
```bash
./xdb_searcher bench --db=../../data/ip2region_v4.xdb --src=../../data/ipv4_source.txt
```
例如:通过 data/ip2region_v6.xdb 和 data/ipv6_source.txt 进行 ipv6 的 bench 测试:
```bash
./xdb_searcher bench --db=../../data/ip2region_v6.xdb --src=../../data/ipv6_source.txt
```
可以设置 `cache-policy` 参数来分别测试 file/vectorIndex/content 不同缓存实现机制的效率。
*请注意 bench 使用的 src 文件需要是生成对应的 xdb 文件的相同的源文件*
bench 程序会逐行读取 `src` 指定的源IP文件然后每个 IP 段选取 5 个固定位置的 IP 进行测试,以确保查询的 region 信息和原始的 region 信息是相同。测试途中没有调试信息的输出,有错误会打印错误信息并且终止运行,所以看到 `Bench finished` 就表示 bench 成功了cost 是表示每次查询操作的平均时间(ns)。