当前位置 博文首页 > 文章内容

    考试系统上线复盘

    作者: 栏目:未分类 时间:2020-09-21 16:01:03

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



     



    1.     概述

    执法人员考试系统(以下简称“考试系统”)是公司第一个顺利支撑全国2500人同时在线考试的系统。本文通过对考试系统的上线部署、问题反馈、测试调优等过程的复盘,为其他类似场景提供借鉴。

    2.     系统简介

    考试系统功能主要包括系统登录、开始答题、题目切换(上一题/下一题)、交卷等,从功能上看并不复杂。

    ——考试系统性能要求:支撑2500人同时在线考试,不能有明显的卡顿。

    ——考试系统主要过程:预先通过后台系统建立考试批次、执法人员信息、人员与批次关联信息、试题信息等。执法人员在考试开始前通过浏览器访问考试系统首页面,通过身份证号+验证码登录系统;当考试开始时间到后,点击开始答题跳转至答题页面开始作答;通过点击上一题/下一题或者具体题号切换试题;完成全部作答后,点击交卷完成考试。若考试结束时间到后仍未交卷,系统将强制交卷。

     

    图 1考试系统操作流程图

    ——系统部署:考虑到面向全国执法人员,网络情况比较复杂,对服务端压力情况也不确定,于是决定基于阿里云环境做系统部署,万一出现性能问题还可以快速升级,也便于做监控。各省执法人员通过互联网访问系统参加考试。

     

    图 2考试系统部署图(初次)

    由上图可知:初次部署我们仅考虑了最简单的方式,服务器选择阿里云ESC通用性服务器g6。具体使用1台应用服务器(配置:4C16G)部署网关+前后端程序、使用1台数据库服务器(配置:4C16G)部署oracle数据库+redis服务+消息服务+消费程序。他们各自的作用如下:

    ——应用服务器-微服务网关:用于提供基于微服务架构的后台接口的注册发布;

    ——应用服务器-前端:vue编译发布的系统前端;

    ——应用服务器-后台接口:实现具体的登录系统、获取试题、切换试题、交卷等逻辑。试题从redis缓存中获取;

    ——数据库服务器-oracle:持久化存储全部数据;

    ——数据库服务器-redis服务:用于缓存每个考生的试题,包括题干、选项等(每人约150道题,2500人共约35w条记录)。这些数据在考试前会一次性全部加载到内存里,考试过程中系统将直接从redis中获取题目,避免从oracle数据库中读取试题造成磁盘io操作;

    ——数据库服务器-消息服务/消费程序:系统会将考生每一道答题结果写入消息队列,以避免对oracle数据库的直接压力;消费程序会将这些消息读出来再写入oracle持久化存储。基本上消费程序会在考生开始答题后就开始工作。

    为什么我们认为这样部署就OK了呢?一是按照设计实现思路,我们认为压力最大的数据库服务器已经通过redis缓存方式避免了耗时的磁盘io操作(主要是避免读数据库。写数据库还是有的,就是消费程序会将答题结果入库);二是在正式考试前,我们基于实际部署环境做了一次考试系统登录接口、交卷接口的压力测试,按照测试结果系统可以支撑并发2000人进行登录与交卷,事务通过率为100%。考虑到实际2500人在线应该不会达到2000的并发,所以我们认为不会与问题,甚至信心满满。但实际上,以上两点都出现了问题,同时还有其他问题没有考虑到,反映出整个团队在应对高并发项目上的经验不足。

    3.     出现的问题与对应调整

    3.1.   第一次模拟考试

    8月14日下午第一次全员参与的模拟考试很快到来。这次参与考试的考生约1750人,考生在3点钟之前就可以登录系统,等到3点钟后开始正式答题。从阿里云的监控上看,在3点之前两台服务器的cpu与内存指标偏高但还算正常,业务人员反馈各省的考生也都陆续正常登录了系统。当时大家虽然有点小紧张但还是比较乐观地认为系统应该没有问题。

    随着3点正式开始答题,噩梦来了。监控显示应用服务器与数据库服务器的cpu占用率一下飙升到100%,大家紧张情绪一下子达到顶点,赶紧使用测试账号访问系统,发现登录页面的验证码已经刷新不了,导致无法登录系统。紧接着业务人员的电话就被打爆了,有很多人在反映系统无法登录、或者登录进去后无法开始答题、或者刷新显示不了试题等问题。大家都懵圈了,不清楚为何会发生系统卡顿。于此同时,业务得到反馈还是有不少用户可以正常进行答题,只是响应速度比较慢,故大家打算先观察。时间很快来到3:30,仍旧不断有电话打来反馈系统卡顿问题,领导与业务人员问能不能解决问题,无奈大家决定重新启动服务器。但重启后系统依旧卡顿,问题并没有解决。大家谁也不说话,脑子基本处于空白状态,气氛窒息。时间来到4点,业务人员决定跟各省沟通,说明系统的问题今日无法修复,改天再进行模拟考试。大家都明白,这次模拟考试搞砸了。

    3天后就是正式考试,如果问题解决不了,那公司口碑就彻底砸了。为了解决问题,大家决定立刻安排系统开发团队从宁夏飞到北京连夜集中排查、同时抽调部分西安研发团队成员飞到北京集中协助排查问题。大家到北京已经是凌晨1点了,都没有休息,直接到公司会议室集合开干,开启了3天2通宵的改进工作。北京这边相关的研发与测试人员也于第二天一早汇合了。在此对各位同学表示感谢!

    开始问题分析:

     

     

    首先从考试的全流程来分析:考生可在统一时间点的开始答题前,登录系统,压力应该是分散的(大家不会在同一时间点同时登录系统),所以登录操作不会出现很高的并发;而主要压力集中在开始答题环节,即时间一到,考生会集中在那几秒钟内点击按钮开始答题;而一旦开始答题后,切换试题操作又不会出现集中并发了(因为每个人的做题时间长短不一,有的人做得快,有的人做得慢,理论上不会集中在一点去切换试题);同理最后交卷操作也不会集中,因为有人会早交卷,有人会晚交卷。

    从以上3图可以看到,应用服务器(即主节点)的cpu在3点之前基本处于正常水平,在接近3点时开始逐步攀升,当达到3点后到达顶峰。这说明3点前,不断有大量用户登录系统,导致cpu被占用;内存在3点之前就一直处于80%的高位,这说明其实服务器本身的内存是不够的,这一点在考试开始答题前被我们忽视了;而tcp链接一下干到了5K多且一直没有释放回落,是实际在线用户的3倍多,说明系统处理不过来了。因为正常来说,用户的一个页面操作过去如果处理完毕,链接会很快释放掉。

    再分析系统登录:系统登录做的事情很简单,只是验证考生身份(在redis里获取数据验证)生成token并记录,正常来说cpu不应该会有这么高的占用率。考虑当开始答题后的实际情况是系统首页面的验证码刷新不出来,分析应该是系统应处于满负荷状态发生了卡顿,考生在不断刷新页面;或者是已经登录系统的考生因为看不到题目,也在不断刷新页面,从而加剧了服务器cpu占用与tcp链接占用。

    分析系统验证码的生成方式:是后台接口随机生成一个4位数的图片,然后将图片通过二进制流的方式返回给前端。这种方式应该会占用一定比例的服务器cpu与内存资源,但最主要的还是会占用服务器的出口带宽,在一定程度上会影响服务器到客户端的响应时间。由于本次考试只是内部考试,实际上并没有必要进行验证码操作,于是大家决定将验证码去掉,这样一是可以节省应用服务器的内存占用与cpu计算,二是可以节省应用服务器的出口带宽(考虑2500人去下载验证码图片,还是不小的量。且如果验证码没出来,用户会去刷新页面,服务器又会重新算一个验证码出来,返给客户端,服务器资源会一直被占用着)。

     

    再来看数据库服务器的监控情况:从以上2图可以看到,从3点开始答题起,数据库服务器cpu与磁盘读操作很高,这就有点奇怪了。理论上系统应该是直接从redis里获取数据,不应该有这么高的读取操作。这说明一定有其他操作导致了数据库实际访问。同时磁盘的写操作太低了,这一点也不正常。因为在正常情况下,考生开始作答切换试题,消息消费程序就会开始干活,将答题结果写入数据库,应该表现出一条相对平直的水平线。如此低的写入,应该是说明没有多少用户真正完成了试题切换以及交卷操作,大部分考生都处于卡顿状态。

    按照这个思路排查,开发人员很快发现在系统开始答题的时候,做了一个数据库的查询操作,去获取关联的题目信息(下图中的左侧试题与右侧题号)。这一部分信息并没有预先放到redis里(应该是修改的时候漏掉了)。于是针对这一部分的逻辑进行修改,将需要获取的信息预先放到redis里。同时对代码进行了一次彻底检查,将一切可以缓存的数据都进行redis处理。

     

    在做完代码层面的检查修改后,考虑到只配置1台应用服务器与1台数据库服务器的情况下,即便优化也可能支持不住,因没有负载方案。于是大家决定将这2台服务器配置升级(由4C16G升级至8C32G),同时将应用服务器进行多机负载、将redis与消息消费程序单独分拆部署,尽量避免出现一机部署多应用(指消耗资源高的应用)的情况。具体来说如下图:

     

    图 4考试系统部署图(优化调整后)

    优化调整后的部署方案包括8台服务器,具体如下:

    ——主应用服务器:用于部署网关,同时使用Nginx做了负载配置,访问该服务器的请求会被均匀分散到其他应用服务器上;

    ——应用服务器1-4:用于部署前端+后台接口;

    ——redis服务器:用于部署redis+消息队列服务;

    ——消费服务器:用于部署入库消费程序,完成考生答题结果入库;

    ——数据库服务器:用于部署oracle数据库,持久化存储全部数据。

    在新的部署方案下,如果这4台应用服务器出现了资源瓶颈,那么我们可以通过阿里云快速加入新的负载服务器来进行压力分担(通过在网关配置Nginx负载等)。考虑到2500人的规模对网关、redis、数据库的压力并不大,所以上述服务器没有再进行负载。

    在完成重新部署之后,我们又联系了第三方测试机构对系统进行了一次相对全面的压测,结果很顺利,通过了2500的严格并发。在这次测试过程中,我们也发现了我们自己的压力测试其实是有问题的,就是应该采用完整连续模拟方式进行测试脚本准备;而我们之前做的独立的接口测试,由于token验证的问题导致接口请求被拒绝,实际上反映的性能结果是失真的。

    3.2.   第二次模拟考试

    经过连续2天的分析与问题排查,增配了服务器进行了部署方案的优化,再加上在模拟考试前请第三方测试进行了一次压测顺利通过,大家又重新点燃了信心。第二次模拟考试时间为8月17日上午10点。这一次大家在会议室将阿里云服务器运行监控投在大屏上,虽然觉得应该没问题,但是还是挺紧张的。随着10点开始答题,考生均正常答题操作,系统显示各项指标均正常,我们的业务人员手机也没怎么响,大家的紧张情绪终于释放了。这次终于成功了!

     

      

    从以上监控图可以看到,主应用服务器最高cpu只在30%左右、redis服务器、数据库服务器cpu也稳定在30%、4台负载的应用服务器cpu都未超过20%;主应用服务器与redis内存稳定在35%;数据库磁盘io操作也很稳定,读操作基本没有,写操作平直稳定;tcp链接没有居高不下的情况,稳定在低位。

    之后就是在本次测试过程中发现的其他一些完善性的修改,基本不涉及到性能调优,这里就不在描述了。

    到了正式考试,大家已经彻底放松了。整个过程也与大家的预料一样非常顺利,只是在计算分值的时候因为性能问题出现了一点小瑕疵,留待后续改进。

    4.     总结

    从整个过程来看,整个团队无疑是收获了很多,主要是这么几个方面:

    一是团队收获了自信心。大家以前对于高并发没有实际经验,只是大致了解有哪些内容需要做准备,通过这次实战,非常清楚地知道了要从哪些方向去找问题、解决问题。包括测试准备、研发调优;具体来说,主要有这么几点:

    ——在方案设计实现阶段,应该对要求的并发规模进行预估,其实只有先确定用户量级,才会有对应的实现与部署方案。如果一开始就只要求2500人并发,那么再要求升级到10w人的并发可能就需要进行彻底重构;

    ——业务层面的提前准备:包括提前组织用户对系统进行试用(基于真实部署环境)、收集系统优化建议等,这一步很重要;

    ——在测试前,研发应该对涉及到性能部分的各个关键环节代码开展自查,避免出现遗漏导致意外状况;

    ——尽可能不要出现可能出现单点故障的部署方案。每一层尽可能都可以实现弹性扩容;

    ——测试一定要做到位,合格的测试非常有利于提前暴露真实问题;

    二是团队为公司赢得了荣誉。不管是业务还是研发的同学,大家都为了系统顺利上线付出了极大的精力,2个通宵没有合眼、连续3天奋战,最终换来的是系统平稳运行的结果,以及领导的肯定与表扬。这确实是有付出就有收获;

    三是验证了使用公有云进行部署、使用微服务进行系统架构的思路是正确的。可想而知,如果没有基于公有云模式进行部署,相关的服务器资源不可能很快就调整到位,甚至连监控发现问题可能都没有抓手;同时如果没有通过微服务进行系统架构,在做应用负载的时候将会非常麻烦。这为我们在其他类似项目中进行架构弹性扩容提供了借鉴。