大厂面试必问:如何设计构建一个支持高并发的系统?

Java面试 潘老师 9个月前 (08-05) 277 ℃ (0) 扫码查看

前言

大家好,以下是路由器没有路网友分享大厂面试的面试经验,核心问题为“如何设计一个支持高并发的系统?”。

三年前,我曾前往字节跳动参与面试。在三轮面试环节中,我遇到了一道关于场景设计的问题:如何构建一个高并发的系统?

当时我的回答相对简洁,但最近有朋友正在准备面试,向我请教有关进入知名公司面试的经验。于是我回想起这个经历,总结出了8个在设计高并发系统时需要考虑的关键技术要点和因素。

我相信这些总结可以帮助大家更好地理解和应对高并发系统的挑战。

 

什么是高并发系统?

高并发系统指的是在短时间内有大量用户请求访问系统,要求系统能够稳定且迅速地应对这些请求。

举例来说,双十一期间电商平台推出大量优惠活动,可能会有数以万计的用户同时涌入平台,这便是高并发系统的一例。如果系统无法有效处理这些请求,用户体验将受损,甚至系统可能崩溃。

因此,高并发系统需要具备迅速、稳定地应对大量请求的能力,以确保系统正常运行和用户满意度。

高并发带来的问题包括:

  1. 系统压力增大:高并发请求增加系统负担,可能导致系统瘫痪或运行缓慢。
  2. 响应时间延长:高并发请求会延长系统响应时间,损害用户体验。
  3. 数据不一致:高并发请求可能导致数据不一致,例如多个请求同时修改同一数据,可能导致数据异常。
  4. 资源浪费:高并发请求可能造成资源浪费,某些请求占用过多内存或CPU资源,影响其他请求运行。

今天我们要讨论如何设计高并发系统,需要考虑哪些因素,以有效解决高并发引发的问题,确保系统具备处理高并发的能力。

1.分而治之:系统拆分

系统拆分,也被称为微服务拆分,是将一个整体系统分解成多个子系统的过程。简单来说,就是将原本的单体应用按照功能单一性划分为多个独立的服务模块。

在这样的拆分后,每个子系统会有自己的数据库,原本的单一数据库变成了多个独立的数据库,这也有助于提高系统的并发处理能力。

以商城系统为例,可以将用户系统、订单系统、商品系统等不同功能拆分为独立的服务模块,从而分散请求流量,增强系统的并发处理能力。

2.访问提速:加缓存

缓存是一项广泛应用于现代计算机系统的技术,不论是操作系统、浏览器,还是一些复杂的中间件,都在其应用中使用了缓存。

在大多数高并发场景下,读取操作要远多于写入操作。为了提升数据访问速度,系统必然需要使用缓存。

缓存的主要目的是优化系统接口性能,尤其在高并发环境下,缓存可以帮助系统同时支持更多用户的访问。

常见的缓存技术包括 Redis 缓存、JVM 本地缓存、memcached 等。

以 Redis 为例,单机即可轻松处理数万的并发请求。因此,在读取密集型业务场景中,使用缓存能够有效应对高并发请求。

然而,在使用缓存时,以下问题需要考虑:

  1. 缓存数据一致性
  2. 缓存雪崩
  3. 缓存穿透
  4. 缓存击穿

3.削峰处理:使用消息队列 MQ

在系统中,高并发写操作的场景可能会出现,例如某个业务操作需要频繁地对数据库进行增删改操作,这可能导致系统崩溃。

当使用 Redis 缓存来处理写操作时,可能会面临数据被 LRU 淘汰的问题,同时 Redis 不支持事务,因此不适用于复杂写业务逻辑的场景。

在这种情况下,虽然你可以考虑直接使用 MySQL 承载写操作,但需注意控制写操作的并发数,避免给 MySQL 带来巨大压力。

解决高并发写场景问题的一种方法是使用消息队列(MQ)来异步处理写请求。

将大量写请求发送至 MQ,让下游系统有序地消费这些请求,控制在 MySQL 承载能力内。

单个 MQ 实例可以应对数万并发

4.数据分离:分库分表

如果业务得以快速发展,数据库可能成为性能上的制约因素。换言之,随着业务规模的扩大,MySQL数据库的存储容量可能会达到极限。

此外,数据库的连接数量也受限,因此在高并发情景下,当大量请求涌入数据库时,MySQL单机难以承受。在高并发环境中,可能会出现”too many connections”的错误提示。

因此,为了应对高并发挑战,需将高并发系统分割为多个数据库,以增强系统的并发处理能力。

如果单一数据表中的数据量过大,存储和查询性能也会受到限制。在进行数据库分割优化后,若性能提升不显著,考虑拆分数据表。

通常情况下,当单一数据表的数据量达到千万级别,考虑拆分数据表,将数据分布到多个表中,从而提升SQL查询性能。

5.读多写少场景:读写分离

读写分离是一项技术,它将数据库中的读取操作和写入操作分别分配到不同的数据库实例来处理。

这种方法的好处在于它可以增强系统的并发处理性能。由于读取操作和写入操作通常有不同的特点,例如读取操作更频繁,而写入操作通常耗时较长,因此将它们分开处理可以有效地提高性能。

以电商平台为例,用户经常执行商品浏览和搜索等读取操作,而商品的添加、修改和删除等写入操作较少。

通过将读取和写入操作分别分配到不同的数据库实例,系统的并发处理能力和性能可以得到提升。

此外,读写分离还能增加系统的可用性和可靠性。当主数据库遇到问题时,从数据库可以接管读取操作,确保系统持续运行。

6.异构数据索引:ElasticSearch

ElasticSearch(ES)是一款分布式搜索和分析引擎,支持弹性扩展且天然适应高并发环境。

ES能够通过动态扩容并引入更多机器以处理更多并发请求,这使得它天然具备处理高并发请求的能力。

因此,适用于一些简单的查询、统计操作,以及全文搜索等场景,可以考虑采用ES来支持。

7.静态资源访问:CDN

什么是 CDN?

CDN 是指内容分发网络,是一种将内容分发到全球各地的网络架构。

CDN 可以将网站的静态资源(如图片、CSS、JavaScript 等文件)缓存到全球各地的服务器上,当用户请求这些资源时,可以从离用户最近的服务器上获取资源,从而提高资源的访问速度和用户的访问体验。

CDN 的作用有哪些?

CDN的主要作用包括:

  1. 提高网站的访问速度:CDN通过将内容分发到全球多个服务器节点,使用户可以从离他们更近的服务器获取内容,从而减少加载时间,提升用户体验。
  2. 降低带宽成本:CDN可以缓存并提供静态资源,如图像、视频和文件,从而减少源服务器的流量负担,降低带宽使用成本。
  3. 提高可用性:CDN的分布式架构意味着即使某个服务器节点发生故障,其他节点仍然可以继续提供内容,从而提高网站的可用性和稳定性。

在高并发场景下,CDN起着重要作用。因为高并发情况下,大量用户同时访问源站会造成带宽和服务器资源的过度负荷,可能导致网站速度下降或宕机等问题。通过使用CDN,流量可以分散到分布在不同地区的服务器上,从而减轻源站的负担,提升网站的速度和可用性。

8.微服务治理:上容器、k8s 弹性伸缩管理

假设有一家电商平台,在某些特定时段,如双十一、618等大型促销活动期间,用户量会迎来高峰。

在这些高峰时刻,平台需要应对大量的同时请求,于是可以运用容器化技术和Kubernetes(k8s)的弹性伸缩特性来解决这个高并发难题。

具体而言,这家电商平台可以将应用程序进行容器化处理,并利用k8s来进行容器编排、服务发现和负载均衡。

每当有用户请求到来,k8s将会智能地将这些请求自动分发到不同的容器实例上,以实现负载的平衡分配。

另外,这家电商平台还能运用k8s的自动伸缩能力,能在高峰时自动增加容器实例的数量,以应对暴增的并发请求。而当高峰时段过后,k8s也会自动缩减容器实例的数量,以免资源浪费。

通过采用容器化技术和k8s的弹性伸缩机制,这家电商平台能够增强系统的稳定性、性能和可用性,从而提升整体性能,创造更出色的用户体验。

总结

构建一个能够应对高并发的系统,对于每位积极进取的开发者而言,是一个不容忽视的任务。

在设计高并发系统时,你可以借鉴上述提到的八个方面,这些观点可以作为出发点,帮助你实现系统在高并发环境下的稳定性和可靠性。

当然,除了这些方面,还有其他值得考虑的因素,例如降级、熔断、限流等。

这些方法都是保障系统高并发运行的重要策略。通过降级可以在高负载时暂时关闭不必要的功能,熔断可以临时停止对某个服务的请求以避免系统崩溃,而限流则可以有效地控制并发请求的数量。

总之,在系统设计中保持弹性、可扩展性和可恢复性至关重要。持续进行性能测试、监控和优化,将确保系统能够在高并发情况下保持稳定运行


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/javainterview/7665.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】