前言

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

原谅我第一时间想到的居然是前段时间阮一峰的博客系统遭到了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').cdnconst {ak, sk, bucket
} = cdnConfigconst mac = new qiniu.auth.digest.Mac(ak, sk)const qiniuConfig = new qiniu.conf.Config()
qiniuConfig.zone = qiniu.zone.Zone_z2const 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}` : fileif (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 = 304res.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协议知识总结

浅谈高并发-前端优化相关推荐

  1. 浅谈高并发系统性能调优

    女主宣言 今天带来的是一个篇长文,主要讲解高并发系统架构指标及调优测试经验,希望能对您的研究有所帮助.本文最先发布于 OpsDev,转载已获取作者授权. PS:丰富的一线技术.多元化的表现形式,尽在& ...

  2. 浅谈 高并发 处理方案

    愿打开此篇对你有所帮助. 文章目录 高性能开发十大必须掌握的核心技术 I/O优化:零拷贝技术 I/O优化:多路复用技术 线程池技术 无锁编程技术 进程间通信技术 Scale-out(横向拓展) 缓存 ...

  3. 浅谈网站访问速度优化

    周末女朋友公司的智慧医保项目上线了,但是web端访问速度比较慢,然后就来问问我有没有好的优化方案.于是就这篇[浅谈网站访问速度优化]就诞生了. 1.备案:好多个人网站为了方便,往往不喜欢备案,就把网站 ...

  4. 浅谈高可用度量及治理

    浅谈高可用度量及治理 高可用的度量 高可用的度量标准 高可用度量的若干问题 关于高可用中的几个9的计算 关于SLO设置的实践 关于故障的透传性 高可用的治理 高可用管理工作 OnCall 应急预案 根 ...

  5. 【浅谈DOM事件的优化】

    浅谈DOM事件的优化 在 JavaScript 程序的开发中,经常会用到一些频繁触发的 DOM 事件,如 mousemove.resize,还有不是那么常用的鼠标滚轮事件:mousewheel (在 ...

  6. 你的驱动听话吗 浅谈ATI显卡驱动优化

    你的驱动听话吗 浅谈ATI显卡驱动优化内容简介:对于显卡稍有了解的朋友一定不会陌生ATI显卡.昔日,ATI显卡凭借其优秀的视频回放能力和出色的着色渲染能力俘获众多DIY爱好者的心,甚至有网友将ATI的 ...

  7. 浅谈高通的MSM7230-评各大厂商

    浅谈高通的MSM7230并解释U8800的FM 有些同学问到为什么U8800没有FM: 有些问到为什么CPU是800MHz而不是1G: 有人问MSM7230比OMAP 3610/3630好还是差:答案 ...

  8. 万字干货 | Python后台开发的高并发场景优化解决方案

    嘉宾 | 黄思涵 来源 | AI科技大本营在线公开课 互联网发展到今天,规模变得越来越大,也对所有的后端服务提出了更高的要求.在平时的工作中,我们或多或少都遇到过服务器压力过大问题.针对该问题,本次公 ...

  9. 浅谈tomcat中间件的优化【转】

    今天来总结一下tomcat的一些优化的方案,由于本人才疏学浅,写的不好,勿喷! tomcat对于大多数从事开发工作的童鞋应该不会很陌生,通常做为默认的开发环境来为大家服务,不过tomcat默认的一些配 ...

最新文章

  1. 如何将自定义代码生成TVM
  2. 科研文献|结肠直肠癌早期检测中跨群体微生物标记物的鉴定
  3. 元素的   is_enable()、is_displayed()和is_selected()
  4. 2函数 matlab_(2)Matlab函数“fmincon”非线性优化问题
  5. 中国液冷数据中心发展白皮书
  6. 职工考勤管理信息系统数据库课设_数据库课程设计--职工考勤管理信息系统
  7. JAVA 可视化日历
  8. 如何避免delete和delete[]的尴尬?
  9. 投影机拼接融合技术--UE4拼接
  10. iPhone系统关闭自动更新并去除设置上的红点
  11. mac java 更新命令行_Java 8 Update 71正在尝试安装新的帮助程序工具。 (在Mac上)...
  12. centos7安装mplayer+smplayer
  13. 新账户的收发邮件服务器,轻松使用新电子邮件系统-信息化建设与管理处
  14. 如何真正做好客户管理
  15. Vscode 自动保存以及保存格式
  16. 为什么c语言是学不完的,为什么C语言诡异离奇、缺陷重重,却获得了巨大的成功?...
  17. xpath解析爬虫爬取豆瓣图书Top250的数据
  18. DBN的浅显易懂解释
  19. python机器学习开源代码_Python简化代码机器学习库PyCaret 2.0发布
  20. 《机器学习-吴恩达》课程笔记week1-2

热门文章

  1. redis源码阅读-zset
  2. >2023_ OceanBase Devcon 开发者大会体验
  3. 路由器的工作原理详解
  4. 拯救U盘之——轻松修复U盘“无法访问”的故障
  5. wx.createinneraudiocontext微信开发者工具没有声音
  6. 十个Flex/Air疑难杂症及解决方案简略
  7. 11-标准库fmt以及文件操作
  8. 微信小程序怎么实现轮播图
  9. python创建集合set()_Python 集合set
  10. 继往开来,我们一直在路上!