perf: name-first geo detection to avoid serial DNS in collection rename
DetectGeoWithServer was doing GeoIP-first (DNS lookup per node) then falling back to name regex. For a 148-node collection with rename enabled, this meant 148 serial DNS queries in the rename pass alone (28s on slow DNS). Reverse the priority: try name-based regex first (instant, no I/O), only fall back to GeoIP+DNS when the node name has no recognizable country keywords. Most proxy names already contain country/city info. Also add in-memory DNS cache in geoip.LookupHost so repeated lookups for the same hostname don't re-resolve. Collection preview with rename: 30s -> 3s.
This commit is contained in:
+27
-3
@@ -24,6 +24,9 @@ var (
|
||||
reader *maxminddb.Reader
|
||||
loaded bool
|
||||
mmdbPath string
|
||||
|
||||
dnsCacheMu sync.RWMutex
|
||||
dnsCache = make(map[string][]net.IP)
|
||||
)
|
||||
|
||||
// countryNameCN maps ISO country codes to Chinese names.
|
||||
@@ -193,14 +196,35 @@ func Lookup(ipStr string) *GeoResult {
|
||||
}
|
||||
|
||||
// LookupHost resolves a hostname to its first IP and then looks up geo info.
|
||||
// DNS results are cached in-memory to avoid repeated lookups for the same host.
|
||||
func LookupHost(host string) *GeoResult {
|
||||
// If it's already an IP, lookup directly
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
return Lookup(ip.String())
|
||||
}
|
||||
// Resolve domain
|
||||
ips, err := net.LookupIP(host)
|
||||
if err != nil || len(ips) == 0 {
|
||||
|
||||
// Check DNS cache first
|
||||
dnsCacheMu.RLock()
|
||||
ips, ok := dnsCache[host]
|
||||
dnsCacheMu.RUnlock()
|
||||
|
||||
if !ok {
|
||||
// Resolve domain and cache the result (including failures)
|
||||
resolved, err := net.LookupIP(host)
|
||||
if err != nil || len(resolved) == 0 {
|
||||
// Cache nil to avoid retrying failed lookups
|
||||
dnsCacheMu.Lock()
|
||||
dnsCache[host] = nil
|
||||
dnsCacheMu.Unlock()
|
||||
return nil
|
||||
}
|
||||
ips = resolved
|
||||
dnsCacheMu.Lock()
|
||||
dnsCache[host] = ips
|
||||
dnsCacheMu.Unlock()
|
||||
}
|
||||
|
||||
if len(ips) == 0 {
|
||||
return nil
|
||||
}
|
||||
return Lookup(ips[0].String())
|
||||
|
||||
@@ -164,10 +164,15 @@ func DetectGeo(name string) GeoInfo {
|
||||
return detectGeoFromName(name)
|
||||
}
|
||||
|
||||
// DetectGeoWithServer returns geographic info by looking up the proxy's
|
||||
// server address via GeoIP first, falling back to name-based detection.
|
||||
// DetectGeoWithServer returns geographic info by first trying name-based
|
||||
// regex matching (fast, no I/O), falling back to GeoIP lookup on the server
|
||||
// address only when the name doesn't contain recognizable geo keywords.
|
||||
func DetectGeoWithServer(name, server string) GeoInfo {
|
||||
// Try GeoIP lookup first
|
||||
// Try name-based detection first (fast, no I/O)
|
||||
if geo := detectGeoFromName(name); geo.CountryName != "" {
|
||||
return geo
|
||||
}
|
||||
// Fallback to GeoIP lookup (slow, involves DNS)
|
||||
if server != "" {
|
||||
host := server
|
||||
// Strip port if present
|
||||
@@ -184,8 +189,7 @@ func DetectGeoWithServer(name, server string) GeoInfo {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback to name-based detection
|
||||
return detectGeoFromName(name)
|
||||
return GeoInfo{}
|
||||
}
|
||||
|
||||
// detectGeoFromName does name-based regex matching for geo detection.
|
||||
|
||||
Reference in New Issue
Block a user