Говоря о высоком уровне параллелизма — фронтенд-оптимизация

внешний интерфейс CDN

предисловие

Недавно получил задачу, бизнес-сценарий должен иметь дело с высоким параллелизмом.

Простите меня за то, что я подумал, что система блога Жуана Ифэна подверглась DDoS-атаке некоторое время назад, потому что, как я понимаю, их принцип уяснен, что сервер не может обрабатывать все параллельные задачи в течение определенного периода времени, вызывает некоторые запросы к быть ненормальным и даже вылетать, как блог Руан Ифэн.

Раньше у меня не было возможности коснуться слишком высокого параллелизма, поэтому у меня не было никакого практического опыта, однако в проекте, который я делал раньше, реализация функции seckill произвела некоторую обработку. использовать кеш для оптимизации и сокращения некоторых ненужных элементов.Внутренние запросы, но поскольку это начинающая компания, трафика не так много.Даже если это секилл, он не был дополнительно оптимизирован.Бизнес не нуждается в нужно, и я не думал об этом слишком много.

На самом деле, у меня все еще были некоторые идеи в начале, используя заголовки HTTP, надежный кеш (управление кешем), согласованный кеш (последнее изменение и Etag) и включение HTTP2, особенно HTTP2, должно значительно улучшить производительность, но большинство из них решения Всем нужна back-end поддержка, так что может front-end, я особо не задумывался и не обобщал.

понимать

Прежде чем строить архитектуру, мы должны сначала полностью понять требования, поэтому я отправился в Google, чтобы найти волну, и сначала посмотреть на несколько терминов:

  • QPS: количество запросов или запросов в секунду в поле Интернет относится к количеству запросов ответа в секунду (относится к HTTP-запросам).
  • Пропускная способность: количество запросов, обработанных в единицу времени (обычно определяется числом запросов в секунду и параллелизмом).
  • Время отклика: От запроса на получение ответа, например, система обрабатывает HTTP-запрос в течение 100 мс, эти 100 мс — это время ответа системы.
  • PV: Просмотр страницы, то есть просмотры страниц или клики, количество страниц, посещенных посетителем в течение 24 часов, и один и тот же человек, просматривающий одну и ту же страницу вашего веб-сайта, записывается как PV только один раз.
  • UV: Уникальный посетитель (UniQue Visitor), то есть один и тот же посетитель посещает веб-сайт несколько раз в течение определенного периода времени и считается только 1 уникальным посетителем.
  • Пропускная способность: чтобы рассчитать размер пропускной способности, вам нужно ориентироваться на два показателя: пиковый трафик и средний размер страницы.

Посмотрите еще несколько картинок:

Обычный доступ:

Высокий параллелизм:

Упрощение и перехват на стороне клиента:

Так как же объяснить высокий параллелизм простым способом? Сравнивая сервер с резервуаром для воды, есть три водопроводные трубы, соединяющие резервуар для воды с внешним миром.При нормальных обстоятельствах подмены воды могут выполняться обычным образом, но внезапно требуется циркуляция большого количества воды в течение определенного периода времени. , и давление водопроводных труб недопустимо. Проще говоря: паводки, утренние и вечерние часы пик, университетские столовые в 12:00, вероятно, основаны на этом принципе. Как решить эти практические проблемы, может ли высокий параллелизм извлечь из этого уроки?

  1. Наводнения: отремонтируйте насыпи (улучшите производительность сервера)
  2. Утренние и вечерние пики: выберите другие маршруты (обход и назначьте серверные линии), избегайте утренних и вечерних пиков, если они вам не нужны (уменьшите количество клиентских запросов).
  3. Университетская столовая в 12:00: школа откроет еще несколько столовых (статические ресурсы и внутренние API назначены на разные серверы)

Возвращаясь к проблеме высокого параллелизма, я думаю, что решения в основном следующие:

  1. Сжатие слияния статических ресурсов
  2. Уменьшите или объедините HTTP-запросы (компромисс, а не сокращение ради сокращения)
  3. Используйте CDN для децентрализации нагрузки на сервер
  4. Фильтровать запросы с помощью кеша

Позже я обнаружил, что если мы хотим хорошо оптимизировать, многие из 35 военных правил Yahoo также эффективны для решения проблемы высокой параллелизма.

вернемся к делу

Вернуться к делу, этот бизнес, чтобы помочь бесплатные заказы. У меня нет нескольких чертежей дизайна, поэтому я не буду размещать какие-либо рисунки из соображений деловой информации.Поскольку требуется несколько страниц, я разделил бизнес на три страницы:

  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 уже сделал это во время сборки.

Загрузка статического ресурса cdn

Затем статические ресурсы загружаются в Qiniu cdn.Конкретная идея реализации заключается в выполнении дополнительных upload.js после сборки запуска npm.При развертывании сервера необходимо развернуть только три html-файла. В упаковке:

"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)
      }
    },

Установите управление кешем заголовка ответа и последнее изменение

Установите заголовки ответа для всех данных и интерфейсов и используйте экспресс-моделирование.Если интервал между двумя запросами меньше 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. Установите управление кешем заголовка ответа и последнее изменение

Наиболее важными мерами являются, наверное, только эти несколько. Оптимизаций очень мало, и впереди еще долгий путь. Еще долгий путь. Продолжайте усердно работать.

Ссылаться на: