Лучший опыт

Node.js быстрее, чем Go.

При тестировании производительности API на соответствие базе данных Timescale Postgres DB локально в контейнере Docker  —  это были созданные в разных фреймворках простые API-интерфейсы, которыми выполнялся поиск записи из более 100 миллионов записей,  —  обнаружилось, что в Go получается около 2000 запросов в секунду. Удивительным было то, что в NestJS и Bun получается на 1000 больше. Как же так, ведь Go на голову выше? Проблема заключалась в применении пул
Node.js быстрее, чем Go...

При тестировании производительности API на соответствие базе данных Timescale Postgres DB локально в контейнере Docker  —  это были созданные в разных фреймворках простые API-интерфейсы, которыми выполнялся поиск записи из более 100 миллионов записей,  —  обнаружилось, что в Go получается около 2000 запросов в секунду.

Удивительным было то, что в NestJS и Bun получается на 1000 больше. Как же так, ведь Go на голову выше?

Проблема заключалась в применении пула соединений, а не в установке ограничений на максимальные и незадействованные соединения. Этого нет во многих руководствах, посвященных пакету SQL для Go.

После установки ограничений стало получаться в 2–3 раза больше запросов в секунду на Go.

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

func NewPostgresStore() (*PostgresStore, error) {
godotenv.Load()
connStr := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s sslmode=%s",
os.Getenv("HOST"), os.Getenv("PORT"), os.Getenv("DBUSER"), os.Getenv("DBNAME"), os.Getenv("DBPASS"), os.Getenv("SSLMODE"))

db, err := sql.Open("postgres", connStr)
if err != nil {
return nil, err
}following:

func NewPostgresStore() (*PostgresStore, error) {
godotenv.Load()
connStr := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s sslmode=%s",
os.Getenv("HOST"), os.Getenv("PORT"), os.Getenv("DBUSER"), os.Getenv("DBNAME"), os.Getenv("DBPASS"), os.Getenv("SSLMODE"))

db, err := sql.Open("postgres", connStr)
if err != nil {
return nil, err
}

db.SetMaxOpenConns(20)
db.SetMaxIdleConns(20)

// defer db.Close()

if err := db.Ping(); err != nil {
return nil, err
}

return &PostgresStore {
db: db,
}, nil
}

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

// Открываем соединение с базой данных
db, err := sql.Open("postgres", connStr)
if err != nil {
return nil, err
}

// Устанавливаем для пула соединений лимит соединений
db.SetMaxOpenConns(20)
db.SetMaxIdleConns(20)

Поэкспериментируйте с этими значениями в поисках подходящих вашей базе данных с точки зрения производительности.

Тестирование производительности

Go без пула соединений:

Go с пулом соединений:

Nodejs с Nestjs:

Bun: