В этой статье используется лицензионное соглашение «Signature 4.0 International (CC BY 4.0)», добро пожаловать на перепечатку или изменение для использования, но вам необходимо указать источник.Атрибуция 4.0 Международная (CC BY 4.0)
Автор этой статьи: Су Ян
Создано: 14 мая 2019 г. Статистические слова: 6024 слова Время чтения: 13 минут на чтение Ссылка на эту статью:Поиск teay.com/2019/05/14/…
Простые стратегии делают интерфейсные ресурсы высокодоступными
Несколько дней назад друг спросил меня, как было сделано решение высокой доступности для интерфейсных ресурсов, которое использовалось в предыдущей компании. Высокая доступность ресурсов звучит так, как будто это должно быть «обязательством» студентов, изучающих бэк-энд, эксплуатацию и техническое обслуживание. Однако высокая доступность интерфейсных ресурсов не так проста: в текущей сложной сетевой среде вы ожидаете, что пользователи будут обновляться несколько раз, или вы ожидаете, что пользователи переключатся с Wi-Fi на 4G и решат проблему по счастливой случайности? Когда стоимость привлечения клиентов сегодня так высока, неразумно отказываться от пользователей.
Подумав, что я давно не писал статей на тему фронтенда, решил кратко рассказать здесь. Надеюсь, это может помочь компаниям и командам на этапе запуска.
Прежде чем говорить о технических деталях, давайте поговорим о том, «что такое высокая доступность интерфейсных ресурсов».
Какова связь между высокой доступностью ресурсов и внешним интерфейсом?
Требование высокой доступности интерфейсных ресурсов должно быть незнакомо студентам с «больших заводов».
Потому что для крупных компаний существует большое количество резервных ресурсов облачного хоста, которые могут быть предоставлены для бизнес-группы, и будет поддерживаться определенный размер группы эксплуатации и обслуживания. Когда система мониторинга обнаруживает, что ресурсы недоступны онлайн, система может автоматически переключить проблемный ресурс на резервный ресурс в соответствии с политикой, а для некоторых услуг, которые не могут быть переключены автоматически, будет дежурный одноклассник по эксплуатации и обслуживанию, который будет вручную переключаться в первый раз. , чтобы обеспечить высокую доступность бизнеса.
Небольшим стартапам не так повезло, их ресурсы относительно ограничены, и у них даже нет полных мер мониторинга, не говоря уже о относительно полной команде эксплуатации и обслуживания.
Можно подумать, что закидывание статических ресурсов на CDN сделано раз и навсегда. Однако в реальном мире сетевая среда очень сложна, а доступность и качество доступа одного и того же хоста в разных линиях, регионах и периодах времени различны, поэтому использование CDN не панацея для решения этой проблемы, а использование нескольких CDN одновременно может быть более общим решением на текущем этапе.
Например, пользователи из разных регионов по умолчанию заходят на сайт по разным линиям, при возникновении проблемы с одной из линий некоторые пользователи не могут получить доступ к услугам, предоставляемым сайтом.
В настоящее время мы обычно используем метод переключения сервера ресурсов запроса для решения проблемы, например следующей.
Когда определенная линия CDN/сервиса не в норме, мы можем решить проблему недоступности ресурсов путем переключения доменных имен, но не забывайте одну очень важную вещь:
Имя доменного имени вступает в силу, требуется время, многоразовый эффективный цикл, в течение этого временного интервала смены доменных имен качество вашего обслуживания будет по-прежнему ухудшаться.
Кроме того, действие переключения ресурсов в этой схеме обычно выполняется на бэкэнде, и в это время страница была передана на сторону пользователя, а ресурс больше недоступен.Пользователю необходимо обновить перед запросом нового ресурса. адрес, и DNS может вступить в силу.Например, мы знаем, что многие популярные клиенты приложений устанавливают длительный срок действия ресурсов (даже включая страницы) для оптимизации производительности.Можно сказать, что это решение не очень эффективное решение.
Итак, если вы принимаете подобную программу, вы должны убедиться, что следующие четыре условия действуют для достижения вашей цели:
- Ваша система мониторинга обнаружила проблему и автоматически переключила ресурсы.
- Ваш владелец бизнеса находит проблему и вручную переключает ресурсы.
- Вы успешно переключили ресурсы, и DNS быстро вступили в силу (сетевой уровень, клиентский уровень).
- После того, как вы переключите ресурсы и DNS вступит в силу, ваши пользователи соответствующим образом обновят страницу, а не покинут ее напрямую.
Разве это не звучит волшебно.
Так есть ли простое и надежное решение этой проблемы?
Да, разрешить автоматическое переключение ресурсов на уровне интерфейса.
Введение в программу
Отслеживая информацию об ошибках загрузки ресурсов в интерфейсной среде и автоматически загружая ресурсы в других местах в соответствии с определенной стратегией, интерфейсно-зависимые ресурсы автоматически переключаются на интерфейс (на стороне пользователя) для достижения цели. высокая доступность интерфейсных ресурсов и уменьшение сбоев при загрузке внешних ресурсов, что приводит к недоступности службы и оттоку пользователей.
Симуляция окружающей среды
Для более интуитивной демонстрации того, как работает решение, я использую Docker для моделирования распространенного сценария.
Моделирование нескольких сетей
Давайте создадимdocker-compose.yml
, который содержит следующее содержимое.
version: '3'
services:
web:
image: ${NGX_IMAGE}
4 expose:
- 80
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.frontend.rule=Host:${MAIN_HOST}"
- "traefik.frontend.entryPoints=${SUPPORT_PROTOCOL}"
volumes:
- ./public/${MAIN_HOST}:/usr/share/nginx/html
extra_hosts:
- "${MAIN_HOST}:127.0.0.1"
cdn1:
image: ${NGX_IMAGE}
expose:
- 80
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.frontend.rule=Host:${CDN_HOST1}"
- "traefik.frontend.entryPoints=${SUPPORT_PROTOCOL}"
- "traefik.frontend.headers.customResponseHeaders=Access-Control-Allow-Origin:*"
volumes:
- ./public/${CDN_HOST1}:/usr/share/nginx/html
extra_hosts:
- "${CDN_HOST1}:127.0.0.1"
cdn2:
image: ${NGX_IMAGE}
expose:
- 80
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.frontend.rule=Host:${CDN_HOST2}"
- "traefik.frontend.entryPoints=${SUPPORT_PROTOCOL}"
- "traefik.frontend.headers.customResponseHeaders=Access-Control-Allow-Origin:*"
volumes:
- ./public/${CDN_HOST2}:/usr/share/nginx/html
extra_hosts:
- "${CDN_HOST2}:127.0.0.1"
networks:
traefik:
external: true
Как видите, веб-сайт приложения и две службы CDN определены в файле оркестровки, чтобы быть ближе к реальной сцене. Одна из CDN имеет то же имя корневого домена, что и веб-сайт приложения, а другая использует совершенно другое доменное имя, например следующее.
# 默认使用的镜像
NGX_IMAGE=nginx:1.15.8-alpine
# 支持访问的协议
SUPPORT_PROTOCOL=https,http
# 主站点的域名
MAIN_HOST=demo.lab.io
# 模拟根域名相同的CDN
CDN_HOST1=demo-cdn.lab.io
# 模拟根域名不同的CDN
CDN_HOST2=demo.cdn2.io
Сохраните вышеуказанное как.env
, и после привязки доменного имени в приведенном выше содержимом к локальному, выполнитьdocker-compose up
, вы можете начать настоящий бой.
Моделирование обычных сценариев
воплощать в жизньdocker-compose up
После этого мы увидим, что Docker автоматически создал для нас несколько каталогов.
./public
├── demo-cdn.lab.io
├── demo.cdn2.io
└── demo.lab.io
мы вdemo.lab.ioСоздано в каталогеindex.html
файл, как запись приложения.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="assets/app.js"></script>
</head>
<body>
</body>
</html>
затем в./demo.lab.io/public/assets/app.js
Создайте файл сценария, напишите все, что хотите, и смоделируйте загруженный ресурс.
document.addEventListener('DOMContentLoaded', function () {
var p = document.createElement('p');
p.innerText = 'script excute success.';
document.body.appendChild(p);
});
когда мы посещаемhttp://demo.lab.io/index.html
, не удивительно, вы увидите вывод скриптаscript excute success.
содержание.
мы будем./public/demo.lab.io/assets/app.js
скопировать в./public/demo-cdn.lab.io/assets/app.js
а также./public/demo.cdn2.io/assets/app.js
, смоделируйте сценарий, в котором ресурсы распределяются по CDN.
Простейшая техническая реализация
Сначала измените адрес ресурса, запрошенный выше, на адрес «CDN», чтобы проверить, доступна ли служба «CDN».
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="//demo-cdn.lab.io/assets/app.js"></script>
</head>
<body>
</body>
</html>
затем, удалив./public/demo-cdn.lab.io/assets/app.js
Этот скрипт имитирует сценарий сбоя ресурса CDN.
Если ваш браузер не ведет себя странно при кэшировании, вы получите пустую страницу со строкой ошибки:
default.html:8 GET http://demo-cdn.lab.io/assets/app.js 404 (Not Found)
Если мы столкнемся со сценарием ошибки разрешения доменного имени, мы получим другое сообщение об ошибке:
GET http://demo-cdn.lab.io/assets/app.js net::ERR_NAME_NOT_RESOLVED
В это время мы можем внести некоторые изменения на страницу, чтобы она могла переключать ресурс на другой ресурс CDN при неправильной загрузке ресурса, например:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
function loadOthers(resource) {
var script = document.createElement('script');
script.src = resource.src.replace('demo-cdn.lab.io','demo.cdn2.io');
document.head.appendChild(script);
}
</script>
<script src="//demo-cdn.lab.io/assets/app.js" onerror="loadOthers(this)"></script>
</head>
<body>
</body>
</html>
Откройте адрес еще раз, и вы обнаружите, что страница снова нормальная.
Расширенная версия
В приведенном выше сценарии мы имитируем способ автоматического переключения ресурсов внешним интерфейсом в обычном сценарии.
Далее давайте проведем небольшую оптимизацию, чтобы разрешить загрузку скриптов для поддержки большего количества адресов ресурсов и повышения удобства использования.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
function loadResource(links, fnSuccess, fnError) {
var script = document.createElement('script');
script.onerror = function () {
document.head.removeChild(script);
fnError();
};
script.onload = fnSuccess
script.src = links.shift();
document.head.appendChild(script);
}
function autoSwitch(resourceList) {
var resource = resourceList.shift();
loadResource([resource], function (success) {
console.log('loaded');
}, function (err) {
console.log('load error')
autoSwitch(resourceList);
});
}
</script>
</head>
<body>
<script>
var resourceList = [
'http://demo-cdn.lab.io/assets/app.js',
'http://demo.cdn2.io/assets/app.js',
'assets/app.js',
];
autoSwitch(resourceList);
</script>
</body>
</html>
В приведенной выше реализации мы сделали загрузку ресурсов более общей, добавили обратные вызовы для успешной и неудачной загрузки, дополнительную функцию для автоматического переключения ресурсов и передали скрипту загрузку ресурсов скрипта страницы для обработки.
Это решение помогло решить проблемы в большинстве сценариев, но что делать, если между вашими ресурсами есть зависимости?
Использовать с загрузчиком ресурсов
Давайте в качестве примера возьмем спецификацию модуля AMD, чтобы поговорить о том, как объединитьrequirejsИспользуйте автоматическое переключение ресурсов.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="assets/require-v2.3.6.min.js"></script>
<script>
function autoSwitch(resourceList) {
var resource = resourceList.shift();
requirejs([resource], function (success) {
console.log('loaded');
}, function (err) {
console.log('load error')
autoSwitch(resourceList);
});
}
</script>
</head>
<body>
<script>
var resourceList = [
'http://demo-cdn.lab.io/assets/app.js',
'http://demo.cdn2.io/assets/app.js',
'assets/app.js',
];
autoSwitch(resourceList);
</script>
</body>
</html>
Будуrequirejsимпортируйте страницу, затем используйтеrequirejs
замена методаloadResource
После метода вы обнаружите, что ничего не меняется.
Но на самом деле вы можете настроитьrequirejs.config
Чтобы позволить ресурсу сначала загрузить и инициализировать зависимый ресурс в процессе загрузки, приведите два практических примера:
requirejs.config({
map: {
// 这是一个 hack 用法,具体含义参考官方 API 文档
'*': { 'http://demo.cdn2.io/assets/app.js': 'lodash' },
}
});
requirejs.config({
shim:{
// 或者这样声明
'http://demo.cdn2.io/assets/app.js':{
deps:['vue']
}
}
});
Конечно, вы также можете преобразоватьautoSwitch
функция, которая сама динамически поддерживает зависимости.
другие ямы
На этом автоматическая загрузка ресурсов почти закончена, но на самом деле есть некоторые дополнительные ямы.
Например, объединение самых популярных инструментов сборкиwebpack
Используйте, ресурс изображения одноразово жестко запрограммирован и должен поддерживать динамизацию.
В 2017 году я однажды представил решение, и заинтересованные студенты могут взглянуть:GitHub.com/collect Teaary/me…, что в основном решает проблему ** Не генерировать вывод с несколькими записями**.
наконец
Многие, казалось бы, высокоуровневые решения на самом деле очень просты по своей природе. Вместо того, чтобы преследовать концепции высокого уровня, лучше успокоиться, изучить детали на практике и подумать о том, как технологии могут эффективно служить бизнесу и создавать ценность.
—ЭОФ
Теперь у меня есть небольшая группа по метанию, в которую входят друзья, которые любят метать.
В отсутствие рекламы мы будем вместе болтать о софте, HomeLab и вопросах программирования, а также время от времени будем делиться технической информацией о салоне в группе.
Друзья, которые любят бросать, могут отсканировать код, чтобы добавить друзей. (Пожалуйста, укажите источник и цель, иначе не пройдет проверку)