Sphagnum. Часть 3. Техобзор, начало.
#sphagnum@eshu_coding
Несмотря на нехватку времени продолжаю потихоньку заниматься новым проектом.
Прежде чем садиться писать код, нужно изучить некоторые моменты, чтобы потом не строить велосипеды из костылей. В науке эту часть работы называют "литобзор", а у меня пусть будет "техобзор" (далее под тегом #sphagnum_theory@eshu_coding)
Набросал примерный план для изучения:
1. Как организовано взаимодействие между инстансами (в т.ч. отказоустойчивость) в рамках одного replica set у следующих продуктов:
А. PostgreSQL
B. MongoDB
C. RabbitMQ
D. Kafka
E. Tarantool
F. NATS
2. Механизмы реализации (и отката, в т.ч. в нескольких инстансах, если их несколько) транзакций у:
A. PostgreSQL
B. RabbitMQ
C. Kafka
D. MongoDB
3. Механизмы шардирования у:
A. Tarantool
B. MongoDB
C. Kafka
4. Сделать обзор, что пишут известные люди в умных книжках по теме распределенных транзакций.
5. Обзор организации обмена сообщениями (Queue, Exchange, Topic etc.) в следующих брокерах сообщений:
1. RabbitMQ
2. Kafka
3. NATS
#sphagnum@eshu_coding
Несмотря на нехватку времени продолжаю потихоньку заниматься новым проектом.
Прежде чем садиться писать код, нужно изучить некоторые моменты, чтобы потом не строить велосипеды из костылей. В науке эту часть работы называют "литобзор", а у меня пусть будет "техобзор" (далее под тегом #sphagnum_theory@eshu_coding)
Набросал примерный план для изучения:
1. Как организовано взаимодействие между инстансами (в т.ч. отказоустойчивость) в рамках одного replica set у следующих продуктов:
А. PostgreSQL
B. MongoDB
C. RabbitMQ
D. Kafka
E. Tarantool
F. NATS
2. Механизмы реализации (и отката, в т.ч. в нескольких инстансах, если их несколько) транзакций у:
A. PostgreSQL
B. RabbitMQ
C. Kafka
D. MongoDB
3. Механизмы шардирования у:
A. Tarantool
B. MongoDB
C. Kafka
4. Сделать обзор, что пишут известные люди в умных книжках по теме распределенных транзакций.
5. Обзор организации обмена сообщениями (Queue, Exchange, Topic etc.) в следующих брокерах сообщений:
1. RabbitMQ
2. Kafka
3. NATS
Telegram
Эшу быдлокодит
Репликация и отказоустойчивость в PostgreSQL.
PostgreSQL предоставляет два вида репликации: физическую и логическую. Физическая репликация создаёт полную копию master-ноды, из которой при желании можно читать, но писать нельзя. Между нодами передаются байтики…
PostgreSQL предоставляет два вида репликации: физическую и логическую. Физическая репликация создаёт полную копию master-ноды, из которой при желании можно читать, но писать нельзя. Между нодами передаются байтики…
Sphagnum. Часть 4. Техобзор. Репликация и отказоустойчивость в PostgreSQL.
#sphagnum@eshu_coding
PostgreSQL предоставляет два вида репликации: физическую и логическую. Физическая репликация создаёт полную копию master-ноды, из которой при желании можно читать, но писать нельзя. Между нодами передаются байтики, записываемые в WAL. В режиме одиночного инстанса WAL удаляется после применения транзакции к данным. При включенной физической репликации - WAL сохраняются дольше и по мере необходимости отдаются репликам.
Логическая репликация передает между инстансами SQL команды. В контексте разработки брокера сообщений - не интересна.
Из коробки механизма поддержания отказоустойчивого кластера в постгресе нет, но есть сторонние решения, например - patroni. Каждому из инстансов replica-set-а постгресов закрепляется по надзирающему сервису. Эти сервисы общаются между собой. В случае падения мастера - выбирается новый мастер, простым голосованием. Прочёл про интересный механизм: если мастер остается изолирован от других реплик, он не начинает думать что он единственный такой в мире, а принудительно гасится patroni, дабы минимизировать шансы грядущей синхронизации двух мастеров.
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. Механизм распространения WAL для синхронизации.
2. Принудительное гашение мастера при изоляции его от остальной части кластера.
#sphagnum_theory@eshu_coding
#postgresql
#sphagnum@eshu_coding
PostgreSQL предоставляет два вида репликации: физическую и логическую. Физическая репликация создаёт полную копию master-ноды, из которой при желании можно читать, но писать нельзя. Между нодами передаются байтики, записываемые в WAL. В режиме одиночного инстанса WAL удаляется после применения транзакции к данным. При включенной физической репликации - WAL сохраняются дольше и по мере необходимости отдаются репликам.
Логическая репликация передает между инстансами SQL команды. В контексте разработки брокера сообщений - не интересна.
Из коробки механизма поддержания отказоустойчивого кластера в постгресе нет, но есть сторонние решения, например - patroni. Каждому из инстансов replica-set-а постгресов закрепляется по надзирающему сервису. Эти сервисы общаются между собой. В случае падения мастера - выбирается новый мастер, простым голосованием. Прочёл про интересный механизм: если мастер остается изолирован от других реплик, он не начинает думать что он единственный такой в мире, а принудительно гасится patroni, дабы минимизировать шансы грядущей синхронизации двух мастеров.
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. Механизм распространения WAL для синхронизации.
2. Принудительное гашение мастера при изоляции его от остальной части кластера.
#sphagnum_theory@eshu_coding
#postgresql
Telegram
Эшу быдлокодит
Sphagnum. Часть 1. Начало.
#sphagnum@eshu_coding
Начинаю новый пет-проект: свой брокер сообщений. Обозвал я его пока Sphagnum, проект планируется в качестве чисто образовательного, под лицензией MIT. Что я хочу получить на выходе:
1. По основному функционалу…
#sphagnum@eshu_coding
Начинаю новый пет-проект: свой брокер сообщений. Обозвал я его пока Sphagnum, проект планируется в качестве чисто образовательного, под лицензией MIT. Что я хочу получить на выходе:
1. По основному функционалу…
Sphagnum. Часть 5. Техобзор. Репликация и отказоустойчивость в MongoDB
#sphagnum@eshu_coding
MongoDB в качестве механизма репликации использует распространение между ведомыми нодами oplog-а. Изменения сперва записываются в WAL (Journaling в терминологии MongoDB), затем применяются к master-у (primary node), а затем - записываются в oplog - operation log - отдельную коллекцию (таблицу), из которой асинхронно расходятся по репликам (secondary).
Для организации отказоустойчивого кластера достаточно средств самой MongoDB. Кластер представляет собой primary-ноду и некоторое количество реплик. По ситуации могут быть добавлены специальные инстансы монги для поддержания целостности кластера: один или несколько arbiter. Выбор нового мастера может осуществляться двумя путями:
1. Совместным голосованием оставшихся в живых secondary инстансов
2. Голосованием с участием арбитров.
Ноды в replica set-е раз в две секунды пингуют друг друга. Если какая-то нода не отвечает 10 секунд - она объявляется недоступной. В случае, если это - primary, одна из нод может запустить выборы. Ноды имеют приоритет вочереди на престолонаследие и неравные веса голосов: целое число, минимум - 0, дефолт - 1.
Ноды с 0 голосов голосовать не могут вообще, но при этом могут наложить вето на запуск процедуры голосования.
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. Механизм вето запуска голосования.
2. Использование арбитров мне пока видится избыточным, но при проектировании системы стоит предусмотреть такую роль на будущее.
#sphagnum_theory@eshu_coding
#mongodb
#sphagnum@eshu_coding
MongoDB в качестве механизма репликации использует распространение между ведомыми нодами oplog-а. Изменения сперва записываются в WAL (Journaling в терминологии MongoDB), затем применяются к master-у (primary node), а затем - записываются в oplog - operation log - отдельную коллекцию (таблицу), из которой асинхронно расходятся по репликам (secondary).
Для организации отказоустойчивого кластера достаточно средств самой MongoDB. Кластер представляет собой primary-ноду и некоторое количество реплик. По ситуации могут быть добавлены специальные инстансы монги для поддержания целостности кластера: один или несколько arbiter. Выбор нового мастера может осуществляться двумя путями:
1. Совместным голосованием оставшихся в живых secondary инстансов
2. Голосованием с участием арбитров.
Ноды в replica set-е раз в две секунды пингуют друг друга. Если какая-то нода не отвечает 10 секунд - она объявляется недоступной. В случае, если это - primary, одна из нод может запустить выборы. Ноды имеют приоритет в
Ноды с 0 голосов голосовать не могут вообще, но при этом могут наложить вето на запуск процедуры голосования.
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. Механизм вето запуска голосования.
2. Использование арбитров мне пока видится избыточным, но при проектировании системы стоит предусмотреть такую роль на будущее.
#sphagnum_theory@eshu_coding
#mongodb
Mongodb
Replica Set Oplog - Database Manual - MongoDB Docs
Sphagnum. Часть 5. Техобзор. Репликация и отказоустойчивость в RabbitMQ
#sphagnum@eshu_coding
RabbitMQ поддерживает создание отказоустойчивых кластеров, но есть небольшой нюанс. Сообщения в обычных очередях не передаются между инстансами. То есть мы имеем отказоустойчивый кластер из 3 кроликов. С мастера на реплики продублированы все настройки, пользователи и т.д. Приходит в RabbitMQ цунами из сообщений, мастер ест их пока не захлебнется, а потом падает. И тут на его месте возникает радостная реплика с криками "я новый мастер, я!" и начинает работу. А данные, зависшие в старом мастере - ну когда-нибудь может быть будут отработаны и переданы. Правда, есть специальные очереди, Quorum Queues, сообщения между которыми таки распространяются по репликами и в случае нештатной ситуации таки будут отработаны. По дефолту такие очереди реплицируются по трем инстансам, но можно настроить и большее количество.
Занятно организовано голосование за право быть новым мастером. Когда мастер пропадает, реплики начинают кричать "я новый мастер!", кто успел крикнуть первым - тот и становится мастером. Если голоса равны, происходит повторное голосование. Я конечно утрирую, но логика примерно такая.
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. Идея разделения данных на реплицируемые и нет - огонь, но в качестве дефолта я бы взял реплицируемые.
2. Механизм голосования довольно забавный, но тут довольно сомнительно.
#sphagnum_theory@eshu_coding
#rabbitmq
#sphagnum@eshu_coding
RabbitMQ поддерживает создание отказоустойчивых кластеров, но есть небольшой нюанс. Сообщения в обычных очередях не передаются между инстансами. То есть мы имеем отказоустойчивый кластер из 3 кроликов. С мастера на реплики продублированы все настройки, пользователи и т.д. Приходит в RabbitMQ цунами из сообщений, мастер ест их пока не захлебнется, а потом падает. И тут на его месте возникает радостная реплика с криками "я новый мастер, я!" и начинает работу. А данные, зависшие в старом мастере - ну когда-нибудь может быть будут отработаны и переданы. Правда, есть специальные очереди, Quorum Queues, сообщения между которыми таки распространяются по репликами и в случае нештатной ситуации таки будут отработаны. По дефолту такие очереди реплицируются по трем инстансам, но можно настроить и большее количество.
Занятно организовано голосование за право быть новым мастером. Когда мастер пропадает, реплики начинают кричать "я новый мастер!", кто успел крикнуть первым - тот и становится мастером. Если голоса равны, происходит повторное голосование. Я конечно утрирую, но логика примерно такая.
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. Идея разделения данных на реплицируемые и нет - огонь, но в качестве дефолта я бы взял реплицируемые.
2. Механизм голосования довольно забавный, но тут довольно сомнительно.
#sphagnum_theory@eshu_coding
#rabbitmq
Telegram
Эшу быдлокодит
Sphagnum. Часть 1. Начало.
#sphagnum@eshu_coding
Начинаю новый пет-проект: свой брокер сообщений. Обозвал я его пока Sphagnum, проект планируется в качестве чисто образовательного, под лицензией MIT. Что я хочу получить на выходе:
1. По основному функционалу…
#sphagnum@eshu_coding
Начинаю новый пет-проект: свой брокер сообщений. Обозвал я его пока Sphagnum, проект планируется в качестве чисто образовательного, под лицензией MIT. Что я хочу получить на выходе:
1. По основному функционалу…
Forwarded from Sandbox
Дорогие друзья если у вас есть возможность пройти этот маленький АНОНИМНЫЙ опрос о стажировках
я буду благодарен.
Если вы сможете поделиться им с друзьями, будет чудесно.
А если попросите их распространить еще дальше
Я буду на 7м небе от счастья
https://forms.gle/VZNzzb7ugtuQwnMDA
я буду благодарен.
Если вы сможете поделиться им с друзьями, будет чудесно.
А если попросите их распространить еще дальше
Я буду на 7м небе от счастья
https://forms.gle/VZNzzb7ugtuQwnMDA
Google Docs
Стажировка и зп
Гитлаб для чайников. Часть 1.
Во второй заход осилил на практике девопсячий минимум, необходимый для построения полнофункциональной системы CI/CD (автодеплой в просторечии) на базе gitlab. То есть ты коммитишь - на сервере автоматически поднимается рабочий экземпляр твоего приложения. В качестве основы используется gitlab. Про первый заход писал выше.
Это не инструкция по эксплуатации и не пошаговая инструкция. Просто набор заметок, к которому я смогу вернуться через пару лет и освежить в памяти некоторые нюансы. Или кто-то, владеющий необходимой базой, получит общее представление о происходящем перед самостоятельным строительством подобной системы.
Необходимая база:
1. Командная строка линукса, хотя бы минимум
2. docker, docker-compose
3. Основы git, чтобы не терять сознание от веток, мержей и коммитов.
Заодно добавлю новый тэг - #devops
#gitlab
Во второй заход осилил на практике девопсячий минимум, необходимый для построения полнофункциональной системы CI/CD (автодеплой в просторечии) на базе gitlab. То есть ты коммитишь - на сервере автоматически поднимается рабочий экземпляр твоего приложения. В качестве основы используется gitlab. Про первый заход писал выше.
Это не инструкция по эксплуатации и не пошаговая инструкция. Просто набор заметок, к которому я смогу вернуться через пару лет и освежить в памяти некоторые нюансы. Или кто-то, владеющий необходимой базой, получит общее представление о происходящем перед самостоятельным строительством подобной системы.
Необходимая база:
1. Командная строка линукса, хотя бы минимум
2. docker, docker-compose
3. Основы git, чтобы не терять сознание от веток, мержей и коммитов.
Заодно добавлю новый тэг - #devops
#gitlab
Telegram
Эшу быдлокодит
На неделе перешагнул ещё одну важную ступеньку: освоил гитлаб на базовом уровне. Собрал пока экспериментальный стенд вида: мы коммитим в репозиторий, сам собирается докер образ, сохраняется в хранилище образов, после чего вытягивается оттуда и запускается…
Гитлаб для чайников. Часть 2.
Система выглядит примерно таким образом:
На первый сервер ставится гитлаб. В нем включается функционал хранения докер-образов.
На второй сервер ставится BaGet - максимально простое хранилище NuGet пакетов (модулей), чтобы шарить функционал и абстракции между проектами.
На третий сервер ставится gitlab runner, который будет собирать образы и NuGet пакеты.
И какое-то количество серверов, на которых будет крутиться то, что мы разработаем. На каждый из серверов ставим по runner-у.
Логика работы примерно такая: когда кто-то коммитит в репозиторий, запускается скрипт ci cd. Первая часть собирает пакеты или образа на сервере 3. Пакеты отправляются в BaGet на втором сервере. Образа - во встроенное в Gitlab хранилище.
Вторая часть скрипта собственно разворачивает проект на серверах. В ней скачивается свежая версия образа из гитлаба и запускается.
Оба этапа предваряются логином к хранилищу образов и зачисткой кэша образов докера на машине с runner-ом. Я логинился с помощью Deploy Token-ов.
#gitlab
#devops
Система выглядит примерно таким образом:
На первый сервер ставится гитлаб. В нем включается функционал хранения докер-образов.
На второй сервер ставится BaGet - максимально простое хранилище NuGet пакетов (модулей), чтобы шарить функционал и абстракции между проектами.
На третий сервер ставится gitlab runner, который будет собирать образы и NuGet пакеты.
И какое-то количество серверов, на которых будет крутиться то, что мы разработаем. На каждый из серверов ставим по runner-у.
Логика работы примерно такая: когда кто-то коммитит в репозиторий, запускается скрипт ci cd. Первая часть собирает пакеты или образа на сервере 3. Пакеты отправляются в BaGet на втором сервере. Образа - во встроенное в Gitlab хранилище.
Вторая часть скрипта собственно разворачивает проект на серверах. В ней скачивается свежая версия образа из гитлаба и запускается.
Оба этапа предваряются логином к хранилищу образов и зачисткой кэша образов докера на машине с runner-ом. Я логинился с помощью Deploy Token-ов.
#gitlab
#devops
Telegram
Эшу быдлокодит
P.S. При публикации потерял картинку ко 2й части, оставлю тут.
Гитлаб для чайников. Часть 3.
В гитлабе нам понадобится создать группу проектов, в ней добавить runner, общий на всю группу (для сборки образов/пакетов во всей группе). Runner может быть как групповым, так и выделенным проекту.
После этого скопировать сгенерированную команду для подключения на сервер номер 3. Выбрать тип runner-а shell, то есть он будет тупо выполнять консольные команды, прописанные в скрипте автодеплоя в гитлабе.
Давлее, повторить процедуру для всех серверов, куда будет идти деплой, runner-ы по ситуации цепляются или к проектам, или к группе.
Если общение с gilab-ом проходит по http, а не по https, надо не забыть добавить gitlab в перечень разрешенных небезопасных источников для докера в файле /etc/docker/daemon.json.
Также надо не забыть выдать пользователю-докеру прав на работу в линухе.
#gitlab
#devops
В гитлабе нам понадобится создать группу проектов, в ней добавить runner, общий на всю группу (для сборки образов/пакетов во всей группе). Runner может быть как групповым, так и выделенным проекту.
После этого скопировать сгенерированную команду для подключения на сервер номер 3. Выбрать тип runner-а shell, то есть он будет тупо выполнять консольные команды, прописанные в скрипте автодеплоя в гитлабе.
Давлее, повторить процедуру для всех серверов, куда будет идти деплой, runner-ы по ситуации цепляются или к проектам, или к группе.
Если общение с gilab-ом проходит по http, а не по https, надо не забыть добавить gitlab в перечень разрешенных небезопасных источников для докера в файле /etc/docker/daemon.json.
Также надо не забыть выдать пользователю-докеру прав на работу в линухе.
#gitlab
#devops
Docker Documentation
Post-installation steps
Find the recommended Docker Engine post-installation steps for Linux users, including how to run Docker as a non-root user and more.
Гитлаб для чайников. Часть 4.
Всю информацию, необходимую для деплоя и работы сервисов, которая не является статичной/открытой я поместил в переменные (Settings => CI/CD => Variables).
Переменные подтягиваются при выполнении скрипта деплоя двумя способами:
1. Обычные переменные просто подставляются в текст скрипта синтаксисом вида
При деплое используется два типа docker-compose файлов. Первый для построения образов, второй - собственно для деплоя.
В обоих файлах адрес хранилища образов и его tag (что-то типа версии) задаются через переменные окружения. Также через переменные окружения подтягиваются build args для образов, чтобы передать какую-то информацию в образ на этапе сборки (например - чтобы не хардкодить адрес бэкенда на фронте).
В docker docker-compose файлы второго типа через переменные окружения передается вся сопуствующая информация: строки подключения к базам данных, данные для подключения к брокерам сообщений, адреса других микросервисов.
В Gitlab CI/CD скриптах можно менять поведение в зависимости от ветки Гита, пока самое удобное для меня место - секция workflow в скрипте. Если ветка - dev, то подтягиваем из переменных файлы
После коммита прогресс выполнения скриптов отображается в разделе Pipelines. В нём можно перезапускать любую из стадий выполнения скрипта деплоя.
А если заморочиться с подсовыванием в теги образов короткого тэга коммита
Механизм подсовывания примерно такой. В файлы с переменными окружения, после выполнения операции
Сей поток сознания - изложение опыта работы с гитлабом, полученного примерно за 16 часов, 8 в июле, 8 - на этой неделе. А предваряла им пара лет эпизодических мучений с GitHub Actions и докером. Естественно, нормальный девопс сделает лучше и быстрее, но если его нет под рукой, вполне реально завести небольшое хозяйство самостоятельно.
#gitlab
#devops
Всю информацию, необходимую для деплоя и работы сервисов, которая не является статичной/открытой я поместил в переменные (Settings => CI/CD => Variables).
Переменные подтягиваются при выполнении скрипта деплоя двумя способами:
1. Обычные переменные просто подставляются в текст скрипта синтаксисом вида
${VAR_NAME}
2. Переменные типа File можно подсунуть в файловую систему проекта во время строки синтаксисом вида cp ${FILE_VAR_NAME} prod.envВ обычных переменных я держу пароли, адреса серверов и т.д. А в файловые сохраняю .env файлы для подтягивания переменных окружения docker-compose-ом.
При деплое используется два типа docker-compose файлов. Первый для построения образов, второй - собственно для деплоя.
В обоих файлах адрес хранилища образов и его tag (что-то типа версии) задаются через переменные окружения. Также через переменные окружения подтягиваются build args для образов, чтобы передать какую-то информацию в образ на этапе сборки (например - чтобы не хардкодить адрес бэкенда на фронте).
В docker docker-compose файлы второго типа через переменные окружения передается вся сопуствующая информация: строки подключения к базам данных, данные для подключения к брокерам сообщений, адреса других микросервисов.
В Gitlab CI/CD скриптах можно менять поведение в зависимости от ветки Гита, пока самое удобное для меня место - секция workflow в скрипте. Если ветка - dev, то подтягиваем из переменных файлы
DEV_BUILD_ENV
и DEV_DEPLOY_ENV
, а также вызываем для деплоя runner, помеченный тегом dev_deploy_runner
. И MASTER_BUILD_ENV
, MASTER_DEPLOY_ENV
, master_deploy_runner
для ветки master соответственно.После коммита прогресс выполнения скриптов отображается в разделе Pipelines. В нём можно перезапускать любую из стадий выполнения скрипта деплоя.
А если заморочиться с подсовыванием в теги образов короткого тэга коммита
$CI_COMMIT_TAG
, можно хранить в гитлабе инкрементальную коллекцию образов, соответствующих каждому коммиту. Это даёт возможность нажатием одной кнопки в любой момент времени откатиться на прошлую версию в течение пары секунд. Или на позапрошлую. Или вообще на год назад, если мы можем позволить себе дисковое пространство для хранения такой истории.Механизм подсовывания примерно такой. В файлы с переменными окружения, после выполнения операции
cp ${FILE_VAR_NAME} .env
подсовывается строка tag_suffix = $CI_COMMIT_SHORT_SHA
, и соответствующее значение начинает подтягиваться в тэг образа.Сей поток сознания - изложение опыта работы с гитлабом, полученного примерно за 16 часов, 8 в июле, 8 - на этой неделе. А предваряла им пара лет эпизодических мучений с GitHub Actions и докером. Естественно, нормальный девопс сделает лучше и быстрее, но если его нет под рукой, вполне реально завести небольшое хозяйство самостоятельно.
#gitlab
#devops
Docker Documentation
Services top-level elements
Explore all the attributes the services top-level element can have.
P.S. При публикации потерял картинку ко 2й части, оставлю тут.
Sphagnum. Часть 6. Техобзор. Репликация и отказоустойчивость в Kafka
#sphagnum@eshu_coding
Кафка по умолчанию сохраняет все сообщения, которые проходят через нее. У каждого сообщения есть свой offset - его порядковый номер. Соответственно, реплики в случае отставания просто просят у мастера "дай мне все сообщения больше моего оффесета". Если отставания нет - получают их в режиме реального времени. По умолчанию сообщение может быть отправлено клиенту только после того, как все реплики подтвердят его получение. Kafka старается поддерживать реплики в состоянии in-sync replicas (ISR), то есть когда состояние реплик идентично.
Выбор нового мастера в случае отказа предыдущего осуществляются инстансом Кафки, имеющим статус Controller-a. Если контроллер оказался мертв, оставшиеся в живых реплики пытаются на скорость занять его место, кто успел - тот и новый контроллер. Из группы реплик, находящихся в статусе ISR выбирается один лидер, через которого осуществляется дальнейшая работа.
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. Мне очень понравилась идея хранить историю сообщений и по ситуации отдавать ее с определенного offset-а.
2. Идея ISR тоже хороша.
#sphagnum_theory@eshu_coding
#kafka
#sphagnum@eshu_coding
Кафка по умолчанию сохраняет все сообщения, которые проходят через нее. У каждого сообщения есть свой offset - его порядковый номер. Соответственно, реплики в случае отставания просто просят у мастера "дай мне все сообщения больше моего оффесета". Если отставания нет - получают их в режиме реального времени. По умолчанию сообщение может быть отправлено клиенту только после того, как все реплики подтвердят его получение. Kafka старается поддерживать реплики в состоянии in-sync replicas (ISR), то есть когда состояние реплик идентично.
Выбор нового мастера в случае отказа предыдущего осуществляются инстансом Кафки, имеющим статус Controller-a. Если контроллер оказался мертв, оставшиеся в живых реплики пытаются на скорость занять его место, кто успел - тот и новый контроллер. Из группы реплик, находящихся в статусе ISR выбирается один лидер, через которого осуществляется дальнейшая работа.
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. Мне очень понравилась идея хранить историю сообщений и по ситуации отдавать ее с определенного offset-а.
2. Идея ISR тоже хороша.
#sphagnum_theory@eshu_coding
#kafka
Telegram
Эшу быдлокодит
Sphagnum. Часть 1. Начало.
#sphagnum@eshu_coding
Начинаю новый пет-проект: свой брокер сообщений. Обозвал я его пока Sphagnum, проект планируется в качестве чисто образовательного, под лицензией MIT. Что я хочу получить на выходе:
1. По основному функционалу…
#sphagnum@eshu_coding
Начинаю новый пет-проект: свой брокер сообщений. Обозвал я его пока Sphagnum, проект планируется в качестве чисто образовательного, под лицензией MIT. Что я хочу получить на выходе:
1. По основному функционалу…
Sphagnum. Часть 6. Техобзор. Репликация и отказоустойчивость в Tarantool
#sphagnum@eshu_coding
Тарантул изначально проектировался как решение, которое можно без боли (ха-ха) раскатать в бесконечное по размеру облако. Вообще, про взаимодействие между инстансами можно почитать вполне себе неплохую статью на Хабре. Если кратко, инстансы обмениваются друг с другом "слухами" о происходящих событиях по UDP (с помощью механизма SWIM) и формируюткартину мира текущее состояние кластера. В случае падения мастера, выборами занимаются специальные инстансы тарантула, имеющие роль failover coordinator. Текущее состояние кластера сохраняется или в etcd (распределенное хранилище ключ-значенин) или в специфическом инстансе тарантула.
И также неплохая статья про механизм репликации. Если коротко - между мастером и репликами распространяется журнал WAL мастера. При том, распространяется отдельными процессами, живущими рядом с основным тарантулом, по процессу на реплику. Репликация может осуществляться как асинхронно (транзакция считается выполненной до того, как все реплики подтвердят получение данных), так и синхронно. Для синхронной репликации используется алгоритм Raft.
Что мне очень понравилось в тарантуле - удобный ui для создания и управления кластером (входит в Tarantool Cartridge). В нем можно проставить репликам как дефолтные роли (failover coordinator, master, replica, router), так и пользовательские, включающие определенный набор "таблиц" и хранимок. При желании, этот же ui можно использовать для написания или правки хранимых процедур и распространения обновлений по кластеру. Все команды ui также могут быть продублированы в виде скриптов в командной строке (что я и делал).
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. UI + дублирующие консольные команды, позволяющие создать кластер без боли. И выбор ролей инстансов через UI - тоже огонь.
2. Идея обмена слухами о происходящем в кластере хороша.
#sphagnum_theory@eshu_coding
#tarantool
#sphagnum@eshu_coding
Тарантул изначально проектировался как решение, которое можно без боли (ха-ха) раскатать в бесконечное по размеру облако. Вообще, про взаимодействие между инстансами можно почитать вполне себе неплохую статью на Хабре. Если кратко, инстансы обмениваются друг с другом "слухами" о происходящих событиях по UDP (с помощью механизма SWIM) и формируют
И также неплохая статья про механизм репликации. Если коротко - между мастером и репликами распространяется журнал WAL мастера. При том, распространяется отдельными процессами, живущими рядом с основным тарантулом, по процессу на реплику. Репликация может осуществляться как асинхронно (транзакция считается выполненной до того, как все реплики подтвердят получение данных), так и синхронно. Для синхронной репликации используется алгоритм Raft.
Что мне очень понравилось в тарантуле - удобный ui для создания и управления кластером (входит в Tarantool Cartridge). В нем можно проставить репликам как дефолтные роли (failover coordinator, master, replica, router), так и пользовательские, включающие определенный набор "таблиц" и хранимок. При желании, этот же ui можно использовать для написания или правки хранимых процедур и распространения обновлений по кластеру. Все команды ui также могут быть продублированы в виде скриптов в командной строке (что я и делал).
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. UI + дублирующие консольные команды, позволяющие создать кластер без боли. И выбор ролей инстансов через UI - тоже огонь.
2. Идея обмена слухами о происходящем в кластере хороша.
#sphagnum_theory@eshu_coding
#tarantool
Хабр
Отказоустойчивая архитектура: почему Tarantool не падает?
Основная проблема в высоконагруженных приложениях — отказоустойчивость. Нагрузка с упавших узлов в кластере должна переключаться на живые. Это кажется несложной задачей, но на практике появляется...
Sphagnum. Часть 7. Техобзор. Репликация и отказоустойчивость в NATS
#sphagnum@eshu_coding
NATS - брокер сообщений, написанный на Go как альтернатива мейнстримным решениям - RabbitMQ и Apache Kafka. Отличительная особенность - он может подключаться в приложения, разрабатываемые на Go как dll-ка. Собственно, этот проект и вдохновил меня на разработку своего брокера сообщений. Изначально NATS был легковесным
Standalone решением, не предполагающим
кластеризацию и персистентное хранение данных. Но вскоре эти
механизмы также завезли,
породив по сути два NATS-а - классический и с наворотами. В чём-то это
похоже на развитие Tarantool.
NATS в кластерной версии, как и Tarantool, использует алгоритм Raft для выявления лидера. Кроме того, данные, попавшие в инстанс, отдаются только его непосредственным соседям. А соседи дальше их не передают. Так формируются Stream groups - группы инстансов внутри кластера с синхронизированным состоянием. Впрочем, как я понял, есть пути пустить данные дальше. Аналогично могут формироваться Consumer groups - группировки инстансов по подключенным клиентам-подписчикам. Как я понимаю (возможно ошибочно), таким образом может достигаться ограниченное горизонтальное масштабирование. В NATS данные могут сохраняться как на диск, так и в СУБД, например - постгрес.
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. Мне очень понравилась идея дополнительной сегментации вроде бы единого кластера.
2. Идея сохранения данных не на диск, а в СУБД выглядит очень интересно, по крайней мере на этапе разработки, чтобы отложить в сторону вопросы оптимальной укладки данных на жёсткий диск.
#sphagnum_theory@eshu_coding
#nats
#sphagnum@eshu_coding
NATS - брокер сообщений, написанный на Go как альтернатива мейнстримным решениям - RabbitMQ и Apache Kafka. Отличительная особенность - он может подключаться в приложения, разрабатываемые на Go как dll-ка. Собственно, этот проект и вдохновил меня на разработку своего брокера сообщений. Изначально NATS был легковесным
Standalone решением, не предполагающим
кластеризацию и персистентное хранение данных. Но вскоре эти
механизмы также завезли,
породив по сути два NATS-а - классический и с наворотами. В чём-то это
похоже на развитие Tarantool.
NATS в кластерной версии, как и Tarantool, использует алгоритм Raft для выявления лидера. Кроме того, данные, попавшие в инстанс, отдаются только его непосредственным соседям. А соседи дальше их не передают. Так формируются Stream groups - группы инстансов внутри кластера с синхронизированным состоянием. Впрочем, как я понял, есть пути пустить данные дальше. Аналогично могут формироваться Consumer groups - группировки инстансов по подключенным клиентам-подписчикам. Как я понимаю (возможно ошибочно), таким образом может достигаться ограниченное горизонтальное масштабирование. В NATS данные могут сохраняться как на диск, так и в СУБД, например - постгрес.
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. Мне очень понравилась идея дополнительной сегментации вроде бы единого кластера.
2. Идея сохранения данных не на диск, а в СУБД выглядит очень интересно, по крайней мере на этапе разработки, чтобы отложить в сторону вопросы оптимальной укладки данных на жёсткий диск.
#sphagnum_theory@eshu_coding
#nats
Вот и закончилась первая часть обзора. Я не ставил себе целью досконально описать каждый из продуктов, для моих целей достаточно общего понимания предметной области.
Следующим этапом постараюсь отыскать ссылки на методы, используемые для организации распределенных транзакций в известнейших СУБД и брокерах сообщения, а затем начну углубляться в каждый из них.
#sphagnum_theory@eshu_coding
Следующим этапом постараюсь отыскать ссылки на методы, используемые для организации распределенных транзакций в известнейших СУБД и брокерах сообщения, а затем начну углубляться в каждый из них.
#sphagnum_theory@eshu_coding
Telegram
Эшу быдлокодит
Sphagnum. Часть 3. Техобзор, начало.
#sphagnum@eshu_coding
Несмотря на нехватку времени продолжаю потихоньку заниматься новым проектом.
Прежде чем садиться писать код, нужно изучить некоторые моменты, чтобы потом не строить велосипеды из костылей. В науке…
#sphagnum@eshu_coding
Несмотря на нехватку времени продолжаю потихоньку заниматься новым проектом.
Прежде чем садиться писать код, нужно изучить некоторые моменты, чтобы потом не строить велосипеды из костылей. В науке…
Подведу итоги года.
В начале января 2023 я решил посмешить богов и опубликовал пост со своими планами на год, пойду по пунктам:
1. Я хотел познакомиться с современной фронтенд разработкой (React.js). Познакомился, осознал основные концепции, необходимые для разработки фронтенда на React-е. Теперь можно начинать что-то писать и набивать руку, но желания нет от слова совсем.
2. Я хотел заполнить пробел в знаниях и познакомиться на практике с ORM Entity Framework. Познакомился, шишек понабивал.
3. В постгрес углубиться не удалось, просто вспомнил забытое с 2021 года и не более того.
4. Я хотел читать умные книжки. Читал намного меньше чем хотелось, осилил только половину Рихтера.
5. Не делал вообще ничего в этом направлении:)
Но наверное главный итог года - что я таки дополз до лычки сеньора и сеньорских должностей и задач соответственно. Теперь движемся в сторону техлида/архитектора.
В начале января 2023 я решил посмешить богов и опубликовал пост со своими планами на год, пойду по пунктам:
1. Я хотел познакомиться с современной фронтенд разработкой (React.js). Познакомился, осознал основные концепции, необходимые для разработки фронтенда на React-е. Теперь можно начинать что-то писать и набивать руку, но желания нет от слова совсем.
2. Я хотел заполнить пробел в знаниях и познакомиться на практике с ORM Entity Framework. Познакомился, шишек понабивал.
3. В постгрес углубиться не удалось, просто вспомнил забытое с 2021 года и не более того.
4. Я хотел читать умные книжки. Читал намного меньше чем хотелось, осилил только половину Рихтера.
5. Не делал вообще ничего в этом направлении:)
Но наверное главный итог года - что я таки дополз до лычки сеньора и сеньорских должностей и задач соответственно. Теперь движемся в сторону техлида/архитектора.
Telegram
Эшу быдлокодит
Ну чтож, надо посмешить богов, озвучить свои планы.
Чего хочу я в этом году:
1. Немного обмазаться фронтенд разработкой, но без фанатизма. Пока думаю о связке React + Typescript.
2. Попробовать на практике стандартную шарповую ORM: Entity Framework.
3.…
Чего хочу я в этом году:
1. Немного обмазаться фронтенд разработкой, но без фанатизма. Пока думаю о связке React + Typescript.
2. Попробовать на практике стандартную шарповую ORM: Entity Framework.
3.…
Анонсирую наверное ещё один проект, которым хочу заняться уже третий год. Это автоматизация настольной ролевой игры Trail of Cthulhu, дальше будет под тегом #cthulhu@eshu_coding. Про саму игру можно подробнее почитать на той же тесере. Правила мудрёны и путаны, потому систематизировать и описать их в виде кода - занятная задача.
Планирую чисто мобильное приложение + бэкенд, возможно - вариант без бэкенда, для взаимодействия между несколькими мобильными устройствами, изолированными от интернета. Приложение строго для домашнего использования, максимум - с друзьями, чтобы не париться на предмет авторских прав и прочего.
Приложение довольно простое. Основной элемент игры - лист сыщика (персонажа), таблица с ~100 меняющимися по разным законам параметрами. Для некоторых сыщиков - законы свои. Также нужно предусмотреть несколько действий, которые может совершить сыщик. И чатик/поле для записей, ну и сохранение истории происходящего.
В далёком светлом будущем ещё хотелось бы сделать поиск по правилам, но это уже рюшечки.
Я несколько раз подступался к разработке, но дальше размышлений и купленного домена так и не продвинулся.
#проекты
Планирую чисто мобильное приложение + бэкенд, возможно - вариант без бэкенда, для взаимодействия между несколькими мобильными устройствами, изолированными от интернета. Приложение строго для домашнего использования, максимум - с друзьями, чтобы не париться на предмет авторских прав и прочего.
Приложение довольно простое. Основной элемент игры - лист сыщика (персонажа), таблица с ~100 меняющимися по разным законам параметрами. Для некоторых сыщиков - законы свои. Также нужно предусмотреть несколько действий, которые может совершить сыщик. И чатик/поле для записей, ну и сохранение истории происходящего.
В далёком светлом будущем ещё хотелось бы сделать поиск по правилам, но это уже рюшечки.
Я несколько раз подступался к разработке, но дальше размышлений и купленного домена так и не продвинулся.
#проекты
Forwarded from .NET Разработчик
День 1804. #TipsAndTricks
10 Крутых Трюков в C#. Продолжение
1-2
3-4
5
6
7
8. Динамическая компиляция кода с Roslyn
Динамическая компиляция кода с помощью Roslyn позволяет компилировать и выполнять код C# во время выполнения. Это может быть полезно для сценариев, плагинов или ситуаций, когда код необходимо генерировать или изменять «на лету».
Вывод:
Как это работает и почему это полезно:
В примере выше метод ExecuteDynamicCodeAsync демонстрирует, как скомпилировать и выполнить фрагмент кода C# во время выполнения с помощью компилятора Roslyn. Метод Roslyn CSharpSyntaxTree.ParseText используется для анализа исходного кода в синтаксическое дерево, которое затем добавляется в новый объект CSharpCompilation. К объекту компиляции также добавляются необходимые ссылки на сборки: библиотеку CoreLib, System.Runtime и System.Console для работы класса Console. Заметьте, что в последних версиях .NET они находятся в разных файлах.
Метод Emit компилирует код в динамически подключаемую библиотеку (DLL) и записывает выходные данные в MemoryStream. Если компиляция прошла успешно, полученная сборка загружается в текущий домен приложения с помощью метода Assembly.Load. Затем класс Runner и его метод Run получаются через рефлексию, и этот метод вызывается, выполняя динамический код.
Этот метод позволяет создавать гибкие и расширяемые приложения, которые могут динамически компилировать и выполнять код C# во время выполнения. Однако будьте осторожны с последствиями для безопасности, поскольку выполнение произвольного кода может создать угрозу безопасности, если с ним не обращаться должным образом.
Продолжение следует…
Источник: https://maherz.medium.com/10-mind-blowing-c-hacks-95fa629cfcef
10 Крутых Трюков в C#. Продолжение
1-2
3-4
5
6
7
8. Динамическая компиляция кода с Roslyn
Динамическая компиляция кода с помощью Roslyn позволяет компилировать и выполнять код C# во время выполнения. Это может быть полезно для сценариев, плагинов или ситуаций, когда код необходимо генерировать или изменять «на лету».
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
async Task ExecuteDynamicCodeAsync(
string code)
{
string sourceCode = $@"
using System;
namespace DynamicCode;
public class Runner
{{
public static void Run()
{{
{code}
}}
}}
";
var syntaxTree = CSharpSyntaxTree.ParseText(sourceCode);
var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);
var references = new List<MetadataReference>
{
MetadataReference.CreateFromFile(
Path.Combine(assemblyPath, "System.Private.CoreLib.dll")),
MetadataReference.CreateFromFile(
Path.Combine(assemblyPath, "System.Console.dll")),
MetadataReference.CreateFromFile(
Path.Combine(assemblyPath, "System.Runtime.dll"))
};
var compilation = CSharpCompilation.Create("DynamicCode")
.WithOptions(new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary))
.AddReferences(references)
.AddSyntaxTrees(syntaxTree);
using var ms = new MemoryStream();
var result = compilation.Emit(ms);
if (!result.Success)
{
Console.WriteLine("Компиляция не удалась");
return;
}
ms.Seek(0, SeekOrigin.Begin);
var assembly = Assembly.Load(ms.ToArray());
var type = assembly.GetType("DynamicCode.Runner");
var method = type.GetMethod("Run",
BindingFlags.Static | BindingFlags.Public);
method.Invoke(null, null);
}
// использование
await ExecuteDynamicCodeAsync(
"Console.WriteLine(\"Привет, динамический код!\");"
);
Вывод:
Привет, динамический код!
Как это работает и почему это полезно:
В примере выше метод ExecuteDynamicCodeAsync демонстрирует, как скомпилировать и выполнить фрагмент кода C# во время выполнения с помощью компилятора Roslyn. Метод Roslyn CSharpSyntaxTree.ParseText используется для анализа исходного кода в синтаксическое дерево, которое затем добавляется в новый объект CSharpCompilation. К объекту компиляции также добавляются необходимые ссылки на сборки: библиотеку CoreLib, System.Runtime и System.Console для работы класса Console. Заметьте, что в последних версиях .NET они находятся в разных файлах.
Метод Emit компилирует код в динамически подключаемую библиотеку (DLL) и записывает выходные данные в MemoryStream. Если компиляция прошла успешно, полученная сборка загружается в текущий домен приложения с помощью метода Assembly.Load. Затем класс Runner и его метод Run получаются через рефлексию, и этот метод вызывается, выполняя динамический код.
Этот метод позволяет создавать гибкие и расширяемые приложения, которые могут динамически компилировать и выполнять код C# во время выполнения. Однако будьте осторожны с последствиями для безопасности, поскольку выполнение произвольного кода может создать угрозу безопасности, если с ним не обращаться должным образом.
Продолжение следует…
Источник: https://maherz.medium.com/10-mind-blowing-c-hacks-95fa629cfcef
Попробую посмешить богов и в этом году. Планы на 2024 год.
1. Читать умные книжки:
- Рихтер
- Внедрение зависимостей на платформе .Net (Симан, ван Дерсен)
- Чистая архитектура (Роберт Мартин)
- Высоконагруженные приложения (Мартин Клеппман)
2. Осознать до конца некоторые архитектурные загибы:
- Аспекто-ориентированное программирование
- Акторы
- Углубиться в DDD
3. На практике освоить магию Source Generators - на этапе компиляции c# проекта, компилятор по заранее заданным правилам анализирует созданное им, на основании анализа генерирует некоторое количество нового c# кода, компилирует снова вместе с генеренным кодом и так сколько настроишь раз.
4. Таки потыкать алгоритмы, задачки на литкоде.
5. Добраться до кода с пет проектом #sphagnum.
6. Добраться до кода с пет проектом #cthulhu
7. Есть желание переписать и перезапустить #палантир@eshu_coding.
1. Читать умные книжки:
- Рихтер
- Внедрение зависимостей на платформе .Net (Симан, ван Дерсен)
- Чистая архитектура (Роберт Мартин)
- Высоконагруженные приложения (Мартин Клеппман)
2. Осознать до конца некоторые архитектурные загибы:
- Аспекто-ориентированное программирование
- Акторы
- Углубиться в DDD
3. На практике освоить магию Source Generators - на этапе компиляции c# проекта, компилятор по заранее заданным правилам анализирует созданное им, на основании анализа генерирует некоторое количество нового c# кода, компилирует снова вместе с генеренным кодом и так сколько настроишь раз.
4. Таки потыкать алгоритмы, задачки на литкоде.
5. Добраться до кода с пет проектом #sphagnum.
6. Добраться до кода с пет проектом #cthulhu
7. Есть желание переписать и перезапустить #палантир@eshu_coding.
tesera.ru
Ктулху / Trail of Cthulhu | Tesera
Trail of Cthulhu — настольная ролевая игра, приключения в мире Лавкрафтовского ужаса, разыгрываемые по правилам «СЫЩИК» (GUMSHOE).
Как обычно ставят нугет пакеты? Зашёл в менеджер, выбрал версию, поставил, побежал дальше писать код.
Предположим, наша инфраструктура растет, у нас появляются собственные нугет пакеты, мы их активно используем, чтобы не копипастить код и не впадать в микросервисное безумие.
Мы продолжаем расти и развиваться. Часть наших пакетов начинает ссылаться на другие наши пакеты. Которые ссылаются на другие наши пакеты. Которые ссылаются на другие наши пакеты.Ой, рекурсия. На самом деле, циклическую зависимость создать никто не даст, но деревья зависимостей могут быть очень развесистыми.
И в какой-то момент ссылки начинают пересекаться. И если мы работаем обычным образом - как описано в начале поста - рано или поздно два установленных пакета начнут ссылаться на разные версии одного и того же пакета. И тут мы попадаем в ад конфликтующих зависимостей, из которого выход только один: в окно. Впрочем, в ад можно попасть даже если два проекта в решении ссылаются на разные версии одного и того же пакета, без всяких страшных древ зависимостей.
Лучше подобные проблемы не решать, а предотвращать, не допуская даже саму возможность появления.
Во-первых, продумать структуру решения. В идеале - нарисовать схему взаимных зависимостей проектов и установленных в них пакетов. И идеале, один пакет в решении должен устанавливаться один раз. Если мы ставим пакет 1 и пакет 2, зависящий от пакета 1, прямую установку пакета 1 мы тоже можем удалить.
Во-вторых, можно указать не конкретную версию пакета, а диапазон, например [1.0.0,3.0.0). В этот интервал попадут все пакеты, имеющие версию 1 или 2. Если у другого пакета будет [1.2.0,2.5.0) - при сборке будет подобрана версия, удовлетворяющая обоим интервалам условий.
В-третьих, версии пакетов можно выносить в константы и подтягивать из .props файлов. Предположим, часть функционала у нас вынесена в пакеты, имеющие в названии "Common", например Common.Math, Common.StringParsing, Common.HttpHelper. Мы можем ввести внутреннее правило - двигать версии этих пакетов только вместе (как на уровне регламента, так и в CI/CD). В .props мы можем определить параметр ${CommonPackageVersion}, после чего в проекте согласованно выставлять все версии Common пакетов через .props файл, указывая в .csproj файлах вместо привычных численных версий пакетов значение ${CommonPackageVersion}
P.S. больше информации по нугет пакетам можно посмотреть в официальной документации.
#csharp
Предположим, наша инфраструктура растет, у нас появляются собственные нугет пакеты, мы их активно используем, чтобы не копипастить код и не впадать в микросервисное безумие.
Мы продолжаем расти и развиваться. Часть наших пакетов начинает ссылаться на другие наши пакеты. Которые ссылаются на другие наши пакеты. Которые ссылаются на другие наши пакеты.
И в какой-то момент ссылки начинают пересекаться. И если мы работаем обычным образом - как описано в начале поста - рано или поздно два установленных пакета начнут ссылаться на разные версии одного и того же пакета. И тут мы попадаем в ад конфликтующих зависимостей, из которого выход только один: в окно. Впрочем, в ад можно попасть даже если два проекта в решении ссылаются на разные версии одного и того же пакета, без всяких страшных древ зависимостей.
Лучше подобные проблемы не решать, а предотвращать, не допуская даже саму возможность появления.
Во-первых, продумать структуру решения. В идеале - нарисовать схему взаимных зависимостей проектов и установленных в них пакетов. И идеале, один пакет в решении должен устанавливаться один раз. Если мы ставим пакет 1 и пакет 2, зависящий от пакета 1, прямую установку пакета 1 мы тоже можем удалить.
Во-вторых, можно указать не конкретную версию пакета, а диапазон, например [1.0.0,3.0.0). В этот интервал попадут все пакеты, имеющие версию 1 или 2. Если у другого пакета будет [1.2.0,2.5.0) - при сборке будет подобрана версия, удовлетворяющая обоим интервалам условий.
В-третьих, версии пакетов можно выносить в константы и подтягивать из .props файлов. Предположим, часть функционала у нас вынесена в пакеты, имеющие в названии "Common", например Common.Math, Common.StringParsing, Common.HttpHelper. Мы можем ввести внутреннее правило - двигать версии этих пакетов только вместе (как на уровне регламента, так и в CI/CD). В .props мы можем определить параметр ${CommonPackageVersion}, после чего в проекте согласованно выставлять все версии Common пакетов через .props файл, указывая в .csproj файлах вместо привычных численных версий пакетов значение ${CommonPackageVersion}
P.S. больше информации по нугет пакетам можно посмотреть в официальной документации.
#csharp