1. 异地出口容灾到底在防什么先把场景说清楚。所谓“职场数据中心异地出口容灾”指的是一个企业有两个数据中心主数据中心和灾备数据中心各自有独立的互联网出口链路。正常情况下所有业务流量从主数据中心的出口出去灾备中心处于待命状态。一旦主数据中心的出口链路整体故障——注意是出口设备或出口链路整体不可用而不是单条线路抖动——流量需要快速切换到灾备中心的出口让业务继续访问外部网络。这个需求听起来简单做起来麻烦。麻烦的地方在于流量切换过去之后回程流量怎么回来如果回程流量走了另一条路径或者被运营商丢掉了那用户就会遇到“能发出去、收不回来”的情况表现为访问超时、连接建立失败。很多团队第一次做异地出口容灾切换动作本身很顺利BGP邻居也起来了路由也宣告了但业务就是不通。排查半天发现是回程路径的问题。H3C的IP上一跳保持技术就是专门解决这个回程路径问题的。它的核心思路是当流量从灾备中心出口出去时让回程流量仍然回到灾备中心的出口设备而不是绕回主数据中心。这样整个转发路径就是对称的不会出现非对称路由导致的丢包。我先把结论放在这里异地出口容灾的难点不在“切过去”而在“回得来”。IP上一跳保持解决的就是“回得来”的问题。下面我会把这个技术的原理、配置、验证、以及实际踩过的坑一层一层拆开讲。1.1 为什么非对称路由会成为致命问题要理解IP上一跳保持的价值得先理解非对称路由为什么在出口容灾场景下会要命。假设主数据中心出口设备是A灾备中心出口设备是B。正常情况下内部业务流量从A出去源IP是A的出口地址或者NAT后的地址外部回程流量自然回到A。现在A故障了流量切换到B出去。如果B在转发时没有做特殊处理源IP可能还是A的地址因为NAT策略、路由策略可能还指向A或者虽然源IP变成了B的地址但外部回程流量因为路由宣告的关系仍然被引导到了A所在的位置。A已经故障了回程流量自然就丢了。更隐蔽的情况是A没有完全故障只是出口链路断了但A设备本身还活着。这时候回程流量到了AA发现自己的出口链路不通想转发给B但A和B之间的互联链路可能带宽不够或者A上的路由表没有指向B的明细路由流量就被丢弃了。这种“半死不活”的状态最难排查因为设备看起来是活的但流量就是不通。非对称路由带来的另一个问题是状态防火墙。如果出口设备上做了状态检测去程流量经过B回程流量经过AA上的状态表里没有对应的会话记录流量会被直接丢弃。这个现象在切换初期特别明显表现为“刚切过去的一小段时间业务全断过一会儿部分业务恢复”因为部分长连接超时后重新建立新建的连接恰好走了正确的路径。所以异地出口容灾的核心诉求可以归纳为两条第一切换要快第二切换后路径要对称。IP上一跳保持技术主要解决第二条第一条靠的是路由收敛和链路检测机制。1.2 IP上一跳保持的基本逻辑IP上一跳保持英文叫IP Last Hop Hold有些文档里也叫IP上一跳保持。它的基本逻辑是当灾备中心的出口设备B需要转发流量到外部时B会检查这个流量的“上一跳”是谁。如果上一跳是主数据中心的出口设备A那么B在转发时会把源IP地址保持为A的地址而不是替换成自己的地址。这样外部网络看到的源IP仍然是A回程流量自然就回到A。但A已经故障了怎么办B会同时通过内部链路把回程流量引导到自己这里或者通过路由宣告让回程流量直接到达B。这里的关键在于“保持”两个字。B不是简单地把源IP改成自己的而是保持为上一跳设备的地址。这样做的好处是外部网络的路由策略、安全策略、NAT策略都不需要改变因为从外部看流量的源IP没有变化。对于外部网络来说它感知不到内部发生了切换回程路径自然还是原来的路径。但这里有一个前提B必须能够接收到回程流量。如果回程流量被路由到了A而A已经故障B就需要通过某种机制把回程流量“拉”过来。常见的做法是在A和B之间运行BGPB向A宣告外部路由A再把流量转发给B。但A故障时这个机制就失效了。所以更可靠的做法是B直接向外部宣告路由让外部网络知道去往A的流量可以经过B。这涉及到路由策略的调整不是单纯一个“保持”功能能解决的。我个人的理解是IP上一跳保持是一个“配合性”技术它需要和路由设计、NAT设计、链路检测机制配合使用单独配置它并不能解决所有问题。下面我会结合具体配置来讲。2. 实验环境搭建与基础配置在讲配置之前先把实验环境说清楚。我用的是H3C的Comware V7平台设备两台出口设备分别模拟主数据中心和灾备中心的出口。内部有一台核心交换机模拟业务网络外部有一台路由器模拟互联网。为了简化NAT和路由策略都做最简配置重点突出IP上一跳保持的行为。2.1 拓扑设计与地址规划拓扑结构是这样的主出口设备A和灾备出口设备B之间有一条互联链路A和B各自有一条上行链路到外部路由器R。内部核心交换机C同时连接A和B业务网段在C上。外部路由器R上配置了去往业务网段的静态路由指向A和B的互联地址。地址规划如下表设备接口地址说明AG1/0/110.0.0.1/30上行到RAG1/0/2192.168.1.1/30互联到BAG1/0/3172.16.1.1/24下行到CBG1/0/110.0.0.5/30上行到RBG1/0/2192.168.1.2/30互联到ABG1/0/3172.16.1.2/24下行到CRG1/0/110.0.0.2/30连接ARG1/0/210.0.0.6/30连接BCVLAN100172.16.1.254/24业务网关业务网段是172.16.1.0/24NAT地址池在A上是10.0.0.1在B上是10.0.0.5。外部有一台测试主机地址是8.8.8.8用来模拟外部服务。这个拓扑的关键点是A和B之间有一条互联链路这条链路在正常情况下不承载业务流量只在切换时用来传递回程流量或者做路由备份。互联链路的带宽不需要很大但延迟要低否则切换后业务体验会变差。2.2 基础路由与NAT配置先配置A的基础路由和NAT。A上的配置大致如下# A设备配置 interface GigabitEthernet1/0/1 ip address 10.0.0.1 30 interface GigabitEthernet1/0/2 ip address 192.168.1.1 30 interface GigabitEthernet1/0/3 ip address 172.16.1.1 24 # 默认路由指向R ip route-static 0.0.0.0 0 10.0.0.2 # 去往业务网段的路由从C学习或静态配置 ip route-static 172.16.1.0 24 172.16.1.254 # NAT配置 acl number 2000 rule 0 permit source 172.16.1.0 0.0.0.255 interface GigabitEthernet1/0/1 nat outbound 2000B上的配置类似但默认路由指向R的另一个接口# B设备配置 interface GigabitEthernet1/0/1 ip address 10.0.0.5 30 interface GigabitEthernet1/0/2 ip address 192.168.1.2 30 interface GigabitEthernet1/0/3 ip address 172.16.1.2 24 ip route-static 0.0.0.0 0 10.0.0.6 ip route-static 172.16.1.0 24 172.16.1.254 acl number 2000 rule 0 permit source 172.16.1.0 0.0.0.255 interface GigabitEthernet1/0/1 nat outbound 2000R上的配置需要两条静态路由分别指向A和B# R设备配置 interface GigabitEthernet1/0/1 ip address 10.0.0.2 30 interface GigabitEthernet1/0/2 ip address 10.0.0.6 30 # 去往业务网段的路由正常情况下走A ip route-static 172.16.1.0 24 10.0.0.1 # 备用路由走B ip route-static 172.16.1.0 24 10.0.0.5 preference 70这里R上的两条静态路由第一条优先级默认是60第二条是70。正常情况下流量走AA故障时第二条生效流量走B。这个设计很简单但已经能说明问题。2.3 不加IP上一跳保持时会发生什么在配置IP上一跳保持之前先看看不加这个功能会怎样。把A的上行接口shutdown模拟主出口故障。这时候R上的备用路由生效去往172.16.1.0/24的流量会走B。但是业务流量从C出发经过B出去时B上的NAT会把源IP转换成10.0.0.5。外部主机8.8.8.8收到请求后回程流量目的地址是10.0.0.5R会直接转发给B看起来没问题。但问题出在内部。C上的业务网关是172.16.1.254C去往外部网络的下一跳可能是A因为C上配置的默认路由指向A。A的上行接口shutdown后A的默认路由失效但A上可能还有一条指向B的备用路由。如果A上没有备用路由C的流量就到不了B业务直接中断。如果A上有备用路由指向B流量到了BB做NAT后出去回程流量回到BB再转发给AA再转发给C。这条路径是通的但多了一跳而且A和B之间的互联链路成了瓶颈。更关键的是如果A完全故障比如断电C的默认路由指向A就彻底失效了。这时候需要C上的路由协议比如OSPF或BGP感知到A不可达把默认路由切换到B。这个收敛时间取决于路由协议的配置可能是几秒也可能是几十秒。在这段时间内业务是中断的。所以不加IP上一跳保持时切换的可靠性依赖于内部路由协议的收敛速度以及A和B之间互联链路的可用性。如果A完全故障互联链路也断了那B就无法把回程流量转发给C业务还是不通。3. IP上一跳保持的配置与行为验证现在进入正题配置IP上一跳保持。在H3C设备上这个功能通常是在接口下配置的命令是ip last-hop hold。但要注意这个命令的行为和接口类型、路由模式有关不是所有场景下都能生效。3.1 配置命令与生效条件在B设备的互联接口和上行接口上配置IP上一跳保持# B设备配置 interface GigabitEthernet1/0/2 ip last-hop hold interface GigabitEthernet1/0/1 ip last-hop hold配置完成后用display ip last-hop hold查看状态。这个命令会显示哪些接口启用了上一跳保持以及当前的保持表项。生效条件有几个第一接口必须是三层接口且配置了IP地址第二接口上必须运行了路由协议或者配置了静态路由否则设备不知道“上一跳”是谁第三保持表项需要有流量触发才能建立不是配置完就立刻生效的。我实测下来的经验是IP上一跳保持的生效依赖于流量触发。也就是说必须有流量从B经过B才能学习到上一跳的信息。如果B上没有任何流量保持表项是空的这时候切换过去第一包流量可能还是会走默认路径。所以在正常情况下建议在B上配置一条指向A的探测流量或者让B定期发送探测报文保持表项活跃。3.2 保持表项的查看与解读配置完成后从C上发起一个到8.8.8.8的ping然后查看B上的保持表项display ip last-hop hold verbose输出大致如下源IP目的IP上一跳出接口状态172.16.1.1008.8.8.8192.168.1.1G1/0/1Active172.16.1.1018.8.8.8192.168.1.1G1/0/1Active这个表说明从172.16.1.100到8.8.8.8的流量上一跳是192.168.1.1也就是A的互联接口地址B在转发时会保持这个上一跳信息。当A故障时B会根据这个表项把回程流量引导到正确的路径。这里有一个细节保持表项是有老化时间的。默认情况下如果一段时间内没有流量匹配表项会被删除。老化时间可以通过命令调整但一般不建议调得太短否则切换时表项可能已经老化导致回程流量丢失。我通常会把老化时间设置为300秒以上确保切换窗口内表项有效。3.3 切换测试与结果分析现在做切换测试。在C上持续ping 8.8.8.8然后在A上shutdown上行接口。观察ping的结果和B上的保持表项变化。测试结果分几个阶段第一阶段A的上行接口shutdown后R上的备用路由生效需要一点时间静态路由的切换是即时的但ARP学习需要时间。在这段时间内ping可能会丢几个包。第二阶段R的流量切换到B后B收到回程流量根据保持表项B知道这些流量的上一跳是A。但A的上行接口已经shutdownB无法把流量转发给A。这时候B会怎么做根据我的实测B会尝试通过互联链路把流量转发给A但A的上行接口不通A会把流量丢弃。所以如果A只是上行接口故障但设备本身还活着B转发给A的流量会被A丢弃业务还是不通。这就是IP上一跳保持的局限性它只能保持上一跳信息但不能解决上一跳设备故障的问题。要解决这个问题需要配合路由策略让B在A故障时直接把回程流量转发给C而不是转发给A。具体做法是在B上配置一条指向C的明细路由优先级高于指向A的路由。当A故障时B上的路由表切换到指向C的路由回程流量直接转发给C不再经过A。这样路径就变成了去程C-B-R回程R-B-C完全对称。这个配置的关键是路由优先级的设计。B上需要两条路由一条指向A优先级高一条指向C优先级低。正常情况下走AA故障时走C。但这里有一个问题B怎么知道A故障了如果A只是上行接口故障但互联接口还活着B通过互联接口还是能到达A路由不会切换。所以需要配合链路检测机制比如BFD或者接口状态联动。我通常的做法是在B上配置一条指向C的静态路由优先级设置为70指向A的静态路由优先级为60。然后在A的互联接口上配置BFD检测检测A的上行接口状态。当A的上行接口故障时BFD会话断开B上的指向A的路由失效指向C的路由生效。这样回程流量就直接走C了。这个配置稍微复杂一点但可靠性高很多。下面我把完整配置列出来。4. 完整容灾方案的路由与检测设计前面讲了IP上一跳保持的基本行为也指出了它的局限性。这一章讲怎么把IP上一跳保持和路由检测结合起来做一个真正可用的异地出口容灾方案。4.1 BFD联动路由切换的配置BFD是双向转发检测用来快速检测链路故障。在A和B之间配置BFD检测A的上行接口状态。当A的上行接口故障时BFD会话断开B上的路由切换。A上的配置# A设备配置 bfd multi-hop enable bfd multi-hop min-transmit-interval 100 bfd multi-hop min-receive-interval 100 bfd multi-hop detect-multiplier 3 # 创建BFD会话检测上行接口 bfd session 1 bind peer-ip 10.0.0.2 source-ip 10.0.0.1B上的配置# B设备配置 bfd multi-hop enable bfd multi-hop min-transmit-interval 100 bfd multi-hop min-receive-interval 100 bfd multi-hop detect-multiplier 3 bfd session 1 bind peer-ip 10.0.0.1 source-ip 10.0.0.5然后在B上配置静态路由关联BFD会话# B设备配置 ip route-static 172.16.1.0 24 192.168.1.1 preference 60 track bfd-session 1 ip route-static 172.16.1.0 24 172.16.1.254 preference 70这样配置后当BFD会话检测到A的上行接口故障时第一条路由失效第二条路由生效回程流量直接走C。切换时间取决于BFD的检测时间我配置的是100ms发送间隔3倍检测倍数检测时间大约是300ms。加上路由收敛时间整体切换时间在1秒以内。4.2 NAT与保持表项的协同这里有一个容易忽略的细节NAT和IP上一跳保持的协同。当B做NAT时源IP被转换成B的出口地址。但IP上一跳保持要求保持上一跳信息这两者会不会冲突实测下来不冲突。IP上一跳保持保持的是“上一跳”信息用于回程流量的路径选择而不是保持源IP地址。NAT转换后的源IP仍然是B的出口地址外部网络看到的源IP是B的地址。回程流量回到B后B根据保持表项知道这个流量的上一跳是A然后把流量转发给A或者C。所以NAT和IP上一跳保持是配合工作的一个负责外部可见性一个负责内部路径选择。但这里有一个坑如果B上的NAT地址池和A上的NAT地址池不同外部网络可能会因为源IP变化而触发安全策略。比如外部防火墙可能只允许A的地址访问B的地址被拒绝。这种情况下需要在外部防火墙上放行B的地址或者让B使用和A相同的NAT地址。但两个设备使用相同的NAT地址会导致IP冲突所以通常的做法是使用不同的地址然后在外部防火墙上放行。我遇到过一个案例外部服务只允许特定源IP访问切换后源IP变了访问被拒绝。排查了半天才发现是外部安全策略的问题。所以在做异地出口容灾时一定要确认外部网络的安全策略是否允许灾备出口的地址。4.3 回程流量路径的验证方法配置完成后怎么验证回程流量路径是否正确我通常用traceroute和抓包结合的方法。在C上traceroute 8.8.8.8正常情况下路径是C-A-R-8.8.8.8。切换后路径应该是C-B-R-8.8.8.8。如果路径是C-B-A-R-8.8.8.8说明回程流量还在绕行A需要检查路由配置。在B上抓包看回程流量的入接口和出接口。正常情况下回程流量从上行接口进入从下行接口出去直接到C。如果从上行接口进入从互联接口出去说明还在走A需要检查路由优先级。还有一个验证方法是查看B上的会话表。用display session table查看NAT会话确认会话的源IP和目的IP是否正确以及会话的出接口是否指向C。我个人的经验是验证回程路径比验证去程路径更重要。去程路径通常比较直观路由表一看就知道。回程路径涉及到NAT、保持表项、路由策略多个环节任何一个环节配置错误都会导致回程流量丢失。所以切换测试时一定要在B上抓包确认回程流量的实际路径。5. 实际部署中的坑与应对这一章讲我在实际部署中踩过的坑。这些坑在实验环境里可能不会遇到但在生产环境里很容易出现。5.1 保持表项老化导致的切换失败第一个坑是保持表项老化。前面提到过保持表项有老化时间如果长时间没有流量匹配表项会被删除。在正常情况下灾备中心的出口设备B可能没有任何业务流量经过保持表项是空的。这时候主数据中心故障流量切换到BB上没有保持表项回程流量无法正确引导业务中断。应对方法有两个第一在B上配置定期探测流量保持表项活跃。比如配置一个定时任务每隔一段时间从C发起一个到外部地址的ping触发B建立保持表项。第二调整保持表项的老化时间设置为一个较大的值比如3600秒。但老化时间太长会占用表项资源需要根据设备规格权衡。我通常的做法是两者结合老化时间设置为600秒同时配置探测流量每300秒触发一次。这样既不会占用太多资源又能保证表项活跃。5.2 非对称路由导致的防火墙丢包第二个坑是状态防火墙。如果出口设备上配置了状态检测去程流量经过B回程流量经过AA上的状态表里没有对应的会话流量会被丢弃。这个现象在切换初期特别明显表现为“刚切过去的一小段时间业务全断过一会儿部分业务恢复”。应对方法是在A和B上都配置状态同步或者关闭状态检测。但关闭状态检测会降低安全性所以更好的做法是配置状态同步。H3C设备支持会话同步功能可以在A和B之间同步会话表。配置命令是session synchronization enable然后在互联接口上配置同步参数。但会话同步也有局限性同步需要时间切换瞬间的会话可能来不及同步。所以对于关键业务建议在应用层做重试机制或者使用长连接保持减少切换对业务的影响。5.3 路由收敛时间与业务超时的关系第三个坑是路由收敛时间。BFD检测时间可以配置得很短但路由收敛还需要时间。如果路由收敛时间超过了业务的超时时间业务就会中断。比如TCP连接的超时时间通常是几秒如果路由收敛需要10秒那TCP连接就会超时断开。应对方法是优化路由收敛速度。除了BFD还可以配置路由协议的快速收敛参数比如OSPF的fast-reroute或者BGP的bestpath快速收敛。另外可以在C上配置多条默认路由分别指向A和B使用不同的优先级。当A故障时C上的默认路由快速切换到B减少对B的依赖。我实测下来BFD检测时间100ms路由收敛时间大约500ms整体切换时间在1秒以内。这个时间对于大多数业务是可以接受的。但如果业务对中断时间要求极高比如金融交易系统可能需要更复杂的方案比如双活出口或者应用层多路径。5.4 互联链路带宽不足导致的性能下降第四个坑是互联链路带宽。切换后回程流量可能经过A和B之间的互联链路。如果互联链路带宽不足业务性能会下降。比如互联链路是1G业务流量是2G切换后互联链路成为瓶颈业务体验变差。应对方法是在设计阶段就评估互联链路的带宽需求。如果业务流量较大互联链路需要足够的带宽。另外可以通过路由策略让回程流量直接走C不经过A减少互联链路的压力。这就是前面提到的BFD联动路由切换方案的价值所在。我通常建议互联链路的带宽至少是业务峰值流量的1.5倍留出余量。如果预算有限至少也要保证关键业务的带宽需求。6. 方案对比与选型建议最后这一章我把几种常见的异地出口容灾方案做个对比方便你根据实际情况选型。方案切换速度回程路径配置复杂度适用场景纯静态路由慢依赖ARP老化可能非对称低小型网络业务中断容忍度高BGPIP上一跳保持中等依赖BGP收敛对称中等中型网络有BGP基础BFDIP上一跳保持静态路由快亚秒级对称中等对切换速度有要求双活出口应用层多路径极快无感知对称高大型网络关键业务选型建议如果业务中断容忍度在秒级BFDIP上一跳保持静态路由的方案性价比最高。如果业务要求无感知切换需要考虑双活出口但成本和复杂度会大幅上升。纯静态路由方案只适合小型网络生产环境不建议使用。另外IP上一跳保持技术在不同厂商的设备上可能有不同的实现方式配置命令和行为可能有差异。在实际部署前建议在实验环境充分验证确认切换行为和回程路径符合预期。我个人在实际操作中的体会是异地出口容灾的核心不是技术本身而是对业务路径的完整理解。去程路径、回程路径、NAT转换、安全策略、路由收敛每一个环节都要考虑到。IP上一跳保持是一个有用的工具但它不是万能的需要和其他技术配合使用。把路径想清楚了配置自然就对了。