乐趣区

关于后端:应对高并发系统有没有通用的解决方案呢

灵魂拷问:

  • 应答高并发零碎有没有一些通用的解决方案呢?
  • 这些计划解决了什么问题呢?
  • 这些计划有那些劣势和劣势呢?

对性能手不释卷的谋求是互联网技术一直倒退的基本驱动力,从最后的大型机到当初的微型机,在实质上也是为了性能而生。软件系统也存在相似的景象,一个零碎从最后的大量拜访申请到前期的大并发申请,这都须要咱们对性能的晋升提供一系列解决方案。像最后的淘宝,也仅仅是一个外包做进去的产品,随着业务的一直倒退,淘宝的并发量指数级减少,同时对系统提出了严厉的挑战,这才逐渐造就了当初淘宝这样能够撑持数千万人同时在线的高并发零碎。

提起应答高并发,每个人都或多或少能够说出几种解决方案,高并发零碎的设计魅力在于咱们可能凭借程序员的聪明才智设计奇妙的计划,从而应答微小流量的冲击。从目前已知的计划中,大体能够演绎为以下几种

晋升单机性能

尽可能的晋升单机的性能是一个永恒的话题,无论是采纳分布式还是其余计划,单机性能的进步,对于一个零碎来说只有好处。拿编程语言来说,c 或者 c ++ 语言编写的程序实践上会比 java,net,Python 写的程序要高效,当然这须要建设在程序失常运行的状况下。晋升单机性能最简略粗犷的形式就是晋升硬件性能,举一个简略例子:如果数据库 DB 的服务器内存为 8G,随着数据量的减少,你会发现有些 sql 执行会缓缓的变慢,起因是数据库的索引或者数据在内存中齐全寄存不下,须要回写磁盘,有些查问在内存中并不能命中,造成了一些 sql 会在磁盘中查问数据,这个时候如果把服务器的内存减少到 16G,你会发现这些慢 sql 竟然凭空隐没了,这是硬件晋升性能的一个典型案例。

对于运行的程序也是同样的情理,尽可能的把程序优化到极致,兴许单机就能够达到他人分布式部署的性能成果,当然这须要咱们在编写代码的时候认真构思。

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

横向扩大

当一个单机零碎无奈抵制微小流量冲击的时候,最简略无效的解决方案之一便是横向扩大,横向扩大是指把微小的流量宰割为数个比拟小的流量,从而解决高并发零碎的性能问题,实质上,横向扩大属于分而治之的实践,属于分布式的概念领域。

举一个很简略的例子,假如目前单机解决申请数为 200/s,当每秒的申请数达到 1000 的时候,单台机器必定会遇到瓶颈,这个时候如果解决申请的服务器减少到 5 台,甚至更多,这样便轻松解决了性能问题。当然,是否不便的横向扩大还要看具体的零碎设计,如果零碎是无状态的,实践上横向扩大是没问题的,然而一些有状态的服务,可能会波及到状态的迁徙等工作,这也是为什么很多架构师提倡无状态服务的一个起因。

一个应用程序的横向扩大能够通过负载平衡来实现,像阿里云的 SLB 服务,nginx 的反向代理性能,这些都能够很不便实现应用程序的横向扩大。然而,像数据库比方 mysql,这样的 DB 零碎,无限度的横向扩大可能只是一个指标。大多数 DB 采纳的主从或者多主多素来解决横向扩大问题,主节点负责写操作,从节点负责读操作,当然这里波及到主从同步的机制,主从同步的提早等问题,有趣味的同学能够去深入研究一下。

那什么时候该抉择横向扩大呢?一般来讲,在零碎的设计之初便会思考横向扩大,因为这种计划足够简略,能够用堆砌硬件来解决的问题就不是问题。当初我敢说 90% 以上的零碎在第一版上线的时候就做了相似负载平衡的部署计划,其中有很多就利用了 nginx 的反向代理性能。

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

分布式系统的问题

缓存

除了下面所说的横向扩大计划,另外一种卓有成效并且足够简略的便是缓存计划。这一点毋庸置疑,缓存能够遍布在一个零碎的各个角落,从操作系统到浏览器,从 cpu 到磁盘,从数据库到音讯队列,任何略微简单的服务和组件中都有缓存的影子。

缓存为什么能够大幅度提高性能的性能呢?这还须要从零碎的瓶颈来说,在客户端一个申请的生命周期中,这个申请的响应工夫重大受限于最慢的那个环节,这相似于木桶效应(一个木桶能够存的水量,取决于最短那个木板)。

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

缓存在语义上要丰盛很多,咱们能够把任何能够升高响应工夫的两头存储都称之为缓存。比方 CPU 的一级缓存,二级缓存,三级缓存,浏览器的缓存等。缓存次要解决了上下游设施速度不匹配的问题

程序界有一句古话:把数据放在离用户最近的中央才是最快的。CDN 实质上就是做的这件事。对于缓存而言,咱们常常会听到浏览器缓存,过程内缓存,过程外缓存等概念。目前针对于服务端个别的缓存策略为采纳第三方 kv 存储设备,比方 redis,Memcache 等。当然在对性能极其刻薄的零碎中,我还是举荐应用过程内缓存,具体可见之前的推文:

高并发下为什么更喜爱过程内缓存

异步

谈到异步,必须要说下同步,同步调用是指调用方要阻塞期待被调用方执行结束才能够返回。零碎当初广泛都会采纳多线程的形式来提供零碎的吞吐量(多过程的形式当初很少,但不代表没有,比方:nodejs,nginx),在同步这种形式下,如果被调用方的响应工夫过长,会造成调用方的线程长时间处于期待状态,线程的利用率大幅度降低,线程对于零碎来说,是很低廉的资源,创立大量的线程去应答高并发是不明智的,不仅仅节约了内存,而且会加大线程上下文 cpu 切换的老本。

一个高吞吐量的零碎,实践上所有的线程都要时时刻刻在工作,而且把 cpu 资源压迫到最多。对于一个 IO 密集型操作来说,采纳异步形式能够大大提高零碎吞吐量。异步不须要期待被调用方执行实现就能够执行其余的逻辑,在被调用方执行结束之后通过告诉回调的形式反馈给调用方。

异步实质上是一种编程思维,一种编程模型。他进步的是零碎整体的吞吐量,然而申请的响应工夫比照同步形式来说会稍微加大。

像平时用的最多的音讯队列,在模型上也属于异步编程模型。调用方会把音讯丢到队列中,而后间接返回去执行其余业务,被调用方接管到音讯而后进行解决,而后依据具体的业务看是否须要给予后果回复。有不少秒杀零碎会采纳音讯队列进行流量削峰,这是异步带来的劣势之一。

对于异步更加具体的介绍能够查看之前的推文:

问世间异步为何物?

在这里我须要多说一句:异步并不是没有代价,在少数状况下,采纳异步会比同步形式编写更多的代码,而且查找 bug 会破费更多的工夫。然而对于一个高并发零碎来说,异步带来的好处还是值得的,前提是你正确利用了异步。

更多精彩文章

  • 分布式大并发系列
  • 架构设计系列
  • 趣学算法和数据结构系列
  • 设计模式系列

退出移动版