
两个月前我把一个对外服务切成了双栈接入上线一周就遇到一个诡异场景IPv4 用户的归属地判断基本靠谱城市级准确率能做到九成上下但只要是走 IPv6 进来的请求归属地经常整段跳变昨天还指向华东某市今天就变成华北某地偶尔还能给你来个跨境的离谱结果。第一反应是商用 IP 库没更新连夜翻了 whois、查了解析链路、对比了好几家数据源最后发现这根本不是某个库的数据质量问题而是 IPv4 和 IPv6 从地址分配结构、注册信息、测量手段到建库方式整条定位链路都存在系统性差异。这篇文章就把我排查过程中整理的差异完整讲一遍重点落在两块两类协议在定位数据模型和精度上的本质区别以及这些差异落到 CDN 调度、风控、区域合规等真实业务时该怎么调整策略。想给正在做双栈服务、IP 归属地查询或者依赖地理位置做业务决策的同行省点弯路。1. 先说清IP地理定位的原理它本质是段归属推断不是GPS1.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、/36IPv6 数据库按前缀组织常见粒度是 /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。我在几个项目里抽样统计过某商用库和我们自建数据的表现经验值如下不保证全行业一致但趋势非常典型维度IPv4IPv6国家/地区级覆盖率99.5% 以上98% 左右区域/省级定位可用率95% 左右80% 左右城市级准确率抽样70%~90%35%~60%数据更新周期日更为主周更/月更为主城市级字段缺失率5% 以内20% 以上最直观的感受就是IPv4 查城市基本能接受IPv6 查城市基本靠猜。这不是偏见是数据样本量决定的。看 IPv6 流量占比逐年上来之后这个差距会慢慢收窄但短期内别指望一夜之间追平。3.4 GeofeedRFC 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 单地址或 /2424小时地址基本固定段与位置绑定稳定IPv6 完整地址5~15分钟临时地址频繁更换长缓存等于垃圾数据IPv6 /64 前缀24~48小时前缀长期不变但要按运营商划分逻辑判断IPv6 /32-/36 运营商前缀7天以上大前缀位置变化慢定期随 Geofeed 刷新这套策略跑下来IPv6 的定位缓存命中率虽然还是不如 IPv4但比按完整地址缓存时好了一个量级。核心思路就一句话缓存对象越接近运营商的划分单元数据越稳定。5. 业务场景实测CDN调度、风控和区域合规的取舍5.1 CDN就近接入IPv6流量被调度歪是常态做内容分发最依赖 IP 归属。DNS 调度除了看递归解析器的位置还能靠 ECSEDNS 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、多源校验和探针反馈慢慢补精度。这个过程不快但比在错误数据上做精细化决策要可靠得多。