preface

I recently received a task for a business scenario that needed to handle high concurrency.

Forgive me for thinking that ruan Yifeng’s blog system was attacked by DDoS some time ago, because in my understanding, their principle is reasonable, the server can not handle all the parallel tasks in a certain period of time, resulting in some abnormal requests, and even crash like Ruan Yifeng’s blog.

Before doesn’t have the chance to contact with high concurrency, so there is no practical experience, is doing projects have seconds before the realization of the function of killing done certain processing, the processing is more use of the cache to optimize and reduce some unnecessary backend request, but because it is a startup, so that is not too much traffic, even seconds to kill, Therefore, there is no further optimization, business requirements do not need, and I do not think too much about this problem.

In the beginning, I had some ideas that using HTTP headers, cache-Control, last-Modified and Etag caching, and enabling HTTP2, especially, would improve performance, but most of these solutions require back-end support, so what can the front-end do? I haven’t really thought about it and summed it up.

understand

We need to understand the requirements thoroughly before we build the architecture, so we did a Google search and started with a few nouns:

  • QPS: The number of requests or queries per second. In Internet terms, the number of requests (HTTP requests) per second
  • Throughput: Number of requests processed per unit of time (usually determined by QPS and concurrency)
  • Response time: the time between sending a request and receiving a response. For example, it takes the system 100ms to process an HTTP request. This 100ms is the system response time
  • PV: Page View, that is, Page views or clicks, the number of pages visited by a visitor in 24 hours, the same person browsing the same Page of your website, only recorded as PV once
  • UV: UniQue Visitor, that is, the same Visitor visits the site many times within a certain period of time, only counted as one UniQue Visitor
  • Bandwidth: To calculate the bandwidth, pay attention to peak traffic and average page size

Look at a few more pictures:

Normal access:

High concurrency:

Client simplification and interception:

So how to explain the high concurrency superficially? The server is compared to a water tank, which is connected with the outside world to change water with three pipes. Under normal circumstances, the water can be changed normally, but suddenly a large amount of water needs to circulate for a period of time, and the pressure of the pipe can not bear it. More simple: flood disaster, morning and evening rush hour, 12 noon university dining hall, probably the same principle. How to solve these practical problems, high concurrency can also be used for reference?

  1. Flood disaster: Fix the dikes (enhance server performance)
  2. Morning and evening peak: Alternate routes (shunting, and allocating server lines), avoiding the morning and evening peak when not necessary (reducing client requests)
  3. 12pm university canteen: The university opens several more canes (static resources and back-end apis are allocated to different servers)

Returning to the problem of high concurrency, I think the main solutions are as follows:

  1. Static resource merge compression
  2. Reducing or merging HTTP requests (trade-offs, not reducing for the sake of reducing)
  3. Use CDN to distribute server stress
  4. Filter requests using caching

It turns out that many of Yahoo’s 35 catch-22 rules are also effective for dealing with high concurrency when it comes to optimizing well.

  • Yahoo front end optimization of 35 catch-22

Back to business

Back to business, this business is to help free orders. There are not many design drawings, so I will not show them for fear of involving commercial information. Because the requirement is multiple pages, I will divide the business into three pages:

  1. Home page, view the activity information page
  2. View your activity progress page, including activity end, start, activity in progress and power failure several states
  3. Help others power page, including to help him and their own to help two states

The solution

Use caching to store data

After a brief analysis, the data needed are as follows:

{
	// This activity id, to prevent multiple support activities launched at the same time, local storage chaos problem
	id:'xxxxxxxxxx'.// End time, this time is usually fixed, can also be stored locally, do not need multiple requests, after the time can clear this
	endTime:'xxxxxxxx'.// The number of people who need help
	needFriendsNumber:3.// Direct purchase price
	directBuyPrice: 9.9.// Own information, which is needed to help others and initiate assistance
	userInfo:{
		id:'xxxxxxxxx'.avatar:'xxxxxxxxx'
	},
	// The list of people who have helped me is displayed on the page that needs to be used. According to the demand, this list is not too many, and can also be stored locally
	helpMeList:[{
		id:'xxxxxxxxx'.avatar:'xxxxxxx'}, {id:'xxxxxxxxx'.avatar:'xxxxxxx'}... ] .// The list of help others can be placed in the local storage, when entering to help others no longer need to initiate a request, after helping others added to the array
	helpOtherList:[{
		id:'xxxxxxxxx'.avatar:'xxxxxxx'}, {id:'xxxxxxxxx'.avatar:'xxxxxxx'}... ] }Copy the code

Well, it seems possible to reduce requests with local storage, and 5M localStrong should be sufficient. There seems to be no need for additional requests beyond helping others and getting basic information for the first time and getting a list of helpers. This is the case with streamlining requests at the moment, because they are not fully written, so there are things that are not considered until the actual business is written.

Resources compression

Compressing resources has already been done by Webpack in build.

Static resource upload CDN

Then, static resources are uploaded to qiniu CDN. The specific implementation idea is to execute additional upload.js after NPM run build. When the server is deployed, only three HTML files need to be deployed. In the package:

"build": "node build/build.js && npm run upload".Copy the code
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)
Copy the code

Regardless of the Http request to the website server, the first time to open the home page:

After:

The principle is roughly this, the effect is still good, their own server only need to perform the necessary interface tasks on the line, do not need to be responsible for static resource transmission

Avoid frequent page refreshes

Make a limit, refresh the page within 5 seconds only to obtain the list data, to avoid frequent refresh to the server pressure

async init() {
      try {
        const store = JSON.parse(util.getStore('hopoActiveInfo'))
        // Avoid frequent flushes that increase server stress
        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 = `The ${this.basicInfo.directBuyPrice
        }Yuan direct purchase '
        this.computedStatus()
      } catch (error) {
        console.log(error)
      }
    },
Copy the code

Set the response headers cache-control and last-Modified

Set the response header for all data and interfaces, using Express simulation, and if the interval between two requests is less than 5 seconds, return 304 directly, without server processing

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

In conclusion, the measures taken are as follows:

  1. Use caching to streamline requests
  2. Consolidation compression
  3. Static resource upload CDN
  4. Avoid frequently refreshing the page to obtain data
  5. Set the response headers cache-control and last-Modified

The most important measures are probably only these a few, do very little optimization, the poor is still far away, heavy responsibility, continue to work hard.

Reference:

  • What is high concurrency
  • High concurrency and high traffic solutions
  • CDN and cache
  • Front-end page optimization method for high concurrent access to the server
  • Multi-dimensional Optimization: A deeper consideration of high concurrency strategy at the front end
  • Yahoo front end optimization of 35 catch-22
  • Summary of HTTP protocol knowledge