Проектирование высокопроизводительных систем: о чем не расскажут в книгах

в 15:41, , рубрики: вредные советы, высокая производительность, надежность, производительность, разработка, метки: , ,

Проектирование высокопроизводительных систем: о чем не расскажут в книгах

Не секрет, что разработчикам программных систем часто приходится решать проблемы производительности, высокой нагрузки, обработки больших объемов данных и отказоустойчивости. В идеале, все эти вопросы учитываются при проектировании системы. Но на практике их часто пытаются решить запоздалыми «оптимизациями» после запуска.

Почему так происходит? Обеспечение высокой производительности и надежности ошибочно почитается многими за «черную магию». И неспроста — чуть ли не в каждой книге или статье на эту тему вы первым делом наткнетесь на утверждение типа «нельзя просто так взять и повысить производительность».


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

Рискуя навлечь на себя гнев высоколобых теоретиков софтостроения, скажу: есть конкретные, понятные практики, следуя которым, вы на 99% решите все проблемы быстродействия, надежности и доступности вашего ПО. И я готов с вами этими практиками поделиться. Сразу отмечу, что речь идет прежде всего о серверных приложениях с бизнес-логикой более сложной, чем обычный CRUD.

Итак, поехали — 7 практических советов повышения производительности, которые реально работают.

Не вникайте в базу данных

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

Используете классическую реляционную базу типа Oracle? Если возникнут проблемы, то есть специально обученные специалисты СУБД, они подкрутят настройки где надо, и все будет хорошо. Используете NoSQL-хранилище вроде MongoDB? Так там и вовсе ничего знать не надо, разработчики 10gen уже обо всем позаботились за вас.

Не надо думать за разработчиков СУБД. У вас есть ORM или клиентская библиотека — вот ее и используйте. Как оно там работает на стороне хранилища, никого не волнует. К тому же, вдруг вы захотите сменить движок БД? Нельзя «затачиваться» на специфику конкретной базы.

Одиночные операции вместо пакетных

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

Вместо всего этого просто используйте одиночные операции — обрабатывайте один объект за другим. Так база данных будет нагружена равномернее, логика приложения останется простой, а время обработки нисколько не пострадает.

Никаких кэшей

Доморощенные оптимизаторы будут советовать вам использовать кэши (для контента страниц, бизнес-объектов, сложных результатов вычислений и тому подобного). Якобы эти кэши позволяют снизить время отклика и уменьшить нагрузку на систему. Ну да, конечно! А как вы будете решать вопрос с устареванием данных в кэшах? Их непротиворечивостью? Эластичностью? Лишними ресурсами, которые они потребляют?

Мой вам совет — просто не используйте кэши. Дисковые подсистемы в современных ОС сами знают, что и когда кэшировать. Добавьте к этому быстрые SSD-диски, и вы поймете, что время кэшей безвозвратно прошло.

Используйте единственный примитив синхронизации

Проектирование высокопроизводительных систем: о чем не расскажут в книгах
Ваша система, конечно же, активно использует мультипоточное программирование для эффективной обработки конкурентных запросов. А многопоточность, как вы знаете, влечет за собой проблемы при доступе к разделяемым ресурсам. Как здесь быть? Очень просто: широко применяйте простой и проверенный временем примитив — блок синхронизации, в котором допускается выполнение только одного потока в каждый момент времени.

Не надо использовать высокоуровневые паттерны многопоточности — все эти неблокирующие коллекции, атомарные типы, агенты и тому подобное. Все они переусложнены и навязывают вам совершенно неудобную модель использования (чего стоит один метод compare_and_set, грубо нарушающий принцип single responsibility).

Если потребуется дальнейшая оптимизация, то от блоков синхронизации можно просто избавиться, и система заработает еще быстрее! Конечно, могут возникнуть небольшие проблемы с конкурирующими потоками, но в итоге все будет в порядке (вы наверно слышали, это называется eventual consistency — достаточно актуальная сейчас тема).

Применяйте как можно более простые алгоритмы

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

Вместо того, чтобы рассуждать об асимптотической сложности и пытаться оценить O-большое для занимаемой памяти, просто возьмите и решите задачу перебором на вложенных циклах. Нет сомнений, что в 95% случаев решение окажется достаточно хорошим. К тому же современные компиляторы прекрасно умеют отлавливать паттерны неэффективных операций в коде и исправлять их прозрачно для программиста.

Используйте умолчательные настройки

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

Локальное взаимодействие ничем не отличается от удаленного

Проектирование высокопроизводительных систем: о чем не расскажут в книгах
Допустим, у вас в системе есть API, который используется локально. Подойдет ли он для взаимодействия по сети, когда клиент может находиться в любой точке земного шара? Конечно, да! Нужно ли как-то его модифицировать, уменьшать гранулярность, особым образом обрабатывать прерывание соединения, вводить дополнительную типизацию ошибок, поддерживать несколько версий интерфейса? Конечно, нет! Библиотеки и фреймворки делают удаленное взаимодействие совершенно прозрачным для клиента и сервера, а стремительный рост пропускной способности и стабильности глобальных сетей нивелирует их отличие от сетей локальных.

Я неоднократно видел, как описанные выше принципы успешно применяются разработчиками в самых разных организациях и проектах. И они неизменно срабатывали! По оценке самих разработчиков, системы получались исключительно быстрые и надежные. Возникали, конечно, иногда некоторые проблемы с их использованием. Но это частности, вызванные несовершенством окружения в котором вынуждена работать система, и они не заслуживают серьезного рассмотрения.

Смело берите 7 советов на вооружение, и вы очень скоро увидите результат в своей системе!


P.S. Иллюстрации любезно предоставлены пользователями Flickr:

Автор: algenon

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js