浅谈高并发-前端优化

浅谈高并发-前端优化前言最近接到个任务 业务场景是需要处理高并发 原谅我第一时间想到的居然是前段时间阮一峰的博客系统遭到了 DDoS 攻击 因为在我的理解中 它们的原理是想通的 都是服务器在一定时间内无法处理所有的并行任

前言

最近接到个任务,业务场景是需要处理高并发。

原谅我第一时间想到的居然是前段时间阮一峰的博客系统遭到了DDoS攻击,因为在我的理解中,它们的原理是想通的,都是服务器在一定时间内无法处理所有的并行任务,导致部分请求异常,甚至会像阮一峰的博客一样崩溃。

之前不太有接触过高并发的机会,所以并没有什么实际经验,倒是之前做的项目中有秒杀功能的实现做过一定的处理,当时的处理就是多利用缓存进行优化和减少一些没必要的后端请求,但是因为是创业公司,所以并没有多少过多的流量,即便是秒杀,所以也没有进行更进一步的优化了,业务需求不需要,自己也没有过多去思考这个问题了。

其实刚开始我还是有些想法,利用HTTP头部,强缓存(cache-control)、协商缓存(last-modified和Etag)、开启HTTP2,尤其是HTTP2应该能将性能提升不少吧,但是这些方案大多都需要后端支持,那么前端能做什么呢,倒是还真没好好思考和总结一下。

理解

架构搭建之前首先要把需求理解透彻,所以去谷歌搜索了一波,首先看几个名词:

  • QPS:每秒钟请求或者查询的数量,在互联网领域,指每秒响应请求数(指HTTP请求)
  • 吞吐量:单位时间内处理的请求数量(通常由QPS与并发数决定)
  • 响应时间:从请求发出到收到响应花费的时间,例如系统处理一个HTTP请求需要100ms,这个100ms就是系统的响应时间
  • PV:综合浏览量(Page View),即页面浏览量或者点击量,一个访客在24小时内访问的页面数量,同一个人浏览你的网站同一页面,只记作一次PV
  • UV:独立访问(UniQue Visitor),即一定时间范围内相同访客多次访问网站,只计算为1个独立访客
  • 带宽:计算带宽大小需关注两个指标,峰值流量和页面的平均大小

再看几张图:

正常访问:

浅谈高并发-前端优化

高并发:

浅谈高并发-前端优化

客户端精简与拦截:

浅谈高并发-前端优化

那么怎么浅显的解释下高并发呢?把服务器比作水箱,水箱与外界连接换水有三根水管,正常情况下都能正常进行换水,但是突然一段时间大量的水需要流通,水管的压力就承受不了了。再简单点:洪涝灾害、早晚高峰、中午12点的大学食堂,大概都是这个原理吧。这些现实问题怎么解决的呢,高并发是不是也可以借鉴一下呢?

  1. 洪涝灾害:修固堤岸(增强服务器性能)
  2. 早晚高峰:多选择其他路线(分流,和分配服务器线路),不是一定需要就避开早晚高峰(减少客户端请求)
  3. 中午12点的大学食堂:学校多开几个食堂(静态资源与后端api分到不同服务器)

回到高并发的问题上,我认为解决方案主要有这些:

  1. 静态资源合并压缩
  2. 减少或合并HTTP请求(需权衡,不能为了减少而减少)
  3. 使用CDN,分散服务器压力
  4. 利用缓存过滤请求

后来发现如果要把优化做到很好,雅虎35条军规中很多条对解决高并发也都是有效的。

  • 雅虎前端优化的35条军规

回到业务

回到业务上,本次业务是助力免单。设计图没有几张,担心涉及商业信息就不放图了,因为要求是多页面,我将业务分成三个页面:

  1. 首页,查看活动信息页
  2. 查看自己活动进程页,包括活动结束,开始活动,活动进行中和助力失败几个状态
  3. 帮助他人助力页,包括帮他助力和自己也要助力两个状态

解决方案

利用缓存存放数据

简单分析了一下,需要的数据有:

{ // 这个活动的id,防止多个助力活动同时发起,本地存储混乱的问题 id:'xxxxxxxxxx', // 结束时间,这个时间一般是固定的,也可以放到本地存储,不需要多次请求,过了时间可以clear这个 endTime:'xxxxxxxx', // 需要助力的人数 needFriendsNumber:3, // 直接购买的价格 directBuyPrice: 9.9, // 自己的信息,在帮助别人和发起助力时需要自己的信息 userInfo:{ id:'xxxxxxxxx', avatar:'xxxxxxxxx' }, // 帮助过我的人列表,显示帮助我的页面需要用,根据需求看,这个列表人数不会太多,也可以放到本地存储 helpMeList:[{ id:'xxxxxxxxx', avatar:'xxxxxxx' },{ id:'xxxxxxxxx', avatar:'xxxxxxx' } ... ], // 帮助别人的列表,可以放到本地存储中,在进入给别人助力时不用再发起请求,帮助过别人后加到数组中 helpOtherList:[{ id:'xxxxxxxxx', avatar:'xxxxxxx' },{ id:'xxxxxxxxx', avatar:'xxxxxxx' } ... ] } 

嗯,貌似都可以借助本地存储实现减少请求的目的,5M的localStrong应该也够用。这样算来除了助力他人和第一次获取基本信息还有获取助力名单,貌似也不需要其他的额外的请求了。精简请求这个方面目前就是这样了,因为还没有完全写完,所以还有没考虑到的就要到写实际业务的时候碰到再处理了。

资源压缩

压缩资源的话webpack在build的时候已经做过了。

静态资源上传cdn

然后就是静态资源上传到七牛cdn,具体实现思路是在npm run build之后,执行额外的upload.js,服务器部署的时候只需要部署三个html文件就可以了。 package中:

"build": "node build/build.js && npm run upload", 
const qiniu = require('qiniu') const fs = require('fs') const path = require('path') var rm = require('rimraf') var config = require('../config') const cdnConfig = require('../config/app.config').cdn const { ak, sk, bucket } = cdnConfig const mac = new qiniu.auth.digest.Mac(ak, sk) const qiniuConfig = new qiniu.conf.Config() qiniuConfig.zone = qiniu.zone.Zone_z2 const doUpload = (key, file) => { const options = { scope: bucket ':' key } const formUploader = new qiniu.form_up.FormUploader(qiniuConfig) const putExtra = new qiniu.form_up.PutExtra() const putPolicy = new qiniu.rs.PutPolicy(options) const uploadToken = putPolicy.uploadToken(mac) return new Promise((resolve, reject) => { formUploader.putFile(uploadToken, key, file, putExtra, (err, body, info) => { if (err) { return reject(err) } if (info.statusCode === 200) { resolve(body) } else { reject(body) } }) }) } const publicPath = path.join(__dirname, '../dist') // publicPath/resource/client/... const uploadAll = (dir, prefix) => { const files = fs.readdirSync(dir) files.forEach(file => { const filePath = path.join(dir, file) const key = prefix ? `${prefix}/${file}` : file if (fs.lstatSync(filePath).isDirectory()) { return uploadAll(filePath, key) } doUpload(key, filePath) .then(resp => { rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { if (err) throw err }) console.log(resp) }) .catch(err => console.error(err)) }) } uploadAll(publicPath) 

抛开与网站服务器的Http请求,第一次打开首页:

浅谈高并发-前端优化

之后:

浅谈高并发-前端优化

原理大概是这样,效果也还是不错,自己的服务器只需要执行必要的接口任务就行了,不需要负责静态资源的传输

浅谈高并发-前端优化

避免高频刷新页面

做了一个限定,5秒内刷新页面只获取一次列表数据,避免高频刷新带给服务器的压力

async init() { try { const store = JSON.parse(util.getStore('hopoActiveInfo')) // 避免高频刷新增加服务器压力 if (store && (new Date() - new Date(store.getTime)) < 5000) { this.basicInfo = store } else { this.basicInfo = await getActiveInfo() this.basicInfo.getTime = new Date() } util.setStore(this.basicInfo, 'hopoActiveInfo') this.btn.noPeopleAndStart.detail[0].text = `${ this.basicInfo.directBuyPrice } 元直接购买` this.computedStatus() } catch (error) { console.log(error) } }, 

设置响应头cache-control和last-modified

对于所有的数据和接口设置响应头,利用express模拟,如果两次请求间隔小于5秒,直接返回304,不需要服务器进行处理

app.all('*', function(req, res, next){ res.set('Cache-Control','public,max-age=5') if ((new Date().getTime() - req.headers['if-modified-since'] )< 5000) { // 检查时间戳 res.statusCode = 304 res.end() } else { var time =(new Date()).getTime().toString() res.set('Last-Modified', time) } next() }) 

最后总结一下,采取了的措施有:

  1. 利用缓存,精简请求
  2. 合并压缩
  3. 静态资源上传cdn
  4. 避免高频刷新页面获取数据
  5. 设置响应头cache-control和last-modified

最主要的措施大概也只有这几个,做到的优化很少,差的也还很远,任重而道远,继续努力吧。

参考:

  • 一起了解什么是高并发
  • 高并发和大流量解决方案
  • CDN 与 缓存
  • 高并发访问服务器时前端页面优化方法
  • 多“维”优化——前端高并发策略的更深层思考
  • 雅虎前端优化的35条军规
  • HTTP协议知识总结
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/230626.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Eclipse安装、使用及卸载

    Eclipse的安装、使用及卸载Eclipse安装网站下载安装包开始安装Eclipse使用开始使用Eclipse创建Java项目运行Java代码导入、导出项目Eclipse设置更新Eclipse卸载EclipseEclipse安装网站下载安装包Eclipse官网Eclipse下载点击左上方的Download进入Eclipse下载页面点击下方的Download进行下载(标黄的位置也可点击,可能安装方式不同)开始安装下载完成后,点击安装包开始安装点击EclipseIDEforj

    2022年4月6日
    68
  • 对比java和python对比「建议收藏」

    对比java和python对比「建议收藏」1.难易度而言。python远远简单于java。  2.开发速度。Python远优于java  3.运行速度。java远优于标准python,pypy和cython可以追赶java,但是两者都没有成熟到可以做项目的程度。  4.可用资源。java一抓一大把,python很少很少,尤其是中文资源。  5.稳定程度。python3和2不兼容,造成了一定程度上的混乱以及大批类库失效。ja

    2022年7月8日
    26
  • docker_docker一键部署

    docker_docker一键部署1、安装mysql自行安装2、安装Gogs自行安装3、安装drone/dronedockerrun-d\–volume=/var/lib/drone:/data\–env=DRONE_DEBUG=true\–env=DRONE_LOGS_TRACE=true\–env=DRONE_LOGS_DEBUG=true\–env=DRONE_LOGS_PRETTY=true\–env=DRONE_AGENTS_ENABLED=true\–env=

    2022年8月15日
    12
  • window10安装mysql8.0_win7安装MySQL所需环境

    window10安装mysql8.0_win7安装MySQL所需环境mysql官网找到下载–>拉到最下面找到社区版下载–>下载下面是我下载好的度盘链接提取码:sws3解压到指定目录此时解压后的文件中没有data目录和ini文件然后做环境变量,也可以最后再做win7和windowsserver2008r2做环境变量都是在Path里用分号隔开前面的路径,直接加上mysql的bin目录绝对路径即…

    2025年11月12日
    5
  • 反应java程序并行机制的特点_【单选题】Java语言具有许多优点和特点,反映了Java程序并行机制的特点的是( )…

    反应java程序并行机制的特点_【单选题】Java语言具有许多优点和特点,反映了Java程序并行机制的特点的是( )…【单选题】Java语言具有许多优点和特点,反映了Java程序并行机制的特点的是()更多相关问题妊娠小便不通,或频数量少,小腹胀急疼痛,坐卧不宁,面色晄白,头重眩晕,短气懒言,大便不爽,舌淡在WDM传输中,色散的有利和有害的影响有哪些?一般可采用什么方法抑制色散的负面影响?下述哪项与妊娠小便不通的特点不符()A.妊娠期间,小便频数量少B.小便不通C.小腹胀急而痛D.烦以下各项中,属于市场调查过程中…

    2022年7月7日
    30
  • acwing-1170. 排队布局(差分约束)[通俗易懂]

    acwing-1170. 排队布局(差分约束)[通俗易懂]当排队等候喂食时,奶牛喜欢和它们的朋友站得靠近些。农夫约翰有 N 头奶牛,编号从 1 到 N,沿一条直线站着等候喂食。奶牛排在队伍中的顺序和它们的编号是相同的。因为奶牛相当苗条,所以可能有两头或者更多奶牛站在同一位置上。如果我们想象奶牛是站在一条数轴上的话,允许有两头或更多奶牛拥有相同的横坐标。一些奶牛相互间存有好感,它们希望两者之间的距离不超过一个给定的数 L。另一方面,一些奶牛相互间非常反感,它们希望两者间的距离不小于一个给定的数 D。给出 ML 条关于两头奶牛间有好感的描述,再给出 MD

    2022年8月9日
    9

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号