Closed eycorsican closed 6 years ago
那iOS的文件读取有什么技巧吗?需不需要对IP查询做缓存?
我的想法是对路由中每一个"ip":[]
单独做一个文件,使用某种特殊的格式。配置文件中可以设置当条目多于一定数量时,将当前的"ip":[]
写入文件。这样配置的格式不用大改。
没有什么特别技巧,我的实现是把 geoip 规则看作跟 ip 规则完全不同的另一个类型,在 Router 中为 geoip 规则加上了它的 Matcher:
func NewGeoIPMatcher(geoipCodes []string) *GeoIPMatcher {
return &GeoIPMatcher{
geoipCodes: geoipCodes,
}
}
func (v *GeoIPMatcher) Apply(ctx context.Context) bool {
ips := make([]net.IP, 0, 4)
if resolver, ok := proxy.ResolvedIPsFromContext(ctx); ok {
resolvedIPs := resolver.Resolve()
for _, rip := range resolvedIPs {
if !rip.Family().IsIPv4() {
continue
}
ips = append(ips, rip.IP())
}
}
dest, ok := proxy.TargetFromContext(ctx)
if ok && dest.Address.Family().IsIPv4() {
ips = append(ips, dest.Address.IP())
}
for _, ip := range ips {
code, err := lookupGeoIP(ip)
if err != nil {
return false
}
for _, c := range v.geoipCodes {
if code == c {
return true
}
}
}
return false
}
你说的把 ip 规则转化为某种读取格式这个方法可能会比较优雅。
我只考虑到客户端,觉得对这个做查询缓存没必要,如果考虑上服务端的话情况可能不一样。
我又想了一下,还有一种方法。
MaxMind 的数据库,IPv4有303746条数据,IPv6有84732条数据,用最朴素的方法存,大约需要2.8MB的空间(303746 5 + 84732 17),这是上限。而你上面给出的geoip列表,IPv4共有55060条数据,IPv6没统计,按空间1:1来算,IPv4+IPv6大约需要500kB的空间。假如用户再多指定一点,1MB的空间应该可以支撑所有的IP规则。在这种情况应该不用写入磁盘了吧。
算法方面我有办法使用上面数据模型进行查询,不会带来性能上的损失。
期待。
看起来像是把磁盘搜索变成内存搜索,不放磁盘上搜索是因为算法方面是要依赖 Go 的特性吗?
基本思路是这样的:c73e899f54f0e4d6d4c2982265efc73c2e4c9b73
配置中新增了一个 geoip 项,需要多个release才能切换到新的配置项。但从API调用的话,你现在就可以测试了。
放内存的原因主要是空间占用足够小。Golang的map有很大的overhead,而新的算法只依赖于朴素的数组,可以有效地减少内存的使用。
新的算法要求传入的GeoIP按country code分类,存储的时候同一country code的IP列表只会存一份,即在多个规则使用同一个GeoIP,也不会重复占用空间。
Why not use mmap() to map the file on disk to the physical memory? Because it is demand paging, this is a nice way to save memory.
http://man7.org/linux/man-pages/man2/mmap.2.html https://godoc.org/golang.org/x/exp/mmap
@GreaterFire It is hard to tell whether iOS considers memory from mmap() as residence memory.
现在 geoip 是启动时把记录解析为 ip 规则,全部加载到内存中,这样做会耗费较多内存,特别是有好多 geoip 规则的情况,比如下面这个配置:
MaxMind 的 geoip 数据库提供了一种二进制数据文件格式:http://maxmind.github.io/MaxMind-DB/ ,用这样的方式去读取性能上对于客户端来说可以满足,也几乎不会耗费内存,对于移动端来说还是很有意义的,golang 也有一些开源的实现,比如这个:https://github.com/oschwald/maxminddb-golang