《看运维如何拯救一个百亿互金平台》要点:
本文介绍了看运维如何拯救一个百亿互金平台,希望对您有用。如果有疑问,可以联系我们。
多年前,又是周六客服打电话过来,平台官网不能访问,app完全无法打开,客户在QQ群和微信群中各种反馈,说平台是不是跑路了?客服的多条400热线完全被打爆,电话已经接不过来…
一直以来总是想以什么方式去记录下自己在互联网金融行业的这段经历,趁着自己还记得清楚,还能找到一些资料原型,一方面可以分享出来供大家参考,但是更重要就是多年以后可以根据这些文章回忆起自己的那段激情岁月.
想了很久但一直没有实施,后来觉得应该从架构的角度来梳理一篇文章,就写了《从零到百亿互联网金融架构发展史》(http://t.cn/RMSnjub)这篇文章;
最后认为只有实战出来的东西和解决问题的过程,才是工作中最宝贵的经验,应该把它分享出来,在梳理的过程中觉得有三起事故比较有代表性就整理出了下面这三篇文章,本篇文章从整体来回忆一下一路走过来所经历过的救火故事.
作为一个互联网金融平台,涉及到用户资金,任何的服务(资金)差错用户都是不可容忍的,用户不懂什么是数据库,不管你什么网络不通,哪怕只是一小会儿,看不到钱在 App 里面展示都会觉得不安.
在已经有很多 P2P 公司跑路的前提下,用户个个都被锻炼成了福尔摩斯侦探,每天打开 App 查看收益,监控着平台的一切,甚至半夜升级断网十分钟,都会被用户察觉,直接就发到群里面,更有甚者直接在 QQ 群或者微信群中开骂:你们的技术行不行?
我们常说的互联网工作经验,一方面是开发经验,但其实更重要的是处理问题的能力.那么处理问题的能力怎么来呢?就是不断的去解决问题,不断的去总结经验,这其中处理生产环境中的问题获得的经验最多.
因为在处理生产环境的问题时,对个人的压力和临危应变的能力要求最高,你不但需要面临千万个用户的反馈,还要面对客服不时的催促,甚至旁边可能就站了 N 个领导在看着你,一副你不行就给我滚蛋的样子,要求立马解决问题!这个时候你的操作就要非常谨慎,稍有不慎便会引发二次生产事故.
说了这么多,只是想说明,生产事故对技术综合能力要求颇高,更是锻炼处理问题能力的最佳时机!
下面给大家介绍我们从零开始大家,到现在可以支持百亿交易量的平台所遇到的几次关键事故,有大也有小,挑出一些比较有代表性的事件跟大家分享.
公司系统刚上线的时候,没有经历过大量用户并发的考验,结果公司做了一个大型推广,涌入一批用户来抢标,共1000万的标的,几乎在10秒之内就没了.
有上万用户同时去抢标,平均每秒就有几千的并发,满标控制这块因为没有经过大的并发测试,上来之后就被打垮了,导致得结果就是:1000万的标的,有可能到一千零几万满标,也有可能九百多万就满标了,也就是说要么多一些,要么少一些.
这就很尴尬,因为用户借款一千万整.如果多出来,就得给他退了,但是用户好不容易才抢上了,无端退了用户会投诉;如果少了,比如用户借款一千万,少了几十万那也不行.少了的还好说,可以想办法找一些有钱的客户直接给买了,但如果多了,就必须重新放出来让用户投资,非常影响士气,这个问题困扰了我们有一段时间.
下图是购买标的流程图,不知道大家是否能根据此图发现问题呢?
为何会产生超募?在最早前的版本中没有使用乐观锁来控制,如果在最后购买的用户一单出现并发,就会出现超募,比如最后剩余30000份的购买份额.
因为并发量特别大,可能同时会有十几个用户拿到了剩余30000份余额的可购买额度,有的买1000份、有的买上3000份、有的买上20000份都会驱动满标,所以最后导致了超募.
针对这个问题,引入了 memcached 乐观锁的概念(底层主要是cas、gets两个命令),在发标的时候存入标的总份额,当用户购买的时候首先去锁定用户购买的份额.
因为乐观锁的原因,如果同时有两个用户拿到份额的时候保证只有一个最后可以更新成功(锁定份额),(锁定份额)失败直接返回,这样就保证了在入口的时候就直接屏蔽了部分并发的请求.
为何产生少募?少募是可能1000万的标的突然到980万就给满标了,这是因为在超募情况下我们完善了代码,用户一进来首先就是锁定购买份额,只有锁定购买份额才能进行下面的流程.
如果锁定购买份额失败直接返回,这样虽然保证了在1000万份额在购买初期必须每一个用户只能锁定一份,但是在高并发的情况下,因为购买流程中有十几个分支,每一个分支失败就会退回锁定的份额,就会导致这样的现象,可能并发一上来,马上就满标了,过了一会进度又回退回来了.
少募主要是因为分支失败回退导致的,一方面我们分析了容易导致回退的热点,因为在用户抢标的时候会给用户实时的展示标的进度,在很早的版本中直接就是存入到一个标的进度表里面,并且采用了乐观锁.
如果并发一高就频繁的更新失败导致回退,因此优化了标的进度这块,直接去掉了标的进度表,实时根据查询来展示标的进度(可以有延迟,有缓存);
另一方面在回退份额的时候再次判断试下 memcached 的份额和标的的状态,如果份额不为零并且标的状态是满标,马上自动更新状态保证后续用户可以立即购买再次驱动满标.
做了以上的两种优化后,我们还遇到了很多的小问题,但是在不断的优化过程中,终于稳定下来;在后期版本中将考虑使用 MQ 队列或者 Redis 队列来处理抢标,这样更合理,对用户也更公平一些.
2015年应该是互联网金融行业受黑客攻击最多的一年吧,各互金公司都深受其害,当时我记得*贷之家有一段时间被黑客攻击的太厉害,连续几天网站都无法打开.
当然我们也未能幸免,DDoS 攻击、SQL 注入、漏洞渗透等等,几乎都经历过,有的黑客比较仁慈,应该是出于善意或者展示自己,将漏洞放到乌云上面或者漏洞盒子里面让厂商来修复.但更多的是一些黑产,完全就是威胁、敲诈、想捞一笔钱,先看看下面这位吧:
这个家伙潜伏到我们公司的客户群里面,冒充我们的客户代表将头像和资料替换成一样,然后给群里所有的客服发消息,让发送我们内部的后台地址给他,想通过这种方式来寻找突破口,当然这是里面的小菜鸟.
DDoS 攻击我们也遇到了很多次,确实没有比较好的办法,最后都是通过一些笨办法来尽量避免的,先说说我们的经历吧.
有一次我正在敲代码,客服 QQ 又闪烁了起来,还没来得及打开查看,客服的经理就直接打电话过来了,我立刻一种不祥的预感,他说官网打不开了,后台也登录不了.
挂了电话,我在本机进行了测试,果然不行,立刻准备登录 VPN 查看服务器各项指标,结果登录不上去,马上上楼找运维经理,他也登录不上,刚准备给机房打电话的时候,机房来电话了,说我们的一个 IP 正经历着 1G 多的流量访问,问我们是否正在做什么活动,话没说完,就又说流量已经到 5G,不到一分钟之后流量已经到达 18G 之多.
因为我们的机房和集团公用了一个入口,结果集团上面陆续反馈他们的网站、服务也都出现了问题,机房方面害怕引起更大的冲击,直接把我们官网对外的IP封掉了,集团的其它业务才慢慢恢复了过来,我们也紧急更换了外网IP,重新切换了域名解析后才恢复.
事后我们根据 Apache 分析了日志,流量来自N多个不同的IP地址根本无法应对,也是因为这次攻击,我们领导重视了起来,将我们公司的机房网络层和公司集团彻底分离.这样不管哪一方受到大流量攻击都不会相互影响.
当然我们也想了一些笨办法,因为上次我们更换了外网 IP 之后攻击也就停止了.那么我们认为肯定是针对我们外网来的,所有我们就准备了多个外网 IP,当监控到某一个外网IP被攻击时,马上切换到另一个外网IP,这样可以起到非常有限的一点作用,因为如果黑客真的想跟我们玩,这个办法就像是小孩子捉迷藏.
还有一次我们正在做周年庆活动,突然有人在 QQ 群里面给我们客服说:叫你们的技术负责人来找我.然后我们的网站就挂了,我还保留了当时的一个截图如下:
黑客:你是平台的技术负责人吗?
我:算是吧
黑客:你信不信我可以让你们官网在5秒之内挂掉?
我:…(沉默,还真害怕又把官网搞挂了)
黑客:你们的官网漏洞很大
我:如果有好的建议请您赐教
黑客:你们的服务器是不是什么防护软件都没有装?
我:…(继续沉默,这会在想不会是那个安全厂商来推广产品的吧,当然我们基础的防护肯定有)
黑客:我们有非常多的肉鸡,想攻击谁,几秒之内肯定搞定
我:…
黑客:我们已经给很多互联网金融行业做了渗透测试,花点钱帮你们摆平,保证以后不会再出事情
我:…
黑客:免费的策略也有很多,比如 360、百度云的安全产品可以免费抵挡10G 左右的流量……(中间省略)
黑客:我说了这多,你们是不是给包烟钱,表示表示?
……
后来也和领导进行了商议,坚决不能给他们钱,不能助长这种嚣张气焰,实在不行就报警!
曝光一下当年使用的假 QQ 号,刚查了下变了个头像和描述,如下:
后来我一直在想:为什么 DDOS 攻击总是喜欢根据外网 IP 来攻击呢?后来慢慢有些理解了,如果针对域名来攻击的话,那不就是攻击到域名商的服务器了吗?而一般域名商比较强大,黑客不太搞的定,也确实没有必要.
当然记的前一段时间,某著名域名服务商被攻击,导致国外 Twitter 等著名的互联网公司访问中断达半天以上,还是很严重的.但是对于我们这样的小公司,倒不至于搞这么大的动作.
那到底如何正确的防止 DDOS 攻击?根据我的个人经验总结了几条:
- 第一种方案:隐藏服务器外网地址,服务器前端加 CDN 中转,免费的有百度云加速、360网站卫士、加速乐、安全宝等,如果资金充裕的话,可以购买高防盾机,用于隐藏服务器真实 IP,域名解析使用 CDN 的 IP,所有解析的子域名都使用 CDN 的 IP 地址.
此外,服务器上部署的其他域名也不能使用真实IP解析,全部都使用CDN来解析;- 第二种方案,买一些安全产品来进行流量清洗,主要是阿里云、腾讯云这种大厂商提供的服务.
- 第三种方案,有很多的防火墙产品声称可以防止 DDOS 攻击,但是我个人使用感觉效果非常有限.
我们的官网使用的是 PHP 开发,因为框架比较老旧的原因,存在着一些 SQL 注入的点,我们发现后进行了修补,没想到还是被一些黑客找到了突破点.
这里要感谢这些黑客在漏洞盒子上提交的 Bug (如下图),最后我们根据提示进行了紧急修复,后来我们也在 WAF 防火墙配置了一些拦截 SQL 注入的策略,起到双保险的作用.
我一直在想为什么 PHP 一般比较容易出现 SQL 注入,而 Java 较少呢?我估摸着有两方面的原因:
通过一段时间的学习,我发现,黑客一般先使用工具对网站做整体的扫描,类似 Acunetix,再根据扫描出来的漏洞做个大概的分析,但是比较深入的漏洞都需要根据网站的业务再进行调整,比如 SQL 注入会根据页面的查询使用 sqlmap 等工具来进一步的渗透.当然我对这方面还是外行,描述的不够清晰.
其它方面的攻击,主要是在业务方面,比如我们当初有一个很小的失误,有一个程序员在 H5 的网页中将发送短信验证码返回了前端,最后被黑客发现了,利用这个漏洞可以给任意的用户重置登录密码;
短信攻击,现在的网站几乎都有发送短信或者短信验证码的功能,如果前端不做校验,黑客会随便写一个 for 循环来发短信,一般系统的短信会进行全方位的防控,比如:
2015年的某一天看到一个新闻说是陆金所的一个用户发现自己银行里面突然多了很多钱,没过多久又被扣走了,然后收到陆金所那边的解释,说是给用户还本派息的时候程序出现了问题导致还本派息两次.
当他们程序员发现了此问题后紧急进行了处理,用户当然闹了,也上了新闻,当然陆金所通道能力确实比较强可以直接从用户卡里面扣,当大家都兴致勃勃的谈论这个话题的时候,我却有一股淡淡的忧伤,为什么呢?
因为这个错误我们也犯过,具体说就是我搞的,大家不知道我当时的心里压力有多大!
事情是这样子的:我们使用的第三方支付的扣款接口不是特别的稳定,于是我们前期就对接了两种不同的扣款接口,平时前端投资的时候走一个接口,后端派息或者还本的时候走另外的一个接口,在初期的时候扣款接口不稳定,因此在给用户派息的时候经常会有个别用户失败,需要手动给失败的用户二次派息.
做为一个有志向的程序员当然觉得这种方式是低效的,于是将程序改造了一下,在后端派息的时候当第一种扣款失败的时候,自动再次调用第二种扣款接口进行扣款,当时想着这种方式挺好的,各个环境测试也没有问题,上线之后监控过一段时间也运行稳定.
当感觉一切都很美妙的时候,事故就来了,突然有一天,客服反馈说,有的用户说自己收到的利息感觉不对,好像是多了(真的是太感谢这个用户了),我登录后台看了一下派息的流水,复核了一遍,果然利息被重复派了,感觉一盆冷水从头而下.
我把当天所有的用户派息记录和到期记录都进行了检查,发现影响了70多个用户,导致多派息了6万多元,幸亏只是派息出了问题,如果是到期的话,金额会翻N倍,其中70多个人里面有几个进行了提现、几个进行了再次投资,绝大部分用户在我们发现的时候还不知情,金额也没有动.
怎么处理呢,当然不能直接就动用户的钱了,只能给每个重复派息的用户打电话,说明原因并赠送小礼物,请求谅解后,我们把重复派过的利息再次调回来.
大部分用户进行了核对之后都还是比较配合的,当然肯定有一些用户不干了,但你也不能怪客户,因为都是我的原因.有的客户需要上门赔礼道歉,有的客户需要公司出具证明材料,我们的老板还亲自给客户打了N个电话,被客户骂了N遍,我心里压力可想而知.
其中有一个客户特别难缠,各种威胁,说既然到了我的账户里面,肯定是我的,你们的失误不应该让我来承担,折腾了很久,还是不能怪客户.
你可能会说有的互联网公司经常出现这种问题后就送给客户了,哎,可是我们是小公司呀!这个噱头玩不起.
到底是什么原因呢,事后进行了复盘也给领导做了汇报:平时都是首先进行派息的定时任务,过一个小时之后进行到期的定时任务,当天的派息标的比较多,跑了一个半小时,就导致了派息和到期的两个定时任务同时进行,转账有了并发,第三方支付的接口不稳定,给我们返回失败,其实有的是成功的,就导致了我们进行了二次的扣款尝试,引发了此问题.
这个事情给我带来了非常大的教训,对于金融扣款的这种事情一定需要谨慎,哪怕付款引发报警之后再人工处理,也不能盲目重试,极有可能引发雪崩效应.
还有就是其它一些零碎的问题了,记的有一次对用户的登录过程进行优化,导致有一块判断少了一个括号,结果用户在那两个小时内,只要输入账户,任意密码就可以登录了,幸好及时发现这个问题,正是这个问题才导致了我们正式确立了规范的上线流程,为以后的上线制度奠定了基础.
还有一次我们在模拟用户投资一种标的时候,留了一个入口通过 http 就可以调用,测试也没有问题,有一天正好给领导演示呢,就再次用 http 请求的方式在浏览器执行了一下,前端就会看到自动投标的过程.
因为生产的数据有点多,投标的过程有点长,我们为了加快进度,找了好几个人同时来执行这个 http 请求,导致最后出现了问题,最后发现写测试脚本的这个同事根本就没有考虑并发的情况,才导致出现了问题.
也做了很多的活动,记得做一个网贷之家的一个活动的时候,活动上线比较紧张,我们团队曾经连续工作超过30个小时(一天一夜再一天),当天晚上我2点左右写完程序,测试从2两点测试到早上9点,最终确认没有任何问题,才进行投产.
半夜公司没有暖气,我们实在冻的不行了,就在办公室跑步,从这头跑到那头,第二天上线之后,又害怕出现问题,监控了一天,确认没有任何问题,才到下午正常下班回家,那时候真是激情满满呀.
说到做活动肯定少不了羊毛党,哪一家互金公司没有遇到过羊毛党?而且现在的羊毛党规模简直逆天了,我们用户里面就有一个羊毛党在两三天之内邀请了六七千位用户,如果邀请一个用户送1元,那这个用户就可以搞几千块一次.
而且有很多专业的网站、QQ群、微信公共账号都是他们的聚集地,那天那个平台有活动门清,他们写的淘羊毛操作手册有时候比我们官网的帮助文档还清晰,所以做活动的时候要考虑特别周全,各种限制,有封定、有预案、讲诚信,只要是符合我们活动规则的坚决按照流程走.
还有一个有趣的事情,是App 推送,一次我在公交车上就看到某盒子 App 弹出 XXX 的推送,这个事情我们也搞过,因为在调试的时候生产和测试就差了一个参数,有时候开发人员不注意就把生产参数部署到 uat 环境了,测试一发送就跑到生产了,这方面只能严格流程管理来防止了.
其实还很多问题:mongodb 集群和 mysql 的同步出现的状况、后台大量数据查询下的 sql 优化、golang 使用 mapreduce 碰到的问题… 限于篇幅这里就不一一描述了.
其实每次出现问题都是对团队一次非常好的锻炼机会,通过发现问题,定位问题,解决问题,再次回过头来反思这些问题,重新梳理整个环节, 举一反三避免下次再次出现类似的问题.
正是因为经历这种种的困难、考验才让团队变的更强大、更稳定,也更体现了流程的重要性,更避免了再次发生类似问题.
古代对将军的要求是,心有万马奔腾,面如湖水平静,在互联网行业,对领导的要求也如此,特别是技术负责人,在面对生产事故的时候,一定是先安抚同事,静下心来找到问题本质,再去解决,而不应该不断去施加压力催促,重压之下很多心里承受能力稍弱的队友,会更加慌乱,不但不利于解决问题,还可能引发二次事故.
在看淘宝双十一视频中,有一段感受特别深,在双十一初期,虽然技术团队做了很多的准备,但是在零点过后流量瞬间涌入,服务被打垮,部分用户投诉刷新不出网页,紧接着隔壁同事也都反馈网站打不开,在大家都在慌乱中,XX一拍桌子大喊一声,大家都别动,三分钟之后再说,过了几分钟之后服务慢慢恢复了正常.
后来回忆说,当时虽然服务瘫痪,但是监控到有部分业务成功,说明系统并没有被压垮,而此时的任何操作都有可能引发更大的问题,从此之后此人一战成名,成为阿里大将.
互联网平台发展大抵都会经历三个阶段:
第一,小公司很难做到生产环境和测试环境一致,成本太高;
第二,时间紧迫,一般都是很短的时间内要求上线,上线之后再快速迭代;
第三,互联网本就是一个快速试错的行业,错过半年时间可能风口早过;
所有的这些问题几乎都集中在14年底到15年初的这个阶段,15年后半年开始到现在,平台慢慢稳定了下来,到现在几乎没有再出现过类似的问题,也因为几乎都是两年前的事情,有很多记的不是特别清楚了,写的比较粗糙望见谅.
本文转载于:http://www.ityouknow.com/
作者:纯洁的微笑
转载请注明本页网址:
http://www.vephp.com/jiaocheng/4335.html