Сводка годового опыта разработки Node.js

Node.js

Эта статья была впервые опубликована в публичном аккаунте: CoyPan, как и ожидалось.

написать впереди

Прежде чем я это узнал, прошел год с тех пор, как я написал Node.js. В отличие от первоначальной демонстрации, местных инструментов и т. д., в этом году все онлайн-бизнесы написаны на Node.js. От начала изоморфизма Node.js до недавнего уровня доступа к Node его можно рассматривать как введение в разработку Node. В настоящее время я сам поддерживаю большинство сервисов Node, переданных группе, включая внутренние системы и онлайн-сервисы. Недавно добавленные фоновые сервисы также разрабатываются с использованием Node, насколько это возможно. Эта статья представляет собой краткое изложение и размышление о моей недавней работе.

В этой статье мы не будем углубляться в особенности, архитектуру и т. д. самого Node.js. Я не писал расширения Node, библиотеки или чего-то еще, и я недостаточно знаю Node.js.

Зачем использовать узел

Для меня, для команды причина для Node на самом деле довольно проста:быстро развиваться. Студенты, знакомые с JS, могут быстро приступить к работе и сэкономить средства. Выберите библиотеку http-сервера, чтобы запустить сервер, выберите соответствующее промежуточное ПО, сопоставьте маршрут запроса и используйте библиотеку ORM для связывания базы данных, добавления, удаления, изменения и запроса в зависимости от ситуации.

Применимые сценарии для узла

Node.js использует управляемую событиями неблокирующую модель ввода-вывода, что делает ее легкой и эффективной. Эта модель позволяет Node.js избежать потери процессорного времени, вызванного ожиданием ввода или вывода (база данных, файловая система, веб-сервер...) для ответа. Таким образом, Node.js подходит для сценариев с высокой степенью параллелизма, интенсивным вводом-выводом и небольшим объемом бизнес-логики.

Соответственно обычному конкретному делу, если это внутренняя система, большинству из них просто нужно добавить, удалить, изменить и проверить определенную базу данных, то серверная часть — это непосредственно шаттл Node.js.

Для онлайн-бизнеса, если трафик невелик и бизнес-логика проста, серверная часть тоже может полностью использовать Node.js. В проектах с большим трафиком и высокой сложностью Node.js обычно используется в качестве уровня доступа, а за реализацию сервисов отвечают студенты. Как показано ниже:

То же самое и с написанием JS, чем отличается разработка Node.js от разработки страницы

Разработка страниц на стороне браузера включает в себя взаимодействие с пользователями и повторное взаимодействие с ними Браузер также предоставляет нам различные веб-API. Node.js в основном ориентирован на данные и после получения запроса возвращает конкретные данные. В этом разница между ними в бизнес-пути. Реальная разница на самом деле заключается в бизнес-модели (бизнес-модель, это слово, о котором я думал). Покажи прямо.

При разработке страницы в браузере каждого пользователя есть копия кода JS. Если код выйдет из строя при определенных обстоятельствах, это повлияет только на текущего пользователя и не повлияет на других пользователей, и пользователь может обновить его для восстановления. В то время как в Node.jsВ случае мультипроцесса не открывается, все пользовательские запросы будут вводить один и тот же код JS, и только один поток выполняет этот код JS. Если запрос пользователя вызывает ошибку, процесс Node.js зависает, и серверная часть зависает напрямую. Хотя может быть защита процесса, зависший процесс будет перезапущен, но в случае большого количества пользовательских запросов часто будут возникать ошибки, а серверная сторона может продолжать зависать и перезапускаться, вызывая влияние.

Вышеупомянутое может быть самой большой разницей между разработкой Node.js и разработкой внешнего интерфейса JS.

Заметки о разработке Node.js

Когда пользователь обращается к службе Node.js, если определенный запрос зависает, служба не может вернуть результат в течение длительного времени или логическая ошибка приводит к зависанию службы, что приведет к масштабным проблемам. Цель серверной части состоит в том, чтобыбыстро и надежновернуть данные.

тайник

Поскольку Node.js плохо справляется со сложной логикой (сам JavaScript имеет низкую эффективность выполнения), если вы хотите использовать Node.js в качестве уровня доступа, вам следует избегать сложной логики. Для быстрой обработки данных и возврата, важный момент: используйте кеш.

Например, используя Node для прямой изоморфности React,renderToStringЭтот API можно назвать относительно тяжелой логикой. Если сложность страницы высокая, каждый запрос выполняется полностьюrenderToString, это займет много времени на выполнение кода, увеличит время отклика и снизит пропускную способность сервиса. В настоящее время кэширование очень важно.

Основной способ реализации кэша: кэш памяти. Может быть реализовано с помощью Map, WeakMap, WeakRef и т. д. Обратитесь к следующему простому примеру кода:

const cache = new Map();

router.get('/getContent', async (req, res) => {
  const id = req.query.id;
  
  // 命中缓存
  if(cache.get(id)) {
    return res.send(cache.get(id));
  }
  
  // 请求数据
  const rsp = await rpc.get(id);
 	// 经过一顿复杂的操作,处理数据
  const content = process(rsp);
  // 设置缓存
  cache.set(id, content);
  
  return res.send(content);
});

При использовании кэшей возникает очень важный вопрос: как обновляется кэш памяти. Один из самых простых способов — запустить таймер, регулярно удалять кеш и сбрасывать кеш при поступлении следующего запроса. В приведенный выше код добавьте следующий код:

setTimeout(function() {
  cache.clear();
}, 1000 * 60); // 1分钟删除一次缓存

Если серверная часть полностью реализована с помощью узла, то для прямого подключения к базе данных необходимо использовать сторону узла.Когда требования к своевременности данных не слишком высоки, а трафик не слишком велик, можно использовать модель, аналогичную приведенной выше. , как показано на рисунке ниже. Это снижает нагрузку на базу данных и ускоряет реакцию узла.

Кроме того,Также нужно обратить внимание на размер кеша памяти. Если вы продолжите записывать новые данные в кеш, память будет становиться все больше и больше и в конечном итоге взорвется. Рассмотрите возможность использования алгоритма LRU (наименее недавно использовавшегося) для кэширования. Откройте блок памяти специально как область кэша. Когда размер кэша достигает верхнего предела, самый старый неиспользуемый кэш удаляется.

Кэш памяти будет полностью аннулирован при перезапуске процесса.

Когда фоновый бизнес сложен, а трафик уровня доступа и объем данных велики, можно использовать следующую архитектуру для использования независимой службы кэширования памяти. Уровень доступа к узлу напрямую извлекает данные из службы кеша, а фоновая служба напрямую обновляет службу кеша.

Конечно, архитектура на рисунке выше — самый простой случай, в действительности же необходимо учитывать вопросы распределенного кэша и когерентности кэша. Это другая тема.

обработка ошибок

Из-за особенностей языка Node.js службы Node относительно подвержены ошибкам. И если что-то пойдет не так, в результате услуга будет недоступна. Поэтому обработка ошибок очень важна.

Обработка ошибок, чаще всего используетсяtry catch . Ноtry catchНе удалось поймать асинхронные ошибки. В Node.js асинхронные операции очень распространены, а асинхронные операции в основном выявляют ошибки в функциях обратного вызова. См. пример:

const readFile = function(path) {
	return new Promise((resolve,reject) => {
		fs.readFile(path, (err, data) => {
			if(err) { 
				throw err; // catch无法捕获错误,这和Node的eventloop有关。
        // reject(err); // catch可以捕获
      }
      resolve(data);
		});
	});
}

router.get('/xxx', async function(req, res) {
  try {
    const res = await readFile('xxx');
    ...
  } catch (e){
    // 捕获错误处理
    ...
    res.send(500);
  }
});

В приведенном выше коде ошибка, выдаваемая в readFile, не может быть обнаружена с помощью catch. если мы положимthrow errзаменитьPromise.reject(err), ошибка может быть поймана в catch.

Мы можем обещать все асинхронные операции, а затем использовать async, try, catch для единообразной обработки ошибок..

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

process.on('uncaughtException', (err) => {
  console.error(`${err.message}\n${err.stack}`);
});

process.on('unhandledRejection', (reason, p) => {
  console.error(`Unhandled Rejection at: Promise ${p} reason: `, reason);
});

Что касается захвата ошибок в Node.js, вы также можете использоватьdomainмодуль. Сейчас этот модуль устарел, и я не практиковал его в проекте, поэтому не буду его здесь раскрывать. Модуль async_hooks, запущенный Node.js в последние годы, все еще находится в экспериментальной стадии, и его не рекомендуется использовать непосредственно в онлайн-среде. Проделайте хорошую работу по защите процессов, включите несколько процессов, своевременно исправьте предупреждения об ошибках, разработайте хорошие стандарты кодирования и используйте соответствующие платформы для повышения эффективности и стабильности служб Node.

написать на обороте

В этой статье собраны итоги практики разработки Node.js за более чем год. Разработка Node.js отличается от разработки интерфейсных веб-страниц, и основное внимание уделяется другому. Я давно не занимаюсь разработкой Node.js, и у меня нет глубокого понимания некоторых моментов.Эта статья просто некоторый опыт. Обмен приветствуется.