当前位置:   article > 正文

阿里P8面试官:如何设计一个扛住千万级并发的架构(超级详细)_千万级高并发

千万级高并发

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

其实,最终要的是,单个应用在性能上的瓶颈很难突破,也就是说如果我们要支持18000QPS,单个服务节点肯定无法支撑,所以服务拆分的好处,就是可以利用多个计算机阶段组成一个大规模的分布式计算网络,通过网络通信的方式完成一整套业务逻辑。

img

如何拆分服务


如何拆分服务,这个问题看起来简单,很多同学会说,直接按照业务拆分啊。

但是实际在实施的时候,会发现拆分存在一些边界性问题,比如有些数据模型可以存在A模块,也可以存在B模块,这个时候怎么划分呢?另外,服务拆分的粒度应该怎么划分?

一般来说,服务的拆分是按照业务来实现的,然后基于DDD来指导微服务的边界划分。**领域驱动就是一套方法论,通过领域驱动设计方法论来定义领域模型,从而确定业务边界和应用边界,保证业务模型和代码模型的一致性。**不管是DDD还是微服务,都要遵循软件设计的基本原则:高内聚低耦合。服务内部高内聚,服务之间低耦合,实际上一个领域服务对应了一个功能集合,这些功能一定是有一些共性的。比如,订单服务,那么创建订单、修改订单、查询订单列表,领域的边界越清晰,功能也就越内聚,服务之间的耦合性也就越低。

服务拆分还需要根据当前技术团队和公司所处的状态来进行。

如果是初创团队,不需要过分的追求微服务,否则会导致业务逻辑过于分散,技术架构太过负载,再加上团队的基础设施还不够完善,导致整个交付的时间拉长,对公司的发展来说会造成较大的影响。所以在做服务拆分的时候还需要考虑几个因素。

  • 当前公司业务所处领域的市场性质,如果是市场较为敏感的项目,前期应该是先出来东西,然后再去迭代和优化。

  • 开发团队的成熟度,团队技术能否能够承接。

  • 基础能力是否足够,比如Devops、运维、测试自动化等基础能力。 团队是否有能力来支撑大量服务实例运行带来的运维复杂度,是否可以做好服务的监控。

  • 测试团队的执行效率,如果测试团队不能支持自动化测试、自动回归、压力测试等手段来提高测试效率,那必然会带来测试工作量的大幅度提升从而导致项目上线周期延期

如果是针对一个老的系统进行改造,那可能涉及到的风险和问题更多,所以要开始着手改动之前,需要考虑几个步骤:拆分前准备阶段,设计拆分改造方案,实施拆分计划

  • 拆分之前,先梳理好当前的整个架构,以及各个模块的依赖关系,还有接口

准备阶段主要是梳理清楚了依赖关系和接口,就可以思考如何来拆,第一刀切在哪儿里,即能达到快速把一个复杂单体系统变成两个更小系统的目标,又能对系统的现有业务影响最小。要尽量避免构建出一个分布式的单体应用,一个包含了一大堆互相之间紧耦合的服务,却又必须部署在一起的所谓分布式系统。没分析清楚就强行拆,可能就一不小心剪断了大动脉,立马搞出来一个 A 类大故障,后患无穷。

  • 不同阶段拆分要点不同,每个阶段的关注点要聚焦

拆分本身可以分成三个阶段,核心业务和非业务部分的拆分、核心业务的调整设计、核心业务内部的拆分。

  • 第一阶段将核心业务瘦身,把非核心的部分切开,减少需要处理的系统大小;

  • 第二阶段。重新按照微服务设计核心业务部分;

  • 第三阶段把核心业务部分重构设计落地。

拆分的方式也有三个:代码拆分、部署拆分、数据拆分。

另外,每个阶段需要聚焦到一两个具体的目标,否则目标太多反而很难把一件事儿做通透。例如某个系统的微服务拆分,制定了如下的几个目标:

  1. 性能指标(吞吐和延迟):核心交易吞吐提升一倍以上(TPS:1000->10000),A 业务延迟降低一半(Latency:250ms->125ms),B 业务延迟降低一半(Latency:70ms->35ms)。

  2. 稳定性指标(可用性,故障恢复时间):可用性>=99.99%,A 类故障恢复时间<=15 分钟,季度次数<=1 次。

  3. 质量指标:编写完善的产品需求文档、设计文档、部署运维文档,核心交易部分代码 90%以上单测覆盖率和 100%的自动化测试用例和场景覆盖,实现可持续的性能测试基准环境和长期持续性能优化机制。

  4. 扩展性指标:完成代码、部署、运行时和数据多个维度的合理拆分,对于核心系统重构后的各块业务和交易模块、以及对应的各个数据存储,都可以随时通过增加机器资源实现伸缩扩展。

  5. 可维护性指标:建立全面完善的监控指标、特别是全链路的实时性能指标数据,覆盖所有关键业务和状态,缩短监控报警响应处置时间,配合运维团队实现容量规划和管理,出现问题时可以在一分钟内拉起系统或者回滚到上一个可用版本(启动时间<=1 分钟)。

  6. 易用性指标,通过重构实现新的 API 接口既合理又简单,极大的满足各个层面用户的使用和需要,客户满意度持续上升。

  7. 业务支持指标:对于新的业务需求功能开发,在保障质量的前提下,开发效率提升一倍,开发资源和周期降低一半。

当然,不要期望一次性完成所有目标,每一个阶段可以选择一个两个优先级高的目标进行执行。

img

微服务化架构带来的问题


微服务架构首先是一个分布式的架构,其次我们要暴露和提供业务服务能力,然后我们需要考虑围绕这些业务能力的各种非功能性的能力。这些分散在各处的服务本身需要被管理起来,并且对服务的调用方透明,这样就有了服务的注册发现的功能需求。

同样地,每个服务可能部署了多台机器多个实例,所以,我们需要有路由和寻址的能力,做负载均衡,提升系统的扩展能力。有了这么多对外提供的不同服务接口,我们一样需要有一种机制对他们进行统一的接入控制,并把一些非业务的策略做到这个接入层,比如权限相关的,这就是服务网关。同时我们发现随着业务的发展和一些特定的运营活动,比如秒杀大促,流量会出现十倍以上的激增,这时候我们就需要考虑系统容量,服务间的强弱依赖关系,做服务降级、熔断,系统过载保护等措施。

以上这些由于微服务带来的复杂性,导致了应用配置、业务配置,都被散落到各处,所以分布式配置中心的需求也出现了。最后,系统分散部署以后,所有的调用都跨了进程,我们还需要有能在线上做链路跟踪,性能监控的一套技术,来协助我们时刻了解系统内部的状态和指标,让我们能够随时对系统进行分析和干预。

image-20210624133950124

整体架构图


基于上述从微观到宏观的整体分析,我们基本上能够设计出一个整体的架构图。

  • 接入层,外部请求到内部系统之间的关口,所有请求都必须经过api 网关。

  • 应用层,也叫聚合层,为相关业务提供聚合接口,它会调用中台服务进行组装。

  • 中台服务,也是业务服务层,以业务为纬度提供业务相关的接口。中台的本质是为整个架构提供复用的能力,比如评论系统,在咕泡云课堂和Gper社区都需要,那么这个时候评论系统为了设计得更加可复用性,就不能耦合云课堂或者Gper社区定制化的需求,那么作为设计评论中台的人,就不需要做非常深度的思考,如何提供一种针对不同场景都能复用的能力。

你会发现,当这个服务做到机制的时候,就变成了一个baas服务。

服务商客户(开发者)提供整合云后端的服务,如提供文件存储、数据存储、推送服务、身份验证服务等功能,以帮助开发者快速开发应用。

image-20210624152616146

了解什么是高并发

========

总结一下什么是高并发。

高并发并没有一个具体的定义,高并发主要是形容突发流量较高的场景。

如果面试的过程中,或者在实际工作中,你们领导或者面试官问你一个如何设计承接千万级流量的系统时,你应该要按照我说的方法去进行逐一分析。

  • 一定要形成可以量化的数据指标,比如QPS、DAU、总用户数、TPS、访问峰值

  • 针对这些数据情况,开始去设计整个架构方案

  • 接着落地执行

高并发中的宏观指标


一个满足高并发系统,不是一味追求高性能,至少需要满足三个宏观层面的目标:

  • 高性能,性能体现了系统的并行处理能力,在有限的硬件投入下,提高性能意味着节省成本。同时,性能也反映了用户体验,响应时间分别是 100 毫秒和 1 秒,给用户的感受是完全不同的。

  • 高可用,表示系统可以正常服务的时间。一个全年不停机、无故障;另一个隔三差五出现上事故、宕机,用户肯定选择前者。另外,如果系统只能做到 90%可用,也会大大拖累业务。

  • 高扩展,表示系统的扩展能力,流量高峰时能否在短时间内完成扩容,更平稳地承接峰值流量,比如双 11 活动、明星离婚等热点事件。

image-20210624211728937

微观指标


性能指标

通过性能指标可以度量目前存在的性能问题,同时作为性能优化的评估依据。一般来说,会采用一段时间内的接口响应时间作为指标。

1、平均响应时间:最常用,但是缺陷很明显,对于慢请求不敏感。比如 1 万次请求,其中 9900 次是 1ms,100 次是 100ms,则平均响应时间为 1.99ms,虽然平均耗时仅增加了 0.99ms,但是 1%请求的响应时间已经增加了 100 倍。

2、TP90、TP99 等分位值:将响应时间按照从小到大排序,TP90 表示排在第 90 分位的响应时间, 分位值越大,对慢请求越敏感。

img

可用性指标

高可用性是指系统具有较高的无故障运行能力,可用性 = 平均故障时间 / 系统总运行时间,一般使用几个 9 来描述系统的可用性。

对于高并发系统来说,最基本的要求是:保证 3 个 9 或者 4 个 9。原因很简单,如果你只能做到 2 个 9,意味着有 1%的故障时间,像一些大公司每年动辄千亿以上的 GMV 或者收入,1%就是 10 亿级别的业务影响。

可扩展性指标

面对突发流量,不可能临时改造架构,最快的方式就是增加机器来线性提高系统的处理能力。

对于业务集群或者基础组件来说,扩展性 = 性能提升比例 / 机器增加比例,理想的扩展能力是:资源增加几倍,性能提升几倍。通常来说,扩展能力要维持在 70%以上。

但是从高并发系统的整体架构角度来看,扩展的目标不仅仅是把服务设计成无状态就行了,因为当流量增加 10 倍,业务服务可以快速扩容 10 倍,但是数据库可能就成为了新的瓶颈。

像 MySQL 这种有状态的存储服务通常是扩展的技术难点,如果架构上没提前做好规划(垂直和水平拆分),就会涉及到大量数据的迁移。

因此,高扩展性需要考虑:服务集群、数据库、缓存和消息队列等中间件、负载均衡、带宽、依赖的第三方等,当并发达到某一个量级后,上述每个因素都可能成为扩展的瓶颈点。

实践方案


通用设计方法

纵向扩展(scale-up)

它的目标是提升单机的处理能力,方案又包括:

1、提升单机的硬件性能:通过增加内存、CPU 核数、存储容量、或者将磁盘升级成 SSD 等堆硬件的方式来提升。

2、提升单机的软件性能:使用缓存减少 IO 次数,使用并发或者异步的方式增加吞吐量。

横向扩展(scale-out)

因为单机性能总会存在极限,所以最终还需要引入横向扩展,通过集群部署以进一步提高并发处理能力,又包括以下 2 个方向:

1、做好分层架构:这是横向扩展的提前,因为高并发系统往往业务复杂,通过分层处理可以简化复杂问题,更容易做到横向扩展。

2、各层进行水平扩展:无状态水平扩容,有状态做分片路由。业务集群通常能设计成无状态的,而数据库和缓存往往是有状态的,因此需要设计分区键做好存储分片,当然也可以通过主从同步、读写分离的方案提升读性能。

高性能实践方案

1、集群部署,通过负载均衡减轻单机压力。

2、多级缓存,包括静态数据使用 CDN、本地缓存、分布式缓存等,以及对缓存场景中的热点 key、缓存穿透、缓存并发、数据一致性等问题的处理。

3、分库分表和索引优化,以及借助搜索引擎解决复杂查询问题。

4、考虑 NoSQL 数据库的使用,比如 HBase、TiDB 等,但是团队必须熟悉这些组件,且有较强的运维能力。

5、异步化,将次要流程通过多线程、MQ、甚至延时任务进行异步处理。

6、限流,需要先考虑业务是否允许限流(比如秒杀场景是允许的),包括前端限流、Nginx 接入层的限流、服务端的限流。

7、对流量进行削峰填谷,通过 MQ 承接流量。

8、并发处理,通过多线程将串行逻辑并行化。

9、预计算,比如抢红包场景,可以提前计算好红包金额缓存起来,发红包时直接使用即可。

10、缓存预热,通过异步任务提前预热数据到本地缓存或者分布式缓存中。

11、减少 IO 次数,比如数据库和缓存的批量读写、RPC 的批量接口支持、或者通过冗余数据的方式干掉 RPC 调用。

12、减少 IO 时的数据包大小,包括采用轻量级的通信协议、合适的数据结构、去掉接口中的多余字段、减少缓存 key 的大小、压缩缓存 value 等。

13、程序逻辑优化,比如将大概率阻断执行流程的判断逻辑前置、For 循环的计算逻辑优化,或者采用更高效的算法。

14、各种池化技术的使用和池大小的设置,包括 HTTP 请求池、线程池(考虑 CPU 密集型还是 IO 密集型设置核心参数)、数据库和 Redis 连接池等。

15、JVM 优化,包括新生代和老年代的大小、GC 算法的选择等,尽可能减少 GC 频率和耗时。

16、锁选择,读多写少的场景用乐观锁,或者考虑通过分段锁的方式减少锁冲突。

高可用实践方案

1、对等节点的故障转移,Nginx 和服务治理框架均支持一个节点失败后访问另一个节点。

2、非对等节点的故障转移,通过心跳检测并实施主备切换(比如 redis 的哨兵模式或者集群模式、MySQL 的主从切换等)。

3、接口层面的超时设置、重试策略和幂等设计。

4、降级处理:保证核心服务,牺牲非核心服务,必要时进行熔断;或者核心链路出问题时,有备选链路。

言尽于此,完结

无论是一个初级的 coder,高级的程序员,还是顶级的系统架构师,应该都有深刻的领会到设计模式的重要性。

  • 第一,设计模式能让专业人之间交流方便,如下:

程序员A:这里我用了XXX设计模式

程序员B:那我大致了解你程序的设计思路了

  • 第二,易维护

项目经理:今天客户有这样一个需求…

程序员:明白了,这里我使用了XXX设计模式,所以改起来很快

  • 第三,设计模式是编程经验的总结

程序员A:B,你怎么想到要这样去构建你的代码

程序员B:在我学习了XXX设计模式之后,好像自然而然就感觉这样写能避免一些问题

  • 第四,学习设计模式并不是必须的

程序员A:B,你这段代码使用的是XXX设计模式对吗?

程序员B:不好意思,我没有学习过设计模式,但是我的经验告诉我是这样写的

image

从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!

image

搜集费时费力,能看到此处的都是真爱!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
样写的

[外链图片转存中…(img-wV6VQmR0-1713166757981)]

从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!

[外链图片转存中…(img-fYnrW56c-1713166757981)]

搜集费时费力,能看到此处的都是真爱!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-emO1VLLq-1713166757982)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/790549
推荐阅读
相关标签
  

闽ICP备14008679号