那一天,我回想起被微众碾压的架构问题!

泪目,不堪回首!

博主毕业4年了,最近秋招开始了,每次回想起本身的秋招,都感受到当时本身特别的惋惜(菜是原罪),本身当时简历上面的项目,只有一个 农资电商平台,当时的秒杀系统尚未那么普及(简历人均秒杀系统)。css

第一次微众面试

当年本身的八股文背的其实还能够,可是本身的项目就只是一个单机系统,分布式微服务? 什么玩意?,还记得当时微众面试,是二面,在一个酒店房间,面试官笑嘻嘻的看着我,说让我先画一下我项目里面的农资电商平台, 我脑子嗡嗡叫,啥? 咋画, 就一个安卓系统,一个前端页面,和一个后台系统html

大概长这样子前端

image.png

我擦,这也太简单了吧, 我是否是该画复杂一点? 或者说,我这个能叫架构吗?就这样,犹豫之间,毛线都没有画出来... 我记得当时好像画了个这样子的玩意。。 毫无心外的,嗝屁了~mysql

这玩意有点四不像,不说了,丢脸~

image.png

第二次微众面试

第二次微众面试,毕业有快一年了,抱着试一下的心态,找了个师姐内推, 那时候我在干啥呢,在搞爬虫。公司离微众比较近,就在金蝶那边,下班了溜过去,跟面试官吧啦了一会八股文,好家伙,没一会就掏出了一张纸:git

来画一下大家如今这个爬虫系统的架构图!github

当时系统的部署架构长这样吧, 比上面的看起来还简单一点。面试

image.png

可是,我就是画不出手啊!!! 内心想着太简单了啊!! 这玩意能叫架构吗?redis

摊牌了, 我不会画!

如今想起来,真的太憋屈了,年轻啊! 那若是如今来回头看的话,能怎么画呢?sql

单体系统的部署架构图数据库

image.png

爬虫系统的分层架构图

image.png

爬虫系统的业务架构

image.png

架构图

从上面的各个方向描述架构来看,其实即便是单体系统 也可以画出不通常的架构图!(为啥当时我就不会呢!)

最近在看架构相关的内容(华仔的课),在4+1 视图里面,从多方面描述了咱们的系统,能够参考下面的描述,

image.png

你的秒杀系统,架构是怎么样的?

单体系统

无论大家简历吹的多牛逼,我猜大家的服务,大部分都是长这个样子的,猜对的话点个关注, 只有浏览器是分布式的。

image.png

那我该如何去描述个人单体系统呢?

架构设计的三大原则:

  • 简单原则
  • 合适原则
  • 演进原则

每一条原则都符合咱们大学作的秒杀系统啊!!

简单原则: 一个系统就能够知足咱们秒杀服务的全部动做,没有太多的中间件依赖

合适原则:在咱们的实践项目中,单体系统是最适合不过的了。(主要是没钱啊!拆分服务,引入中间件,部署集群,都得钱啊!)

演进原则:这个比较好理解,没有什么系统架构是一出生就定下来的,是随着时间,业务需求,不断演变出来的。

总结:

咱们架构的优点: 成本低系统复杂度低维护成本低快速定位问题

劣势: 稳定性差并发量低扩展性弱

在梳理架构时,每一个方案都有他的优点和缺点,因此须要了解你目前方案的优缺点。才能更好的向面试官展现你的系统!

服务拆分

好家伙,参加了个科创比赛,资金到位了,能买更多机器了,那不得将服务优化一下,拆分个微服务系统出来!

image.png

在这个服务拆分的架构中,咱们作了哪些动做?

  • 静态资源隔离(CDN加速
  • 代理服务器(Nginx
  • 服务拆分,应用独立部署
  • 服务rpc通讯 (rpc框架 & 注册中心

一、先后端分离

在单体系统中,咱们的静态资源(Html,JS,CSS 和 IMG)可能都是经过咱们服务端进行返回,存在的问题是:

  • 前端代码维护成本比较高(全栈开发成本也高)
  • 前端代码发布,须要整个系统进行发布
  • 服务器带宽请求资源占用等

那么经过先后端分离所带来的好处就很明显了:

  • 代码独立维护(低耦合),发布成本低(高效率)
  • 先后端经过接口交互动态数据
  • CDN资源访问加速,减小后端服务压力(高性能

二、反向代理

反向代理的做用比较明显, 因为咱们服务拆分红多个,那么咱们和前端进行交互时,须要提供一个通用的入口。而这个入口,就是咱们的反向代理服务器(Nginx)。 例如: 服务域名:https://www.jiuling.com ,根据restful规范,咱们能够经过 https://www.jiuling.com/user/1.0/login 将请求转发到 用户服务的登陆接口中。

3.进程间通讯

随着服务的拆分,在部分功能的实现上,就会涉及到服务间相互调用的状况,例如:

image.png

在常见的实现方案上,咱们会采用 注册中心RPC框架,来实现这一能力。而咱们比较经常使用的实现方案就是 zookeeper & dubbo

image.png

为何要使用 RPC 框架?

当咱们提到使用 RPC框架 的时候,是否有去思考过,为何要使用 RPC框架? 每一个服务提供 RESTful 接口,不是也可以完成服务间通讯吗?

这里就须要进行对比 RPCRESTful 的区别了:

  • 数据报文小&传输效率快RPC简化了传输协议中一些必要的头部信息,从而加快了传输效率。
  • 开发成本低:例如 Dubbo框架,封装好了服务间调用的逻辑(如:反射建连超时控制等),只须要开发相应的接口数据模型便可。
  • 服务治理: 在分布式场景下,咱们的服务提供者不止一台,那么就涉及到 服务健康负载均衡服务流控等状况须要处理,而这部分能力在rpc & 注册中心 的架构下,都已经知足了。

说完优势后,再来分析一下,RPC的缺点:

  • 耦合性强: 相较于 RESTful而言,RPC 框架在跨语言的场景下实现比较困难。而且版本依赖比较强。服务脱离了当前内网环境后,没法正常提供服务,迁移成本高。
  • 内网调用RPC更适合内网传输,在公网环境下,显得没那么安全。

分布式微服务

在上一个版本的服务拆分中, 咱们根据不一样的业务边界功能职责,划分出了多个子系统,而针对不一样的系统,他所承受的负载压力是不同的,例如: 订单服务的每一个请求处理耗时较长(其余服务压力不大),为了挺升咱们的下单量,咱们能够只扩容订单服务便可,这就是咱们在服务拆分所带来的收益,性能使用率提高!

image.png

从上面的图咱们能够看到,有些服务出现了不一样的重影,每个方块,能够理解为一台机器,在这个架构中, 为了保证咱们的下单成功率,以及下单量,咱们主要将服务器集中在了订单服务

除此以前,再来看看咱们的中间件集群部署:

  • mysql 主从架构: 读写分离,减轻主库压力,确保数据能正常写入,保障订单数据落库.
  • zookeeper 主从架构: 保障注册中心可用,避免致使全链路雪崩。
  • redis 哨兵集群: 避免redis宕机致使大流量直接打到数据库中。

小结

到这里为止,通常咱们本身开发的系统,也就基本完成了整个秒杀系统的演进了。可能大伙一直有个疑问,为何少了咱们最熟悉的MQ呢?

在整个调用链路中,我都是以同步调用的方式去讲述这一个秒杀系统的架构,由于这个已经知足咱们当前的流量诉求了,在架构设计的原则里面,提到的,合适原则,和演进原则。在当前知足流量需求的状况下,咱们须要先思考引入消息中间件,带来的问题是什么? 解决的问题又是什么? 在权衡利弊后,才是咱们决策是否要使用这个方案的时候。

高性能

在上述架构演进的过程当中,咱们经过服务拆分垂直扩容分布式部署等方式,提高了咱们架构的性能稳定性,对于咱们自研阶段的架构演进已是足够知足咱们的流量诉求了,但若是咱们想继续优化咱们的系统,提高服务性能,能够从如下几个方面进行优化:

  • 资源预热
  • 缓存预热
  • 异步调用

一、资源预热

在上面的服务拆分阶段, 咱们就提到了资源动静分离, 这里的静态资源包括:html,js,css,img 等。咱们活动阶段,能够经过后台管理系统,将商品服务中的活动的静态资源预热到CDN,加速资源的访问。

资源预热: 经过预先将资源加载到CDN
回源: CDN找不到资源后,会触发源站(商品服务)调用,进行查询对应资源,若是源站存在该资源,则会返回到CDN中进行缓存。
OSS: 实际存储静态资源的服务(可参考阿里云OSS)

image.png

上面有反复提到,引入一个技术的时候,须要同时考虑它所带来的利和弊,那么 CDN的风险是什么呢?

  • 成本 : 比较直接,就是得多花钱!
  • 带宽 : 在大流量的访问下, CDN 是否能支撑那么多的带宽,每一个服务器能支撑的流量是有限的,须要考虑CDN是否能支撑业务的访问量。
  • CDN命中率: 在CDN命中率低的状况下,好比活动图片,每个小时都会发生改变,那么每次图片的替换,都会触发回源操做,这时候的资源访问效率反而有所降低。

二、缓存预热

与上面的静态资源加速相对比,动态数据则须要经过缓存进行性能上的优化,老生常谈,为何redis 那么快?

  • 单线程(redis的性能瓶颈并不在这,因此这个不算优点)
  • 多路I/O复用模型
  • 数据结构简单
  • 基于内存操做

image.png

引入 redis 带来的风险主要有:

  • reids 宕机: 单机部署的状况下,会致使大量的服务调用超时,最终引发服务雪崩。可经过Sentinel集群优化。
  • 缓存击穿:大流量下,缓存MISS缓存过时等状况,会致使请求穿透到数据库,若是数据库扛不住压力,会形成服务雪崩。能够经过 布隆过滤器进行优化。
  • 数据一致性缓存数据与DB 的数据一致性问题,须要经过更新策略进行保障。

三、异步调用

经过异步的方式,将减库存成功的用户,经过消息的方式,发送给订单服务,进行后续的下单操做。能够在短期内,将全部的商品销售出去。总体的流程以下图所示:

MQ异步调用为何能过提高咱们服务的吞吐量呢?

主要缘由在于,经过异步调用的方式,咱们将消息投递过去了,就完成了这一次的请求处理,那么性能的瓶颈,由订单服务,转移到了秒杀服务这里。经过减小调用依赖,从而提高了总体服务的吞吐量。

image.png

MQ 带来的常见问题:

  • 数据一致性
  • 重复消费:因为生产者重复投递消息,或者消费缓慢致使重复推送消息。须要经过加锁,消费幂等来保证消费正常。
  • 消息堆积: 生产能力远大于消费能力状况下,会致使消息堆积。
  • MQ可用性:MQ宕机的状况下,须要支持同步调用切换。

这里不作详细介绍,后面会专门写一篇MQ相关的文章

高可用

能看到这里真不容易,感谢你们的支持。关于可用性这里,以前有写过一篇 # 《高可用实战》-B站蹦了,关我A站什么事? 感兴趣能够看一下。

高可用主要能够从:

同城双活

部署在同一个城市不一样区的机房,用专用网络链接。两个机房距离通常就是几十公里,网络传输速度几乎和同一个机房相同,下降了系统复杂度、成本

image.png

这个模式没法解决极端的灾难状况,例如某个城市的地震、水灾,此方式是用来解决一些常规故障的,例如机房的火灾、停电、空调故障

异地多活

在上述模式中,没办法解决城市级别的服务容灾,好比水灾地震等情。而经过异地多活的部署方案,则能够解决这种问题。

可是每一个方案都是存在利和弊的,那么异地多活的弊端主要体如今网络传输数据一致性的问题上!

跨城异地主要问题就是网络传输延迟,例如北京到广州,正常状况下的RTT(Round-Trip Time 往返时延)是50毫秒,
当遇到网络波动等状况,会升到500毫秒甚至1秒,并且会有丢包问题。

物理距离必然致使数据不一致,这就得从“数据”特性来解决,
若是是强一致性要求的数据(如存款余额),就没法作异地多活。

点关注,不迷路

图片地址:draw.io原图

好了各位,以上就是这篇文章的所有内容了,我后面会每周都更新几篇高质量的大厂面试和经常使用技术栈相关的文章。感谢大伙能看到这里,若是这个文章写得还不错, 求三连!!! 感谢各位的支持和承认,咱们下篇文章见!

我是 九灵 ,有须要交流的童鞋能够 加我wx,Jayce-K,关注公众号:Java 补习课,掌握第一手资料! 若是本篇博客有任何错误,请批评指教,不胜感激 !

相关文章
相关标签/搜索