предисловие
Недавно получил задачу, бизнес-сценарий должен иметь дело с высоким параллелизмом.
Простите меня за то, что я подумал, что система блога Жуана Ифэна подверглась 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, вероятно, основаны на этом принципе. Как решить эти практические проблемы, может ли высокий параллелизм извлечь из этого уроки?
- Наводнения: отремонтируйте насыпи (улучшите производительность сервера)
- Утренние и вечерние пики: выберите другие маршруты (обход и назначьте серверные линии), избегайте утренних и вечерних пиков, если они вам не нужны (уменьшите количество клиентских запросов).
- Университетская столовая в 12:00: школа откроет еще несколько столовых (статические ресурсы и внутренние API назначены на разные серверы)
Возвращаясь к проблеме высокого параллелизма, я думаю, что решения в основном следующие:
- Сжатие слияния статических ресурсов
- Уменьшите или объедините HTTP-запросы (компромисс, а не сокращение ради сокращения)
- Используйте CDN для децентрализации нагрузки на сервер
- Фильтровать запросы с помощью кеша
Позже я обнаружил, что если мы хотим хорошо оптимизировать, многие из 35 военных правил Yahoo также эффективны для решения проблемы высокой параллелизма.
вернемся к делу
Вернуться к делу, этот бизнес, чтобы помочь бесплатные заказы. У меня нет нескольких чертежей дизайна, поэтому я не буду размещать какие-либо рисунки из соображений деловой информации.Поскольку требуется несколько страниц, я разделил бизнес на три страницы:
- Главная, просмотреть страницу информации о событии
- Просмотр собственной страницы хода выполнения действий, включая состояние окончания действия, начала действия, выполняемого действия и сбоя помощи
- Страница справки «Помогите другим», включая два состояния помощи другим и помощи себе
решение
Использовать кеш для хранения данных
После краткого анализа требуемые данные таковы:
{
// 这个活动的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()
})
В заключение, принятые меры:
- Используйте кэширование для оптимизации запросов
- объединить сжатие
- Загрузка статического ресурса cdn
- Избегайте частых обновлений страницы для получения данных
- Установите управление кешем заголовка ответа и последнее изменение
Наиболее важными мерами являются, наверное, только эти несколько. Оптимизаций очень мало, и впереди еще долгий путь. Еще долгий путь. Продолжайте усердно работать.
Ссылаться на:
- Давайте разберемся, что такое высокий параллелизм
- Решения с высоким параллелизмом и большим трафиком
- CDN и кеширование
- Метод оптимизации страницы внешнего интерфейса при большом количестве одновременных обращений к серверу
- Многомерная оптимизация — более глубокое осмысление стратегии высококонкурентного интерфейса.
- 35 армейских правил для оптимизации пользовательского интерфейса Yahoo
- Краткий обзор знаний протокола HTTP