两个月前我把一个对外服务切成了双栈接入,上线一周就遇到一个诡异场景:IPv4 用户的归属地判断基本靠谱,城市级准确率能做到九成上下;但只要是走 IPv6 进来的请求,归属地经常整段跳变,昨天还指向华东某市,今天就变成华北某地,偶尔还能给你来个跨境的离谱结果。第一反应是商用 IP 库没更新,连夜翻了 whois、查了解析链路、对比了好几家数据源,最后发现这根本不是某个库的数据质量问题,而是 IPv4 和 IPv6 从地址分配结构、注册信息、测量手段到建库方式,整条定位链路都存在系统性差异。这篇文章就把我排查过程中整理的差异完整讲一遍,重点落在两块:两类协议在定位数据模型和精度上的本质区别,以及这些差异落到 CDN 调度、风控、区域合规等真实业务时该怎么调整策略。想给正在做双栈服务、IP 归属地查询或者依赖地理位置做业务决策的同行省点弯路。
1. 先说清IP地理定位的原理:它本质是"段归属"推断,不是GPS
1.1 定位表是怎么被拼出来的
网上聊 IP 定位,很多人以为拿到一个 IP 就能查到一个精确坐标,好像有个云端神仙数据库。其实不是。IP 地理定位从原理上讲是对"某个地址段被部署在哪个网络出口"的推断,它由几类数据源拼装而成:注册信息(whois 里登记的归属和联系地址)、BGP 路由表(看这个段在哪个自治系统里被宣告)、主动测量(从分布各地的探针去探测目标地址,靠往返时延估算距离)、以及终端反馈情报(比如移动端拿到的 WiFi BSSID、GPS 坐标回传信息)。这些源经过清洗和交叉校验,最终压缩成一张"地址段→位置"的映射表。
查询时就是把用户 IP 换算成段,再查表。所以精度从根上取决于"段"切得细不细、表更新得勤不勤。理解了这一点,才能明白为什么 IPv4 和 IPv6 的定位结果会差这么多——两个协议在这张表的原料和构建方式上,从出生起就不在一个水平线。
1.2 IPv4的"挤"反而喂出了更细的数据
IPv4 只有 32 位,满打满算 42.9 亿个地址,去掉保留段、内网段,能被公网实际使用的远比理论值少。稀缺带来的结果是:地址在运营商、企业、IDC 之间被反复交易转手,whois 里的登记信息经常和实际部署对不上,出现"注册地在 A、实际用在 B"的情况。商业 IP 库为了修正这种误差,被迫投入大量探测和终端反馈,把每个 /24 甚至更小的段都长期打磨过,这反而沉淀出了一套精细的数据资产。
也正因为稀缺,运营商和企业规划地址时非常仔细,一个 /24 往往就对应一个机房或一个园区,数据天然容易做细。举个我实际抽样验证的例子,华东某运营商的某个 /24 段,连续三个月归属地都没变过,网段与地理位置的绑定非常稳定。用个生活化比喻:IPv4 是城市老小区,每个门牌都有历史登记,虽然偶尔错登,但可考据的东西多。
1.3 IPv6的"宽松"带来了粗颗粒的代价
IPv6 是 128 位,约等于取之不竭。分配模式是层级式的:全球顶级地址空间交给各地区的地址注册管理机构,再往下分给运营商和大型机构,运营商再把 /48、/56 分给最终用户。因为地址不稀缺,几乎没有像 IPv4 那样的交易转让市场,注册链在结构上反而很完整——但注意,完整不等于精细。
一个运营商拿到 /32 甚至更短的前缀,可能横跨全国甚至覆盖多个地区,整个前缀下面的用户位置五花八门。运营商没有激励去细分地理位置标注,因为没这个必要、也没这个人力。最后的结果就是:IPv6 的 whois 很干净,但里面基本都是国家/地区级别的粗信息,城市一级大量缺失。比喻一下:IPv4 是挤在公寓楼里的住户,每户要登记门牌;IPv6 是一片开发商卖的别墅大盘,合同上只写了城市,精确到楼栋门牌?不存在的。
2. 归因粒度彻底变了:IPv4按"点"查,IPv6只能按"段"猜
2.1 IPv4的映射单元通常是 /24
绝大多数 IPv4 数据库的构建单元是 /24。一个 /24 是 256 个地址,在现网里往往归属于同一个运营商接入点或者同一家企业的出口。查询时把 IP 归到 /24,再查这一段的归属地,城市级准确率在数据积累充分的地区能做到 80% 以上。反过来看 whois 记录也能感受到这种粒度差异,一条典型的 IPv4 登记长这样:
inetnum: 203.0.113.0 - 203.0.113.255 netname: EXAMPLE-NET-XX country: XX登记信息往往只给了国家和网络名,城市位置要靠探测数据去补。但因为 /24 这个粒度足够小,一旦补上,精度就非常稳定。
2.2 IPv6的映射单元动辄 /32、/36
IPv6 数据库按前缀组织,常见粒度是 /32、/36、/40,到终端侧才是 /64。这里要特别注意一个概念:/64 是"子网",不是"用户"。你拿一个用户的 IPv6 地址去查,数据库大概率只能告诉你这个地址落在某个 /32 里,而这个 /32 覆盖的可能是某个运营商的全国网。
极端一点说,同一个 /32 下的两个用户,一个在南方沿海,一个在北方内陆,数据库对它们返回的往往是同一个国家级结果。这不是库做得差,而是信息源头就没有更细的标注。跟我一起做测试的同行经常吐槽,IPv6 归属地查询的城市级可用率只有 IPv4 的一半左右,这句话真不夸张。整个 IPv6 的定位逻辑从"查点"变成了"查段",段越大,猜测成分越多。
2.3 PI地址和"注册地址≠部署地址"的老坑,在IPv6里更常见
IPv4 时代就有"注册地不等于实际部署地"的问题。IPv6 因为地址管够,很多企业会直接申请独立前缀(PI),自己管理、多宿主导入。PI 的 whois 联系地址填的往往是公司注册办公室,而设备可能部署在别处的机房;一家公司一个 /48,又可能同时用在总部、分公司、多个机房。
遇到这种段,数据库只能按公司登记地去标,真实位置可能差出上千公里。我在项目里专门统计过,IPv6 段里这类"公司登记地"误标的比例明显高于 IPv4 的常规段。所以看到 IPv6 返回一个城市级结果时,先别急着信,尤其是企业级前缀——很可能这个"城市"只是公司法务在注册文件里随手填的一个地址。
3. 数据源和解析链路的代差:whois、探测、商业库各有各的痛
3.1 whois注册信息:IPv6更规范,但字段更"秃"
whois 是 IP 定位的地基。IPv4 的 inetnum 记录因为历史分配混乱,经常出现断档、重叠、转让备注;IPv6 的 inet6num 记录则是按层级前缀写的,结构规范很多。但规范不等于有用。翻一条典型的 IPv6 记录:
inet6num: 2001:db8:1000::/36 netname: EXAMPLE-ISP-CUST01 country: XX能看到国家代码,但城市、机房位置、联系地理信息几乎没有。IPv4 的老记录好歹很多是当年人工登记的,带着城市名和机房描述;IPv6 这一代是批量生成的,人工细节反而更少。这就形成了一种反差:IPv6 的注册链比 IPv4 更完整,但对定位有用的信息密度却更低。
3.2 主动探测的测量面:IPv6的探针密度差太远
时延测量是 IP 定位的另一个重要手段:从多个已知位置的探针同时探测目标地址,根据往返时延推算距离圈,再用交汇区域估算位置。这套方法对 IPv4 很成熟,全球探针节点密度高、分布均匀,反馈数据能被持续训练。IPv6 的探针数量少了不只一个数量级,而且很多 IPv6 路由在部分网络里还没做最优路径优化,时延噪声明显更大。
还有一层更麻烦的:大量 IPv6 流量会经过地址翻译或封装机制(比如运营商的过渡技术),你从外部测量看到的"最后一跳"并不是用户真实接入点,时延和物理位置的关系就被打断了。实际做 IPv6 主动测量时,很多情况下得出的结论只能是"这个段可能在某某大区",再往下就无能为力。所以 IPv6 定位在数据源层面就缺了一条腿。
3.3 商业IP库为什么在IPv6上"厚此薄彼"
商业 IP 库是绝大多数业务直接依赖的入口。说句公道话,库商不是不想做好 IPv6,而是投入产出比太难看:IPv6 流量占比还不够高,愿意为 IPv6 定位精度付费的更少,所以商业库在 IPv6 上的探测密度、更新频率、纠错反馈闭环都明显弱于 IPv4。
我在几个项目里抽样统计过某商用库和我们自建数据的表现,经验值如下(不保证全行业一致,但趋势非常典型):
| 维度 | IPv4 | IPv6 |
|---|---|---|
| 国家/地区级覆盖率 | 99.5% 以上 | 98% 左右 |
| 区域/省级定位可用率 | 95% 左右 | 80% 左右 |
| 城市级准确率(抽样) | 70%~90% | 35%~60% |
| 数据更新周期 | 日更为主 | 周更/月更为主 |
| 城市级字段缺失率 | 5% 以内 | 20% 以上 |
最直观的感受就是:IPv4 查城市基本能接受,IPv6 查城市基本靠猜。这不是偏见,是数据样本量决定的。看 IPv6 流量占比逐年上来之后,这个差距会慢慢收窄,但短期内别指望一夜之间追平。
3.4 Geofeed(RFC 8805)是目前最靠谱的补课方式
好消息是行业已经出了一个标准解法:Geofeed,定义在 RFC 8805 里。简单说,就是让运营商把自己名下前缀对应的地理位置以 CSV 形式主动发布,消费端定时拉取、覆盖库里的旧猜测。这是一个"源头填报"机制,从根上把"信息缺失"变成"主动申报"。
格式非常朴素,一行 CSV 就搞定:
2001:db8:1000::/36,XX,XX,XX,,12.34,56.78字段依次是前缀、国家代码、省级、城市、邮编、纬度、经度。我们这边把主要运营商已经发布的 Geofeed 全部接了,凡是走 Geofeed 的 IPv6 段,城市级准确率能从不到 50% 拉到 75% 以上;没发布 Geofeed 的段,只能继续靠库里那些陈年数据猜。这里也真心建议:如果你手头有独立前缀,去把 RFC 8805 读一遍,发布一版 Geofeed;如果你是使用方,去订阅你能找到的所有 Geofeed。这是目前性价比最高的 IPv6 定位补全手段。
4. 动态IPv6地址与移动性:稳定性被"隐私扩展"搅乱了
4.1 SLAAC临时地址(RFC 4941)干掉的是缓存和身份
IPv6 的大坑之一,是地址默认会自己变。标准的无状态地址自动配置(SLAAC)允许主机根据路由通告里的 /64 前缀自己生成接口标识部分;而 RFC 4941 的隐私扩展规定,主机要周期性生成随机临时地址,几小时到一天就换一个,用于对外发起连接。
这个机制本来是为了防止通过 MAC 追踪用户,但对依赖"IP→位置"缓存的系统简直是灾难。同一台设备,今天的请求来自一个临时地址 A,明天就变成临时地址 B。如果按完整地址缓存定位结果,缓存命中率会掉得很惨;更麻烦的是,风控系统如果认定"一个地址一个用户",就会发现同一前缀下一堆不同地址,误判成用户量异常暴增。
好消息是对定位本身影响不大——临时地址只是接口标识在变,/64 前缀是稳定的。所以对策也很明确:IPv6 的定位和缓存一律按前缀粒度做,不要按完整地址做。
4.2 双栈环境下,同一个用户的两个地址可能指向两个"位置"
现在大量网络是 IPv4/IPv6 双栈,同一个终端的两个协议族流量走的路径完全可能不一样。最典型的是运营商采用集中式地址翻译或过渡策略:IPv6 流量走原生接入链路,IPv4 流量却汇总到少数集中出口节点再出去。结果就是:同一台设备,IPv4 查到的归属地是集中出口所在的城市,IPv6 查到的归属地反而是用户真实所在的城市,两个结果能差出上千公里。反过来的情况也有。
这就是双栈业务里最容易被忽视的"定位打架"问题。遇到这种不一致,不要盲目信任某一个协议的结果,应该设置一致性判定:如果 IPv4 和 IPv6 返回的归属在大区级别都冲突,就把置信度降级到区域级甚至国家级继续使用。我线上遇到过真实案例,某个支付类服务的风控因为没做这层判定,把一批正常双栈用户全拦了,误杀率高得吓人。
4.3 缓存策略要按协议分开定
因为稳定性差异,缓存策略不能一刀切。我目前用的规则是这样的:
| 缓存对象 | 建议TTL | 理由 |
|---|---|---|
| IPv4 单地址或 /24 | 24小时 | 地址基本固定,段与位置绑定稳定 |
| IPv6 完整地址 | 5~15分钟 | 临时地址频繁更换,长缓存等于垃圾数据 |
| IPv6 /64 前缀 | 24~48小时 | 前缀长期不变,但要按运营商划分逻辑判断 |
| IPv6 /32-/36 运营商前缀 | 7天以上 | 大前缀位置变化慢,定期随 Geofeed 刷新 |
这套策略跑下来,IPv6 的定位缓存命中率虽然还是不如 IPv4,但比按完整地址缓存时好了一个量级。核心思路就一句话:缓存对象越接近"运营商的划分单元",数据越稳定。
5. 业务场景实测:CDN调度、风控和区域合规的取舍
5.1 CDN就近接入:IPv6流量被"调度歪"是常态
做内容分发最依赖 IP 归属。DNS 调度除了看递归解析器的位置,还能靠 ECS(EDNS Client Subnet)把客户端真实子网传给权威服务器,从而精确定向。ECS 在 IPv4 场景已经很普及,但在 IPv6 场景,很多递归解析器要么不支持,要么不透传客户子网,导致调度只能退回到"按递归器位置猜"。
递归器离用户往往不近,特别是运营商集中部署递归 DNS 的环境。实测下来,同一地区双栈用户走 IPv6 解析到的边缘节点,比走 IPv4 平均多了 20~40ms 的往返时延,跨省调度也比比皆是。所以我给做分发业务的建议是:IPv6 调度精度没补齐之前,双栈用户优先走 IPv4 接入;同时推动递归侧开启 ECSv6,把边缘覆盖逐步做起来。别一上来就把 IPv6 流量全量导入,否则用户感知到的"慢"会算在你自己头上。
5.2 风控和反欺诈:不要拿IPv4的经验硬套IPv6
风控里 IP 归属地主要用来做一致性校验,比如支付卡所在地、注册地、IP 归属地三者要吻合。IPv4 城市级判定勉强够用,IPv6 城市级定位不准的前提下,直接用同一套阈值,结果就是大量真实用户被误杀,或者反过来被绕过。
我的做法有两个调整:第一,IPv6 的身份维度从前缀走,用 /48 或 /64 做长期稳定标识,不要去解析每一条临时地址;第二,把城市级校验对 IPv6 放宽一级,改到区域级,宁可降低一点区分度,也不让误杀率失控。另外特别提醒一句:同一 /64 下短时间内出现多个不同 IPv6 地址,在启用了隐私扩展的环境里是绝对正常的,千万别当成"共享出口、多用户聚集"的信号——这是我见过最普遍的误判。
5.3 区域合规与访问控制:宁可保守,也别放错区域
如果一个业务对访问区域有硬性要求,比如有内容授权范围限制,或者需要按地区提供差异化服务,那 IPv6 定位的国家级准确率其实够用,98% 以上能判对。但边界情况还是要警惕:跨境的网络段、靠近区域边界的用户,偶尔会被标串;企业级 PI 前缀注册地在 A、部署在 B 的情况也会造成误判。
这类场景我的原则是:访问控制的默认动作是拒绝,只对经过人工复核的高置信度前缀放行;金融交易、登录授权这类高风险操作,不仅要查 IP 归属,还要叠加设备、行为、会话等多维验证,别把宝都押在一个定位字段上。用一个词概括:宁可错杀边缘,不可放错大门。区域的代价远比误伤的代价要小。
6. 我的调优清单和几个容易翻车的地方
6.1 多库交叉校验,别迷信单一IP库
我现在的查询链路是聚合多家数据源:至少两家商业库加自建 Geofeed 叠加层,再加 whois 解析结果。每家返回的位置和置信度拿出来投票:三票一致才采信城市级;不一致的,自动退到区域级;连区域都冲突的,退到国家级并打上低置信度标记。
def resolve_location(ip, sources, geofeed_map): results = [] for src in sources: loc = src.lookup(ip) if loc and loc.confidence >= 0.5: results.append(loc) gf = geofeed_map.match_prefix(ip) if gf: results.append(gf) if not results: return None, 0 country_majority = max_count(results, "country") region_agree = all_regions_same(results) city_agree = all_cities_same(results) if city_agree and len(results) >= 3: return city_result, 0.8 if region_agree: return region_result, 0.65 return country_majority, 0.5这套逻辑不复杂,但能把单库抽风造成的影响压到最低。线上跑了大半年,效果明显,至少没再出现过跨境级别的离谱错误。
6.2 Geofeed要订阅,更要主动推广
使用方要做的:把能拿到的 Geofeed 源都订阅下来,最好每周拉一次,存成前缀叠加表,查询时优先查这张表。运营方要做的:去把 RFC 8805 读一遍,给自己名下前缀发布一版 Geofeed,哪怕是国家级都能帮行业少踩很多坑。
我一直觉得,IPv6 定位能不能变好,不在于库商,而在于源头的运营商愿不愿意把"已知的位置信息"吐出来。Geofeed 机制的价值就在这——它让位置信息从"猜"变成"报",这是本质区别。
6.3 置信度和降级策略要落在代码里
别在代码里默认"查到城市就能用"。我给每个定位结果都带 confidence 字段,业务侧按场景设阈值:展示类业务城市置信度 0.5 就能用;调度类要求 0.7 以上;风控一致性校验只接受 0.8 以上的城市结果,其余全降级。阈值要随数据源质量动态调,别写死。
配合这条的还有一条经验:把"降级路径"提前设计好。国家、区域、城市三级都有兜底表,一旦城市级数据不可靠,系统能立刻从上一级取结果,而不是抛异常让业务直接断掉。
6.4 避坑清单(每一条都是真金白银换的)
- 不要对 IPv6 完整地址做超过 15 分钟的缓存,隐私扩展会让缓存快速失效变垃圾。
- 不要把 IPv6 whois 里的联系地址当成部署位置,PI 前缀尤其严重。
- 不要用 IPv6 的接口标识部分做设备指纹,那是会变的东西。
- 不要忽略过渡技术对 IPv4 定位的污染,集中出口会让 IPv4 位置指向城市 A 而用户其实在城市 B。
- 不要在 IPv6 流量比例不高时,把风控规则直接从 IPv4 平移过去,先灰度、再放量。
- 不要只依赖一家商业库,多源交叉才是双栈时代的及格线。
做 IP 地理定位这些年,最大的体会是:位置永远是概率推断,不是确定性事实,IPv6 只是把这个真相暴露得更明显。如果你现在才开始接 IPv6 定位,我的建议是先接受粗的,再想办法变细——先用区域级结果把业务跑通,再通过 Geofeed、多源校验和探针反馈慢慢补精度。这个过程不快,但比在错误数据上做精细化决策要可靠得多。