Всем привет!
В предыдущем посте я упомянул про защиту от DOS аттак в коде. Раскрою тему.
Для начала стоит различать DDOS и DOS - (Distribted) Denial of Service.
Первый - это когда злоумышленник долбит миллионами запросов в секунду. Такое не выдержит ни один сервис, не поможет даже k8s, т.к. ресурсы кластера не резиновые - https://kubernetes.io/docs/setup/best-practices/cluster-large/ да и подымаются новые ноды не мгновенно. Следовательно, от DDOS должна защищать сетевая инфраструктура, прикладной разработчик тут ничего сделать не может.
Другое дело DOS - RPS на порядки меньше, эксплуатируются уязвимости в коде. Вопрос - откуда злоумышленники про них узнают?
Во-первых они могут действовать наугад, во-вторых - всегда могут быть болтливые сотрудники, а главное - защита типа "об этом никто никогда не узнает" - плохая защиты.
Суть всех уязвимостией при DOS одна - поднять на сервере столько потоков одновременно, чтобы закончилась память или загрузка процессора ушла под 100%
Итак, как можно улучшить код для защиты от DOS.
1) проводить нагрузочное тестирование (НТ). НТ позволяет точно определеить сколько нужно серверов, чтобы держать расчетную и пиковую нагрузку. Пиковую нагрузку можно взять как расчетная умножить на два. Утечки памяти, неоптимальный код - все это с большой вероятностью можно увидеть на НТ
2) нет бесконечным и большим таймаутам. Если смежник упал, а у нас бесконечный таймаут - потоки и память кончатся быстро. Что касается больших таймаутов - это минуты, или таймауты необоснованные с точки зрения бизнес-задачи.
2) таймауты должны быть согласованы. Если мы обрабатываем запрос с таймутом 5 секунд, он синхронный, а вызываем смежника с таймутом 10 секунд - мы зря тратим его и свои ресурсы. Согласование может быть ручным, либо можно слать, например в заголовках, свой таймаут смежнику, чтобы он не ждал зря.
3) использовать circuit breaker, он же предохранитель, он же техперерыв. Если известно, что смежная система прилегла - не надо ее добивать и тратить на это свои ресурсы. Берем данные из кэша если это возможно или возвращаем клиенту ошибку. Принцип fail fast. Стоит отметить, что настройку таймаутов, предохранителя, и числа повторов можно делать либо в коде, либо отдать на откуп Istio или аналогичной системе если мы в облаке. Что лучше - это отдельная тема
4) защищаться от уязвимостей типа Injection. Суть их в том, что злоумышленник передает в параметрах входящего запроса что-то, что приводит к нелинейному потреблению ресуросов или тяжелым запросам в БД. Примеры первого вида DTD схемы https://habr.com/ru/post/170333/, регулярки - https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS, второго - SQL Injection со сложными JOIN. Решение: валидация параметров, регулярно сканировать библиотеки на наличие уязвимостей, регулярно обновляться в части хотфиксов
5) логика сервиса не должна линейно зависеть от числа входных параметров либо число параметров должно ограничено. Чем-то похоже на предыдущий пункт, но тут приложение спроектировано криво, поэтому никакие уязвимости не нужны)
6) использовать пулы потоков. Во многих случаях они уже используются - обработка входящих веб-запросов, JDBC запросы к БД. Но есть потоки, которые создаем мы сами. Если на каждый входной запрос мы будем создавать дополнительно хотя бы +1 поток, то это примерно удвоит потребление ресурсов. А если больше одного... Пул потоков защищает от такой ситуации
7) не забывать закрывать ресурсы - файлы, коннекты к БД. Все что java.io.Closeable. И делать это правильно - try with resources. В отличие от памяти в куче ресурсы никто за вас не закроет. А они жрут память и часто ограничены: максимальное число открытых файлов в Linux, максимальное число запросов, которое может обрабатывать СУБД
8) не использовать тяжелые JOIN и GROUP BY запросы к БД. Создавать индексы, смотреть план выполнения запроса. Об этом должен позаботиться ваш DBA, но, увы, не всегда он есть
9) не использовать излишне сильные уровни блокировки в БД, не использовать блокировки файлов без явной необходимости
#code_quality #security #patterns
В предыдущем посте я упомянул про защиту от DOS аттак в коде. Раскрою тему.
Для начала стоит различать DDOS и DOS - (Distribted) Denial of Service.
Первый - это когда злоумышленник долбит миллионами запросов в секунду. Такое не выдержит ни один сервис, не поможет даже k8s, т.к. ресурсы кластера не резиновые - https://kubernetes.io/docs/setup/best-practices/cluster-large/ да и подымаются новые ноды не мгновенно. Следовательно, от DDOS должна защищать сетевая инфраструктура, прикладной разработчик тут ничего сделать не может.
Другое дело DOS - RPS на порядки меньше, эксплуатируются уязвимости в коде. Вопрос - откуда злоумышленники про них узнают?
Во-первых они могут действовать наугад, во-вторых - всегда могут быть болтливые сотрудники, а главное - защита типа "об этом никто никогда не узнает" - плохая защиты.
Суть всех уязвимостией при DOS одна - поднять на сервере столько потоков одновременно, чтобы закончилась память или загрузка процессора ушла под 100%
Итак, как можно улучшить код для защиты от DOS.
1) проводить нагрузочное тестирование (НТ). НТ позволяет точно определеить сколько нужно серверов, чтобы держать расчетную и пиковую нагрузку. Пиковую нагрузку можно взять как расчетная умножить на два. Утечки памяти, неоптимальный код - все это с большой вероятностью можно увидеть на НТ
2) нет бесконечным и большим таймаутам. Если смежник упал, а у нас бесконечный таймаут - потоки и память кончатся быстро. Что касается больших таймаутов - это минуты, или таймауты необоснованные с точки зрения бизнес-задачи.
2) таймауты должны быть согласованы. Если мы обрабатываем запрос с таймутом 5 секунд, он синхронный, а вызываем смежника с таймутом 10 секунд - мы зря тратим его и свои ресурсы. Согласование может быть ручным, либо можно слать, например в заголовках, свой таймаут смежнику, чтобы он не ждал зря.
3) использовать circuit breaker, он же предохранитель, он же техперерыв. Если известно, что смежная система прилегла - не надо ее добивать и тратить на это свои ресурсы. Берем данные из кэша если это возможно или возвращаем клиенту ошибку. Принцип fail fast. Стоит отметить, что настройку таймаутов, предохранителя, и числа повторов можно делать либо в коде, либо отдать на откуп Istio или аналогичной системе если мы в облаке. Что лучше - это отдельная тема
4) защищаться от уязвимостей типа Injection. Суть их в том, что злоумышленник передает в параметрах входящего запроса что-то, что приводит к нелинейному потреблению ресуросов или тяжелым запросам в БД. Примеры первого вида DTD схемы https://habr.com/ru/post/170333/, регулярки - https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS, второго - SQL Injection со сложными JOIN. Решение: валидация параметров, регулярно сканировать библиотеки на наличие уязвимостей, регулярно обновляться в части хотфиксов
5) логика сервиса не должна линейно зависеть от числа входных параметров либо число параметров должно ограничено. Чем-то похоже на предыдущий пункт, но тут приложение спроектировано криво, поэтому никакие уязвимости не нужны)
6) использовать пулы потоков. Во многих случаях они уже используются - обработка входящих веб-запросов, JDBC запросы к БД. Но есть потоки, которые создаем мы сами. Если на каждый входной запрос мы будем создавать дополнительно хотя бы +1 поток, то это примерно удвоит потребление ресурсов. А если больше одного... Пул потоков защищает от такой ситуации
7) не забывать закрывать ресурсы - файлы, коннекты к БД. Все что java.io.Closeable. И делать это правильно - try with resources. В отличие от памяти в куче ресурсы никто за вас не закроет. А они жрут память и часто ограничены: максимальное число открытых файлов в Linux, максимальное число запросов, которое может обрабатывать СУБД
8) не использовать тяжелые JOIN и GROUP BY запросы к БД. Создавать индексы, смотреть план выполнения запроса. Об этом должен позаботиться ваш DBA, но, увы, не всегда он есть
9) не использовать излишне сильные уровни блокировки в БД, не использовать блокировки файлов без явной необходимости
#code_quality #security #patterns
Kubernetes
Considerations for large clusters
A cluster is a set of nodes (physical or virtual machines) running Kubernetes agents, managed by the control plane. Kubernetes v1.33 supports clusters with up to 5,000 nodes. More specifically, Kubernetes is designed to accommodate configurations that meet…
Всем привет!
Пару слов про на мой взгляд достаточно важную, но часто недооцененную штуку, как комментарии к commit-ам в git. На самом деле к любой Version Control System, но у нас же на 95+% git)))
Что должно быть:
1) комментарии обязательны
2) в теле комментария должен быть тикет, по которому ведутся работы. В начале текста комментария. В идеале - один тикет. Если правка одной строки исправляет несколько багов\закрывает несколько задач - то лучше закрыть лишние тикеты как дубликаты. Если не хочется заводить тикет на каждый чих - можно завести и использовать тикет типа "мелкие правки"
3) любой комментарий должен быть содержательным, т.е. описывать суть изменений. Лучше не привязваться к именам файлов\классов, т.к. они меняются при рефакторинге, а оперировать понятиями предметной области
4) по длине рекомендую сильно не увлекаться, ограничиваться одной или несколькими фразами. Заодно и сommit-ы будут более атомарными, проще будет revert-ть.
5) формат сommit должен быть единообразным, можно даже контролировать это на сервере. Т.к. по моему опыту без контроля сложно придерживаться единообразия, периодически проскакивают неформатные комментарии)
6) конечная цель комментариев - чтобы список commit-ов нес полезную информацию и его можно было использовать как changelist сервиса
7) следствие из предыдущего пункта - можно и нужно использовать amend для слияния нескольких commit-ов в один. Единственное исключение - если ваш git server синхронизируется, в другую подсеть например, и синхронизация ломается при amend. Опять же при односторонней синхронизации проблему решить можно.
8) следующий уровень - перед созданием Pull request\Merge request можно отрефакторить список commit-ов - переименовать, слить несколько из середины. IDEA позволяет все это сделать. Также можно хардкорно, через коммандную строку с помощью rebase - https://habr.com/ru/post/201922/ С одной стороны так мы становится на путь перфекционизма, но помнить о такой возможности надо)
9) Описание формата commit должно быть в readme.md проекта
Отдельно хочу сказать про язык комментариев. Есть мнение о необходимости английского - я с ним не согласен. По желанию команды. Все-таки не все в совершенстве владеют английским, как среди текущих разработчиков сервиса, так и среди будущих. А читаемость прежде всего!) Да, в английском нет родов у глаголов, поэтому с ним проще. В русском лучшим вариантом кажется использовать стадательный залог - "сделано то-то". Добавление рода или числа - сделал\сделали\сделала - кажется лишней информацией.
Также отдельная тема - нужны ли какие-то специальные обозначения в commit message. Например, алиас для тип изменений: фича, багфикс, рефакторинг, конфиги, тесты. Или указание модуля, где менялся код. Считаю, что не обязательно, но может быть полезно.
#git #code_review
Пару слов про на мой взгляд достаточно важную, но часто недооцененную штуку, как комментарии к commit-ам в git. На самом деле к любой Version Control System, но у нас же на 95+% git)))
Что должно быть:
1) комментарии обязательны
2) в теле комментария должен быть тикет, по которому ведутся работы. В начале текста комментария. В идеале - один тикет. Если правка одной строки исправляет несколько багов\закрывает несколько задач - то лучше закрыть лишние тикеты как дубликаты. Если не хочется заводить тикет на каждый чих - можно завести и использовать тикет типа "мелкие правки"
3) любой комментарий должен быть содержательным, т.е. описывать суть изменений. Лучше не привязваться к именам файлов\классов, т.к. они меняются при рефакторинге, а оперировать понятиями предметной области
4) по длине рекомендую сильно не увлекаться, ограничиваться одной или несколькими фразами. Заодно и сommit-ы будут более атомарными, проще будет revert-ть.
5) формат сommit должен быть единообразным, можно даже контролировать это на сервере. Т.к. по моему опыту без контроля сложно придерживаться единообразия, периодически проскакивают неформатные комментарии)
6) конечная цель комментариев - чтобы список commit-ов нес полезную информацию и его можно было использовать как changelist сервиса
7) следствие из предыдущего пункта - можно и нужно использовать amend для слияния нескольких commit-ов в один. Единственное исключение - если ваш git server синхронизируется, в другую подсеть например, и синхронизация ломается при amend. Опять же при односторонней синхронизации проблему решить можно.
8) следующий уровень - перед созданием Pull request\Merge request можно отрефакторить список commit-ов - переименовать, слить несколько из середины. IDEA позволяет все это сделать. Также можно хардкорно, через коммандную строку с помощью rebase - https://habr.com/ru/post/201922/ С одной стороны так мы становится на путь перфекционизма, но помнить о такой возможности надо)
9) Описание формата commit должно быть в readme.md проекта
Отдельно хочу сказать про язык комментариев. Есть мнение о необходимости английского - я с ним не согласен. По желанию команды. Все-таки не все в совершенстве владеют английским, как среди текущих разработчиков сервиса, так и среди будущих. А читаемость прежде всего!) Да, в английском нет родов у глаголов, поэтому с ним проще. В русском лучшим вариантом кажется использовать стадательный залог - "сделано то-то". Добавление рода или числа - сделал\сделали\сделала - кажется лишней информацией.
Также отдельная тема - нужны ли какие-то специальные обозначения в commit message. Например, алиас для тип изменений: фича, багфикс, рефакторинг, конфиги, тесты. Или указание модуля, где менялся код. Считаю, что не обязательно, но может быть полезно.
#git #code_review
Хабр
Изменение коммитов в Git
Это пост для тех, кто начинает работу с Git. Все, что здесь написано по частям можно найти в многочисленных простынях о Git на Хабре. Но я подумал, что неплохо было бы иметь отдельный предельно...
Всем привет!
Сегодня хотел бы поговорить про код-ревью.
Для начала - что оно нам дает?
1) единообразие кодовой базы. Люди приходят и уходят, а код остается) Новичок в команде должен во-первых быстро разобраться в проекте, а во-вторых - писать код в едином стиле. Я говорю не только про код-стайл, но и про наименования, разделение по модулям и слоям, переиспользование кода и многое другое
2) понятный, "чистый" код в проекте. Тут можно снова сказать про важность быстрого вхождения в проект новых людей. Важная ремарка - чтобы код был простым и понятным ревьювер должен сознательно ставить себе такую цель.
3) общее владение кодом в команде. Если код посмотрел ревьювер и сделал это качественно, а не формально - этот код теперь знают два человека. Легче вносить какие-то правки, проводить рефакторинг.
4) альтернативный взгляд на решение задачи. Не всегда предложенное решение будет правильным, и нужно все переделывать. Но узнать о других вариантах и обсудить к примеру будущий рефакторинг точно будет полезно. Отдельно хочется отменить, что иногда лучше прорабатывать решение до написания кода, чтобы избежать потерь времени на код-ревью и переделывание. Примеры: новичок в коданде или просто сложная задача.
5) обмен знаниями о проекте, библиотеках, утилитах и даже языке программирования. Причем узнать что-то новое может и автор кода, и ревьювер.
6) повторяющиеся ошибки\"холиварные" вопросы на код-ревью должны обсуждаться и фиксироваться. И т.об. они являются источником для новых правил в статическом анализаторе кода и в правилах работы над проектом
И как следствие вышесказанного получаем повышение качества кода.
P.S. Далее расскажу про рекомендации для автора и ревьювера, а также про кросс-командное ревью.
#code_review
Сегодня хотел бы поговорить про код-ревью.
Для начала - что оно нам дает?
1) единообразие кодовой базы. Люди приходят и уходят, а код остается) Новичок в команде должен во-первых быстро разобраться в проекте, а во-вторых - писать код в едином стиле. Я говорю не только про код-стайл, но и про наименования, разделение по модулям и слоям, переиспользование кода и многое другое
2) понятный, "чистый" код в проекте. Тут можно снова сказать про важность быстрого вхождения в проект новых людей. Важная ремарка - чтобы код был простым и понятным ревьювер должен сознательно ставить себе такую цель.
3) общее владение кодом в команде. Если код посмотрел ревьювер и сделал это качественно, а не формально - этот код теперь знают два человека. Легче вносить какие-то правки, проводить рефакторинг.
4) альтернативный взгляд на решение задачи. Не всегда предложенное решение будет правильным, и нужно все переделывать. Но узнать о других вариантах и обсудить к примеру будущий рефакторинг точно будет полезно. Отдельно хочется отменить, что иногда лучше прорабатывать решение до написания кода, чтобы избежать потерь времени на код-ревью и переделывание. Примеры: новичок в коданде или просто сложная задача.
5) обмен знаниями о проекте, библиотеках, утилитах и даже языке программирования. Причем узнать что-то новое может и автор кода, и ревьювер.
6) повторяющиеся ошибки\"холиварные" вопросы на код-ревью должны обсуждаться и фиксироваться. И т.об. они являются источником для новых правил в статическом анализаторе кода и в правилах работы над проектом
И как следствие вышесказанного получаем повышение качества кода.
P.S. Далее расскажу про рекомендации для автора и ревьювера, а также про кросс-командное ревью.
#code_review