2024年最新阿里P8面试官:如何设计一个扛住千万级并发的架构(超级详细),Java进阶

写在最后

学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!

最后再分享的一些BATJ等大厂20、21年的面试题,把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

蚂蚁金服三面直击面试官的Redis三连,Redis面试复习大纲在手,不慌

Mybatis面试专题

蚂蚁金服三面直击面试官的Redis三连,Redis面试复习大纲在手,不慌

MySQL面试专题

蚂蚁金服三面直击面试官的Redis三连,Redis面试复习大纲在手,不慌

并发编程面试专题

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

数据库写操作为IO写入,写入过程中通常会涉及唯一性校验、建索引、索引排序等操作,对资源消耗比较大。一次写操作的响应时间往往是读操作的几倍甚至几十倍。
  • 锁争用
写操作很多时候需要加锁,包括表级锁、行级锁等,这类锁都是排他锁,一个会话占据排它锁之后,其他会话是不能读取数据的,这会会极大影响数据读取性能。
所以MYSQL部署往往会采用读写分离方式,主库用来写入数据及部分时效性要求很高的读操作,从库用来承接大部分读操作,这样数据库整体性能能够得到大幅提升。
  • 不同类型的数据采用不同的存储库,

  • MongoDB nosql 文档化存储

  • Redis nosql key-value存储

  • HBase nosql, 列式存储,其实本质上有点类似于key-value数据库。

  • cassandra,Cassandra 是一个来自 Apache 的分布式数据库,具有高度可扩展性,可用于管理大量的结构化数据

  • TIDB,是PingCAP公司自主设计、研发的开源分布式关系型数据库,是一款同时支持在线事务处理与在线分析处理 (Hybrid Transactional and Analytical Processing, HTAP) 的融合型分布式数据库产品

为什么把mysql数据库中的数据放redis缓存中能提升性能?

  1. Redis存储的是k-v格式的数据。时间复杂度是O(1),常数阶,而mysql引擎的底层实现是B+TREE,时间复杂度是O(logn)是对数阶的。Redis会比Mysql快一点点。
  1. Mysql数据存储是存储在表中,查找数据时要先对表进行全局扫描或根据索引查找,这涉及到磁盘的查找,磁盘查找如果是单点查找可能会快点,但是顺序查找就比较慢。而redis不用这么麻烦,本身就是存储在内存中,会根据数据在内存的位置直接取出。
  1. Redis是单线程的多路复用IO,单线程避免了线程切换的开销,而多路复用IO避免了IO等待的开销,在多核处理器下提高处理器的使用效率可以对数据进行分区,然后每个处理器处理不同的数据。
  • 池化技术,减少频繁创建数据库连接的性能损耗。

每次进行数据库操作之前,先建立连接然后再进行数据库操作,最后释放连接。这个过程涉及到网络通信的延时,频繁创建连接对象和销毁对象的性能开销等,当请求量较大时,这块带来的性能影响非常大。

数据存储

磁盘数据访问优化


对于磁盘的操作,无非就是读和写。

比如对于做交易系统的场景来说,一般会设计到对账文件的解析和写入。而对于磁盘的操作,优化方式无非就是

  • 磁盘的页缓存,可以借助缓存 I/O ,充分利用系统缓存,降低实际 I/O 的次数。

  • 顺序读写,可以用追加写代替随机写,减少寻址开销,加快 I/O 写的速度。

  • SSD代替HDD,固态硬盘的I/O效率远远高于机械硬盘。

  • 在需要频繁读写同一块磁盘空间时,可以用 mmap (内存映射,)代替 read/write,减少内存的拷贝次数

  • 在需要同步写的场景中,尽量将写请求合并,而不是让每个请求都同步写入磁盘,即可以用 fsync() 取代 O_SYNC

合理利用内存


充分利用内存缓存,把一些经常访问的数据和对象保存在内存中,这样可以避免重复加载或者避免数据库访问带来的性能损耗。

调用远程服务


远程服务调用,影响到IO性能的因素有。

  • 远程调用等待返回结果的阻塞

  • 异步通信

  • 网络通信的耗时

  • 内网通信

  • 增加网络带宽

  • 远程服务通信的稳定性

异步化架构


微服务中的逻辑复杂处理时间长的情况,在高并发量下,导致服务线程消耗尽,不能再创建线程处理请求。对这种情况的优化,除了在程序上不断调优(数据库调优,算法调优,缓存等等),可以考虑在架构上做些调整,先返回结果给客户端,让用户可以继续使用客户端的其他操作,再把服务端的复杂逻辑处理模块做异步化处理。这种异步化处理的方式适合于客户端对处理结果不敏感不要求实时的情况,比如群发邮件、群发消息等。

异步化设计的解决方案: 多线程、MQ。

应用服务的拆分

=======

除了上述的手段之外,业务系统往微服务化拆分也非常有必要,原因是:

  • 随着业务的发展,应用程序本身的复杂度会不断增加,同样会产生熵增现象。

  • 业务系统的功能越来越多,参与开发迭代的人员也越多,多个人维护一个非常庞大的项目,很容易出现问题。

  • 单个应用系统很难实现横向扩容,并且由于服务器资源有限,导致所有的请求都集中请求到某个服务器节点,造成资源消耗过大,使得系统不稳定

  • 测试、部署成本越来越高

其实,最终要的是,单个应用在性能上的瓶颈很难突破,也就是说如果我们要支持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

可用性指标

最后

学习视频:

大厂面试真题:

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

img

可用性指标

最后

学习视频:

[外链图片转存中…(img-XjNfl9vx-1715259239917)]

大厂面试真题:

[外链图片转存中…(img-hGWR2LFn-1715259239917)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值