СЛЕГ! <Z> ️
Photo
К репосту. Инструменты разработчика в браузере - дичайшее читерство. При первом, и даже втором взгляде - перегружено и неочевидно. Но если жизнь заставляет погрузиться, как заставила уважаемого @ssleg, они оказываются волшебным окном во внутренности портала.
Современные сайты состоят в большей степени из кода на JavaScript, чем из html. Они живут - постоянно запрашивают какие-то данные у бэкенда, шевелят анимациями и т.д. И вся эта внутренняя кухня находит отражается в инструментах разработчика.
В запросе результатов опроса с Активного Гражданина (АГ) есть занятный момент. Протокол HTTP поддерживает несколько разных запросов: POST, GET и т.д. Разница между ними в том, что в методе GET все параметры запроса открытые, а в POST так с ходу их не прочитать. Потому, когда не хотят показывать, что в запросе, метод POST, предназначенный для загрузки данных на сервер, используют и не по назначению, в т.ч. и для получения информации, как это сделал программист, писавший модуль запроса.
Вот только безопасности это никакой не дало: JavaScript код-то открыт всему миру! Существуют разные способы защиты кода, авторы АГ выбрали далеко не самый надежный: обфускацию кода.
Есть еще один путь, к сожалению не всегда применимый в современной парадигме веба: писать сайт на C#:)
Современные сайты состоят в большей степени из кода на JavaScript, чем из html. Они живут - постоянно запрашивают какие-то данные у бэкенда, шевелят анимациями и т.д. И вся эта внутренняя кухня находит отражается в инструментах разработчика.
В запросе результатов опроса с Активного Гражданина (АГ) есть занятный момент. Протокол HTTP поддерживает несколько разных запросов: POST, GET и т.д. Разница между ними в том, что в методе GET все параметры запроса открытые, а в POST так с ходу их не прочитать. Потому, когда не хотят показывать, что в запросе, метод POST, предназначенный для загрузки данных на сервер, используют и не по назначению, в т.ч. и для получения информации, как это сделал программист, писавший модуль запроса.
Вот только безопасности это никакой не дало: JavaScript код-то открыт всему миру! Существуют разные способы защиты кода, авторы АГ выбрали далеко не самый надежный: обфускацию кода.
Есть еще один путь, к сожалению не всегда применимый в современной парадигме веба: писать сайт на C#:)
MDN Web Docs
Методы HTTP запроса - HTTP | MDN
HTTP определяет множество методов запроса, которые указывают, какое желаемое действие выполнится для данного ресурса. Несмотря на то, что их названия могут быть существительными, эти методы запроса иногда называются HTTP глаголами. Каждый реализует свою семантику…
После первой пробы отладки ПО с настроенным микроскопом я ощутил, что не только в производительности счастье.
Реальный мир оказался жесток:
Интерфейс программы, на скорую руку накиданный в WinForms, оказался неюзабельным говном.
Следующим нежданчиком оказалось то, что даже над хорошей камерой приходится колдовать,чтобы получить приличную картинку. И колдовать, что характерно, из пользовательского интерфейса.
Цифровая камера при низкой интенсивности света выдает жуткие цифровые шумы. А при высокой - засвечивается и уходит в насыщение, утрачивая вообще какую-либо полезную информацию.
Для подавления шумов пока что я реализовал два простейших подхода: сглаживание окном 5х5 и накопление сигнала - использование для вычислений скользящего среднего последних 10 картинок.
В итоге, при правильно выставленных времени экспозиции, усилении (gain), насыщенности (saturation), сглаживании и скользящем среднем хотя бы по 3 картинкам качество вычисляемого изображения стало... условно приемлемым.
На очереди:
1. Детектирование движения кадра (для сброса накопления)
2. Вычитание из картинки плоскости или сферы по 3 точкам.
3. Режим вычисления фразового изображения по jpg файлу.
4. Новый UI на WPF
5. Ускорение ивычислений: распараллеливание и оптимизация быстрого преобразования Фурье, возврат к развёртке фазы.
6. Реализация различных Фурье фильтров, как для шумоподавления, так и для замены части используемой математики.
7. Разработка версии программы для записи картинок под GPU.
8. Собственно начало диссертационного исследования: погружение в мир цифрового анализа изображений, скорее всего уже на питоне.
Реальный мир оказался жесток:
Интерфейс программы, на скорую руку накиданный в WinForms, оказался неюзабельным говном.
Следующим нежданчиком оказалось то, что даже над хорошей камерой приходится колдовать,чтобы получить приличную картинку. И колдовать, что характерно, из пользовательского интерфейса.
Цифровая камера при низкой интенсивности света выдает жуткие цифровые шумы. А при высокой - засвечивается и уходит в насыщение, утрачивая вообще какую-либо полезную информацию.
Для подавления шумов пока что я реализовал два простейших подхода: сглаживание окном 5х5 и накопление сигнала - использование для вычислений скользящего среднего последних 10 картинок.
В итоге, при правильно выставленных времени экспозиции, усилении (gain), насыщенности (saturation), сглаживании и скользящем среднем хотя бы по 3 картинкам качество вычисляемого изображения стало... условно приемлемым.
На очереди:
1. Детектирование движения кадра (для сброса накопления)
2. Вычитание из картинки плоскости или сферы по 3 точкам.
3. Режим вычисления фразового изображения по jpg файлу.
4. Новый UI на WPF
5. Ускорение ивычислений: распараллеливание и оптимизация быстрого преобразования Фурье, возврат к развёртке фазы.
6. Реализация различных Фурье фильтров, как для шумоподавления, так и для замены части используемой математики.
7. Разработка версии программы для записи картинок под GPU.
8. Собственно начало диссертационного исследования: погружение в мир цифрового анализа изображений, скорее всего уже на питоне.
Вчера был первый эксперимент нового витка диссертационного исследования. Планируется попробовать засечь влияние нового ветеринарного препарата на иммунную систему на примере лабораторных животных (крыс).
Самое удивительное, что все получилось близко к программе максимум.
У нас был пересобранный необкатанный микроскоп с сырой глючной программой, две крысы, две студентки, один ветеринар, один оптик и один программист.
Ещё было лабораторное оборудование, "позаимствованное" с миру по нитке. Описание ритуала выделения лимфоцитов в телеграммном чатике и методика взятия крови из хвоста на ютубчике. Способ приготовления препарата для микроскопа на ходу зачитывался из электронной почты.
В качестве установки для контроля был микроскоп 1990 года сборки, работающий под MS DOS.
Первую крысуизрасходовали употребили на то, чтобы просто потренироваться: слепили препарат, увидели клетки, с помощью старого микроскопа проверили, что этой действительно эритроциты, а не следы пальца на покровном стеклышке.
Из второй крови удалось взять 50-100мкл крови вместо нужного нам 1мл (в 10-20 раз меньше). Несмотря на это, ритуал выделения клеток прошёл успешно и мы засняли некоторое количество картинок с лимфоцитами. Характерное ядро с чуть скошенным центром масс, ступенька цитоплазмы, размер процентов на 30 меньше, чем у человеческих, это без сомнений лимфоциты!
Теперь предстоит оценить качество заснятых картинок, допилить микроскоп и потренироваться брать кровь у крысы. А так, микроскоп можно поздравить с крещением: теперь он окроплен крысиной кровью!
P.S. Крысы отделались небольшими гематомами у основания хвоста и дефекацией в процессе забора крови.
#диссер
Самое удивительное, что все получилось близко к программе максимум.
У нас был пересобранный необкатанный микроскоп с сырой глючной программой, две крысы, две студентки, один ветеринар, один оптик и один программист.
Ещё было лабораторное оборудование, "позаимствованное" с миру по нитке. Описание ритуала выделения лимфоцитов в телеграммном чатике и методика взятия крови из хвоста на ютубчике. Способ приготовления препарата для микроскопа на ходу зачитывался из электронной почты.
В качестве установки для контроля был микроскоп 1990 года сборки, работающий под MS DOS.
Первую крысу
Из второй крови удалось взять 50-100мкл крови вместо нужного нам 1мл (в 10-20 раз меньше). Несмотря на это, ритуал выделения клеток прошёл успешно и мы засняли некоторое количество картинок с лимфоцитами. Характерное ядро с чуть скошенным центром масс, ступенька цитоплазмы, размер процентов на 30 меньше, чем у человеческих, это без сомнений лимфоциты!
Теперь предстоит оценить качество заснятых картинок, допилить микроскоп и потренироваться брать кровь у крысы. А так, микроскоп можно поздравить с крещением: теперь он окроплен крысиной кровью!
P.S. Крысы отделались небольшими гематомами у основания хвоста и дефекацией в процессе забора крови.
#диссер
К вопросу о том, почему я называю процесс выделения лимфоцитов ритуалом.
Ингредиенты:
1. Лизирующий буфер (NH4Cl, KHCO3, ЭДТА) для разрушения эритроцитов.
2. Фосфатный буфер для разведения крови
3. Фиколл - синтетическое сахароподобное нечто, используется, чтобы создать градиент плоскости, на который наслаиваются лимфоциты.
Примерная последовательности действий:
1. Берётся кровь, откручивается пару раз на центрифуге с фосфатными буфером.
2. Добавляется лизирующий буфер, откручивается на центрифуге.
3. Все это перемешивается на специальной мешалке-дрожалке.
4. Откручивается на центрифуге.
5. Несколько раз разбавляется фосфатным буфером, откручивается, мусор со дна удаляется.
6. На дно пробирки наливается фиколл, на него наслаиваются (как в слоёных коктейлях) результат из предыдущего пункта.
7. Всё центрифугируется еще раз, на границе раздела застревают Т и B лимфоциты, которые собираются дозатором и, в объеме 3-6 мкл используются для приготовления препарата.
#диссер
Ингредиенты:
1. Лизирующий буфер (NH4Cl, KHCO3, ЭДТА) для разрушения эритроцитов.
2. Фосфатный буфер для разведения крови
3. Фиколл - синтетическое сахароподобное нечто, используется, чтобы создать градиент плоскости, на который наслаиваются лимфоциты.
Примерная последовательности действий:
1. Берётся кровь, откручивается пару раз на центрифуге с фосфатными буфером.
2. Добавляется лизирующий буфер, откручивается на центрифуге.
3. Все это перемешивается на специальной мешалке-дрожалке.
4. Откручивается на центрифуге.
5. Несколько раз разбавляется фосфатным буфером, откручивается, мусор со дна удаляется.
6. На дно пробирки наливается фиколл, на него наслаиваются (как в слоёных коктейлях) результат из предыдущего пункта.
7. Всё центрифугируется еще раз, на границе раздела застревают Т и B лимфоциты, которые собираются дозатором и, в объеме 3-6 мкл используются для приготовления препарата.
#диссер
Палантир. Начало.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, #палантир@eshu_coding
Цель - выкачать весь открытый русскоязычный контент из телеги (посты и комменты к ним) в одну базу данных, после чего начать развлекаться с NLP.
Попутная цель - попрактиковаться в незнакомых технологиях. В итоге я потыкал палочкой в Docker, grpc (гугловый протокол передачи данных), секционирование таблиц в postgesql, настройку cd/ci с помощью github actions и немного в администрирование линуксовых серверов.
Пока что система проста как топор: master на c#, отдающий команды и принимающий результаты для сохранения в постгрес и slave-ы, выгружающие данные из телеги и передающие их master-у.
Для написания slave-ов пришлось пересилить себя и обмазаться питоном: в клиентских библиотеках под js или c# не было реализации одного важного запроса.
В итоге питоновские slave-ы плодятся коротеньким bash скриптом в любом месте, где установлен Docker. Мастера я не стал ставить в контейнер: плодить я их не намерен, а без контейнера проще хотябы в файлы логов заглянуть в случае чего.
Связь между компонентами осуществляется через grpc. В целом проект запустился в пятницу 2 апреля успешно. Сейчас уже трудятся 4 сборщика, спарсил 10 млн сообщений и постов от 400 тысяч пользователей из 13 тыс каналов и чатов.
#проекты
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, #палантир@eshu_coding
Цель - выкачать весь открытый русскоязычный контент из телеги (посты и комменты к ним) в одну базу данных, после чего начать развлекаться с NLP.
Попутная цель - попрактиковаться в незнакомых технологиях. В итоге я потыкал палочкой в Docker, grpc (гугловый протокол передачи данных), секционирование таблиц в postgesql, настройку cd/ci с помощью github actions и немного в администрирование линуксовых серверов.
Пока что система проста как топор: master на c#, отдающий команды и принимающий результаты для сохранения в постгрес и slave-ы, выгружающие данные из телеги и передающие их master-у.
Для написания slave-ов пришлось пересилить себя и обмазаться питоном: в клиентских библиотеках под js или c# не было реализации одного важного запроса.
В итоге питоновские slave-ы плодятся коротеньким bash скриптом в любом месте, где установлен Docker. Мастера я не стал ставить в контейнер: плодить я их не намерен, а без контейнера проще хотябы в файлы логов заглянуть в случае чего.
Связь между компонентами осуществляется через grpc. В целом проект запустился в пятницу 2 апреля успешно. Сейчас уже трудятся 4 сборщика, спарсил 10 млн сообщений и постов от 400 тысяч пользователей из 13 тыс каналов и чатов.
#проекты
Палантир. Часть 1. Начинаю серию постов по изученным мной в процессе разработки сборщика данных с телеграма техническим нюансам.
#палантир@eshu_coding
Как уже было сказано, мной используется схема master - slave. Для связи между ними вместо традиционных http запросов я использую gRPC.
Суть технологии в следующем в файлах с расширениями .proto описываются основные точно взаимодействия элементов приложения и используемые структуры данных.
Видов взаимодействия может быть четыре:
1. Одиночный вызов. Клиент стучит на сервер, закидывает туда данные в описанном формате, получает ответ заданного формата.
Остальное - варианты стримминга. Доступны следующие варианты:
А) Клиент шлет одиночный запрос, в ответ получает поток ответов.
Б) Клиент отправляет на сервер поток сознания, получает одиночный ответ.
В) Клиент отправляет поток сознания и получает поток в ответ.
Все эти режимы работы, а также формат отдельных сообщений прописан в .proto файле.
gRPC - мультиязычная платформа, что крайне удобно для связи сервисов, написанных на разных языках. Структуры данных, описанные в протофайле, доступны для использования как обычные классы.
В случае с# и node.js достаточно добавить в проект протофайл и можно пользоваться этими структурами. В питоне нужно отдельной командой сгенерировать питоновские файлы, в которых будут автогенерированные классы, описанные в протобуфе.
Чем еще хороша gRPC? Во-первых - удобство. Описал взаимодействие всех компонентов и гоняй стандартизированные структуры данных через стандартизированные API туда-сюда. Многие ошибки отваливаются на этапе сборки проектов.
Во вторых - стримминг и подписка на события реализуется просто и без боли.
В третьих grpc тупо шустрее обычных http запросов: от 20% до 7-10 раз, вот одна из статей с замерами.
В общем, годная технология, но наверняка есть и подводные камни.
#кодинг
#палантир@eshu_coding
Как уже было сказано, мной используется схема master - slave. Для связи между ними вместо традиционных http запросов я использую gRPC.
Суть технологии в следующем в файлах с расширениями .proto описываются основные точно взаимодействия элементов приложения и используемые структуры данных.
Видов взаимодействия может быть четыре:
1. Одиночный вызов. Клиент стучит на сервер, закидывает туда данные в описанном формате, получает ответ заданного формата.
Остальное - варианты стримминга. Доступны следующие варианты:
А) Клиент шлет одиночный запрос, в ответ получает поток ответов.
Б) Клиент отправляет на сервер поток сознания, получает одиночный ответ.
В) Клиент отправляет поток сознания и получает поток в ответ.
Все эти режимы работы, а также формат отдельных сообщений прописан в .proto файле.
gRPC - мультиязычная платформа, что крайне удобно для связи сервисов, написанных на разных языках. Структуры данных, описанные в протофайле, доступны для использования как обычные классы.
В случае с# и node.js достаточно добавить в проект протофайл и можно пользоваться этими структурами. В питоне нужно отдельной командой сгенерировать питоновские файлы, в которых будут автогенерированные классы, описанные в протобуфе.
Чем еще хороша gRPC? Во-первых - удобство. Описал взаимодействие всех компонентов и гоняй стандартизированные структуры данных через стандартизированные API туда-сюда. Многие ошибки отваливаются на этапе сборки проектов.
Во вторых - стримминг и подписка на события реализуется просто и без боли.
В третьих grpc тупо шустрее обычных http запросов: от 20% до 7-10 раз, вот одна из статей с замерами.
В общем, годная технология, но наверняка есть и подводные камни.
#кодинг
Telegram
Эшу быдлокодит
Прошу прощения за долгое молчание, было безумно много работы.
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
А ещё сегодня была очередная серия экспериментов с крысами и микроскопом.
Микроскоп у нас отдает чем-то из некромантии: ломается, переделывается прямо на ходу, но работает. Трупы дохли и снова оживали в общем.
При этом часть, касающаяся вычисления изображения, работает достойно, хотя в скором времени будет второй раунд оптимизаций, но только после хорошего интерфейса: я окончательно осознал, что в гробу видел WinForms и таки надо делать всё на WPF.
Кроме моей косорукости при разработке UI, у нас другая проблема: крысы не очень-то спешат отдавать кровь из хвостовой вены, а зубки у них ого-го, приходится ветеринарам делать небольшое усекновение кончика хвоста. Людской крови, впрочем, пролилось во много раз больше крысиной.
В целом эксперименты налаживаются, скоро поставим на поток.
#диссер
Микроскоп у нас отдает чем-то из некромантии: ломается, переделывается прямо на ходу, но работает. Трупы дохли и снова оживали в общем.
При этом часть, касающаяся вычисления изображения, работает достойно, хотя в скором времени будет второй раунд оптимизаций, но только после хорошего интерфейса: я окончательно осознал, что в гробу видел WinForms и таки надо делать всё на WPF.
Кроме моей косорукости при разработке UI, у нас другая проблема: крысы не очень-то спешат отдавать кровь из хвостовой вены, а зубки у них ого-го, приходится ветеринарам делать небольшое усекновение кончика хвоста. Людской крови, впрочем, пролилось во много раз больше крысиной.
В целом эксперименты налаживаются, скоро поставим на поток.
#диссер
Довольно важная и модная сейчас тема - автоматическое развертывание кода и в пределе - непрерывная поставка. После того как программист отправил несколько строк кода в репозиторий запускаются сонмы автотестов, если всё ок - строки попадают на прод или в грядущее большое обновление.
Для автоматизации развертывания и тестирования используются разные инструменты, но для пет проектов лучший выбор - Github Actions. В репозитории нужно лишь найти вкладку Actions и следуя указаниям добавить себе в репозиторий простейший пример.
Использовать Actions можно двумя путями (в т.ч. комбинируя их): для проверки работоспособности кода, прогоняя автотесты и для развертывания собранного ПО на сервер. Тестирование - отдельная тема, расскажу о нём потом, как разберусь до конца сам. В целом, документация довольно подробная, потому остановлюсь только на некоторых неочевидных моментах.
1. Github Actions позволяет выполнять консольные команды как на удаленном сервере, так и на виртуалке, выделяемой гитхабом на время работы скрипта. На этой виртуалке осуществляется компиляция и сборка, а также отправка готовой программы по назначению. Дисковое пространство виртуалки организовано довольно неочевидно, потому не стесняйтесь после каждого чиха делать
run: |
ls
pwd
Чтобы понять где вы находитесь и что происходит. Результат будет выведен в лог выполнения Action-а.
2. Для работы с внешним миром стоит воспользоваться готовыми решениями. Так, для исполнения скрипта на сервере можно воспользоваться пакетом appleboy/ssh-action@master, а для архивирования и отправки результата сборки - appleboy/scp-action@master
Главное - не забывать, что вы имеете дело со стандартным консольным линуксом. Практически всё, что можете сделать там - можно сделать и тут.
3. Приватная информация. К серверу надо логиниться, а раскрывать IP адрес и пароль от сервера или SSH-ключ - не комильфо. Специально для этого добавлены Секретки: вкладка Settings, там - Secrets. Туда можно приватную информацию и использовать её в скриптах по необходимости примерно таким образом: ${{ secrets.DOCKER_HUB_LOGIN }}.
Что мне особенно понравилось - посмотреть содержимое секреток так с ходу нельзя даже через аккаунт, только с адскими заморочками с помощью написания скрипта в Actions, который пошлёт куда-то во внешний мир информацию, например с помощью какого-то линуксового почтового клиента.
4. При сборке образов докера (подробнее расскажу о них в следующий) тоже не стоит забывать, что при сборке из файла также доступна линуксовая виртуалка, которая умеет во все стандартные команды (т.е. не стесняйтесь сделать ls), а еще оно может исполнять питоновские скрипты прямо во время сборки образа.
Вообще же примеры сборки и развертывания можно посмотреть в моем репозитории: в файловую систему, в докер.
#кодинг
#devops
Для автоматизации развертывания и тестирования используются разные инструменты, но для пет проектов лучший выбор - Github Actions. В репозитории нужно лишь найти вкладку Actions и следуя указаниям добавить себе в репозиторий простейший пример.
Использовать Actions можно двумя путями (в т.ч. комбинируя их): для проверки работоспособности кода, прогоняя автотесты и для развертывания собранного ПО на сервер. Тестирование - отдельная тема, расскажу о нём потом, как разберусь до конца сам. В целом, документация довольно подробная, потому остановлюсь только на некоторых неочевидных моментах.
1. Github Actions позволяет выполнять консольные команды как на удаленном сервере, так и на виртуалке, выделяемой гитхабом на время работы скрипта. На этой виртуалке осуществляется компиляция и сборка, а также отправка готовой программы по назначению. Дисковое пространство виртуалки организовано довольно неочевидно, потому не стесняйтесь после каждого чиха делать
run: |
ls
pwd
Чтобы понять где вы находитесь и что происходит. Результат будет выведен в лог выполнения Action-а.
2. Для работы с внешним миром стоит воспользоваться готовыми решениями. Так, для исполнения скрипта на сервере можно воспользоваться пакетом appleboy/ssh-action@master, а для архивирования и отправки результата сборки - appleboy/scp-action@master
Главное - не забывать, что вы имеете дело со стандартным консольным линуксом. Практически всё, что можете сделать там - можно сделать и тут.
3. Приватная информация. К серверу надо логиниться, а раскрывать IP адрес и пароль от сервера или SSH-ключ - не комильфо. Специально для этого добавлены Секретки: вкладка Settings, там - Secrets. Туда можно приватную информацию и использовать её в скриптах по необходимости примерно таким образом: ${{ secrets.DOCKER_HUB_LOGIN }}.
Что мне особенно понравилось - посмотреть содержимое секреток так с ходу нельзя даже через аккаунт, только с адскими заморочками с помощью написания скрипта в Actions, который пошлёт куда-то во внешний мир информацию, например с помощью какого-то линуксового почтового клиента.
4. При сборке образов докера (подробнее расскажу о них в следующий) тоже не стоит забывать, что при сборке из файла также доступна линуксовая виртуалка, которая умеет во все стандартные команды (т.е. не стесняйтесь сделать ls), а еще оно может исполнять питоновские скрипты прямо во время сборки образа.
Вообще же примеры сборки и развертывания можно посмотреть в моем репозитории: в файловую систему, в докер.
#кодинг
#devops
Amazon
Что такое непрерывная доставка? – Amazon Web Services
❤1
Палантир. Часть 2. Жизненный цикл команд.
#палантир@eshu_coding
Как я уже упоминал, мой сборщик построен на микросервисной архитектуре: центральный сервер - master для хранения информации, находящийся над БД (postgresql) и slave-ы сборщики, в некотором количестве.
В master-е генерируются приказы: загрузить историю из определенного чатика/канала или проверить наличие чата для дискуссий у канала.
И как только пошла +- боевая нагрузка, я начал собирать грабли за граблями. Казалось бы, логика работы простая:
1. Чекаем базу, если есть чаты или каналы, которые давно не обновлялись - создаём приказ на обновление.
2. Сборщик берет приказ, пытается выполнить его.
З. Если приказ не может быть выполнен каким-либо сборщиком (лимиты телеги на спам например) - приказ возвращается "на базу", авось кто сможет выполнить.
Всё логично? Но если счёт приказов идёт на десятки тысяч, достаточно быстро возникает "шторм" из невыполнимых приказов: сервисы перебрасываются ими 99% времени.
Пришлось додумывать жизненный цикл приказов. Проблема вроде решилась.
Через какое-то время я обнаружил, что полезли дубли в засосанных сообщениях. Сначала нашел небольшой баг в сборщике, пофиксил. А следом началась чертовщина: дубли никуда не делись, их стало только больше.
Выяснилось, что при рабочей нагрузке возникает ситуация, когда приказ уже ушел на исполнение, данные грузятся, грузятся, грузятся, попадают в длииинную очередь. В это время приходит время генерации следующей партии приказов, генерится дубль уже выполняющегося и отправляется на исполнение другому сборщику. Как результат - число дублей в какой-то момент дошло до 25%.
Пришлось додумывать жизненный цикл приказов. Проблема вроде решилась.
Но вылезла другая проблема: "узкий" запрос на получение чатика от канала имеет один счетчик флуда с простым поиском юзера/канала по юзернейму. В итоге у меня сеть перестала расти, т.к. сборщики исчерпывали свой суточный лимит запросов буквально за час.
Будь у меня один сборщик - проблем бы не было, т.к. вся нужная для доступа информация сохраняется в сессии. Но у меня их несколько, потому, чтобы получить доступ к каналу/чату первый раз нужно сделать поиск.
Пришлось додумывать жизненный цикл приказов. Проблема вроде решилась.
Вся система стала работать как часы, производительность сборки улучшилась... И тут всплыла проблема ограниченной памяти сервера: если все сборщики одновременно натыкаются на огромные каналы/чаты база перестает справляться с нагрузкой на запись, потребление оперативки растет, что в итоге засталяет линуксsacrifice cild убить или postgres или master сборщика.
Пришлось додумывать жизненный цикл приказов. Проблема вроде решилась.
Продолжение следует...
P.S. В итоге у меня приказы возвращаются ограниченное количество раз, а поиск по юзернейму случается только когда предыдущие несколько сборщиков вернули запрос. Кроме того менеджер приказов анализирует очереди и при необходимости выдает slave-ам команду "поспать".
#палантир@eshu_coding
Как я уже упоминал, мой сборщик построен на микросервисной архитектуре: центральный сервер - master для хранения информации, находящийся над БД (postgresql) и slave-ы сборщики, в некотором количестве.
В master-е генерируются приказы: загрузить историю из определенного чатика/канала или проверить наличие чата для дискуссий у канала.
И как только пошла +- боевая нагрузка, я начал собирать грабли за граблями. Казалось бы, логика работы простая:
1. Чекаем базу, если есть чаты или каналы, которые давно не обновлялись - создаём приказ на обновление.
2. Сборщик берет приказ, пытается выполнить его.
З. Если приказ не может быть выполнен каким-либо сборщиком (лимиты телеги на спам например) - приказ возвращается "на базу", авось кто сможет выполнить.
Всё логично? Но если счёт приказов идёт на десятки тысяч, достаточно быстро возникает "шторм" из невыполнимых приказов: сервисы перебрасываются ими 99% времени.
Пришлось додумывать жизненный цикл приказов. Проблема вроде решилась.
Через какое-то время я обнаружил, что полезли дубли в засосанных сообщениях. Сначала нашел небольшой баг в сборщике, пофиксил. А следом началась чертовщина: дубли никуда не делись, их стало только больше.
Выяснилось, что при рабочей нагрузке возникает ситуация, когда приказ уже ушел на исполнение, данные грузятся, грузятся, грузятся, попадают в длииинную очередь. В это время приходит время генерации следующей партии приказов, генерится дубль уже выполняющегося и отправляется на исполнение другому сборщику. Как результат - число дублей в какой-то момент дошло до 25%.
Пришлось додумывать жизненный цикл приказов. Проблема вроде решилась.
Но вылезла другая проблема: "узкий" запрос на получение чатика от канала имеет один счетчик флуда с простым поиском юзера/канала по юзернейму. В итоге у меня сеть перестала расти, т.к. сборщики исчерпывали свой суточный лимит запросов буквально за час.
Будь у меня один сборщик - проблем бы не было, т.к. вся нужная для доступа информация сохраняется в сессии. Но у меня их несколько, потому, чтобы получить доступ к каналу/чату первый раз нужно сделать поиск.
Пришлось додумывать жизненный цикл приказов. Проблема вроде решилась.
Вся система стала работать как часы, производительность сборки улучшилась... И тут всплыла проблема ограниченной памяти сервера: если все сборщики одновременно натыкаются на огромные каналы/чаты база перестает справляться с нагрузкой на запись, потребление оперативки растет, что в итоге засталяет линукс
Пришлось додумывать жизненный цикл приказов. Проблема вроде решилась.
Продолжение следует...
P.S. В итоге у меня приказы возвращаются ограниченное количество раз, а поиск по юзернейму случается только когда предыдущие несколько сборщиков вернули запрос. Кроме того менеджер приказов анализирует очереди и при необходимости выдает slave-ам команду "поспать".
Telegram
Эшу быдлокодит
Палантир. Часть 1. Начинаю серию постов по изученным мной в процессе разработки сборщика данных с телеграма техническим нюансам.
#палантир@eshu_coding
Как уже было сказано, мной используется схема master - slave. Для связи между ними вместо традиционных…
#палантир@eshu_coding
Как уже было сказано, мной используется схема master - slave. Для связи между ними вместо традиционных…
👍1
Палантир. Часть 3. Клиентские библиотеки для взаимодействия с телеграмом.
#палантир@eshu_coding
Часть сборщика у меня написана на питоне. 300 строк быдлокода осуществляют взаимодействие с телеграмом. Питон я не люблю и умею писать на нем сильно хуже, чем на c#, потому с самого начала проекта испытываю постоянные позывы переписать питоновскую часть.
К сожалению, адекватных клиентских библиотек под с# в настоящий момент нет. Не хватает одного важного запроса: GetFullChannel, который позволяет перейти от канала к прикреплённому к нему чатику.
TLSharp был написан во времена, когда комментариев, да и чатиков при каналах ещё не было в природе, потому нужный мне запрос работает неправильно, не позволяя перейти к чату.
Потому последние несколько дней я разбирался с принципами работы Telegram API, в надежде обновить TLSharp и переписать таки взаимодействие на него.
Итог одного из экспериментов на картинке: аккаунт просто удалили без следа, итого -1 сборщик.
#телеграм
#палантир@eshu_coding
Часть сборщика у меня написана на питоне. 300 строк быдлокода осуществляют взаимодействие с телеграмом. Питон я не люблю и умею писать на нем сильно хуже, чем на c#, потому с самого начала проекта испытываю постоянные позывы переписать питоновскую часть.
К сожалению, адекватных клиентских библиотек под с# в настоящий момент нет. Не хватает одного важного запроса: GetFullChannel, который позволяет перейти от канала к прикреплённому к нему чатику.
TLSharp был написан во времена, когда комментариев, да и чатиков при каналах ещё не было в природе, потому нужный мне запрос работает неправильно, не позволяя перейти к чату.
Потому последние несколько дней я разбирался с принципами работы Telegram API, в надежде обновить TLSharp и переписать таки взаимодействие на него.
Итог одного из экспериментов на картинке: аккаунт просто удалили без следа, итого -1 сборщик.
#телеграм
👍1
Палантир. Часть 4. Протокол телеграма.
#палантир@eshu_coding
Помните, раньше говорилось, что телеграм - самый быстрый из мессенджеров и работает на самом убогом интернете? Причина скрыта в реализации протокола обмена данными клиентов и серверов.
Первое знакомство с протоколом вызывает бурю эмоций, но по прошествии времени проникаешься гениальностью замысла. API описано, на основании описания авторы клиентских библиотек генерируют основной код, после чего доводят библиотеку напильником.
Данные передаются через голый TCP, без всяких наворотов.
Принцип работы следующий: любая сущность представляет собой поток байтов. Первые 4 байта описывают тип сущности: канал, чат, человек, сообщение, прикреплённое медиа. Тип сущности и что какие байты значат берется из генерированного по API кода.
Необязательные параметры в документации помечаются степенью двойки. Наличие параметра определяется следующим образом: берутся 4 байта. Если логическое И этих байтов и двойки в степени из документации не равно нулю - значит параметр есть, повторяем вышеописанную процедуру разбора на нем. Если нет - идём дальше.
Жуткая наркомания, но в итоге по сети передаётся только полезная информация.
#телеграм
#палантир@eshu_coding
Помните, раньше говорилось, что телеграм - самый быстрый из мессенджеров и работает на самом убогом интернете? Причина скрыта в реализации протокола обмена данными клиентов и серверов.
Первое знакомство с протоколом вызывает бурю эмоций, но по прошествии времени проникаешься гениальностью замысла. API описано, на основании описания авторы клиентских библиотек генерируют основной код, после чего доводят библиотеку напильником.
Данные передаются через голый TCP, без всяких наворотов.
Принцип работы следующий: любая сущность представляет собой поток байтов. Первые 4 байта описывают тип сущности: канал, чат, человек, сообщение, прикреплённое медиа. Тип сущности и что какие байты значат берется из генерированного по API кода.
Необязательные параметры в документации помечаются степенью двойки. Наличие параметра определяется следующим образом: берутся 4 байта. Если логическое И этих байтов и двойки в степени из документации не равно нулю - значит параметр есть, повторяем вышеописанную процедуру разбора на нем. Если нет - идём дальше.
Жуткая наркомания, но в итоге по сети передаётся только полезная информация.
#телеграм
Telegram
СЛЕГ! <Z> ️
Ночные разговоры. Ещё один мой друг-программист познакомился с реальным протоколом телеграм вблизи. Причём, в отличии от меня, любителя, он программист настоящий.
Библиотеки высокого уровня абстракции (telethon, aiogram, etc) прячут от нас чудовищную мешанину…
Библиотеки высокого уровня абстракции (telethon, aiogram, etc) прячут от нас чудовищную мешанину…
Палантир, Часть 5. Питоновские клиенты-сборщики.
#палантир@eshu_coding
Сборщиков сейчас работает 4 штуки, написаны они на питоне, с использованием библиотеки telethon. Крутятся по два, каждый в своем докер контейнере на машинах с 0.5 Гб оперативки и 1 ядром 2.2 ГГц (слабее витуалки не нарезает хостер).
При работе сборщикам нужно куда-то сохранять данные о просмотренных ими телеграммных сущностях. Дефолтное решение - хранение в sqlite в файлах в рабочей директории - для докеризированного приложения не подходит.
Добрые люди создали удаленное хранилище сессий: ставишь пакет, указываешь тип бд и connection string к ней, а дальше все работает само.
В итоге при старте slave стучится к мастеру: есть сессия для коннекта? Если есть, master отдает ему данные для подключения к хранилищу сессий и номер телефона реги, slave цепляется к бд, берет данные, коннектится, работает.
Написаны сборщики за один день и написаны ужасно: там используется god-class и несколько вложенных друг в друга циклов while True:
Но к сожалению альтернатив питону для этой задачи нет (кроме php, бгг), необходимости переписывать пока тоже, так что работает - не трогаю.
P.S. У меня сегодня небольшой юбилей: в базе сейчас 91 тыс каналов и групп, из них выгружено 57 тыс, 1.7 млн юзеров и
150 млн сообщений.
#палантир@eshu_coding
Сборщиков сейчас работает 4 штуки, написаны они на питоне, с использованием библиотеки telethon. Крутятся по два, каждый в своем докер контейнере на машинах с 0.5 Гб оперативки и 1 ядром 2.2 ГГц (слабее витуалки не нарезает хостер).
При работе сборщикам нужно куда-то сохранять данные о просмотренных ими телеграммных сущностях. Дефолтное решение - хранение в sqlite в файлах в рабочей директории - для докеризированного приложения не подходит.
Добрые люди создали удаленное хранилище сессий: ставишь пакет, указываешь тип бд и connection string к ней, а дальше все работает само.
В итоге при старте slave стучится к мастеру: есть сессия для коннекта? Если есть, master отдает ему данные для подключения к хранилищу сессий и номер телефона реги, slave цепляется к бд, берет данные, коннектится, работает.
Написаны сборщики за один день и написаны ужасно: там используется god-class и несколько вложенных друг в друга циклов while True:
Но к сожалению альтернатив питону для этой задачи нет (кроме php, бгг), необходимости переписывать пока тоже, так что работает - не трогаю.
P.S. У меня сегодня небольшой юбилей: в базе сейчас 91 тыс каналов и групп, из них выгружено 57 тыс, 1.7 млн юзеров и
150 млн сообщений.
Палантир. Часть 6. Out of memory kill. Моя борьба.
#палантир@eshu_coding
Основной сервер существенно мощнее сборщиков: 4гб оперативки, 2 ядра 2.2 ГГц. Крутятся там два компонента системы: база данных - postgresql и сервис-обертка на ней. Сервис принимает подключения по grpc, генерирует и отдаёт приказы и укладывает пришедшие данные в бд.
Как только вся система начала работать в штатном режиме, ещё на 2 Гб оперативки, у меня возникла проблема: в какой-то момент Линуксу перестает хватать памяти и он пишет следующее: Out of memory: kill process X or sacrifice child. И убивает процесс.
Добавил файл подкачки в 3 Гб, накинул оперативку до 4гб, понизил приоритет моих процессов для OOM киллера. Вроде проблема прошла.
Смотрю утром: Out of memory: kill process postgresql or sacrifice child.
К тому же сервер начал негодовать, что бд нету и отложил 25 Гб ругательных логов, продублированных и в системные логи убунты.
По логам восстановил произошедшее: все 4 сборщика наткнулись на жирные каналы с большим количеством объемных (по 2кб в среднем) постов.
База не успевала всё переварить, скопилась очередь в 2 млн сообщений (2 Гб оперативки), OOM грохнул базу и все сошло с ума. Добавил приказы сборщикам на торможение: если в очереди на запись больше 100 тыс постов - сборщики получают команды поспать 10 секунд пока ситуация не разрешится. Также снизил лимит размера кэша у Постгреса с 1Гб до 500 мб. Запустил.
Утром: Out of memory: kill process postgresql or sacrifice child.
Покурил мануалы по постгресу, покрутил настройки, снизил лимит сна до 60 тыс сообщений.
На следующее утро: Out of memory: kill process postgresql or sacrifice child.
Проверил весь код на предмет утечки памяти. Нету. Наткнулся где-то на совет закрывать ненужные соединения с БД, решил попробовать.
Out of memory: kill process postgresql or sacrifice child.
Продолжил искать корень зла. Можно было бы конечно накинуть оперативки до 16 Гб, добавить пару ядер в цпу и перейти на SSD, но это во-первых не спортивно, во-вторых нет никакой гарантии, что проблема решится, а в-третьих - проект учебный. Люди когда-то жили без неограниченных ресурсов, значит и мне было бы неплохо научиться писать эффективный код.
И тут в какой-то момент я решил посмотреть, какой процесс сколько потребляет памяти в реальном времени.
Мой сервер-надстройка над базой - 500 мб-1.5 Гб по ситуации.
Постгрес основной процесс - 500 мб, как и прописал к конфиге. И ещё - 7 процессов по 250-300 мб. 3 - подключения моего сервера к БД: для записи сообщений, для записи юзеров и для записи чатов и каналов. 4 - подключения сборщиков, ведь именно на эту БД я повесил удаленное хранилище сессий, вот они и пользуются им.
Началась оптимизация: хранилище сессий уехало в другое место, все подключения сервера к БД я засунул в одно. А ещё добавил более адекватную тормозилку разогнавшихся сборщиков: при заходе за лимит (80 тыс сообщений в очереди на запись), сервер устанавливает паузу на прием следующего сообщения в 1 с. Когда очередь разгружается до 40 тысяч прием возобновляется в полном объеме.
Так и поборол я OOM Killer. Все крутится уже недели полторы без единого чиха.
#палантир@eshu_coding
Основной сервер существенно мощнее сборщиков: 4гб оперативки, 2 ядра 2.2 ГГц. Крутятся там два компонента системы: база данных - postgresql и сервис-обертка на ней. Сервис принимает подключения по grpc, генерирует и отдаёт приказы и укладывает пришедшие данные в бд.
Как только вся система начала работать в штатном режиме, ещё на 2 Гб оперативки, у меня возникла проблема: в какой-то момент Линуксу перестает хватать памяти и он пишет следующее: Out of memory: kill process X or sacrifice child. И убивает процесс.
Добавил файл подкачки в 3 Гб, накинул оперативку до 4гб, понизил приоритет моих процессов для OOM киллера. Вроде проблема прошла.
Смотрю утром: Out of memory: kill process postgresql or sacrifice child.
К тому же сервер начал негодовать, что бд нету и отложил 25 Гб ругательных логов, продублированных и в системные логи убунты.
По логам восстановил произошедшее: все 4 сборщика наткнулись на жирные каналы с большим количеством объемных (по 2кб в среднем) постов.
База не успевала всё переварить, скопилась очередь в 2 млн сообщений (2 Гб оперативки), OOM грохнул базу и все сошло с ума. Добавил приказы сборщикам на торможение: если в очереди на запись больше 100 тыс постов - сборщики получают команды поспать 10 секунд пока ситуация не разрешится. Также снизил лимит размера кэша у Постгреса с 1Гб до 500 мб. Запустил.
Утром: Out of memory: kill process postgresql or sacrifice child.
Покурил мануалы по постгресу, покрутил настройки, снизил лимит сна до 60 тыс сообщений.
На следующее утро: Out of memory: kill process postgresql or sacrifice child.
Проверил весь код на предмет утечки памяти. Нету. Наткнулся где-то на совет закрывать ненужные соединения с БД, решил попробовать.
Out of memory: kill process postgresql or sacrifice child.
Продолжил искать корень зла. Можно было бы конечно накинуть оперативки до 16 Гб, добавить пару ядер в цпу и перейти на SSD, но это во-первых не спортивно, во-вторых нет никакой гарантии, что проблема решится, а в-третьих - проект учебный. Люди когда-то жили без неограниченных ресурсов, значит и мне было бы неплохо научиться писать эффективный код.
И тут в какой-то момент я решил посмотреть, какой процесс сколько потребляет памяти в реальном времени.
Мой сервер-надстройка над базой - 500 мб-1.5 Гб по ситуации.
Постгрес основной процесс - 500 мб, как и прописал к конфиге. И ещё - 7 процессов по 250-300 мб. 3 - подключения моего сервера к БД: для записи сообщений, для записи юзеров и для записи чатов и каналов. 4 - подключения сборщиков, ведь именно на эту БД я повесил удаленное хранилище сессий, вот они и пользуются им.
Началась оптимизация: хранилище сессий уехало в другое место, все подключения сервера к БД я засунул в одно. А ещё добавил более адекватную тормозилку разогнавшихся сборщиков: при заходе за лимит (80 тыс сообщений в очереди на запись), сервер устанавливает паузу на прием следующего сообщения в 1 с. Когда очередь разгружается до 40 тысяч прием возобновляется в полном объеме.
Так и поборол я OOM Killer. Все крутится уже недели полторы без единого чиха.
Dependency injection (DI).
В процессе написания сборщика я осознал логику современного подхода к проектированию приложений: использования внедрения зависимостей (DI).
Ранее я многократно использовал этот подход для подключения готовых компонентов из ASP. Net Core. Но как-то не задумывался о сути подхода, лежащего в основе.
В стандартной логике проектирования приложения мы полностью сами выстраиваем путь, который проходят данные от точки входа к точке выхода.
Внедрение зависимостей - шажок в сторону декларативного программирования: мы описываем взаимоотношения элементов программы друг с другом, после чего регистрируем эти элементы, указывая их жизненный цикл.
После попадания в точку входа, CLR соберёт все необходимые для работы элементы, в идеале нам не придется самим ни создавать, ни удалять классы.
Элементы программы - сервисы - могут иметь один из четырех вариантов жизненного цикла:
1. Transient. Каждый раз когда есть необходимость в экземпляре класса будет создан новый экземпляр, а по выполнении работы - удален.
2. Scoped. Один экземпляр класса на одну порождающую причину.
3. Singleton. На веки будет лишь один экземпляр класса, с ним и работайте. CLR проследит за его единственностью, если использовать его только через DI.
4. Hosted Service. В отличие от первых трёх видов, создаваемых "по пинку" из внешнего мира, создаётся сразу при старте приложения. Обычно выполняет какую-то постоянную/периодическую работу, в остальном - как Singleton.
В идеале все сервисы абстрагируются до интерфейсов, а конкретный используемый тип указывается только при регистрации.
Преимущества использования внедрения зависимостей:
1. Программа превращается
в конструктор, можно
многократно и без мучений переиспользовать удачный код, вынеся его в библиотеки и подключая по мере необходимости.
2. Исключается часть ошибок по невнимательности: нельзя забыть создать класс или создать его с неверными параметрами. В обычном случае проблема может всплыть нескоро и вызвать много затруднений. А в случае с DI программа завалится на старте и сообщит, где и чего ей не хватает для счастья.
3. Удобство тестирования и разработки "по частям". Можно прямо со старта накидать архитектуру, понатыкав заглушек. И реализовывать их постепенно, меняя одно слово при регистрации класса. Также удобно покрывать тестами отдельные сервисы.
Недостатки:
1. Логика приложения становится труднее в восприятии посторонним человеком: что делает каждый сервис понятно, а вот что они делают вместе - уже не всегда.
2. Написание тестов, которые реально что-то проверяют, хоть и становится намного проще, но при этом и более трудоемким, требуя больше кода на заглушки и моки.
В целом, подход мне очень зашёл, пока не разочаровался в нем, внедряю его везде где это получается сделать быстро и просто.
P.S. Внедрение зависимостей есть и для питона.
#кодинг
В процессе написания сборщика я осознал логику современного подхода к проектированию приложений: использования внедрения зависимостей (DI).
Ранее я многократно использовал этот подход для подключения готовых компонентов из ASP. Net Core. Но как-то не задумывался о сути подхода, лежащего в основе.
В стандартной логике проектирования приложения мы полностью сами выстраиваем путь, который проходят данные от точки входа к точке выхода.
Внедрение зависимостей - шажок в сторону декларативного программирования: мы описываем взаимоотношения элементов программы друг с другом, после чего регистрируем эти элементы, указывая их жизненный цикл.
После попадания в точку входа, CLR соберёт все необходимые для работы элементы, в идеале нам не придется самим ни создавать, ни удалять классы.
Элементы программы - сервисы - могут иметь один из четырех вариантов жизненного цикла:
1. Transient. Каждый раз когда есть необходимость в экземпляре класса будет создан новый экземпляр, а по выполнении работы - удален.
2. Scoped. Один экземпляр класса на одну порождающую причину.
3. Singleton. На веки будет лишь один экземпляр класса, с ним и работайте. CLR проследит за его единственностью, если использовать его только через DI.
4. Hosted Service. В отличие от первых трёх видов, создаваемых "по пинку" из внешнего мира, создаётся сразу при старте приложения. Обычно выполняет какую-то постоянную/периодическую работу, в остальном - как Singleton.
В идеале все сервисы абстрагируются до интерфейсов, а конкретный используемый тип указывается только при регистрации.
Преимущества использования внедрения зависимостей:
1. Программа превращается
в конструктор, можно
многократно и без мучений переиспользовать удачный код, вынеся его в библиотеки и подключая по мере необходимости.
2. Исключается часть ошибок по невнимательности: нельзя забыть создать класс или создать его с неверными параметрами. В обычном случае проблема может всплыть нескоро и вызвать много затруднений. А в случае с DI программа завалится на старте и сообщит, где и чего ей не хватает для счастья.
3. Удобство тестирования и разработки "по частям". Можно прямо со старта накидать архитектуру, понатыкав заглушек. И реализовывать их постепенно, меняя одно слово при регистрации класса. Также удобно покрывать тестами отдельные сервисы.
Недостатки:
1. Логика приложения становится труднее в восприятии посторонним человеком: что делает каждый сервис понятно, а вот что они делают вместе - уже не всегда.
2. Написание тестов, которые реально что-то проверяют, хоть и становится намного проще, но при этом и более трудоемким, требуя больше кода на заглушки и моки.
В целом, подход мне очень зашёл, пока не разочаровался в нем, внедряю его везде где это получается сделать быстро и просто.
P.S. Внедрение зависимостей есть и для питона.
#кодинг
Хабр
Внедрение зависимостей the Python way
Зачем нужно внедрение зависимостей? Оно уменьшает связанность компонентов в приложение и упрощает тестирование. У некоторых разработчиков есть мнение, что внедрение зависимостей нужно только в...
Палантир. Часть 7. Dependency injection в master-сервере.
#палантир@eshu_coding
В продолжение предыдущего поста и в завершение серии про сборщик.
Регистрация всех элементов gRPC осуществляется через внедрение зависимостей: даётся указание использовать grpc, а также - какие сервисы использовать.
Кроме того, остальные компоненты, используемые мной также подключены.
Сервис, пишущий в БД через одну очередь - singleton. Кроме него, singleton-ами являются классы "State" (хранится всё взаимодействие со сборшиками slave-ами) и LoadManager, притормаживающий сборщики при риске перегрузки.
Также используется два Hosted Service: генератор приказов и периодически синхронизирующийся с базой менеджер учёток сборщиков.
В виде Transient зарегистрированы всякие служебные штуки, а кроме того, класс Report. В него через DI заведены основные синглтоны. При http запросе на контроллер, выведенный мной для мониторинга, создаётся экземпляр Report.
В конструкторе он сохраняет информацию о состоянии синглтонов в свои поля, после чего сериализуется и отправляется мне,а потом - уничтожается.
Scoped не нашли себе места в моем сервере. При других обстоятельствах в качестве Scoped я мог бы объявить запись в БД, чтобы информация каждого вида писалась через своё подключение. Но, во-первых я экономлю память, а во-вторых, при использовании HDD в качестве хранилища, выигрыш от распараллеливания записи крайне сомнителен.
#кодинг
#палантир@eshu_coding
В продолжение предыдущего поста и в завершение серии про сборщик.
Регистрация всех элементов gRPC осуществляется через внедрение зависимостей: даётся указание использовать grpc, а также - какие сервисы использовать.
Кроме того, остальные компоненты, используемые мной также подключены.
Сервис, пишущий в БД через одну очередь - singleton. Кроме него, singleton-ами являются классы "State" (хранится всё взаимодействие со сборшиками slave-ами) и LoadManager, притормаживающий сборщики при риске перегрузки.
Также используется два Hosted Service: генератор приказов и периодически синхронизирующийся с базой менеджер учёток сборщиков.
В виде Transient зарегистрированы всякие служебные штуки, а кроме того, класс Report. В него через DI заведены основные синглтоны. При http запросе на контроллер, выведенный мной для мониторинга, создаётся экземпляр Report.
В конструкторе он сохраняет информацию о состоянии синглтонов в свои поля, после чего сериализуется и отправляется мне,а потом - уничтожается.
Scoped не нашли себе места в моем сервере. При других обстоятельствах в качестве Scoped я мог бы объявить запись в БД, чтобы информация каждого вида писалась через своё подключение. Но, во-первых я экономлю память, а во-вторых, при использовании HDD в качестве хранилища, выигрыш от распараллеливания записи крайне сомнителен.
#кодинг
Telegram
Эшу быдлокодит
Dependency injection (DI).
В процессе написания сборщика я осознал логику современного подхода к проектированию приложений: использования внедрения зависимостей (DI).
Ранее я многократно использовал этот подход для подключения готовых компонентов из ASP.…
В процессе написания сборщика я осознал логику современного подхода к проектированию приложений: использования внедрения зависимостей (DI).
Ранее я многократно использовал этот подход для подключения готовых компонентов из ASP.…
Немного поясню за тормозящих ботов, ну и похвастаюсь.
Проблема у ботов Когана скорее всего следующей природы: у телеграма у ботов есть лимиты на число отправляемых сообщений. Если много человек одновременно нажмет "Start", бот им одновременно ответит, скорее всего - каким-то меню, в ответ на которое он должен тоже что-то получать.
Люди тыкают, бот - отвечает. Выхватывает спам - ограничение, начинает тупить. Психующие люди тыкают больше кнопок, бот всё активнее пытается отвечать, в итоге очередь обработки запросов растягивается до бесконечности.
Еще прошлым летом я подумал об этой проблеме, что породило пару постов, где я предотвращал такую ситуацию: раз, два.
Угробил я на решение проблемы спам-блокировок ботов дней 5, но решил её навсегда, в виде небольшого модуля, который легко воткнуть в любое место в боте. А самое прикольное, что пару месяцев назад мне по работе понадобилось делать примерно то же самое, в результате чего я сэкономил несколько дней, просто скопировав свой код.
Проблема у ботов Когана скорее всего следующей природы: у телеграма у ботов есть лимиты на число отправляемых сообщений. Если много человек одновременно нажмет "Start", бот им одновременно ответит, скорее всего - каким-то меню, в ответ на которое он должен тоже что-то получать.
Люди тыкают, бот - отвечает. Выхватывает спам - ограничение, начинает тупить. Психующие люди тыкают больше кнопок, бот всё активнее пытается отвечать, в итоге очередь обработки запросов растягивается до бесконечности.
Еще прошлым летом я подумал об этой проблеме, что породило пару постов, где я предотвращал такую ситуацию: раз, два.
Угробил я на решение проблемы спам-блокировок ботов дней 5, но решил её навсегда, в виде небольшого модуля, который легко воткнуть в любое место в боте. А самое прикольное, что пару месяцев назад мне по работе понадобилось делать примерно то же самое, в результате чего я сэкономил несколько дней, просто скопировав свой код.
Telegram
СЛЕГ!
Интересно, каким местом пишут ботов "разработчики", что у них бот помирает от сотен и тысяч обращений? Помирает так, что нужно ручное восстановление базы, судя по воплям Когана.
У меня левой ногой сделанный код выдерживает 9к обращений за пять минут и обрабатывает…
У меня левой ногой сделанный код выдерживает 9к обращений за пять минут и обрабатывает…
Палантир. Часть 8. Переезд между хостингами.
#палантир@eshu_coding
Назрела необходимость в переезде сборщика на другой хостинг, с более гуманными ценами на дисковое пространство.
Я начал пилить нечто вроде поисковика по постам телеги, скорость работы HDD на базе размером 250 ГБ меня совершенно не устраивает.
Перешёл в облако к Яндексу из-за гуманных цен на SSD. Сразу подкупила встроенная в личный кабинет система мониторинга. Не Zabbix конечно, но позволяет понять, что там внутри происходит. На старом хостере инструмент мониторинга существенно хуже.
Я снял виртуалку, на которую поставил master-сервер и postgres. Вообще, яндекс предоставляет и Postgresql as service. Суть услуги - конфигурируем из личного кабинета постгрес, оплачиваем и пользуемся.
Без переписывания конфиг файлов и установки Postgres на Линукс. Но цена х1.5 от цены виртуалки с теми же параметрами меня отпугнула. К тому же, мне нужно куда-то ставить master-сервер.
Порадовал процесс клонирования и репликации в postgres. Сначала утилитой перетягиваем всё содержимое БД на другую машину.
Потом дописываются несколько строчек в конфигурации и у нас появляется репликация вида master-slave. Фантастически удобно, привет MySQL!
В общем, переезд состоялся, самое время нырнуть в глубины полнотекстового поиска.
#палантир@eshu_coding
Назрела необходимость в переезде сборщика на другой хостинг, с более гуманными ценами на дисковое пространство.
Я начал пилить нечто вроде поисковика по постам телеги, скорость работы HDD на базе размером 250 ГБ меня совершенно не устраивает.
Перешёл в облако к Яндексу из-за гуманных цен на SSD. Сразу подкупила встроенная в личный кабинет система мониторинга. Не Zabbix конечно, но позволяет понять, что там внутри происходит. На старом хостере инструмент мониторинга существенно хуже.
Я снял виртуалку, на которую поставил master-сервер и postgres. Вообще, яндекс предоставляет и Postgresql as service. Суть услуги - конфигурируем из личного кабинета постгрес, оплачиваем и пользуемся.
Без переписывания конфиг файлов и установки Postgres на Линукс. Но цена х1.5 от цены виртуалки с теми же параметрами меня отпугнула. К тому же, мне нужно куда-то ставить master-сервер.
Порадовал процесс клонирования и репликации в postgres. Сначала утилитой перетягиваем всё содержимое БД на другую машину.
Потом дописываются несколько строчек в конфигурации и у нас появляется репликация вида master-slave. Фантастически удобно, привет MySQL!
В общем, переезд состоялся, самое время нырнуть в глубины полнотекстового поиска.
Telegram
Эшу быдлокодит
Прошу прощения за долгое молчание, было безумно много работы.
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Небольшое пояснение к предыдущему посту.
Скорость чтения и записи даже на шустрых SSD конечна. При росте нагрузки на базу рано или поздно она начинает тормозить.
Одно из ухищрений в данной ситуации - репликация. Самый простой вариант - одна база на запись (master) рассылает обновления по readonly slave-ам. В master - только пишут, со slave-ов - только читают.
Собственно настройку такого режима я и отработал при переезде, получилось неплохо. Нужды в этом пока нет: на SSD данные от 9 сборщиков проваливаются со свистом, зато теперь я умею и это.
#кодинг
#палантир
Скорость чтения и записи даже на шустрых SSD конечна. При росте нагрузки на базу рано или поздно она начинает тормозить.
Одно из ухищрений в данной ситуации - репликация. Самый простой вариант - одна база на запись (master) рассылает обновления по readonly slave-ам. В master - только пишут, со slave-ов - только читают.
Собственно настройку такого режима я и отработал при переезде, получилось неплохо. Нужды в этом пока нет: на SSD данные от 9 сборщиков проваливаются со свистом, зато теперь я умею и это.
#кодинг
#палантир
Палантир. Часть 9. Боль и страдания с организацией полнотекстового поиска.
#палантир@eshu_coding
Следующим этапом реализации сборщика я наметил запуск полнотекстового поиска, хочу сделать что-то типа яндекса по всей истории русскоязычной телеги.
Для него нужны словари русского языка, которые в стандартной версии так себе. В результате я пришел к необходимости ставить расширения для Постгреса.
Первое - оформленные в пакет словари от OpenOffice поставилось легко: просто ставим очередной лмнуксовый пакет.
Со вторым же словарем я познал, что такое боль олдскульного линуксоида. Пакета этого расширения в доступе нет, потому коммпилим и ставим из исходников: есть репозиторий.
Сначала мне не хватало репозитория со всем постгресом. Скачал.
Потом я долго не мог понять, как им воспользоваться. Запустил сборку, пропустив установку необязательных пакетов. Спустя несколько часов выяснилось, что они вроде как не нужны, но без них работать ничего не будет. Исправил, сам постгрес даже скомпилировался.
Перешел к запуску сборки самого расширения. Не работает. Не хватает компилятора для С++, поставил. Сборка началась!
Только не в ту папку, куда я хотел, потому расширение не устанавливается. Переместил всё куда надо... Извините, расширение сделано для 14 бета версии PostgreSQL, потому работать на 13, стоящей у меня не будет.
Так и не нашел, как скомпилиться под определенную версию, потому пошел на колхоз: перешел на коммит годичной давности и сборался под него... И не помогло.
Удалил всё к черту, заново склонировал конкретную ветку с нужным мне релизом постгреса (13.3), заново склонировал репозиторий с расширением, поправил перебил в нем инклюды, удостоверился, что от старых компиляций не осталось и следа и ... о чудо! Расширение подключилось к базе данных, теперь можно тестировать два словаря в сравнении.
Похоже где-то что-то кешировалось при компиляции...
#палантир@eshu_coding
Следующим этапом реализации сборщика я наметил запуск полнотекстового поиска, хочу сделать что-то типа яндекса по всей истории русскоязычной телеги.
Для него нужны словари русского языка, которые в стандартной версии так себе. В результате я пришел к необходимости ставить расширения для Постгреса.
Первое - оформленные в пакет словари от OpenOffice поставилось легко: просто ставим очередной лмнуксовый пакет.
Со вторым же словарем я познал, что такое боль олдскульного линуксоида. Пакета этого расширения в доступе нет, потому коммпилим и ставим из исходников: есть репозиторий.
Сначала мне не хватало репозитория со всем постгресом. Скачал.
Потом я долго не мог понять, как им воспользоваться. Запустил сборку, пропустив установку необязательных пакетов. Спустя несколько часов выяснилось, что они вроде как не нужны, но без них работать ничего не будет. Исправил, сам постгрес даже скомпилировался.
Перешел к запуску сборки самого расширения. Не работает. Не хватает компилятора для С++, поставил. Сборка началась!
fatal error: namespace.h: no such file...
Действительно, файла в папке нет, но в компилятор передан параметр "искать файлы в дополнительной папке, где он есть". Перебил все инклюды с #include <namespace.h> на #include "../libdict/namespace.h". Билд прошел! Только не в ту папку, куда я хотел, потому расширение не устанавливается. Переместил всё куда надо... Извините, расширение сделано для 14 бета версии PostgreSQL, потому работать на 13, стоящей у меня не будет.
Так и не нашел, как скомпилиться под определенную версию, потому пошел на колхоз: перешел на коммит годичной давности и сборался под него... И не помогло.
Удалил всё к черту, заново склонировал конкретную ветку с нужным мне релизом постгреса (13.3), заново склонировал репозиторий с расширением, поправил перебил в нем инклюды, удостоверился, что от старых компиляций не осталось и следа и ... о чудо! Расширение подключилось к базе данных, теперь можно тестировать два словаря в сравнении.
Похоже где-то что-то кешировалось при компиляции...
Wikipedia
Полнотекстовый поиск
Полнотекстовый поиск (англ. Full text searching, фр. Recherche en texte integral) — автоматизированный поиск документов, при котором поиск ведётся не по именам документов, а по их содержимому, всему или существенной части. Многие веб-сайты и прикладные программы…
Как разные словари для полнотекстового поиска в постгресе (для #палантир@eshu_coding) разбирают текст.
Структура таблицы:
1. Исходный текст
2. Текст, разобранный дефолтным парсером
3. Текст, разобранный парсером со словарем от OpenOffice
4. Текст, разобранный парсером со словарем, который я компилировал вчера.
#postgresql
Структура таблицы:
1. Исходный текст
2. Текст, разобранный дефолтным парсером
3. Текст, разобранный парсером со словарем от OpenOffice
4. Текст, разобранный парсером со словарем, который я компилировал вчера.
#postgresql