Получи случайную криптовалюту за регистрацию!

EazyDev

Логотип телеграм канала @eazydev — EazyDev E
Логотип телеграм канала @eazydev — EazyDev
Адрес канала: @eazydev
Категории: Технологии
Язык: Русский
Количество подписчиков: 41
Описание канала:

Канал о разработке на PHP / NodeJS / Golang, безопасности веб-приложений и т.п. Пишу не часто, но по делу. Зеркало сайта https://blog.eazy-dev.com.

Рейтинги и Отзывы

4.00

3 отзыва

Оценить канал eazydev и оставить отзыв — могут только зарегестрированные пользователи. Все отзывы проходят модерацию.

5 звезд

1

4 звезд

1

3 звезд

1

2 звезд

0

1 звезд

0


Последние сообщения

2021-10-31 19:23:07 Linux, supervisord и максимальное количество открытых файлов

Настройки ядра Linux

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

- somaxconn - backlog-очередь установленных соединений;
- tcp_max_syn_backlog - очередь для не полностью установленных соединений;
- fs.file-max - максимально допустимое количество открытых дескрипторов в системе (обычно он достаточно высокий).

Помимо этих параметров, есть еще /etc/security/limits.conf, который устанавливает всяческие ограничения на уровне пользователя. Среди ограничений в этом файле, есть 1 очень важное - nofile или максимальное количество открытых файловых дескрипторов для процесса, максимальное значение которого, обычно 4096, то для высоконагруженных приложений очень мало. В linux, сокеты - это тоже файлы поэтому этот лимит так же включает сетевые соединения.

Supervisord

Supervisord - достаточно старый инструмент написанный на python, который используется для запуска приложений в фоне и их рестарт, в случае падения. Он все еще активно используется для legacy-приложений, которые не отмигрировались на docker. Пример конфигурации приложения на nodejs:


[program:app]
command=/usr/bin/node index.js
autostart=true
autorestart=true
user=app
redirect_stderr=true
stdout_logfile_maxbytes=200MB
stderr_logfile=/var/logs/app/stderr.log
stdout_logfile=/var/logs/app/stdout.log
environment=NODE_ENV="production"
directory=/app/


Огромная проблема в том, что по умолчанию, supervisord задает свой лимит на количество файлов, игнорируя системные из /etc/security/limits.conf. В этом можно убедиться, запустив программу и посмотрев файл /proc/%d/limits:


# cat /proc/%d/limits | grep "open files"
Max open files 1024 4096 files


Чтобы это пофиксить, необходимо добавить в supervisord.conf параметр minfds с новым значением:


[supervisord]
...
minfds=15000;


И рестартнуть сервисы.

Наиболее лучшим решением будет миграция на systemd или docker.
57 views16:23
Открыть/Комментировать
2021-05-04 01:49:52 Следующая часть - Создание API на базе Symfony 5. Часть 4. Обработка исключений.

В этой части мы сконцентрируемся на обработке исключений, и для этого мы добавим еще пару методов в наше API: получение книги по id и получение списка книг по id категории.

Когда мы вызываем сервисы, они могут выбрасывать исключения и их нужно каким-то образом обрабатывать так, чтобы отдавать пользователю адекватные сообщения об ошибках. Поскольку мы пишем API с json-форматом, то ошибки так же должны преобразовываться в json-ответы с правильным http-кодом. Для начала займемся созданием новых моделей и сервисов а потом рассмотрим варианты решений.

Читать полностью

#symfony #backend #php #api #tutorial
143 views22:49
Открыть/Комментировать
2021-04-04 22:38:03 Затемнение переменной в golang

Казалось бы, в интернете гора статей из рубрики golang gotchas, но это не мешает повторять одни и те же ошибки снова и снова.

Разработчики проекта Temporal рассказали с как столкнулись с багом из-за того, что затемнили ошибку в условии. Даже не знаю, что может быть банальнее

Затемнение переменной (variable shadowing) можно продемонстрировать на примере:


func test() (string, error){
return "str", errors.New("error")
}

func main() {
var err error

defer func() {
fmt.Println(err)
}()

if true {
str, err := test()
fmt.Println(str, err)
}
}


Для нешарящих результат будет сюрпризом:


str error



Баг достаточно известный и возникает из-за того, что оператор := ограничен только текущим скоупом и не выходит наружу. IDE и линтер далеко не всегда могут указать на косяк. Удивительно, что разработчики из Temporal не знали об этом =\

Ссылка на статью

#backend #golang
164 viewsedited  19:38
Открыть/Комментировать
2021-03-18 13:08:10 Один из разработчиков из DigitalOcean написал статью про разработку собственного api gateway и раскрыл немного подробностей о внутреннем устройстве хостинга. Было написано свое решение из-за того, на тот момент особо не было вариантов, а nginx нормально кастомизируется только через lua, что выглядит и деплоится не очень.

В статье описывается как DigitalOcean плавно пытаются мигрироваться от монолитов в микросервисам и с какими трудностями они столкнулись.

Ссылка на статью

#devops #golang #ruby
101 views10:08
Открыть/Комментировать
2021-03-17 11:28:02 Вышла очередная версия java. Хорошее описание нововведений можно почитать на хабре.

#java #backend
90 viewsedited  08:28
Открыть/Комментировать
2021-03-14 16:22:40 Немного новостей из OpenSource, к которому недавно приложился:

Hoverfly

Теперь умеет загружать файл из внешнего источника по http и использовать его в качестве response body. Поддерживаются так же ограничение на доверенность источника. Пример:


"response": {
"status": 200,
"encodedBody": false,
"templated": false,
"bodyFile": "https://raw.githubusercontent.com/SpectoLabs/hoverfly/master/schema.json"
}


При этом hoverfly должен быть запущен с флагом разрешающим скачивание (по аналогии с CORS):


$ hoverfly -response-body-files-allow-origin="https://raw.githubusercontent.com/"


Документация
Pull Request

Spring Cloud Consul

Первый пул реквест на джаве Недавно столкнулся со следующей проблемой - был хост, на котором был запущен nginx, consul, grafana, prometheus и т.п. Любой входящий траффик должен был проходить через nginx, соответственно, все сервисы за nginx'ы были доступны через rewrite.

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

Релиза новой версии пока не было, но скоро будет

Pull Request

#backend #sv #spring #java #golang #opensource
84 viewsedited  13:22
Открыть/Комментировать
2021-01-21 13:54:20 Будущее CentOS и RHEL

После того, как CentOS официально лишился поддержки, RedHat аннонсировали 2 новые программы, которые позволят использовать RHEL совершенно бесплатно и обе они, по сути, расширяют старую Red Hat Developer. Расширение позволит использовать RHEL для продакшена с лимитом до 16 серверов.

Помимо этого, RedHat пояснили отличия между своими дистрибутивами:

- Fedora будет следующей мажорной RHEL т.е. содержать большие и внушительные изменения;
- CentOS Stream - система, которая будет следующей минорной RHEL.

Там есть некоторые ограничения, поэтому рекомендуется дополнительно почитать FAQ.

Нововведения начнут действовать с 1го февраля

#redhat #devops
107 viewsedited  10:54
Открыть/Комментировать
2021-01-20 21:15:04 Закрытие Symfony Security Monitoring

Буквально недавно я писал о том, как подключить к проекту практически штатную проверку зависимостей на уязвимости. Тогда я упомянул про то, что SensioLabs Security Checker позволяет загружать лок-файл на удаленный сервер с целью проверки, а штатный security:check не open source.

Недавно все изменилось. Сервис по проверке лок-файлов закрылся, а утилиту выложили в open source. Как по мне, идея была очень странная - брать деньги за пользование облачной проверкой лок-файла, учитывая, что все уязвимые версии находятся в открытом репозитории. Даже если на старте это стоило 2 евро за 3 года

#php #symfony #security
89 views18:15
Открыть/Комментировать
2021-01-11 23:03:21 Правильное закрытие http-сервера в golang

Прежде чем закрывать http-сервер, разберемся как нужно правильно закрывать приложение К сожалению, в golang многие вещи приходится писать руками и первое из этого — обработка сигналов.

Сигналы

Сигналы это одно из средств межпроцессорного взаимодействия (IPC). К примеру, когда мы запускаем приложение и нажимаем Ctrl + C, операционная система посылает сигнал SIGINT процессу с просьбой завершиться. Помимо этого сигнала, нужно иметь в виду еще SIGTERM, что в принципе тоже самое, что и SIGINT, но отправляется не с терминала. Оба этих сигнала процесс может перехватить и выполнить какие-либо действия (закрыть дескрипторы, залогировать что-то и т.д.) и завершиться. Это называется Graceful shutdown. Последний важный для нас сигнал - SIGKILL, но его уже нельзя отловить, он убивает процесс не давая ему времени нормально завершиться. Kubernetes и другие платформы отправляют сначала SIGTERM, ждут 10+ секунд и потом нещадно убивают через SIGKILL. Бойлерплейт для ожидания сигнала в golang обычно выглядит так:

func handleSignals(cancel context.CancelFunc) {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)

<-c
cancel()
}

На вход передается cancel-функция для отмены контекста всего приложения поле получения сигнала.

HTTP-сервер

Создать http-сервер достаточно просто:

server := &http.Server{Addr: config.ListenAddr, Handler: h.Router}

Сложнее правильно его закрыть. Для начала определим функцию, которая его запустит:

func run(ctx context.Context) error {
return server.ListenAndServe()
}

Казалось бы, на этом можно закончить Но нет. Эта функция работает не очень правильно, и дальше мы будем ее прокачивать. Начнем с того, что run возвращает ошибку если она произошла. Но ListenAndServe возвращает не nil даже если сервис был закрыт успешно:

func run(ctx context.Context) error {
err := server.ListenAndServe()
if err == http.ErrServerClosed {
return nil
}

return err
}

Но как завершить сервер успешно? Программно мы обычно делаем только в 1 случае — когда родительский контекст отменили (к примеру из-за сигнала). Для нашего примера, мы оставим функцию run блокирующей, добавим обработку отмены и graceful shutdown с таймаутом для завершения всех текущих запросов:

func run(ctx context.Context) error {
go func() {
<-ctx.Done()

graceCtx, graceCancel := context.WithTimeout(context.Background(), 5 * time.Second)
defer graceCancel()

if err := server.Shutdown(graceCtx); err != nil {
// log, ...
}
}()

err := server.ListenAndServe()
if err == http.ErrServerClosed {
return nil
}

return err
}

server.Shutdown заставит сервер перестать принимать новые подключения и даст 5 секунд уже активным соединениям завершиться. Здесь практически все правильно, кроме 1 детали — когда вызывается server.Shutdown, server.ListenAndServe моментально возвращает результат. Это значит активным соединениям нужно успеть отработать до того, как мы закончим исполнение программы. Чтобы сделать поведение более предсказуемым и стабильным, нужно добавить канал, который будет блокировать выход из функции, пока в него что-то не запишут, а писать будем сразу после вызова server.Shutdown. Финальный вид функции:

func run(ctx context.Context) error {
httpShutdownCh := make(chan struct{})

go func() {
<-ctx.Done()

graceCtx, graceCancel := context.WithTimeout(context.Background(), 5 * time.Second)
defer graceCancel()

if err := server.Shutdown(graceCtx); err != nil {
// log, ...
}

httpShutdownCh <- struct{}{}
}()

err := server.ListenAndServe()
<-httpShutdownCh

if err == http.ErrServerClosed {
return nil
}

return err
}

Тип данных в канале — пустой struct для микро оптимизации, потому он не занимает память. От последнего можно избавиться, если server.ListenAndServe убрать в горутину, а server.Shutdown и ожидание завершения контекста в функцию.

#golang #backend
104 viewsedited  20:03
Открыть/Комментировать
2021-01-07 01:38:22 Новая часть про разработку на PHP. Создание API на базе Symfony 5. Часть 3. Начало проекта. Пришла пора определиться с проектом. Мы будем разрабатывать часть API книжного магазина издательства (типа manning).

Читать полностью

#php #symfony #backend #api #tutorial
77 viewsedited  22:38
Открыть/Комментировать