有趣的网络问题被我轻松解决

114 阅读5分钟

难题袭来

是这样的,项目上用到一款MQTT中间件,需要以集群形式部署到云虚拟机ECS上面。部署前需要在MQTT配置文件中配置好每个节点的ip地址。启动后各个节点会根据配置文件中其他节点地址去向其他节点发送加入集群请求。这个需求在同一区域下的云ECS上是没问题的,因为大家内网网段是通的,直接连接就行。但是客户有个需求要在跨region下这个集群能正常搭建运行起来,这就暴露出来一个问题......

问题描述

我们都知道在跨region情况下,不同区域下的ECS之间的内网是不通的,所以用之前普通方式去搭建集群就会出现网络访问不通的情况,那么为了让不同区域ECS之间能通信,我们首先想到的是使用eip去通信,eip确实能保证网络通。但是有个MQTT自身的问题随之暴露了出来,就是在该MQTT启动的时候会有绑定ip的过程,在此过程会根据配置文件中配置的ip去自己机器上找相应的网卡进行绑定。但是我们填写的是eip,是在ECS之外的一个虚拟IP,肯定不会在ECS上有对应的网卡。所以结果可想而知,报了找不到网卡的错误。这样事情便进入了僵局......

将计就计

就在大家一筹莫展的时候,不知是谁说了一声久违的docker,顿时有关虚拟化、云计算、docker网桥等知识飞速从我脑海中闪过,突然有个知识点停在了我思绪之间。没错是虚拟网卡,于是一个惊人计划便浮现脑海之中。我想既然报错是因为找不到ip对应的网卡,那不如逢山开路,遇水架桥,缺啥补啥,干脆创建个虚拟网卡给MQTT绑定用。说干就干先在ECS上用ip 命令创建一对虚拟网卡,并且给该网卡绑定配置文件中eip的地址。命令如下:

创建虚拟网卡:
ip link add veth0 type veth peer name veth1

启动网卡:
ip link set veth0 up
ip link set veth1 up

绑定ip:
ip addr add 192.168.1.100/24 dev veth0

这样心想不就成了,但是启动后还是不如所愿,集群还是没搭建起来,但是这次能启动,就是集群节点之间还是不能相互识别,仔细想了想为啥,从头到尾梳理了一遍,是因为有了网卡后,还得创建路由,将进出的流量的路得搭建好,要不流量出不去也进不来,本来ECS上用的是默认的eth0网卡,但是现在绑定了创建的vth0网卡后,就得改变一下流量的路由规则,在别的节点的请求过来时,是eip->eth0->vth0,完事从MQTT发出去的流量的路径应该是vth0->eht0->eip,这样新加两条路由规则就行,进入的路由规则:eth0->vth0,出去的路由规则:vth0->eth0。语法如下:

允许eth0的流量转发至vth0:
iptables -t nat -A PREROUTING -i eth0 -j DNAT --to-destination <veth0_IP>

允许veth0的流量转发到eth0
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source <eth0_IP>

启用ip转发:
echo 1 > /proc/sys/net/ipv4/ip_forward

如此,在加了路由规则后再试,果然跟预期结果一致,MQTT集群搭建成功,在规定时间内解决了客户的问题,更重要的是让我以为之前用不到的知识派上了用场,心里别提有多高兴,大家也很好奇我究竟是怎么解决这个问题的,因为大家好多都想不到那儿去,所以知识不是白学的,只是还没用上而已。

趁热打铁

在初步试验成功后,要把这套方案给固化起来,所以我决定直接修改源码,把这套机制在MQTT软件中以代码形式保存下来。所以我便开启了急速编码模式,怎么个急速法呢,当然不可能自己编写。现在大家都在用各种包装chat,我也不例外,跟chat说明了逻辑之后,chat三下五除二就给生成出来了,说实话是真的好用。所以像这样的只要逻辑清晰的任务都可以交给chat去帮你,我的逻辑无非是绑定网卡前先判断有无该ip对应的网卡,如果没有就生成虚拟网卡并进行绑定,并且还得创建两条路由规则,一般来说ECS上默认都是单网卡并且是eth0,所以路由规则中我用的是eth0,没考虑什么特殊情况,因为客户就是在云上。生成之后简单改了下,完事打包放在ECS上直接启动即可,无需自己再执行什么命令之类的东西。用户还是以之前的方式配置便可,做到了用户无感知。这就完了吗?当然不是,这么费劲不得用张图来总结下吗?图片在下面,图中ECS中蓝色的线条就是新的流量路线,黑色的是老的流量路线,以上就是我对这次云上网络问题的总结,希望对大家有所帮助,大家如有意见建议请评论区告诉我,下期再见!

图片1.png