Минутка просвещения

Читать в телеге. Когда-то там были посты не только от меня.

Модель акторов для построения бигдаты

А вот и доклад посвежее про Erlang, полуторагодичной давности. В нем кратко объясняется идея акторов и рассказывается о системе учета пациентов, построенной на этой модели. В какой-то момент там внезапно появляются фильтр Блума, рандеву-хеширование, алгоритмы консенсуса и выбора лидера.

Стоит отметить, что система не является основным источником информации (а только для всякой бигдаты), поэтому вопросы того, как делать все транзакционно, тут не поднимаются (впрочем, пациенты довольно изолированы друг от друга, так что это ок, наверно). А так получается практически event sourcing.

СсылкаКомментировать

Модель акторов для построения отказоустойчивой системы

Занятный, хоть и немного старый доклад про проблемы построения отказоустойчивых распределенных систем от автора языка Erlang. Сначала небольшое вступление и полунаглядные примеры, потом на 30 минуте начинается мякоть. Сформулированы 6 правил для потенциального решения проблем:

  1. Изоляция
  2. Конкурентность
  3. Обнаружение ошибок
  4. Понимание, почему они возникли
  5. Обновление кода
  6. Стабильное хранилище

Один из ключевых подходов — “let it crash”. Убийца — дворецкий, Erlang и модель акторов решают все проблемы:)

Я бы посмотрел на этот доклад с двух сторон. Во-первых, со стороны текущих проектов: а как это решается не Erlang’ом? Кубер, телеметрия, helm, postgres, какая-нибудь очередь для доменных событий — вроде уже типовой стек и он почти работает, да? А во-вторых, докладу скоро 10 лет — хорошо ли он состарился?

СсылкаКомментировать

Контракты в Kotlin

Недавно наткнулся на случай, когда они пригодились. Рассмотрим пример:

data class OptionalResult(val data: Payload?, val someFlag: Boolean)

fun OptionalResult?.getData(): Payload {
	this ?: throw NoResultException()
	return this.data ?: throw NoPayloadException()
}

fun someFun(){
	val payload: Payload = getResult().getData()
	doStuffWithPayload(payload)
	if (payload.someFlag){ //oopsie
		// do more stuff 
	}
	...
}

По сути имеем дважды опциональный результат, и в ФП-парадигме это красиво легло бы в мона.. Option, но у нас Kotlin с исключениями. Однако строка с oopsie вызовет ошибку компиляции, т.к. компилятор не понимает, что payload уже был проверен на null. Причем если тело функции подставить вместо вызова, то все будет ок (ссылочная прозрачность плачет в уголочке). Чтобы решить проблему, можно использовать контракты и явно сказать компилятору, что если функция что-то вернула, то ее аргумент — не null:

fun OptionalResult?.getData(): Payload {
	contract {
		returns() implies (this@getData != null)
	}
	this ?: throw NoResultException()
	return this.data ?: throw NoPayloadException()
}

В общем, фича интересная, но, кажется, компилятору стоит быть поумнее.

СсылкаКомментировать

Запуск команды без пароля sudo

Лучше такой пост, чем никакой, наверно :/

  1. Создаем исполняемый скрипт. Его нужно создать через sudo, чтобы нельзя было редактировать. Иначе это будет дырищей, через которую можно будет запускать что угодно.
sudo nano /usr/sbin/some_command
# добавляем shebang и саму команду
# ...
sudo chmod +x /usr/sbin/some_command
  1. Добавляем настройку через sudo visudo, обязательно в конец файла.
some_user ALL=(ALL) NOPASSWD: /usr/sbin/some_command

some_user — имя пользователя.

  1. Теперь можно запускать команду через sudo some_command, и пароль не будет запрашиваться. Можно повесить на хоткей какой-нибудь.

Мне пригодилось для того, чтобы рестартовать демон частоты процессора. Ноут почему-то периодически решает, что 400 MHz хватит всем, почему — быстро не докопался, поэтому решил костылем.

СсылкаКомментировать

Составные шаблоны индексов в Elasticsearch

Оказывается, уже давненько в Elasticsearch можно собрать шаблон индекса по кусочкам, причем их можно переиспользовать — например, какие-нибудь преобразования текста типа стемминга вынести в общий кусочек. Долой копипасту!

СсылкаКомментировать

Исключение файлов без расширения в .gitignore

В дополнение к предыдущему посту — занятная проблемка. По умолчанию go build генерирует исполняемый файл прямо в корень проекта (sic!). Исполняемый файл в репозитории мы не хотим хранить, и чтобы его исключить, обычно делают Makefile (еще один прекрасный язык, кстати) или добавляют в .gitignore название проекта. Но есть способ поинтереснее:

*
!/**/
!*.*

Тут сначала игнорируются все файлы, потом с помощью отрицания (!) разрешаются все файлы внутри папок и все файлы, имеющие расширение. Правда, отвалится Dockerfile, но у него хотя бы имя фиксированное.

СсылкаКомментировать

Еще один шанс для Go

По работе надо было написать микросервис для перекладывания JSON’ов, решил дать еще один шанс языку Go и написать на нем, с разбором впечатлений, как для Elm или Rust. Микросервис-то я написал, а вот пост писать раздумал, решил ограничиться примером, который, как мне кажется, довольно показательный.

Вот у нас есть метод из стандартной библиотеки, log.Fatal. Что он делает?

Ответ

Ожидаемый ответ — выводит сообщение в лог с уровнем FATAL. Сообщение он действительно выведет. Но еще он и завершит программу с кодом возврата 1. А я еще студентам пытаюсь что-то про SRP и хорошие имена говорить…

Ок, а что делают log.Info и log.Error?

Ответ

Ошибку компиляции делают, потому что нет таких методов.

СсылкаКомментировать

Тренажер сисадмина

Приезжает дальнобойщик домой, думает, в какую бы игру залипнуть для расслабона — Euro Truck Simulator, каеф!

Если не хватает подобного для решения проблем в Linux — есть игруля. Задания не очень сложные, местами жизненные. Если непонятно, что делать, то есть подсказки и можно даже какие-то команды новые узнать.

Бонус для ИБшников и прочих хакеров — вам дают рутовый доступ к временному контейнеру в AWS, RCE as a Service, налетай!

СсылкаКомментировать

Текущие проблемы с потоками и асинхронщиной

Неплохой доклад про текущее состояние асинхронного выполнения задач в JVM, хоть и очень тезисный.

Вначале немного повторения кэши L1-L3 и устройство процессора в целом, про потоки, очередь задач и их конкурентное выполнение, переключение контекста. Потом внезапно переключается на JVM — каждый поток это корень для сборщика мусора. Чем больше потоков, тем медленнее он работает. Какой-нибудь FixedThreadPool не решает проблемы, т.к. у него случайный порядок выполнения.

Далее — основы асинхронного выполнения и epoll. “Многие из вас плохо читают на C, поэтому я перевел этот кусок кода на Scala”:) Как решить проблему, что потоки ничего не делают, пока ждут? Перекинуть все ожидание на 1 поток. Но даже это дороговато. Эту проблему решили в nodejs-ной библиотеке libuv, которая в одном потоке и полезную работу делает, и ждет IO.

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

СсылкаКомментировать