当前位置: 首页 > news >正文

程序员过关斩将——应对高并发系统有没有通用的解决方案呢?

灵魂拷问:

  • 应对高并发系统有没有一些通用的解决方案呢?

  • 这些方案解决了什么问题呢?

  • 这些方案有那些优势和劣势呢?

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

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

提升单机性能

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

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

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

横向扩展

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

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

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

image

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

image

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

分布式系统的问题

缓存

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

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

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

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

image

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

高并发下为什么更喜欢进程内缓存

异步

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

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

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

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

image

关于异步更加详细的介绍可以查看之前的推文:

问世间异步为何物?

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

RECOMMEND

推荐阅读

01

《Java并发编程实战》

推荐理由

Java并发编程里程碑著作!10年畅销100000册。书中采用循序渐进的讲解方式,从并发编程的基本理论入手,逐步介绍了在设计Java并发程序时各种重要的设计原则、设计模式以及思维模式,同时辅以丰富的示例代码作为对照和补充,使得开发人员能够更快地领悟Java并发编程的要领,快速地构建大规模的并发应用程序。

02

《Java高并发编程详解:深入理解并发核心库》

推荐理由

《Java高并发编程详解:多线程与架构设计》的姊妹篇!从底层原理总结和归纳各个技术细节,结合真实的案例深入分析微基准测试、性能度量、Java高并发类库的原理及应用。详细介绍Java微基准测试工具集JMH与平台级性能指标数据度量工具Metrics的使用方法,帮助读者快速开发出高效、健壮的并发应用程序。

03

《Java异步编程实战》

推荐理由

这是一部全面解析Java异步编程的实战型著作,针对各种常见异步编程场景,从编程语言、开发框架等角度深入讲解了异步编程的原理和方法。作者是阿里资深Java技术工程师加多,在Java异步编程、并发编程领域有深厚的积累。本书得到周志明、李运华、毗卢、于君泽、方腾飞等Java技术领域的资深专家的高度评价。

 

04

《Effective Java中文版(原书第3版)》

推荐理由

Java之父James Gosling鼎力推荐,Jolt获奖作品全新升级,Java程序员必备参考书。

包含大量完整的示例代码和透彻的技术分析,通过90条经验法则,探索新的设计模式和语言习惯用法,帮助读者更加有效地使用Java编程语言及其基本类库。

 

更多精彩回顾

书讯 |9月书讯(下)| 开学季,读新书

书讯 |9月书讯(上)| 开学季,读新书

资讯 |TIOBE 9 月编程语言:C++ 突起、Java 流行度下降

上新 | Webpack优化——将你的构建效率提速翻倍
书单 | 开学季——计算机专业学生必读的10本畅销经典

干货 | 为什么Spark能成为最火的大数据计算引擎?它是怎样工作的?

收藏 | 红帽资深解决方案架构师魏新宇:云原生应用构建之路

视频 | 大佬出镜推荐不可不读系列——程序员陈彼得

赠书 |【第21期】以实际项目作驱动,换种方式学Java

点击阅读全文查看更多好书

相关文章:

  • 8个流行的Python可视化工具包,总有一款适合你
  • 20张图片梳理工业软件全貌
  • 使用pandas进行数据快捷加载
  • 大数据必备的十大工具
  • SpringBoot基于jar包启动核心原理及流程详解
  • 【第22期】网络安全在身边|最强学习书单整理
  • 从“新基建”重新认识数据中心
  • 还在为面试被问JVM发愁?来看看阿里P7大佬的JVM笔记吧
  • 从“判断力”到“创造力”:GAN在图像生成上的应用
  • Istio进入1.7版本,Service Mesh 落地还有什么障碍?
  • 开源搜索引擎排名第一,Elasticearch是如何做到的?
  • 创客教育:青少年软体机器人制作的实践与探索
  • 架构师的成长之路
  • 区块链应用开发实战 | Dapp开发专业指南
  • RPA 如何赋能金融行业数字化转型?
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • Apache Zeppelin在Apache Trafodion上的可视化
  • Consul Config 使用Git做版本控制的实现
  • js如何打印object对象
  • markdown编辑器简评
  • PaddlePaddle-GitHub的正确打开姿势
  • python 装饰器(一)
  • Spring Boot快速入门(一):Hello Spring Boot
  • SpriteKit 技巧之添加背景图片
  • Swift 中的尾递归和蹦床
  • tab.js分享及浏览器兼容性问题汇总
  • 基于 Babel 的 npm 包最小化设置
  • 每天一个设计模式之命令模式
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 用mpvue开发微信小程序
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • 我们雇佣了一只大猴子...
  • 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源 ...
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​Java并发新构件之Exchanger
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • (10)Linux冯诺依曼结构操作系统的再次理解
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • ***监测系统的构建(chkrootkit )
  • **PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**
  • .net core 6 集成 elasticsearch 并 使用分词器
  • .net6+aspose.words导出word并转pdf
  • .NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2
  • .net利用SQLBulkCopy进行数据库之间的大批量数据传递
  • .Net中的设计模式——Factory Method模式
  • [Android Studio] 开发Java 程序
  • [AutoSar]BSW_Memory_Stack_004 创建一个简单NV block并调试
  • [C++]类和对象【下】
  • [CC2642R1][VSCODE+Embedded IDE+IAR Build+Cortex-Debug] TI CC2642R1基于VsCode的开发环境
  • [C语言]——内存函数
  • [Docker]五.Docker中Dockerfile详解
  • [NOIP 2003] 栈(三种方法:DP、数论、搜索)
  • [one_demo_15]模拟交通灯管理系统
  • [PHP] 算法-顺时针打印矩阵的PHP实现
  • [PHP]严格类型