Dropbox - это самый простой способ... Dropbox

  • Хранить файлы в безопасном месте
  • Делиться файлами с другими людьми
  • Постоянно иметь к ним доступ вне зависимости от своего месторасположения

Взрывной рост

  • 1 миллион файлов сохраняются в Dropbox каждые 15 минут (по презентации это больше, чем твитов в Twitter за тот же период времени, но это несколько преувеличено)
  • Одно из самых скачиваемых приложений, уступает лишь Skype
  • Важная часть жизни многих пользователей: "не могу жить без этого"
  • Рост обеспечен "сарафанным радио", практически без рекламы

Dropbox

Команда в начале проекта

  • Все хорошие друзья
  • Самые умные, голодные и страстные, которых они знали :)
  • Для каждого это была первая реальная работа, очень ограниченный опыт в данной индустрии
  • Эти качества хорошо сочетаются с итеративной методологией разработки на Python

Ранние достижения

  • Reverse engineering приложения Finder для Mac OSX 10.4/5 для отображения иконок статуса синхронизации ("в процессе", "все готово")
  • Сложная инфраструктура HTTP нотификаций для избежания регулярного опроса серверов на каждом клиенте, основанная на Twisted
  • Общая кодовая база, работающая на всех основных операционных системах: Windows, Mac OS, Linux (на основе PyObjC, wxPython, ctypes, py2exe, py2app, PyWin32)
  • Горизонтально масштабируемое хранилище для информации о файлах на основе MySQL
  • Собственная инфраструктура для аналитики в реальном времени
  • Собственный механизм выделения памяти для Python, позволивший сократить её потребление на 90%

Сферы применения Python

По сути он используется во всех частях проекта:

  • логика backend синхронизации;
  • клиенты для основных ОС (Windows, Mac, Linux);
  • контроллер основного сайта;
  • обработка API запросов;
  • аналитика.

Исключения из-за ограничений по доступной оперативной памяти:

  • Android (мог бы быть Jython)
  • iPhone (мог бы быть Cpython)

Почему именно Python?

  • Легок в изучении и понимании:
    • новые люди легко втягиваются в процесс;
    • позволяет людям переключаться с проекта на проект.
  • Легок в написании: важно для быстрой реализации функционала и выпуска новых версий.
  • Легок в изменении:
    • нет необходимости в перекомпиляции;
    • высокая скорость итерации;
    • динамическая типизация:
      • рефакторинг очень прост;
      • уменьшение прямых зависимостей модулей;
      • динамические инструменты.
  • Позволяет обеспечивать качество путем создания более-менее работающей версии продукта и доведения её до качественного уровня путем быстрых итераций.

Не без трудностей

Аргх!!! Python потребляет слишком много оперативной памяти и о-о-очень медленный!

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

Как с этим бороться?

  • Убедитесь, что все длинные внутренние циклы выполняются в C (может сэкономить до 44% процессорного времени)
  • С оптимизацией потребления вычислительных ресурсов все просто:
    • есть много готовых решений для профайлинга;
    • проблемный код чаще всего не раскидан по всей кодовой базе.
  • С оптимизацией потребляемой памяти все сложнее:
    • нет готовых решений для профайлинга память (одновременно в Python и C);
    • много потенциальных причин для повышенного потребления памяти:
      • утечки в Python и C;
      • фрагментация памяти;
      • неэффективное её использование.
    • Как исправить? Однозначного решения нет - чаще всего приходится перерывать всю кодовую базу в поисках неоптимальных мест и источников утечек.
    • Почему память фрагментируется?
      • Большинство объектов расположены в heap памяти (большой последовательный кусок, выделенный приложению);
      • Много маленьких объектов вперемешку с большими;
      • Много временных объектов вперемешку с постоянными;
      • В CPython нет сборщика мусора, позволяющего собрать объекты компактно в одной части heap'а.
    • Решением проблемы с фрагментацией стал собственный аллокатор памяти (механизм её выделения под определенные типы объектов):
      • В Dropbox обнаружили, что большая часть heap-памяти захламляется контейнерами с метаданными файлов, которые синхронизируется;
      • Было решено вынести их куда-нибудь еще;
      • CPython позволяет управлять процессом выделения памяти для типов данных расширений;
      • Делается это с помощью простых структур на C;
      • "Not Rocket Science, just C code";
      • Выделяются области памяти по 4Мб, состоящие из заголовка и буферов фиксированной длины.
      • Что насчет внутренней фрагментации?
        • по идее же даже в одном буфере останутся данные, весь блок нельзя будет освободить...
        • потенциально этот факт может привести к еще большему расходу оперативной памяти;
        • но это оказывается не так, если учесть, что все объекты являются временными, то есть живут не долго!
        • в результате Dropbox редко использует более 100Мб памяти для больших синхронизаций (раньше эта цифра могла достигать 1.5Гб)
      • Но писать C расширение для каждой структуры данных, которую может понадобиться вынести в отдельный аллокатор - дело неблагодарное: в результате эта история закончилась изменением type_new() в Objects/typeobject.c для того, чтобы можно было указывать __use_region_allocator__ = True** для тех классов, которым требуется такой механизм выделения памяти.

Подводим итоги

  • Python стал ключом к технической реализации обоих сторон Dropbox: серверной и клиентской.
  • Залогом успеха является максимальная простота с пользовательской точки зрения: "положил файл в папку и он становится доступен отовсюду"
  • Dropbox не брали на себя реализацию стороннего функционала, вроде собственно создания хранилища файлов - используется Amazon S3, что позволило им запуститься очень быстро и стремительно.
  • Лучше решать одну задачу, но качественно, чем много, но так себе!

Источники информации