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

灵魂拷问:

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

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

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

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

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

提升单机性能

尽可能的提升单机的性能是一个永恒的话题,无论是采用分布式还是其他方案,单机性能的提高,对于一个系统来说只有益处。拿编程语言来说,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会花费更多的时间。但是对于一个高并发系统来说,异步带来的益处还是值得的,前提是你正确应用了异步。

●程序员修神之路--为什么我会了SOA,你们还要逼我学微服务?

●程序员过关斩将--数据库的乐观锁和悲观锁并非真实的锁

●程序员修神之路--设计一套RPC框架并非易事

●程序员过关斩将--要想获取我的用户信息,就得按照规矩来

●程序员过关斩将--更加优雅的Token认证方式JWT

●程序员过关斩将--cookie和session的关系其实很简单

●程序员修神之路--用NOSql给高并发系统加速

●程序员修神之路--高并发系统设计负载均衡架构

●程序员过关斩将--你为什么还在用存储过程?

●程序员修神之路--问世间异步为何物?

●程序员修神之路--提高网站的吞吐

长按添加菜菜好友

关注后回复:“大礼包”和“福利”,领取惊喜

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307917.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the

一:报错 org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement com.wyj.Dao.Bill.BillMapper.getBill. Its likely that neither a Result Type nor a Result Map was specified.二:解决 未在mapper.xml…

.NET5.0 单文件发布打包操作深度剖析

.NET5.0 单文件发布打包操作深度剖析前言随着 .NET5.0 Preview 8 的发布,许多新功能正在被社区成员一一探索;这其中就包含了“单文件发布”这个炫酷的功能,实际上,这也是社区一直以来的呼声,从 WinForm 的 msi 开始&am…

webpack实战之手写一个loader和plugin

webpack实战之编写一个简易的loader和plugin🔔序言🎵一、如何编写一个Loader1. 碎碎念2. 项目结构3. 业务代码编写(1)入口文件代码(2)编写loader(3)引用loader(4&#xf…

手写一个简易bundler打包工具带你了解Webpack原理

用原生js手写一个简易的打包工具bundler🥝序言🍉一、模块分析(入口文件代码分析)1. 项目结构2. 安装第三方依赖3. 业务代码4. 开始打包🥑二、依赖图谱Dependencies Graph1. 结果分析2. 分析所有模块的依赖关系🍐三、生成代码1. 逻…

不喜欢 merge 分叉,那就用 rebase 吧

阅读本文大概需要 3 分钟。有些人不喜欢 merge,因为在 merge 之后,commit 历史就会出现分叉,这种分叉再汇合的结构会让有些人觉得混乱而难以管理。如果你不希望 commit 历史出现分叉,可以用 rebase 来代替 merge。rebase &#xf…

你可能对position和z-index有一些误解

一文详解css中的position和z-index🧃序言🍷一、文章结构抢先知🍸二、position1. position的取值2. 标准文档流3. 各取值解析(1)static(2)relative(3)absolute&#xff08…

数据结构与算法专题——第九题 外排序

说到排序,大家第一反应基本上是内排序,是的,算法嘛,玩的就是内存,然而内存是有限制的,总有装不下的那一天,此时就可以来玩玩外排序,当然在我看来,外排序考验的是一个程序…

谁动了我的选择器?深入理解CSS选择器优先级

深入理解CSS选择器优先级😏序言🧐文章内容抢先看🤐一、基础知识1、为什么CSS选择器很强2、CSS选择器的一些基本概念(1)4种基本概念Ⅰ. 选择器Ⅱ. 选择符Ⅲ. 伪类Ⅳ. 伪元素(2)CSS选择器的命名空…

leetcode239. 滑动窗口最大值(思路+详解)

一:题目 二:思路 1.这个题不能用优先队列,虽然我们可以通过优先队列得到最大值,但是我们在移动 窗口的时候,便不可以正常的删除元素了 2.虽然不能用优先对列,但是我们依然希望可以得到队首的元素的时候是最大值,同时还…

《ASP.NET Core 与 RESTful API 开发实战》-- (第10章)-- 读书笔记

第 10 章 部署10.1 部署到 IISASP.NET Core 应用程序支持部署到 IIS 中,之后它将作为应用程序的反向代理服务器和负载均衡器,向应用程序中转传入的 HTTP 请求默认情况下,ASP.NET Core 项目的 Program 类使用如下方式创建 WebHostpublic stati…

翠香猕猴桃 和 薄皮核桃,快来下单

猴桃品种有很多,但不是所有的果子都叫翠香。椭圆形,果喙端较尖,黄褐色硬短茸毛;果肉翠绿色,质细多汁,香甜爽口,有芳香味,白色果心。这就是“翠香”,是集酸甜香于一身的猕…

你可能没有听说过 js中的 DOM操作还有这个: HTMLCollection 和 NodeList

一文了解DOM操作中的HTMLCollection和NodeList⛱️序言🎈一、基础知识1. 定义(1)HTMLCollection(2)NodeList2. 属性和方法(1)HTMLCollection(2)NodeList🪁二、…

leetcode144. 二叉树的前序遍历(递归+迭代)

一:题目 二&#xff1a;上码 1&#xff1a;递归 class Solution { public:void preorder(TreeNode* root,vector<int>&v ) {if(root NULL) return;v.push_back(root->val);preorder(root->left,v);preorder(root->right,v);}vector<int> preorderT…

都说性能调优难?玩转这3款工具,让你秒变“老司机”!

鲁迅说过&#xff1a;菜鸟写业务&#xff0c;老鸟搭架构&#xff0c;高手玩调优。性能调优可谓是食物链顶端的技术&#xff0c;高薪面试必备良品。然而有不少的开发者&#xff0c;工作多年&#xff0c;却对性能调优几乎一无所知&#xff0c;今天就带大家掰扯掰扯&#xff0c;从…

一文梳理JavaScript中常见的七大继承方案

阐述JavaScript中常见的七大继承方案&#x1f4d6;序言&#x1f4d4;文章内容抢先看&#x1f4dd;一、基础知识预备1. 继承的定义2. 继承的方式&#x1f4da;二、6大常见继承方式1. 原型链继承 &#x1f4a1;&#xff08;1&#xff09;构造函数、原型和实例的关系&#xff08;2…

微软发布 Microsoft Edge 85 稳定版

喜欢就关注我们吧&#xff01;微软推出了 Microsoft Edge 85 稳定版&#xff08;85.0.564.41&#xff09;&#xff0c;现在正逐步向用户推送。此版本带来了以下新特性&#xff1a;收藏夹和设置的本地同步。现在可以在自己的环境中的 Active Directory 配置文件之间同步浏览器收…

leetcode94. 二叉树的中序遍历(左中右)

二:上码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* Tre…

浅谈前端路由原理hash和history

浅谈前端路由原理hash和history&#x1f3b9;序言&#x1f3b8;一、前端路由原理1、SPA2、什么时候需要路由&#x1f3b7;二、Hash模式1、定义2、网页url组成部分&#xff08;1&#xff09;了解几个url的属性&#xff08;2&#xff09;演示3、hash的特点&#x1f3ba;三、Histo…

leetcode145. 二叉树的后序遍历

一:题目 二:上码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*…

.NET Core API文档管理组件 Swagger

Swagger这个优秀的开源项目相信大家都用过&#xff0c;不多介绍了&#xff0c;这里简单记录一下使用过程。开源地址&#xff1a;https://github.com/domaindrivendev/Swashbuckle.AspNetCore在项目中添加组件Install-Package Swashbuckle.AspNetCore下面用最少的代码完成接入&a…