PHP, Node.js или Go: какой бэкенд выбрать

Чем PHP, Node.js и Go отличаются для серверной части: тринадцать критериев, какой язык под какой проект, как разница проявляется на практике, один API на всех трёх и частые ошибки.

Стек и технологии Обновлено

Коротко

PHP, Node.js и Go — три самых частых выбора для серверной части веб-проекта, и каждый выигрывает на своём месте. PHP — самый быстрый путь к сайту, магазину или админке: хостинг везде, каждый запрос с чистого листа, огромная экосистема. Node.js — выбор, когда фронтенд на JavaScript или TypeScript и сервер должен делить с ним код и типы или когда много реального времени — чаты, уведомления, живые данные. Go — для сервисов, которые должны держать высокую нагрузку на скромном железе со стабильным временем ответа: API, очереди, шлюзы. Многие проекты используют два из них рядом.

Коротко: что выбрать

Начните с того, чем сервер в основном занят. Если он собирает страницы, обрабатывает формы и обслуживает админку — это родная стихия PHP: дёшево в хостинге, быстро в разработке, легко найти разработчиков. Если он держит тысячи открытых соединений или делит логику с интерфейсом на React — Node.js. Если это API под настоящей нагрузкой, обработчик очередей или шлюз, который должен отвечать за миллисекунды при любом трафике, — Go.

Выбор не исключающий. Типичная здоровая схема: сайт и админка на PHP, нагруженная часть на Go, а сборка интерфейса — на Node.js и Vite. Каждый язык делает то, что у него лучше всего получается.

  • Сайты и админки — PHP
  • Реальное время и общий код — Node.js
  • Нагрузка и стабильные задержки — Go

PHP, Node.js и Go: подробное сравнение

Тринадцать критериев рядом. Скорость зависит от кода и базы, поэтому в таблице — взаимное положение, а не бенчмарки.

КритерийPHPNode.jsGo
Модель запроса каждый запрос с чистого листа один процесс, цикл событий горутина на запрос
Типизация динамическая + строгие типы по желанию с TypeScript — статическая при сборке статическая, проверяет компилятор
Скорость под нагрузкой хорошая с OPcache высокая на вводе-выводе самая высокая из трёх
Память на воркер; много воркеров складываются один процесс, умеренно экономнее всех
Долгие соединения с доп. инструментами из коробки из коробки
Тяжёлые вычисления слабо блокирует цикл, нужны потоки сильно, использует все ядра
Хостинг любой, включая виртуальный VPS или платформа VPS, один файл
Выкладка скопировать файлы код плюс node_modules, менеджер процессов один бинарник, менеджер процессов
Готовые CMS и магазины больше всего немного почти нет
Общий код с фронтендом нет да, один язык нет
Скорость разработки очень высокая для сайтов высокая высокая, когда основа написана
Разработчиков на рынке очень много очень много меньше, но растёт
Лучше всего для сайтов, магазинов, админок реального времени, API для React, ботов нагруженных API, очередей, шлюзов

Какой язык под какой проект

Двенадцать типичных проектов с рекомендацией и причиной.

ПроектБратьПочему
Корпоративный сайт или лендинг PHP недорогой хостинг, быстрая разработка
Интернет-магазин или каталог PHP классическая задача с самой богатой экосистемой
Админка или CRM PHP формы, таблицы и роли — его повседневная работа
API для интерфейса на React Node.js общие типы и один язык
Чат, уведомления, живые данные Node.js или Go открытые соединения — родная стихия обоих
Telegram-бот и Mini App Node.js или Go долгоживущие процессы и хорошие библиотеки
Сайт на Next.js Node.js серверной отрисовке React он нужен
Нагруженный API Go стабильные задержки и мало памяти
Обработчик очередей и интеграций Go горутины обрабатывают тысячи задач параллельно
Шлюз или прокси Go стандартная библиотека создана для сети
Импорт и скрипты по расписанию любой тот, что уже есть в проекте
Только виртуальный хостинг PHP остальным нужен VPS

Как разница проявляется в настоящем проекте

  1. Утечка памяти

    В PHP она умирает вместе с запросом; в Node.js и Go растёт, пока процесс не перезапустят, — нужен мониторинг.

  2. Необработанная ошибка

    В PHP она ломает один запрос; в Node.js может уронить весь процесс; в Go паника в обработчике перехватывается сервером.

  3. Десять запросов к чужим API

    PHP делает их по очереди, если не взять curl_multi; Node.js и Go — параллельно, естественным образом.

  4. Пик трафика

    PHP нужны достаточное число воркеров и память под них; Go поглощает пик горутинами; Node.js — пока ничто не блокирует цикл.

  5. Обновление на сервере

    PHP — скопировать файлы; Go — заменить один бинарник и перезапустить; Node.js — поставить зависимости и перезапустить.

  6. Через пять лет

    Код на Go и чистом PHP стареет медленно; проект на Node.js с множеством зависимостей требует регулярных обновлений.

Один API на трёх языках

Один и тот же адрес — список товаров с фильтром по цене — на PHP, Node.js и Go. Каждый запущен настоящим сервером и дал одинаковый ответ.

PHP

Файл, который выполняется с нуля на каждый запрос, — никакого серверного кода, который нужно держать живым.

index.php
<?php
declare(strict_types=1);

// PHP: каждый запрос выполняет файл с чистого листа — состоянию нечему утечь между запросами
$products = [
    ['sku' => 'A-100', 'title' => 'Дубовый стол', 'price' => 24000],
    ['sku' => 'B-200', 'title' => 'Сосновая полка', 'price' => 5000],
];

if (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) !== '/api/products') {
    http_response_code(404);
    exit;
}
$max = (int) ($_GET['max'] ?? PHP_INT_MAX);
header('Content-Type: application/json');
echo json_encode(
    array_values(array_filter($products, fn(array $p): bool => $p['price'] <= $max)),
    JSON_UNESCAPED_UNICODE,
);

Node.js

Один долгоживущий процесс на встроенных модулях; тот же язык, что у интерфейса.

server.ts
import { createServer } from 'node:http';

// Node.js: один долгоживущий процесс, цикл событий обслуживает каждый запрос
const products = [
  { sku: 'A-100', title: 'Дубовый стол', price: 24000 },
  { sku: 'B-200', title: 'Сосновая полка', price: 5000 },
];

createServer((req, res) => {
  const url = new URL(req.url ?? '/', 'http://localhost');
  if (url.pathname !== '/api/products') {
    res.writeHead(404).end();
    return;
  }
  const max = Number(url.searchParams.get('max') ?? Infinity);
  res.writeHead(200, { 'content-type': 'application/json' });
  res.end(JSON.stringify(products.filter((p) => p.price <= max)));
}).listen(8082);

Go

Типизированные данные и маршрут с методом в шаблоне; результат — один бинарник.

main.go
package main

import (
	"encoding/json"
	"math"
	"net/http"
	"strconv"
)

type Product struct {
	SKU   string `json:"sku"`
	Title string `json:"title"`
	Price int    `json:"price"`
}

var products = []Product{
	{"A-100", "Дубовый стол", 24000},
	{"B-200", "Сосновая полка", 5000},
}

// Go: один скомпилированный бинарник, каждый запрос обслуживается в своей горутине
func main() {
	http.HandleFunc("GET /api/products", func(w http.ResponseWriter, r *http.Request) {
		limit := math.MaxInt
		if v, err := strconv.Atoi(r.URL.Query().Get("max")); err == nil {
			limit = v
		}
		found := []Product{}
		for _, p := range products {
			if p.Price <= limit {
				found = append(found, p)
			}
		}
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(found)
	})
	http.ListenAndServe(":8083", nil)
}

Частые ошибки при выборе бэкенда

  1. Go для лендинга

    Компилируемый сервис и VPS ради страницы с формой — больше эксплуатации, а выигрыша нет.

  2. PHP для тысяч WebSocket

    Модель запроса не подходит для долгих соединений без дополнительных инструментов.

  3. Node.js для тяжёлых вычислений

    Одно долгое вычисление останавливает все остальные запросы.

  4. Выбирать по моде

    Язык должен подходить задаче и команде, а не трендам года.

  5. Один язык на всё

    Небольшой сервис на Go рядом с сайтом на PHP часто решает нагрузку лучше, чем переписывание сайта.

  6. Винить язык в проблемах базы

    Большинство медленных бэкендов медленные из-за запросов и отсутствующих индексов, а не из-за языка.

Вопросы о PHP, Node.js и Go

Какой язык лучше для бэкенда?

Единого ответа нет: PHP — для сайтов и админок, Node.js — для реального времени и общего кода с фронтендом, Go — для нагрузки.

Какой самый быстрый?

Обычно Go, но для типичного сайта время уходит на базу, и все три достаточно быстры.

PHP хуже Node.js?

Нет, он другой: PHP проще и дешевле для сайтов, Node.js сильнее в реальном времени и общем коде.

Когда переходить с PHP на Go?

Не весь проект, а только ту часть, что не справляется с нагрузкой, — отдельным сервисом.

Можно ли их совмещать?

Да, и это частая схема: сайт на PHP, сервис на Go для нагрузки, Node.js для сборки фронтенда.

Что дешевле в хостинге?

PHP работает на любом виртуальном хостинге; Go расходует меньше всего памяти на VPS; Node.js нужен VPS или платформа.

Под что проще найти разработчиков?

PHP и Node.js — разработчиков очень много; Go — меньше, но обычно это сильные бэкенд-инженеры.

Форма

Подобрать
бэкенд

Работаю с PHP, Node.js и Go и выбираю по задаче: PHP для сайтов и админок, Go для сервисов под нагрузкой, Node.js там, где фронтенд и бэкенд делят код. Расскажите о проекте — отвечу в течение рабочего дня.

Или пишите на [email protected]