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

dev notes

Логотип телеграм канала @junsenior — dev notes D
Логотип телеграм канала @junsenior — dev notes
Адрес канала: @junsenior
Категории: Технологии
Язык: Русский
Количество подписчиков: 1.63K
Описание канала:

Для связи @itxor
Twitter: https://twitter.com/SeniorJun

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

4.33

3 отзыва

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

5 звезд

2

4 звезд

0

3 звезд

1

2 звезд

0

1 звезд

0


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

2021-11-26 13:36:15 Вышел PHP 8.1

https://www.php.net/releases/8.1/ru.php

Основные новые возможности:

Enums они же перечисления;
Readonly свойства;
First-class callable — получение ссылки на любую функцию;
Оператор new в инициализаторах (и вложенные атрибуты);
Файберы;
final константы в классах;
Новый тип never для (не)возвращаемых значений;
Запись восьмеричных чисел с префиксом 0o;
Оператор ... поддерживает массивы со строковыми ключами;
Много улучшений по производительности
(+23% к скорости для на демо приложении Symfony)

В релизе также много депрекейшнов, улучшений консистентности и обработки ошибок.

Основные депрекейшны:

Объявлено устаревшим неявное преобразование float в int, где теряется дробная часть;
Интерфейс Serializable объявлен устаревшим;
Ограничено использование $GLOBALS;
Объявлено устаревшим передача значения null в параметры встроенных функций, которые не nullable;
Добавлены типы для возвращаемых значений встроенных классов (и новый атрибут #[ReturnTypeWillChange]);
Продолжено удаление типа resource. Ресурсы file_info, imap FTP Connection, LDAP, PostgreSQL теперь будут объектами, соответственно finfo, IMAP\Connection, FTP\Connection, PgSql\Connection, PgSql\Result.

Еще почитать-посмотреть:

• Подробно: php.watch/versions/8.1
• Коротко в видео: What's New in PHP 8.1
• Валентин Удальцов: Лайв-кодинг-обзор PHP 8.1
• Максимально полный список изменений: php-8.1.0/UPGRADING
214 views10:36
Открыть/Комментировать
2021-11-26 13:36:15 Я тут изначально про PHP говорил, так что не могу не поделиться важным для сообщества релизом!
226 views10:36
Открыть/Комментировать
2021-11-23 20:05:17
В go мне очень не хватало архитектурных примеров построения приложений. Когда кто-то взял какой-либо тип архитектуры, и показал, как возможностями этого языка её реализовать и как это было бы правильно. Конечно, дефолтный "контроллер-сервис-репозиторий" реализовать не сложно, но чистую архитектуру по Роберту Мартину - хотелось бы подглядеть.

На днях вышел ман с отличной реализацией clean architecture дядя Боба -

(https://github.com/theartofdevel/golang-clean-architecture).
Крайне качественный контент по гошке (да ещё и на русском!) - делюсь. Мне понравился стиль изложения, понравилась теория и понравился абстрактный пример, где раскрываются основные принципы. И что самое приятное - этого примера хватило, чтобы на практике заюзать подобный формат реализации этой архитектуры.
255 views17:05
Открыть/Комментировать
2021-11-20 06:04:16 Конспекты микросервисов отложились до лучших времен, и на то у меня есть причина: уже с месяц на работе я пилю проект на go. Проект небольшой, но интересный: много асинхронщины, много новых паттернов, и повсеместное страдание :D Страдание - это набитие шишек, а нибитие шишек - это лучший опыт.
Сервис я почти допилил, и за время работы над ним вынес несколько, вероятно очевидных, но интересных для меня вещей, которыми поделюсь ниже.

1. Если к обработке ошибок я уже давно привык, к тому, что каждую привычную конструкцию нужно писать с нуля - тоже, то вот к тому, что в go не принято делать подпакеты - не могу привыкнуть. Мне бы очень хотелось иметь 2 дирректории: internal/repository/mysql/ и internal/repository/clickhouse/, но так не принято :) Так что имеем internal/repository, где имеем кучу файлов, и стараемся к этому привыкнуть.

2. Для контроля количества одновременно запущенных горутин, в рамках какой-то задачи отлично подходит буферизированный канал: перед go func().. кидаем в канал значение, а в defer, внутри функции, запускаемой в горутине, убираем.

3. Чем лучше у тебя теоретическая база по асинхронщине, параллельному программированию и прочим страшным вещам - тем проще. В процессе всплывали ещё те знания, которые я получил в универе на курсе параллелки, и частенько помогали найти верное решение.

4. ORM в go (я юзал gorm) - плохое решение, не теряй время и бахай нативные запросы через sqlx. Лично у меня было несколько кейсов, которые ORM решить не смогла.

5. Все найденные мной библиотеки, реализующие работу с clickhouse - умеют в ограниченное число типов. Клик поддерживает, например, мапы, а либы, которая умела бы в такое - я не нашёл. В следующий раз буду это учитывать :)

6. Если тебе нужно проверять, запущена ли сейчас какая-либо задача в горутине, лучшее решение, которое я нашёл - go.uber.org/atomic + мапа.

7. gin - наиболее удобный веб-фреймворк, из тех, с которыми мне довелось работать. Прям максимально всё для людей.

8. Архитектурные паттерны (https://github.com/golang-standards/project-layout) - мастхэв. Просто подведя свой проект под такую структуру ты уже в процессе понимаешь, насколько она удобная и продуманная.

9. Gitlab ci/cd из коробки отлично справляется с деплоем go-приложения, за что ему честь и почет. На днях попробую github actions в пет-проекте и дам фидбэк, что удобней и проще.

Список будет дополняться по мере открытия мной чего-то интересного :)
79 viewsedited  03:04
Открыть/Комментировать
2021-10-18 04:40:17 Продолжаю конспектировать Микросервисы Ричардсона, сегодняшняя глава - "Транзакционный обмен сообщениями", или когда нам нужно атомарно выполнить операции через брокер.

Сервису часто нужно публиковать сообщения в рамках транзакции, обновляющей базу данных.
Тут мы возвращаемся к паттерну, о котором я писал пару лет назад - https://t.me/junsenior/70
Подробно и на примере - по ссылке, тут лишь повторю краткий алгоритм:
* Сервис, отправляющий сообщения, записывает их в таблицу outbox, в реляционную субд или nosql (но с поддержкой ACID) субд
* Таблица outbox - гарантирует атомарность записи (спасибо ACID), и играет роль временной очереди сообщений
* Ретранслятор - компонент, читающий таблицу outbox и передающий сообщения брокеру
* Шаблон "Опрашивающий издатель" - шаблон для ретранслятора, подходящий для случая, если outbox реляционная: ретранслятору достаточно просто вычитать все новые сообщения, отправить их брокеру и удалить из базы
* Шаблон "Отслеживание транзакционного журнала" - более интересный и сложный способ, имеющий значительный плюс - он не даёт нагрузки на базу данных, анализируя только журнал фиксации. Если ты не знаешь, что такое журнал фиксации или транзакционный журнал - я упоминал про него тут - https://t.me/junsenior/184, когда разбирался с "Высоконагруженными приложениями" Клеппмана.

Есть несколько готовых инструментов, реализующих анализ журнала транзакций и умеющий отправлять новые сообщения в брокеры:
* debezium.io - публикует изменения базы данных для брокера Apache Kafka
* github.com/linkedin/databus - анализирует журнал Oracle и публикует изменения в виде событий
* DynaboDB streams (https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html) - создает поток упорядоченных по времени изменений, приложения может читать эти изменения из потока и публиковать их в брокер.
* Eventuate Tram (github.com/eventuate-tram/eventuate-tram-core) - либа от самого Ричардсона, использует протокол двоичного журнала MySQL, Postgres или просто проверяет изменения, внесенные в таблицу outbox, и публикует их в Apache Kafka.
426 viewsedited  01:40
Открыть/Комментировать
2021-10-12 21:05:36 Попиливаю небольшой пет-проектик, идея которого - трансформатор телеграм канала в сайт. Пару лет назад видел аналоги, сейчас таковых не нашёл. Если ты видел что-то подобное и активное в сети - пиши в комменты :)
Проект с открытым исходным кодом, основная цель - набивать навыки гошки, протестировать в нём пару интересных мне технологий, с которыми до этого не работал, и, вероятно, попробовать запилить микросервисную архитектуру на основе всего этого.
Сам проект видится интересным, особенно на волне блокировок всего и вся :) Сдампить свои статьи и заметки куда-то - всегда хорошая идея.
Сейчас более-менее проработана архитектура основного модуля, реализован парсинг статей из канала, все это работает в связке с nats и монгой, в качестве основной базы. В планах добавить эластику, сделать поиск по каналам, развертку сайтов из каналов и все это запустить :)

Если кто-то пишет на golang - велком, всегда рад ревью: https://github.com/itxor/tgsite
Если есть идеи, что допилить/докрутить - тоже буду рад, го в комментарии :)

Кто бахнет звездочку на репу - тому плюс от меня в карму.
295 viewsedited  18:05
Открыть/Комментировать
2021-10-12 07:38:02 Дублирование сообщений: клиент может отказать после получения сообщения, его обработки, но перед подтверждением сообщения. Тогда брокер доставит сообщения повторно, и мы получим дубль. В идеале брокер должен сохранять порядок следования сообщений (отправлять сообщение тому же потребителю), тогда потребитель может проигнорировать сообщение, которое уже обработано и отправить подтверждение обработки. Существупет несколько методов борьбы с повторяющимися сообщениями:
* Добавление идемпотентных дескрипторов: логика обработки считается идемпотентной, если её многократное выполнение с одинаковыми входными параметрами не несёт рассогласования данных. Например, отмена уже отменённого заказа - идемпотентная операция. К сожалению, логику обработки не всегда можно сделать идемпотентной, и брокер не всегда может отправить сообщение тому же получателю (например, при выходе последнего из строя). В таких случаях обработчики должны отслеживать сообщения и отклонять результаты.
* Отслеживание и отклонение дубликатов: например, обработчик сообщений авторизует банковскую карту. Для каждого заказа он должен выполнить ровно одну авторизацию. Идемпотенция обработчика в этом случае достигается отслеживанием и отклонением дублей. В качестве простого решения можно сделать так, чтобы потребитель отслеживал обработанные сообщения с помощью идентификаторов (например, записанных в БД), и отклонял те, что уже были обработаны. Ещё один вариант состоит в том, чтобы обработчик записывал сообщения не в отдельную таблицу, а в таблицу приложения. Этот подход полезен при использовании NoSQL, которые имеют ограниченную транзакционную модель и не поддерживают обновление двух таблиц в рамках одной транзакции (Про NoSQL я писал выше, и писал много - смотри конспекты "Высоконагруженных приложений" от Клеппмана).
368 views04:38
Открыть/Комментировать
2021-10-12 07:38:02 Сегодня будет конспект главы "Взаимодействие с помощью асинхронного обмена сообщениями".
В контексте асинхронного обмена мы будем говорить про брокеры сообщений.

Сообщения могут быть нескольких видов:
* Документ - только данные
* Команда - сообщение, эквивалентное RPC-запросу
* Событие - сообщение о том, что с отправителем что-то произошло
В рамках книги автор рассматривает использование команд и событий.

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

Каналов есть 2 вида:
* Точка - точка: доставка сообщений от одного издателя к одному потребителю
* Издатель - подписчик: доставка сообщений всем подключенным потребителям

Есть множество брокеров, на основе которых можно реализовать обмен сообщениями, и автор сразу выделяет наиболее популярные, и что не менее важно, с открытым исходным кодом:
* RabbitMQ
* ActiveMQ
* Apache Kafka

Проблемы при использовании брокеров.

Нарушение порядка следования сообщений: например, у нас есть много обработчиков, и есть 3 сообщения, которые должны быть выполнены в четком порядке: Order Created, Order Updated, Order Cancelled.
Распространённое решение, которое используют, например, Apache Kafka и AWS Kinesis - сегментированные каналы:
* Сегментированный канал - это два или более сегмента, где каждый сегмент - так же является каналом.
* Отправитель указывает в заголовке ключ сегмента, который обычно представляет собой произвользую строку или байты. Брокер использует этот ключ, чтобы привязать сообщение к определённому сегменту/разделу. Например, он может выбрать сегмент взятием остатка от целочисленного деления хеша сегментного ключа на количество сегментов.
От себя добавлю, что такой подход шардинга был реализован в видосах SovietReliable -

(да, тут чувак с потрясающим русским акцентом пилит распределённый брокер на Go, кто не смотрел - всем рекомендасьён)
* Брокер группирует экземпляры получателя и обращается с ними как с одним логическим получаетелем. В kafka применяется термин "группа получателей". Брокей назначает каждый сегмент отдельному получаетлю, при запуске и остановке получателей процедура повторяется.
343 viewsedited  04:38
Открыть/Комментировать
2021-09-29 09:44:34 Сегодня рассмотрим ещё один простой паттерн - шаблон обнаружения сервисов.

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

Решение: реестр сервисов - некая база данных, с которой сервисы либо работают напрямую, либо за обнаружение сервисов и запись отвечает инфраструктура развертывания.
Рассмотрим первый и наиболее простой способ реализации обнаружения - работу с реестром напрямую. Для вызова сервиса клиент сначала обращается к реестру, получает его экземпляры, и затем начинает с ними работать. Тут подключается второй шаблон - шаблон саморегистрации (microservices.io/patterns/self-registration.html) сервиса. Экземпляр сервиса обращается к API реестра, чтобы зарегистрировать своё сетевое местоположение. Он так же может предоставить URL для проверки работоспособности - конечную точку, которую реестр периодически запрашивает, чтобы убедиться, что сервис работает в нормальном режиме. Затем отрабатывает второй шаблон - "Обнаружение на клиентской стороне": клиент извлекает из реестра список доступных экземпляров сервиса и выбирает один из них с учетом балансирования нагрузки (https://microservices.io/patterns/client-side-discovery.html).

Второй способ - обнаружение на стороне развертывания. Docker и Kubernetes имеют встроенный механизм обнаружения и регистрации. Платформа выдаёт каждому сервису DNS-имя, адрес и привязанный домен. Клиент делает запрос к DNS, а платформа сама решает, к какому из доступных экземпляров его направить. Этот механизм более предпочтительный, т.к. нам не нужно искать или реализовывать реестр, и не нужно писать имплементацию работы с ним на стороне каждого сервиса.
В процессе такой маршрутизации участвуют два шаблона: "Сторонняя регистрация" - экземпляры сервиса автоматически регистрируются внешним компонентом (https://microservices.io/patterns/3rd-party-registration.html) и "Обнаружение на стороне сервера" - клиент делает запрос к маршрутизатору, который отвечает за обнаружение (https://microservices.io/patterns/server-side-discovery.html).
297 views06:44
Открыть/Комментировать
2021-09-28 09:58:39 Я вернулся из отпуска, отдохнул и с новыми силами планирую дочитать "Микросервисы" Ричардсона. Параллельно (до отпуска) уже пару недель у меня был в работе небольшой пет-проект на go, в рамках которого удалось заюзать много интересных вещей, которые в ближайшее время начну описывать. Но главное - проект будет на микросервисах, где мы на практике попробуем концепции этой книги. А сейчас небольшой конспект главы 3.2.3 - "Работа в условиях частичного отказа с применением шаблона 'Предохранитель'".

Каждый раз, когда сервис в распределённой системе делает синхронный запрос к другому сервису - возникает риск частичного отказа. Поскольку сервис является отдельным процессом, он может не ответить вовремя на запрос клиента (сбой, тех. обслуживание, перегрузка).
Клиент блокируется в ожидании ответа, и появляется опасность блокировки всей системы по цепочке. Тут нам помогает шаблон "Предохранитель": RPI-прокси, который в случае достижения определённого лимита последовательных отказов начинает отклонять все вызовы, пока не истечет определённое время.
Разберём на примере: сервис Order перестаёт отвечать (этот сервис я выделял и описывал в постах выше): мобильный клиент делает REST-запрос к API-шлюзу, тот проксирует запрос к недоступному сервису Order. OrderServiceProxy (сервис, проксирующий запросы к микросервису Order) будет блокироваться до бесконечности в ожидании ответа, что плохо скажется на удобстве использования и, что ещё хуже, на потреблении ресурсов. Рано или поздно ресурсы закончатся, и весь API станет недоступен.
Чтобы частичный отказ не распространился по всему приложению, при проектировании сервисов нам нужно:
* Использовать RPI-прокси, наподобие OrderServiceProxy, чтобы справляться с недоступными сервисами
* Решить, как восстанавливаться после отказа удалённого сервиса.
Для начала рассмотрим, как написать надежный RPT-прокси.

Каждый раз, когда сервис вызывает другой сервис, он должен защитить себя следующими механизмами:
* Сетевое время ожидания (корректно выставить таймаут)
* Ограничение количества неудачных запросов от клиента к сервису
* Шаблон "Предохранитель": отслеживание количества успешных и битых запросов. Если часоста ошибок привысит некоторый порог, предохранитель размыкается, и все дальнейшие попытки на некоторое время сразу завершаются с некоторым ошибочным кодом. Если через некоторое время сервис успешно отвечает, предохранитель смыкается, и появляется возможность обработать все битые запросы, которые можно хранить в какой-либо очереди, и корректно обрабатывать новые.

Восстановление после отказа
Самый простой способ - вернуть ошибку клиенту, если такой подход имеет место быть и данные, не полученные от сервиса, не критичны.
В ином случае можно вернуть резервное значение (например, значение по умолчанию), либо закэшированный ранее ответ.
440 views06:58
Открыть/Комментировать