某618大促项目的复盘总结

1、前言

618期间上线一个活动项目。但上线不顺利,当天就出现了性能问题,接口超时,用户没法打开网页,最后不得的临时下线。花了三天两夜,重构了后台核心代码,才让活动进行下去。前端

回头看了一下本身的时间记录,从5月31号那天晚上8点25分开始准备上线,发现异常,分析缘由,重构代码,离开公司时已是6月2号的23点54,经历51小时29分,中间的睡眠时间不到5个小时,这已是爆发小宇宙了。redis

这一波刚过去了,一波未平另外一波又起,因为活动的奖励丰厚,大批羊毛党闻风而至,某宝上公开卖脚本的都有了,严重影响了正经常使用户薅羊毛。数据库

某客户反馈说:咱们别说薅羊毛了,如今是整头羊都被他们牵走了!后端

接下来的几天,又得和薅羊毛的脚本们斗智斗勇,直到活动结束。缓存

而本文就对此作一次深度的复盘,在之后的项目中让本身快活一点。服务器

2、一份看似完美的项目总结

当咱们复盘项目过程时,能找到不少问题点,好比:并发

  1. 人力不足,需求过于复杂,开发和测试工做量大。分布式

  2. 先后端开发、测试都是从其余团队抽掉的,对当前项目的业务和技术不熟悉。高并发

  3. 跨团队组建的临时团队,职责定义不清晰,项目管控不严格。性能

  4. 开发对项目的用到的技术不熟悉,没有通过原有项目成员的CodeReview。

  5. 测试经过太草率,压测方案设计不合理。

....

列出问题后,很快就能一一写出改进点。

  1. 从公司层面增强的总体项目安排,避免重复玩法的项目,资源投入到重点的几个活动中。

  2. 增强团队的能力培养,总结文档,供新人学习。

  3. 对于核心代码进行CodeReview,遇到问题时,项目经理协调资深开发协助解决。

  4. 将临时组建团队职责定义清晰,各负责人沟通清楚。

  5. 严格控制测试质量,测试有上线的否决权。

...

这些总结看起来一点问题没有,列出了问题,也列出了改进点,甚至能够当成样板去使用了,是否是我们就这么结束了呢。

固然不是, 它自己的说法没有错,错在把问题的前提看成问题的缘由。

咱们来看两种表述。

  1. 下次咱们要组建一个经验丰富的项目团队,避免质量问题发生。

  2. 当下次咱们面临一个临时组建,经验不足的项目团队时,如何避免质量问题发生。

这两种表述的差别在哪?

前一种表述是由于咱们“团队”的缘由,致使了本次质量问题,因此咱们要解决“团队”的问题。

然后一种是咱们的团队就是临时组建的,咱们的开发、测试就是对新项目的业务和技术不熟悉,在这个前提下,才会出现质量问题,那么在这个前提下,怎么避免质量问题呢?

临时组建,经验不足不是问题的缘由,它们是出现问题的前提,这是客观存在的。

这就比如咱们说解决一个问题时,最快的方式是,咱们不解决问题,解决出问题的人就好了。

在这里不就变成了,咱们不解决问题,解决出问题的团队就好了。

正是由于这个误区,咱们不少时候一出现项目质量问题,就把锅甩给咱们团队的协做有问题,或者咱们的项目时间紧张,而后一句下次改进就结束了。

这样的万能回答,看似一点没错,但每每就无法落地了。

明明项目时间紧,新团队协做经验不足原本就客观的存在,没有它就没有问题,怎么能够看成问题自己给解决掉呢。

一、质量问题的关键缘由

带着这个前提,咱们再回头看前面的总结,其实就能过滤出真正有价值的点了。

咱们也能够这么问,问题是不能避免的,但为何在项目过程当中咱们的性能问题没有暴露出来?

三个角度:

  1. 从项目角度,没有严格按项目流程来,特别是最后测试任务紧张,bug较多时,赶工给出了测试报告。

  2. 从开发角度,没有找熟悉业务和技术的同窗作CodeReview。

  3. 从测试角度,压测方案设计不合理,不符合真实场景。

逐一分析下。

前面提到事故是后台的性能问题,从项目角度,就算流程严谨也无法暴露出性能问题,特别是在项目过程当中,已暴露的风险是前端人力不足,中间加了人手,从功能的角度,后端进度彻底正常。

再看开发角度,这里我没有提开发的经验不足,不是在推脱责任,这同咱们做为一个临时团队对业务的经验不足同样,它是一个客观存在的前提。当你接触新项目,使用新技术时,经验不足是确定存在的。

问题是在自身经验不足时,如何去完成任务,那么和熟悉业务和技术的同窗作CodeReview是主要的手段。

再从测试角度,功能测试是没有问题的,但跟性能相关的压测方案是有问题的,而且一开始就没有引发正视。最开始的压测方案是开发只出接口和参数文档,直接丢给测试去压,如今看来,这是错误的。

所以,此次质量问题的关键总结以下。

当下次咱们面临一个临时组建,经验不足的项目团队时,面对大流量的业务需求,开发们须要注意:

  1. 让熟悉业务和技术的同窗帮忙作CodeReview。

  2. 设计出符合业务场景的压测方案。

这两点就能够落地了,这也不是说项目管理上没有改进的,而是优先保证这两点,能更有效的下降风险。

CodeReview的技巧这里就很少少说,来谈谈咱们作的几回压测方案的改进。

二、三轮的压测改进

  1. 单用户,单接口,双机压测

  2. 随机用户,多接口,全量压测

  3. 随机用户,功能分组接口,全量压测

最开始压测方案是用一个用户,两台服务器,一个缓存分片作压测,而后简单的用服务器QPS的均值乘以线上部署机器数量看成压测结果。

这个方案若是是下图左侧的场景,调用链路上的服务器能够同时弹性扩展天然是能够的。

但要是右侧的场景,调用链路上存在瓶颈,好比数据库是一个节点,而且没法扩展,那就问题了。

一样的,此次项目的问题就是Redis成为了一个单节点的瓶颈。另外因为用户id是固定的,因此缓存极可能被重复使用,这样就难以测试到频繁建立缓存的场景。

在系统重构后,改进了一种压测方案,经过随机用户Id,批量轮询接口,而且经过测试环境的弹性扩展,彻底模拟线上的部署环境

还经过加降级开关,把入参合法性、风控、时效性校验等临时关闭,以便能让压测的请求贯穿整个主流程。

接着在这一方案的基础上,经过对接口分组和伪造恰当的数据,编写贴近真实的调用行为的脚本,再次作了压测。

在执行人员上,也经历了从开发提供数据,测试全权负责;到测试主导,开发参与;再到开发主导,测试协助的过程。

由此,压测方案就愈来愈贴近真实场景,压测结论天然就更加可信 。

三、高并发场景下的设计

前面谈到了系统设计的不合理致使了本次性能问题,来分析下这里面的根本缘由。

首先要理解的是,Redis集群是由多个分片构成的,一条数据被写到哪一个分片里,是由key的hash值来离散的。

好比说,咱们要在Redis里面缓存一批用户信息,而且能经过ID来存取。

若是用Redis自带的Hash表结构写法以下:

存:redis.hset("userMap",ID,userInfo)

读:redis.hget("userMap",ID)

那么,由于key是固定的userMap,这意味着全部的用户信息都会被写到一个分片里。

而对于一般的分布式系统的设计,一个基本原则是:让流量尽量的被集群的机器平摊。

固定的key就没法利用分布式的优点了,而且若是并发量高,这就会让一个分片去抗全部的流量,再加上若是用户量数十万,还有一次性读取全部数据的操做,这样就变成一场灾难了。

实际设计时,直接把整个Redis集群看成一个Hash表的方式更加高效。

存:redis.set("userMap"+ID,userInfo)

读:redis.get("userMap"+ID)

这里的key="userMap"+ID,ID不一样key就被离散了,请求会集群平摊,从而充分发挥分布式系统的性能。

3、黑产和羊毛党的问题

在项目上线后另外一个没重视的问题出现了,那就是大量的黑产和羊毛党出现,活动奖励全被这些用脚本的人占据了。

对黑产的事前考虑太少了,仅作了简单的风控校验,根本检测不足异经常使用户,致使黑产能够经过脚本大量刷接口。

这里的经验有两点:

  1. 对包含现金、现金等价物或高价值奖励的活动,要有面对黑产的心理预期。

  2. 在大公司,专业的事情找专业的人作,基于业务场景,提早跟风控团队沟通好。

对于第一点,基本上只要值点钱的活动,黑产确定跑不了,空手套白狼,抢到就是赚到,不妨想一想若是你是黑产,结合下业务场景,你会怎么来刷本身的系统。

基于第一点,公司没有风控团队那就只能本身作了,而通常上点规模的公司都有本身的风控团队,利用好现成资源。

风控主要考虑两方面:

  1. 有风控团队的,接入他们的通用风控模型。

  2. 针对项目的业务场景,定制化一些风控模型。

通用风控模型基本是经过新老帐号、异地登陆、人机识别等等用户行为创建的用户画像,经过离线计算和实时校验来处理。

定制化模型视状况而定,好比拉一个单独的小黑户,放进去的用户不能参与这个活动等等。

被拦截的用户通常是走验证码或直接拉黑,对于后者,别忘了和客服的妹子们打好招呼,准备下话术应对客诉。

4、结语

最后总结下项目的经验。

首先是前提:

  1. 当你的面前的是一个临时组建,对如今项目经验不足的项目团队时。

  2. 当你面临一个大流量,包含现金或等价物的活动时。

请务必作好这三点:

  1. 找熟悉本项目的业务和技术的开发参与方案的设计和CodeReview。

  2. 请开发主动参与压测任务,设计压测方案,注意尽量模拟真实场景。

  3. 作好应对黑产的心理准备,直到大促活动结束。

来自于,一个连续加班51小时29分,被用户吐槽整只羊都被人家牵走了的开发。

相关文章
相关标签/搜索