从单体开始的架构演进

背景:因为公司业务发展,销售玩法已经不满足於单纯的下单平台,玩起了“惊心动魄”的秒杀活动,然而服务端并不能承载这么高的瞬时流量。表现在于数据库意料之中的挂了,被打的起不来,于是部门同事说:“数据库压力太大,可能配置没有整好,我们需要换阿里云的!”

可能是我太年轻,见猎心喜,这不正好是《大型网站技术架构:核心原理与案例分析》中架构的演进吗?为了避免大家在错误的道路上越走越远,于是我提出给大家做一次技术分享,干活儿之前统一思想,我党的优良传统~

“架构是演进的”—这句话相信不少开发都听过,但是究竟什么是架构,很多人都没法说明白。有幸在一家“大”公司的技术部做后端开发,更有幸经历了从单体开始的一次架构演进,下文是我在公司部门技术分享的内容。

大纲:

  1. 什么是架构?

  2. DB裸奔时代。

  3. 引入Cache扛读。

  4. 引入MQ削峰填谷。

  5. 关于秒杀。

一、什么是架构?

本文开始之前,我想问一下大家,你觉得什么是架构?

(此处思考三秒钟🤔)

先不急着回答,我们先看看考量一个架构好坏的五个指标:

  • 高性能

  • 高可用

  • 可伸缩

  • 可扩展

  • 安全

—《李智慧:大型网站技术架构:核心原理与案例分析》

  1. 高性能:有QPS和TPS很多指标,但我个人更倾向于从用户角度去理解,也就是给用户响应时间的快慢。

  2. 高可用:就是服务的可用性,我们常说的99%,99.9%,99.99%就是在一年的时间里,停机的时间要分别低于3.65天,8.76小时,52.56分钟。

  3. 可伸缩:一个架构师及格线就在于他实现的架构是否是可伸缩的,也就是当业务量突然爆发的时候,我们能不能通过简单加机器的方式来保障服务性能和可用性。当然,不需要的时候直接撤掉机器即可。

  4. 可扩展:基础设施不需要经常变更,松耦合,通俗的来讲就是我现有的架构是一辆车,我在车上装一些东西,不需要改造我的车就能完成。

  5. 安全:这个不用多说,但是常常被人所忽视~

看完以上五个衡量架构好坏的指标,你有没有对“架构”这个词有了新的理解?不急,我们继续进行下一步,单体架构的演进!

二、DB裸奔时代

大部分公司都是从无到有,从小到大慢慢的做起来的,架构是不断演进的,也就是说架构是符合当前业务实际需要的,太超前浪费资源,落后肯定完球呗~

场景:初创公司业务量小,用户量也小,无需过于复杂,单体+DB直接扛就行了。

图一·应用基本架构
图一·应用基本架构

上图是一个再简单不过的基本架构图,省略了web前端和移动端。一个Nginx做反向代理,单体server,MongoDB一主一副本一投票。这个架构对于一般的初创公司是毫无问题的,但是随着业务量和用户量的日益增多,对于一些热点功能和突发情况,越来越力不从心。

大流量过来直接打在数据库上,先挂的肯定是数据库,一个正常的思路是DB不行了,咱们换一个DB嘛~然而这个思路真的可行吗?

显然不可能,就像我需要去摘二层楼高树上果子,我不是要让自己长得更高一点,而是需要一个梯子~

这个时候架构的演进就开始了~

三、引入Cache扛读

**读瓶颈:**据不完全调查统计,互联网应用特性之一是读高于写,大概10:1?的比例,多少记不清了,反正大部分公司都是读先于写出现瓶颈。所以我们首先要解决的是读的问题。

图二·引入Cache后
图二·引入Cache后

无论是Memcache还是Redis都是非常优秀的高性能内存型KV数据库,官方数据表示Redis读的速度是110000次/s,写的速度是81000次/s。远远超过DB的读写性能,显而易见,比起更换DB使用cache缓存扛读才是性价比最高的解决方案。(PS:比之MySQL的读写分离,MongoDB官方不建议使用读写分离,更建议使用分片技术。)

这里注意几个点:

  • **缓存穿透:**就是读cache的时候没有发现数据,转而请求数据库。这个叫缓存穿透,有个攻击手段就是攻击者故意请求一个根本不存在的数据,此时肯定要去DB中取数据,流量还是打在DB上,Cache没有发挥作用,一旦并发量过大,DB压力会很大,解决办法之一就是一旦查询DB没有,就返回空值进行缓存。

  • **缓存雪崩:**是指大批量数据到过期时间,而此时查询压力过大,DB很可能会挂!解决办法是缓存设置不同的过期时间,热点数据不过期。

  • **缓存预热:**在Redis刚启动的时候里面显然没有数据,这个时候需要缓存预热,通过手动,或者程序脚本的方式,将数据预热到缓存中。

四、引入MQ削峰填谷

随着用户量进一步增多,原来没有压力的写也变得有问题了,这个时候就需要引入MQ—消息队列,来削峰填谷,消息队列的特性之一就是生产者生产消息,丢入消息队列,消费者从消息队列取消息,处理完了继续取,不存在DB写任务太多,被压死的情况。
图三·加入消息队列
图三·加入消息队列

还有一个原因在于,在我司秒杀活动中,巨大的瞬时订单写入请求,用户支付完成后,DB挂了订单数据不一致怎么办?我觉得这是个致命的问题,但是我司没有出现这样的情况。

五、关于秒杀

关于秒杀活动设计网络上帖子一抓一大把,在这里我只挑重点说明,不再详细赘述。

秒杀业务和高并发小异大同,都是高并发,但是秒杀活动是瞬时流量高,**最最关键的还是在于:秒杀活动,大部分流量都是无效流量。**因为活动商品数远远小于参与活动的用户数,抢不到很正常,弄明白了这一点就什么都好办了。

专业术语:随机不请求

前端!

1. 动态页面静态化,善用CDN。

2. 随机丢弃请求,取随机数0-100,取在1-10的请求提交服务器,剩下的告诉用户“秒杀中···请等待”,实则秒杀失败,这样就过滤掉了90%的流量,我们的server 非常安全!

但是!我们要做的还有很多:

  1. 活动开始前跟市场运营人员预估参与活动人数,大概过滤多少比较合适,知彼。

  2. 进行压力测试,看看自己系统能够扛住多少的并发量,找出系统的薄弱环节,进行优化,知己。

  3. 无他,加机器。

子曰:知己知彼,百战而不怠。

尾声:

非常有幸能够见证一家公司架构上的演进,也非常荣幸能够参与到这个过程中,贡献自己力量,这是一个后端工程师莫大的荣幸。

因为公司业务的不断发展,需求部门涉及市场,供应链等多部门,项目功能重合,不断开发已有业务而不能很好的整合。

对此,虽然我才疏学浅,但是于上周还是为部门同事做了一次有关于《SOA与微服务》的技术分享,讲明我司技术部遇到的问题,应该如何解决。后文我将继续写文分享出来,供大家参考。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章