利用 ip2region
进行 IP 地址定位
import ("fmt""log""github.com/lionsoul2014/ip2region/binding/golang/xdb"
)func main() {ip := "213.118.179.98"dbPath := ".\\cmd\\ip\\ip2region.xdb"// 1、初始化查询器//searcher, err := searcherByFile(dbPath)//searcher, err := searcherByVectorIndex(dbPath)searcher, err := searcherByBuffer(dbPath)// 2、执行查询resp, err := searcher.SearchByStr(ip)if err != nil {log.Fatal("failed to search ip", err)}fmt.Printf("IP: %s, Location: %s\n", ip, resp)
}
方式1:完全基于文件的查询
func searcherByFile(dbPath string) (*xdb.Searcher, error) {searcher, err := xdb.NewWithFileOnly(dbPath)if err != nil {log.Println("Failed to load ip2region database", err)return nil, err}return searcher, nil
}
特点
- 内存占用少:这种方法不会将数据库文件加载到内存,而是在查询时直接从磁盘读取文件,所以内存占用非常少。
- 查询速度较慢:由于每次查询都需要进行磁盘 I/O 操作,所以查询速度相对较慢,尤其是在高并发场景下,频繁的磁盘 I/O 可能会成为性能瓶颈。
- 并发使用限制:和
searcherByVectorIndex
方法一样,并发使用时每个 goroutine 都要创建独立的searcher
对象。
方式2:缓存 VectorIndex 索引
func searcherByVectorIndex(dbPath string) (*xdb.Searcher, error) {vIndex, err := xdb.LoadVectorIndexFromFile("ip2region.xdb")if err != nil {log.Println("Failed to load vector index", err)return nil, err}searcher, err := xdb.NewWithVectorIndex(dbPath, vIndex)if err != nil {log.Println("Failed to create searcher with vector index", err)return nil, err}return searcher, nil
}
特点
- 性能优化:借助加载
VectorIndex
缓存,查询时能减少磁盘 I/O 操作。VectorIndex
是一种索引结构,可快速定位到可能包含目标 IP 的数据块,从而加快查询速度。 - 内存占用适中:相较于将整个数据库加载到内存,仅加载
VectorIndex
缓存占用的内存较少,不过比直接从文件查询时占用的内存多。 - 并发使用限制:并发使用时,每个 goroutine 都要创建独立的
searcher
对象,因为searcher
并非线程安全的。
方式3:缓存整个数据库
func searcherByBuffer(dbPath string) (*xdb.Searcher, error) {buff, err := xdb.LoadContentFromFile(dbPath)if err != nil {log.Println("Failed to load ip2region database", err)return nil, err}searcher, err := xdb.NewWithBuffer(buff)if err != nil {fmt.Println("failed to create searcher with content", err)return nil, err}return searcher, nil
}
特点
- 查询速度最快:该方法把整个数据库文件加载到内存中,查询时无需进行磁盘 I/O 操作,直接在内存中进行查找,因此查询速度最快。
- 内存占用大:需要将整个数据库文件加载到内存,所以内存占用较大。如果数据库文件较大,可能会对系统内存造成压力。
- 并发安全:使用整个数据库缓存创建的
searcher
对象可以安全地用于并发,多个 goroutine 可以共享同一个searcher
对象,无需为每个 goroutine 创建独立的searcher
对象。
总结
- 若系统内存有限,对查询速度要求不高,可选用
searcherByFile
方法。 - 若希望在内存占用和查询速度之间取得平衡,可采用
searcherByVectorIndex
方法。 - 若系统内存充足,对查询速度要求极高,且有高并发查询需求,可使用
searcherByBuffer
方法。