面试官:应对高并发系统有没有通用的解决方案?

简介: 灵魂拷问:应对高并发系统有没有一些通用的解决方案呢?这些方案解决了什么问题呢?这些方案有哪些优势和劣势呢?

灵魂拷问:


  • 应对高并发系统有没有一些通用的解决方案呢?
  • 这些方案解决了什么问题呢?
  • 这些方案有哪些优势和劣势呢?

对性能孜孜不倦的追求是互联网技术不断发展的根本驱动力,从最初的大型机到现在的微型机,在本质上也是为了性能而生。软件系统也存在类似的现象,一个系统从最初的少量访问请求到后期的大并发请求,这都需要我们对性能的提升提供一系列解决方案。像最初的淘宝,也仅仅是一个外包做出来的产品,随着业务的不断发展,淘宝的并发量指数级增加,同时对系统提出了严峻的挑战,这才逐步造就了现在淘宝这样可以支撑数千万人同时在线的高并发系统。

提起应对高并发,每个人都或多或少可以说出几种解决方案,高并发系统的设计魅力在于我们能够凭借程序员的聪明才智设计巧妙的方案,从而应对巨大流量的冲击。从目前已知的方案中,大体可以归纳为以下几种


提升单机性能


尽可能的提升单机的性能是一个永恒的话题,无论是采用分布式还是其他方案,单机性能的提高,对于一个系统来说只有益处。拿编程语言来说,c或者c++语言编写的程序理论上会比java ,net,Python写的程序要高效,当然这需要建立在程序正常运行的情况下。提升单机性能最简单粗暴的方式就是提升硬件性能,举一个简单例子:假如数据库DB的服务器内存为8G,随着数据量的增加,你会发现有些sql执行会慢慢的变慢,原因是数据库的索引或者数据在内存中完全存放不下,需要回写磁盘,有些查询在内存中并不能命中,造成了一些sql会在磁盘中查询数据,这个时候如果把服务器的内存增加到16G,你会发现这些慢sql居然凭空消失了,这是硬件提升性能的一个典型案例。

对于运行的程序也是同样的道理,尽可能的把程序优化到极致,也许单机就可以达到别人分布式部署的性能效果,当然这需要我们在编写代码的时候仔细构思。

无论什么时候,我觉得提升单机性能都有必要


横向扩展


当一个单机系统无法抵抗巨大流量冲击的时候,最简单有效的解决方案之一便是横向扩展,横向扩展是指把巨大的流量分割为数个比较小的流量,从而解决高并发系统的性能问题,本质上,横向扩展属于分而治之的理论,属于分布式的概念范畴。

举一个很简单的例子,假设目前单机处理请求数为200/s,当每秒的请求数到达1000的时候,单台机器肯定会遇到瓶颈,这个时候如果处理请求的服务器增加到5台,甚至更多,这样便轻松解决了性能问题。当然,能否方便的横向扩展还要看具体的系统设计,如果系统是无状态的,理论上横向扩展是没问题的,但是一些有状态的服务,可能会涉及到状态的迁移等工作,这也是为什么很多架构师提倡无状态服务的一个原因。

一个应用程序的横向扩展可以通过负载均衡来实现,像阿里云的SLB服务,nginx的反向代理功能,这些都可以很方便实现应用程序的横向扩展。但是,像数据库比如mysql,这样的DB系统,无限制的横向扩展可能只是一个目标。大多数DB采用的主从或者多主多从来解决横向扩展问题,主节点负责写操作,从节点负责读操作,当然这里涉及到主从同步的机制,主从同步的延迟等问题,有兴趣的同学可以去深入研究一下。

9669a3f9b8c6713466141ce59aab8c58.jpg

那什么时候该选择横向扩展呢?一般来讲,在系统的设计之初便会考虑横向扩展,因为这种方案足够简单,可以用堆砌硬件来解决的问题就不是问题。现在我敢说90%以上的系统在第一版上线的时候就做了类似负载均衡的部署方案,其中有很多就利用了nginx的反向代理功能。

c9a6ccca9b41db318f64d5f999f19dee.jpg

当然横向扩展并非没有负面影响,和单机系统一样,横向扩展也要考虑某个节点down掉的问题,所以监控和健康检查是现在一个系统必备的手段,而且在系统设计之初便会在整体架构之中。就像我前几篇的文章所说,横向扩展既然属于分布式范畴,必然需要考虑分布式系统需要考虑的问题:


分布式系统的问题


缓存除了上面所说的横向扩展方案,另外一种行之有效并且足够简单的便是缓存方案。这一点毋庸置疑,缓存可以遍布在一个系统的各个角落,从操作系统到浏览器,从cpu到磁盘,从数据库到消息队列,任何稍微复杂的服务和组件中都有缓存的影子。

缓存为什么可以大幅度提高性能的性能呢?这还需要从系统的瓶颈来说,在客户端一个请求的生命周期中,这个请求的响应时间严重受限于最慢的那个环节,这类似于木桶效应(一个木桶可以存的水量,取决于最短那个木板)。

举一个很简单的例子:当客户端请求商城的一个商品信息的时候,请求经过http协议到达服务器的某个端口,服务端程序把请求解包然后去请求数据库,数据库不单单在另外一台服务器上,而且还需要从磁盘中加载数据,所谓的DB缓存没有命中。在这整个过程中,请求磁盘的过程是最慢的,普通磁盘是由机械手臂,磁头,转轴,盘片组成,磁盘在查询数据的时候,磁头是需要花费很长时间累寻道的,当然SSD的速度要比普通磁盘快的多,但是相比较内存还是要慢几个量级。而我们最想要的流程是这样的:当一个请求到达服务端的时候能尽快的从某个设备上取出信息,然后返给客户端,这个设备绝不可能是磁盘,这个设备在速度和容量上比较均衡,它应该是内存。

“缓存在语义上要丰富很多,我们可以把任何可以降低响应时间的中间存储都称之为缓存。比如CPU的一级缓存,二级缓存,三级缓存,浏览器的缓存等。缓存主要解决了上下游设备速度不匹配的问题

e3bef2c0dd35fd71d30987de319dbe19.jpg

程序界有一句古话:把数据放在离用户最近的地方才是最快的。CDN本质上就是做的这件事。对于缓存而言,我们经常会听到浏览器缓存,进程内缓存,进程外缓存等概念。目前针对于服务端一般的缓存策略为采用第三方kv存储设备,比如redis,Memcache等。当然在对性能极其苛刻的系统中,我还是推荐使用进程内缓存。

异步谈到异步,必须要说下同步,同步调用是指调用方要阻塞等待被调用方执行完毕才可以返回。系统现在普遍都会采用多线程的方式来提供系统的吞吐量(多进程的方式现在很少,但不代表没有,比如:nodejs,nginx),在同步这种方式下,如果被调用方的响应时间过长,会造成调用方的线程长时间处于等待状态,线程的利用率大幅度降低,线程对于系统来说,是很昂贵的资源,创建大量的线程去应对高并发是不明智的,不仅仅浪费了内存,而且会加大线程上下文cpu切换的成本。

一个高吞吐量的系统,理论上所有的线程都要时时刻刻在工作,而且把cpu资源压榨到最多。对于一个IO密集型操作来说,采用异步方式可以大大提高系统吞吐量。异步不需要等待被调用方执行完成就可以执行其他的逻辑,在被调用方执行完毕之后通过通知回调的方式反馈给调用方。

“异步本质上是一种编程思想,一种编程模型。他提高的是系统整体的吞吐量,但是请求的响应时间对比同步方式来说会略微加大。

像平时用的最多的消息队列,在模型上也属于异步编程模型。调用方会把消息丢到队列中,然后直接返回去执行其他业务,被调用方接收到消息然后进行处理,然后根据具体的业务看是否需要给予结果回复。有不少秒杀系统会采用消息队列进行流量削峰,这是异步带来的优势之一。

7bcc0061e781b24169cf72894c8b4402.jpg

在这里我需要多说一句:异步并不是没有代价,在多数情况下,采用异步会比同步方式编写更多的代码,而且查找bug会花费更多的时间。但是对于一个高并发系统来说,异步带来的益处还是值得的,前提是你正确应用了异步。

相关文章
|
4月前
|
消息中间件 算法 数据库
架构设计篇问题之商城系统高并发写的问题如何解决
架构设计篇问题之商城系统高并发写的问题如何解决
|
22天前
|
缓存 算法 架构师
京东面试:如何设计600Wqps高并发ID?如何解决时钟回拨问题?
资深架构师尼恩在其读者交流群中分享了关于分布式ID系统的设计与实现,特别是针对高并发场景下的解决方案。他强调了分布式ID系统在高并发核心组件中的重要性,并详细介绍了百度的UidGenerator,这是一个基于Snowflake算法改进的Java实现,旨在解决分布式系统中的唯一ID生成问题。UidGenerator通过自定义workerId位数和初始化策略,支持虚拟化环境下的实例自动重启和漂移,其单机QPS可达600万。此外尼恩的技术分享不仅有助于提升面试表现,还能帮助开发者在实际项目中应对高并发挑战。
京东面试:如何设计600Wqps高并发ID?如何解决时钟回拨问题?
|
1月前
|
C语言
经典面试题:嵌入式系统中经常要用到无限循环,怎么样用C编写死循环呢
在嵌入式系统开发中,无限循环常用于持续运行特定任务或监听事件。使用C语言实现死循环很简单,可以通过`while(1)`或`for(;;)`的结构来编写。例如:`while (1) { /* 循环体代码 */ }`,这种写法明确简洁,适用于需要持续执行的任务或等待中断的场景。
|
1月前
|
存储 消息中间件 缓存
系统设计面试参考-设计Spotify系统
【10月更文挑战第4天】支持用户将自己喜欢的音乐、专辑、播放列表等分享到社交媒体平台,如 Facebook、Twitter、Instagram 等。分享内容可以包括音乐链接、封面图片、简介等信息,吸引更多的用户来使用 Spotify 系统。同时,系统可以跟踪分享的效果,如点击量、转化率等,以便评估社交分享对系统推广的贡献。
|
23天前
|
Java Go 云计算
Go语言在云计算和高并发系统中的卓越表现
【10月更文挑战第10天】Go语言在云计算和高并发系统中的卓越表现
|
27天前
|
缓存 关系型数据库 API
京东面试题:ElasticSearch深度分页解决方案!
京东面试题:ElasticSearch深度分页解决方案!
|
3月前
|
存储 NoSQL Java
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
这篇文章是关于Java面试中的分布式架构问题的笔记,包括分布式架构下的Session共享方案、RPC和RMI的理解、分布式ID生成方案、分布式锁解决方案以及分布式事务解决方案。
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
|
3月前
|
算法 关系型数据库 MySQL
技术分享:600W QPS高并发ID设计与时钟回拨解决方案
【8月更文挑战第26天】在大型分布式系统中,高并发ID生成和时钟同步是两个至关重要的技术挑战。随着业务量的快速增长,如美团点评的金融、支付、餐饮等业务场景,每秒需要处理数百万级别的请求,这就对ID的生成效率和唯一性提出了极高要求。同时,时钟回拨问题也时常困扰着系统管理员,影响数据一致性和系统稳定性。本文将围绕这两个主题,分享一些工作学习中的技术干货。
59 1
|
3月前
|
数据库
面试准备 数据迁移解决方案
【8月更文挑战第8天】
46 7
|
3月前
|
监控 算法 Java
企业应用面临高并发等挑战,优化Java后台系统性能至关重要
随着互联网技术的发展,企业应用面临高并发等挑战,优化Java后台系统性能至关重要。本文提供三大技巧:1)优化JVM,如选用合适版本(如OpenJDK 11)、调整参数(如使用G1垃圾收集器)及监控性能;2)优化代码与算法,减少对象创建、合理使用集合及采用高效算法(如快速排序);3)数据库优化,包括索引、查询及分页策略改进,全面提升系统效能。
45 0