前言
女士们,先生们!请你们大声的告诉我,程序员最怕的是什么?
产品经理!!!错。。。(有一点点怕)
产品经理改需求!!!错。。。(不是那么的怕)
Bug!!!错。。。(不是很严重的怕)
线上Bug!!!错。。。(有一点瑟瑟发抖的怕)
那最怕的是什么?最怕的是产品经理改的需求在现上运行的时候出了bug,特么bug还是间歇性出现
背景
本文与线上环境没有关系,是公司的测试环境下出现的问题;尽管不是现上bug,然而这个间歇性的网络问题差点让我本人成了间歇性精神病。
-
网络环境
由于公司不大,人数不多,因此,就没有真正的网络工程师,整个公司的网络环境都是由我一个不懂网络的技术人员搭建并维护者在,凭借着当年组装小霸王的经验,勉勉强强将公司的网络搭建起来了 -
技术需要
本着节约成本的宗旨,公司的固定IP并没有直接迁电信的(测试环境需求量也不大),因此就找了一家三方运营商买了一个固定IP,运营商那边就弄了思科的路由器放在了公司的内部 -
网络拓朴图
根据一切的一切,公司的网络环境被我搭建成了这样:
根据上面的图来看,是不是一切都挺完美的,满足个几十人的用户数也是轻轻松松,没有那么复杂的结构,大家用起来也没什么问题,自己都有点佩服自己了,真特么的吊! -
请求转发过程
公司的其他同事也就只需要上上网,只有技术这边的网络需求是最复杂的。
以下是技术部这边的一个请求转发的过程。
从上面的流程图来看,貌似也没有什么问题,调用关系也很清晰
回路问题的出现
- 小程序的出现
开发小程序功能的时候,由于微信那边必须使用域名进行业务访问,因此就上域名,上固定IP呗!如上面的拓扑图所示,假如192.168.1.111为后端的接口服务,这个服务是映射在123.45.7.8这个外网IP的80端口上,固定IP的是解析在a.mydname.com这个域名下面;此时,开发人员在192.168.1.112上面开发同时通过a.mydname.com这个域名访问后端服务的时候;操蛋的一刻发生了,接口特么时灵时不灵; - 漫长的问题定位过程
- 代码问题
一开始我怀疑的并不是网络问题,作为写的一手好Bug的资深码农,第一时间怀疑的不是人生,而是自己的代码,什么端口检测,请求追踪、流量检测、外加各种shell脚本测试,发现,代码并没有任何异常,因为,当请求在出现问题的时候,压根儿后台服务就没有收到任何的请求(手都没有摸到,你说你怀孕了,不可能)!!!, 排除!!! - 怀疑NG
怀疑NG的配置有问题,那么就直接直连服务,不通过NG,发现还是有问题,说明这个第三者(NG)并不是破坏感情的罪魁祸首, 排除!!! - 怀疑部署的那台服务器
同样的方式,调用其他机器的服务也会出现这样的问题,嚯嚯的美女(服务器)还不止一个, 排除!!! - 诡异现象
这一切的一切,如果使用外部网络,都不会出现,都能正常调用 - 最后怀疑的才是网络
上面测试了个遍,最后才怀疑到网络上,然后就对着自己画的拓朴图,仔细脑部这整个场景的请求调用过程,总算是发现了罪魁祸首,网络回路,一个曾经架设网络环境的时候就遇到的坑,又再次趴了一遍,只不过这一次和上一次不太一样。下面开始详细分析过程
- 代码问题
原因分析
- 正常的外部调用
上面的调用流程图已经说明了一个正常的外部用户请求的全过程 - 正常的内部调用
上文中说过,面临的问一个间歇性的问题,那说明时候是正常的呢?假如现在小M就是112那台上的码农,让发起一个请求的时候;请求到达路由器(H3c),根据路由器的分发策略,此时转发走wan1口(非固定ip),经过电信–>代理服务商–>到公司的固定IP路由->111的机器,就完成了一次正常的请求。 - 非正常的请求
同上过程,小M发起一次请求,此时H3C的策略将请求转到了wan2口;发现请求的目的地(123.45.7.8)已经到了,根据映射规则就把请求发到了111的机器,当111的机器响应到路由的时候,路由根据映射策略又把响应的结果回给了111,因此就形成了一个回路的现象,这次请求就在来回的路上将整个带宽耗尽,在此期间,服务的再次请求是没办法请求到的;直到回路里面的所有链接全部超时之后,整个网络才会恢复;这就是间歇性精神病的病根;
解决方案的分析
- 待解决的问题
根据上面的一系列的分析,问题的就是因为内网下通过外网IP访问内网服务造成的回路问题,那我们需要解决的就是如何在内网下通过域名访问内网的服务,同时这个过程不走外网IP;
域名映射内网
- 方式
在万网下将域名的解析地址解析成内网地址,如a.mydname.com原来解析的是123.45.7.8,现在改成192.168.1.111;此时回路的问题是可以解决了 - 带来的问题
此时如果脱离了内网环境,比如用手机移动网络去访问就没法正常使用了
配置Host
-
方式
在本机windows的Hosts记录下面添加一条域名映射关系192.168.1.111 a.mydname.com
此时,在本机下请求a.mydname.com这个域名的时候,就直接转发到了192.168.1.111这台机器
-
问题
- 所有相关的人员的电脑上面都得配置相关的Host记录
- 小程序的测试必然会使用到手机,手机没办法配置host记录,请求的时候同样会导致回路(有其他策略解决,但还是很麻烦)
搭建私有DNS(推荐)
- DNS
关于什么是DNS这里不做解释,百度一下,很容易理解,简单来说,就是解析域名所映射的真实IP的服务器 - 可行性分析
上面有说到,在万网下将域名的解析地址配置成内网的方案是可以解决回路的问题,只是域名解析的A记录被保存到了DNS的根服务器了,从而导致外网获取到的真实IP也是内网IP,从而导致外网下不可用,那我们可以不在内网下搭建一个DNS;配置上需要解析到内网的一系列域名,然后我们所有的机器都只需要把首选DNS指向内网DNS,这样就可以保证内网和外网都可以访问,而且不会出现回路问题,因为到内部DNS服务器之后,域名就已经解析成内网IP了,都没有经过路由器。详细拓扑图如下:
如何搭建私有DNS
自从使用了Docker之后,对于这种软件的安装,第一时间复现在脑海的就是看有没有Docker版本的,官方镜像仓库搜了一圈,果然有,确认了一翻,决定使用以下的镜像 andyshinn/dnsmasq:2.75 ;
再次安利一下Docker,很舒坦,想这种软件的安装,运行个镜像即可,并不会对我的Linux环境造成任何的影响,那天不用了,删除容器,卸载的干干净净;
-
下载镜像
docker pull andyshinn/dnsmasq:2.75
-
检查53端口是否被占用
-
运行镜像
run -d -p 53:53/tcp -p 53:53/udp --cap-add=NET_ADMIN --name dns-server andyshinn/dnsmasq:2.75
-
进入容器配置环境
docker exec -it 容器ID /bin/sh
记住,这里是在镜像内部的配置,也可以在宿主机做配置,然后做文件挂载,这里按简单的方式来,因为配置不多,我们不担心丢了 -
配置根DNS
vi /etc/resolv.dnsmasq
添加以下配置nameserver 114.114.114.114 nameserver 8.8.8.8
-
配置本地的域名映射关系
vi /etc/dnsmasqhosts
为了测试效果,我们用a.baidu.com b.baidu.com c.baidu.com 做测试192.168.1.111 a.baidu.com b.baidu.com c.baidu.com
上面的域名请根据自己的情况更换
-
添加配置生效
修改私有DNS的配置文件
vi /etc/dnsmasq.conf
在最后添加以下记录resolv-file=/etc/resolv.dnsmasq addn-hosts=/etc/dnsmasqhosts
-
退出容器
exit
-
重启容器
docker restart 容器ID
到此,本地DNS已经安装完成;
本地DNS使用
-
将本地的首选DNS设置为你本地DNS所处的机器的IP
如下图,192.168.1.8为上面我安装DNS服务的机器对应的内网IP
-
刷新本地dns
ipconfig /flushdns
-
测试本地DNS
ping a.baidu.com
上面的域名请根据个人配置的更换,如出现下图效果,说明配置无误:
根据测试的结果可以看出,本地DNS配置的域名已经成功的解析了,没有配置的就到根DNS下解析了对应的地址进行访问
此问题的延伸
通过上面对DNS的配置,我们貌似可以延伸出很多其他方面的需求解决方案
内部服务的访问地址
- 问题描述
服务没变,但是服务所部署的位置变了 - 解决方式
我们将所有的服务全部以域名的形式访问,域名映射的地址均配置在本地DNS上,当我环境发生变化时,只需要切换DNS的映射,而不需要发布代码即可解决