一次惨痛的线下机房上云的经历

背景

所有的应用都在本地机房部署

有大概应用在20个左右,其中微服务应用各种组件和服务在8个左右,其他的都是老系统留下来的应用

准备

服务类型

阿里云ECS规格

内存

CPU

机械硬盘

固态硬盘

外网IP和带宽

数量

nginx代理转发

计算网络增强型 sn1ne

8G

4核

300G

带宽10M(根据实际使用情况调整)

1

tomcat类后端服务器

通用型g6

8G

2核

300G

10

redis缓存队列

通用型g6

8G

2核

300G

100G

3

redis(可选配置)

内存网络增强型 se1ne

16G

2核

300G

100G

 

redis(可选配置)

内存型(原独享)se1

16G

2核

300G

100G

 

数据库

通用型g6

16G

4核

500G

300G

4

数据库(可选配置)

内存型(原独享)se1

32G

4核

500G

300G

 

数据库(可选配置)

内存网络增强型 se1ne

32G

4核

500G

300G

 

部署迁移

        我们的运维小哥哥从6月2号开始进行部署和迁移,三天之后也就是6月5号的时候完成整体的迁移工作,因为我们还在进行项目的迭代工作,所以我们的测试周期啦的比较长。到6月18号左右才完成测试工作。

       6月20号,全员休息,对我们来说是一个好日子,奋斗开始了我和我们的运维小哥哥,测试小哥哥一大早开始来到公司,挂起维护页面。然后就开始干起来了:

       第一步:数据同步,这是一个漫长的等待时间,当然这个主要是运维小哥哥在操作。

       第二步:配置更新,对于微服务来说比较轻松,更改nacos上的配置文件就好了。

      预期规划如下:

  数据库 redis
微服务应用 一主多从 哨兵模式
老应用 多写分离加多数据源 哨兵模式

      对于的老的应用来说,用git做的配置中心,脚本拉取替换(WAR包,JAR包就别想了)的方式,其实更改起来也比较OK。所以配置更新也是相当顺利

        第三步:更新所有的应用到最新的版本,这个就是jenkins上操作即可,无问题。

测试与当天问题发现

     问题1:与第三方应用通讯需要外网的问题。

     解决方式:弹性公网IP

     问题2:文件共享问题

     解决方式:因为本地机房应用是没有专门的文件服务器的,所以采用的软连等相关操作,阿里云上采用的共享和挂载操作

     问题3:第三方推送地址更换问题

    解决方式:联系第三方更改推送地址

    问题4:访问白名单问题

    解决方式:针对443端口开放所有的访问权限。

其他相关功能没有什么问题,基本上到这来说理论上这次迁移是很成功的,虽然忙活了一天但是还是心满意足的下班了。

悲剧的第二天

       第二天,怀着很忐忑的心情,早早的就起来坐到电脑旁边了。8点开始没什么问题,貌似很稳定的情况,8点50左右,我的同事们都开始上班上系统干活了,这个时候悲剧开始了。

      第一个炸弹:大量的同事都是第一次通过外网的域名访问系统,所以大量的并发导致需要拉取大量的静态资源。瞬间带宽超了。这个其实好理解,只是瞬时的,而且后面访问基本趋于平稳状态,10M的带宽基本上能满足需求。OK,这个可以过了。

      第二个炸弹:所有的同事都说卡,访问系统超级慢。然后就是整个钉钉群,微信群就炸了。

开始排查:

     排查一:redis毫无压力,是不是redis没起作用?

     因为redis没有开放外网端口,登录服务器查看。

./redis-cli -a 'pwd'

     使用命令查看所有的key

keys *

   redis正常缓存数据,没有问题。那么这个时候考虑是不是老系统不兼容哨兵配置,改回单机模式。并没有任何效果,redis正常读写没问题。排除

     排查二:数据库,是否是数据库压力过大。

     查看主库:没问题,兼职就是毫无压力

     查看从库:压力爆满,CPU完成超超负荷运行。那么问题来了,为什么会出现这种情况?

     解决方案1:分压,既然主库没有任何压力,那么先在某些应用的节点更改主库为从库,也就是主从一致。

     效果:瞬间主库压力上来,从库反而没有任何压力了。卡顿现象并没有解决。

     解决方案2:查看系统日志,发现某些节点的日志输出频率较慢。是不是因为某些服务器的配置的问题,重启相关服务器和从库。

     效果:依然没有解决我们的问题。

     此时时间已经走到了10点多了。但是经过这几轮的折腾,运维小哥哥突然记起来了,老的应用为了保持会话,是做了IP HASH的问题。以前使用的是内网环境,所以每一个的IP地址都不一样,现在用的外网环境,而公司统一的是专线固定IP,这样就变成了访问系统的IP变成了全一样的了。所以就全路由的一个服务节点上去了,其他的服务节点完全就没起作用了。

       解决方案3:去掉IP HASH策略。

      效果:去掉IP HASH会造成系统整个功能失常,所以基本上这个方案不可取。瞬间感觉好像走到死胡同了,连饭都不想吃了。

       解决方案4:运维小哥哥在拿外卖的时候突然告诉我,我们可以根据IP手动指定路由节点。虽然我们的出网带宽固定了,但是还是有区域划分的,每个区域的IP还是不一样的。

      效果:这个貌似解决了服务节点单一路由的问题。但是还是存在某些节点负载过大的情况,但是相比之前的情况,已经是好很多了。当然问题到这里只是万里长征走了第一步,完全没有实际的解决现在的系统的问题。

      随着一天的上班结束,查询系统数据的人越来越多,查询量增大。这里就得说一下我们的老系统的报表相关的功能了,全是大的SQL汇总起来,有时候一个SQL包含了各种计算,函数,汇总,分组统计等功能。基本上我这么一个程序员老司机都不愿意看这些SQL。

飞升的第三天

      解决方案5:增加数据库从库的CPU能力,升级数据库配置。

      效果:这个时候已经是第二天了,毕竟花钱还是有流程的,当然领导很给力,直接给特事特办了。升级数据库配置,在增加1个从库,这个效果是立竿见影的,速度马上就上来。这个过程本来是个很轻松的过程,但是由于挂载问题,nginx所在的服务器居然重启失败,导致外网IP失效。最后还是联系阿里云的售后解决的。

       这个时候基本上系统访问不存在的问题了,但是各位不要忘记了,IPHASH的问题我们还没有解决。

       这个时候我一直在想nginx的IP hash的这个事情,其实所谓的IP hash不就是通过客户的IP来计算hash值,来确认他的路由保持,那么我在想我们是不是可以找一个替代IP的东西来解决这个会话保持的问题呢。

      在我们的系统里面正好有这么一个东西对于客户来说是唯一的,那就是请求TOKEN,而且这个请求Token就在请求头里面。

      解决方案6:自定义HASH策略

      开启请求头检测

 underscores_in_headers on;

    定义2个路由规则:为什么是两个呢?因为我们有的请求是不需要登录就能获取的也就是没有token的,我们也希望随机轮询。

    upstream https_prod {
	hash $token;
	server 172.17.150.127:8080 ;
	server 172.17.150.128:8080 ;
	server 172.17.150.129:10080 ;
    }
    upstream https_prods {
	server 172.17.150.127:8080 ;
	server 172.17.150.128:8080 ;
	server 172.17.150.129:10080 ;
    }

   获取TOKEN,这里比较特殊的就是,websocket的连接的token我们放在的是Sec-WebSocket-Protocol上,这里注意了,在nginx配置文件中获取的时候,需要吧-换成_

set $token $http_Sec_WebSocket_Protocol;
        if ($http_Authorization != '') {
            set $token $http_Authorization;
        }

定义自动的路由规则

	set $group https_prod;
	set $groups https_prods;

   location ^~ /api/ {
            if ($token != '') {
                proxy_pass http://$group;
            }
            if ($token = '') {
                proxy_pass http://$groups;
            }
            #proxy_pass http://$group;
            proxy_redirect off;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            #WebScoket Support
            proxy_read_timeout 600s;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
	}

到这里,自定义路由规则就完成,重启nginx加载策略。

       效果:比较完美的解决了IP HASH的问题,理论上比IP HASH更加完美。这个时候系统访问速度的问题已经完全解决了

第三个炸弹:老系统的导出功能是,先在服务器上生产一个Excel文件,在吧连接返回给前端,前端通过a连打开下载的。因为a连请求是没有Token的,所以无法保持会话,所以有可能找不到这个文件。

        解决方法:临时,运维小哥哥做了一个共享。

                         最终:文件下载改成流式下载。

        三天已经过去,说实话,心里是贼几把累的,按一个正常程序员的心里,估计已经把前任骂的的飞起,但是其实我反而觉得这次的事情我自己应该有很多值得反思的事情。

  • 服务器压力预估不足
  • 未深入的去了解系统的功能
  • IP HASH的替代方案应该能更快给出,对nginx等相关软件了解的还是不够深
  • 定位问题的速度过慢,定位到IP的问题已经超出2个小时。

总结 

    借阿里的事故的一句话:敬畏每一行代码!在成长的过程中壮大自己!

 

你可能感兴趣的:(nginx)