- PVSM.RU - https://www.pvsm.ru -
Одна из отличительных особенностей языка Python — это посвящённые этому языку конференции, так называемые PyConы. Не так давно мне удалось побывать на одном таком PyCon-е — EuroPython 2014. EuroPython — это одна из наиболее крупных европейских ежегодных конференций по языку Python, которая три последних года проводилась во Флоренции, а в 2014м — первый раз в Берлине. Пока свежи воспоминания решил написать небольшой отчётик — что и как было.
Сразу оговорюсь, тут будут исключительно впечатления и короткие тезисы, и не будет подробного пересказа содержания докладов, так как при большом желании все их можно посмотреть на YouTube [1] — организаторы данной конференции мало того, что не стали делать из видео выступлений какую-то коммерческую тайну, так ещё и организовали прямую трансляцию всех этих видео (кстати, видео с прошлогодних конференций тоже можно отыскать в открытом доступе на том же самом YouTube).
И ещё. Далеко не все доклады затрагивали Python напрямую. То есть зачастую в докладах шел обзор каких-либо полезных технологий, и немного сбоку рассказывалось, как эти технологии можно использовать в мире Python. Поэтому если в процессе прочтения некоторого абзаца данного опуса у вас возникнет мысль «так а где же тут питон? o_O» — советую сразу посмотреть видео — там все будет.
Начну с того, что практический каждый день конференции строился по расписанию: сутра — Keynotes, потом доклады — по 20-45 минут каждый (с перерывом на обед и кофебрейки), под вечер — Lightning Talks. Думаю, тут стоит поподробнее сказать что же такое Keynotes и Lightning Talks.
Keynotes — это такие доклады, не сильно технические, с большим обилием философии. На мой взгляд, практического применения в них мало, поэтому в своем повествовании я их упущу.
По поводу Lightning Talks — это такие продолжительные сессии часа так на 1.5, в течении которых любой желающий мог выйти и высказаться. На каждое выступление давалось порядка 10ти минут. Среди этих вот мини-докладиков было достаточно много флейма (реклама своих продуктов, реклама всяких event-ов, типо PyCon-а в Бразилии, какие-то общие философские мысли и т.п.). Поэтому в своем рассказе я постараюсь отразить только те выступления, которые мне показались наиболее полезными и интересными.
Поскольку в первый день было открытие конференции, то докладов и чего-то более-менее полезного было мало. Собственно, самый главный доклад дня: чему Python может поучиться у Haskell-а [2]. На самом деле, в докладе речь шла не только про один Haskell, но и немного про Erlang, но это не суть важно. Основная мысль доклада сводилась к тому, что статические анализаторы кода ни разу не отлавливают ошибки вида 1 + "1", и что всему виной динамическая строгая неявная типизация в Python, что влечет за собой проблемы рефакторинга и т.п. Варианты решения — использовать аннотации [3] (привет, Python 3), использовать экспериментальный вариант интерпретатора Python: mypy [4], который на уровне синтаксиса языка позволяет задавать типы у аргументов функций. То есть можно писать вот так:
def fib(n: int) -> None:
a, b = 0, 1
while a < n:
print(a)
a, b = b, a+b
и это будет корректно восприниматься интерпретатором. Конечно, штука довольно интересная, вот только опять-таки это работает только для кода Python 3. Я попробовал поискать mypy [4] в стандартных репах Debian и не нашел, а компилять вручную как-то лениво. Возможно от него был бы толк, будь он чуть более распространен, была бы поддержка на уровне IDE и т.п. (кстати докладчик активно призывал контрибьютить в этот проект). Так же прозвучали утверждения, что mutability есть зло, а так же про слабую поддержку Python-ом алгебраических типов данных. Все это на мой взгляд очень и очень спорно. Тем не менее я рекомендую посмотреть видео доклада хотя бы, чтобы иметь представление о том, что творится в других языках (ну и конечно же чтобы быть готовым к аргументированному спору в холиварах аля “какой язык лучше”).
Так же мне запомнился один доклад из Lightning Talks, парень (кстати из России), пиарил свою библиотечку под названием Architect [5], главное преимущество которой — добавление возможности автоматического партицирования таблиц в БД посредством ORM (поддерживаются модели Django, SQLAlchemy, Pony). Из баз данных — MySQL и postgreSQL. Людям, кто работает с этими базами, возможно данная либа иногда может быть полезной.
Прозвучал довольно интересный доклад про пакетный менеджер nix [6]. На сам деле есть целый дистрибутив, построенный на этом пакетном менеджере. И называется он NixOS [7]. Его полезность, если честно, мне кажется несколько сомнительной, а вот сам пакетный менеджер nix в некоторых кейсах может быть весьма полезен (особенно учитывая тот факт, что он не запрещает использование основного пакетного менеджера, т.е. yum или apt). Основная фишка данного пакетного менеджера заключается в том, что все операции, производимые им, не являются деструктивными. То есть грубо говоря при установке каждого нового пакета, предыдущая версия пакета не затирается, а создается новое пользовательское окружение, с новым набором симлинок. Это позволяет:
Из минусов — если хранить все версии пакетов со всеми зависимостями, то естественно места на HDD потребуется больше и в довесок мы получаем некоторую избыточность пакетов. На мой взгляд, это недостатки с которыми можно мириться. Так же в докладе кратко рассказывалось, как можно собирать свои пакеты для nix, и в частности, python-ячьи пакеты. В общем, если есть проблема Dependency hell [8], то nix позволяет решить эту проблему довольно элегантно.
В этот же день был доклад про потоковую обработку больших объемов данных с использованием Kafka и Storm [9]. Единственное полезное, что я вынес из этого доклада, это то, что Storm [10] отлично подходит для обработки непрерывных потоковых данных (а не статических, в отличии от Hadoop), а Kafka [11] даст гигантскую фору rabbitMQ в плане дичайшей пропускной способности сообщений (100k+/sec сообщений на ноду против 20k/sec у rabbitMQ), но при этом проигрывает в плане топологии распределения сообщений между consumer-ами. В контексте доклада две данные технологи рассматривались вместе, и Kafka [11] выступала в качестве транспорта для доставки сообщений в Storm [10].
Был неплохой вводный доклад про Marconi [12] — это система messaging-а в рамках OpenStack (кто не в курсе, OpenStack полностью написан на python). Marconi используется в качестве связующего звена между компонентами облака OpenStack, а так же к качестве обособленного сервиса уведомлений. Собственно является прямым аналогом SNS и SQS от Amazon-а. Предоставляет RESTfull API, может использовать MongoDB, Redis а так же SQLAlchemy в качестве хранилища сообщений (правда SQLAlchemy не рекомендовали в production из соображений производительности), поддержки AMPQ протокола нет, но планируют добавить в будущем.
Ещё был доклад про Logstash / Elasticsearch / Kibana [13] — набор мегаполезных утилит для сбора, фильтрации, хранения, агрегации и отображения логов. Кстати говоря, полезность logstash несколько раз упоминалась в различных докладах от разных людей. Лично я ничего особенно нового именно из этого доклада не услышал. Одна из идей, которая рассказывалась на данном докладе — как при помощи logstash отслеживать все логи из одного request-а, а так же собирать воедино все связные по единому признаку логи от всех компонент распределённой системы. Кстати, в ходе доклада была упомянута интересная библиотечка для логирования под названием Logbook [14]. Судя по описанию, достойная альтернатива стандартной библиотеке логирования в Python.
Третий день начался с написания мультиязыковой Sphinx-документации [15]. Данный доклад был весьма полезен для меня лично, потому что в рамках проекта, которым я сейчас занимаюсь, возникала задача поддержки двух языковых версий API документации — английской и русской, при этом хотелось бы сделать этот процесс как можно более простым и прозрачным. На самом деле все довольно просто. Есть такая замечательная GNU утилита gettext [16], которая активно используется для интернационализации различных OpenSource проектов (думаю, что про gettext все и так знают без пояснений), и есть замечательный пакет sphinx-intl [17]. Из sphinx-овой rst-овой документации при помощи нехитрых команд готовятся *.po файлы, которые потом переводятся в специальном gettext-редакторе, и на основе которых делается документация sphinx под какой-то конкретный выбранный язык. Так же в докладе был упомянут SAAS сервис Transifex [18], который облегчает труд переводчиков. Насколько я понял, общий принцип работы сервиса такой — при помощи нехитрых консольных утилиток, можно загружать и скачивать файлы переводов на этот сервис, который предоставляет для переводчиков удобный Web-интерфейс для перевода текстов. Консольные утилитки для этого сервиса, насколько я понял, работают по принципу git push/pull. Сервис не бесплатный. Думаю всем заинтересовавшимся (кто сталкивался с проблемой интернационализации) смотреть видео доклада [15] необязательно, достаточно полистать слайды [19], чтобы все понять.
Из интересных докладов, которые были в этот день: доклад про gevent [20] (я посчитал важным сходить на этот доклад, потому что на gevent-е чуть более чем полностью построен WebDAV-сервис проекта, которым я занимаюсь). На самом деле ничего принципиально нового не рассказали, начали с вводной по реализации асинхронности на Python и закончили собственно gevent [21]-ом. Если кто не знает, что такое gevent [21] — тому данный доклад возможно покажется интересным, ну а тем, кто уже знаком с данной технологией — врят ли. Из услышанных интересностей: 1. web-микрофреймворк [22], целиком сделанный на gevent-е, с поддержкой PostgreSQL, 2. AMQP-библиотечка [23], также целиком сделанная на gevent-е.
Ещё был весьма занятный доклад «DevOps Risk Mitigation: Test Driven Infrastructure» [24], про тестировании инфраструктуры в рамках процесса deploy-я. На самом деле никакой магии нет — собирается RPM-ка, раскатывается куда-то на тестовые машины, и далее автоматизированно через rsh заходим на эти машины и тестируем все что только можно, начиная от HTTP proxy и заканчивая системой сбора логов. Докладчик, весьма колоритный old school-ный админ, как я понял, не признает всяких этих puppet-ов / chef-ов / salt-ов, но зато осознает идею того, что для поддержания качества продукта, тестами должен покрываться не только лишь один код. На мой взгляд, идея верная, и это и правда то, к чему надо стремиться. Возможно не такими способами, как говорится в докладе, но тем не менее. Всем DevOps-ам — must see.
День начался с замечательнейшего по полезности доклада «Multiplatform binary packaging and distribution of your client apps» [25]. Думаю многие программисты, кто пишет коммерческие приложения, хотя бы раз в жизни задумывались над проблемой: «они могут скопировать и прочитать наш код!». То есть иными словами возникает задача — поставлять продукт в зашифрованном виде, ну или же в виде бинарников, из которых выцепить и модифицировать исходный код достаточно проблематично. К слову, Dropbox, у которого PC клиент написан на Python, решает данную проблему довольно геморройно — они кладут в инсталлятор свою собственную патченную версию интерпретатора Python, которая умеет читать зашифрованные *.pyc файлы. Решение, предлагаемое в докладе:
Для больших деталей рекомендую посмотреть видео [25] доклада и слайды [27]. Естественно каждый из 4х описанных мною этапов в докладе разобран более подробно — приводятся образцы кода, как и что делать. Ну и конечно же стоит оговориться, что данного рода обфускация не спасает о реверсинженеринга, когда человек может заимпортить обфусцированный пакет и просто банально пробежаться по именам методов/переменных. Кстати, ещё по данной к теме рекомендую к прочтению вот эту статью [28] (она упоминается в докладе).
Следующим был весьма неплохой доклад от одного из разработчиков Disqus [29]. В докладе говорилось про преимущества SOA [30]-архитектуры на примере сервиса Disqus. Cервис Disqus чуть более чем полностью построен на Django, точнее он разделен на кучу-кучу мелких микросервисов (REST API, worker-ы, cron-ы и т.п.), каждый из которых построен на Django. К слову, докладчик доступно объяснил почему именно Django, а не что-то другое — большое комьюнити, куча готовых решений + намного проще найти специалистов. Если смотреть на технологический стек, то у Disqus из основных компонент используется uwsgi, django, celery, postgreSQL в качестве базы и redis для кэша. Чтобы шарить общий код между своими микросервисами, я так понял, они собирают отдельные python-овские пакетики. Из плюсов SOA подхода:
из минусов:
Python Debugger Uncovered [31] — вот это очень классный доклад от разработчика PyCharm. Советую всем backend-разработчикам посмотреть для общей эрудиции, как устроен некий абстрактный дебаггер в вакууме. Никакой высокой магии нет, все дебаггеры сделаны по одному принципу и подобию при помощи нативных средств самого языка Python. Кстати, для справки, дебаггеры PyCharm и PyDev объединяются.
Ещё в этот день был очень стоящий доклад про tool-у dh-virtualenv [32] от Spotify. Spotify в качестве основой production ОС используют Debian, и цель создания данной утилиты заключалась в том, чтобы объединить deploy проекта в виде deb-ок с инкапсулированным virtualenv-ом. Общий смысла какой — с одной стороны Debian адски стабилен, а Debian-пакеты удобны тем, что позволяют прописать все не-python-ячи зависимости (типо libxml), с другой стороны virtualenv удобен тем, что позволяет изолировать внутри себя python-ньи зависимости, и все эти зависимости будут самыми свежими пакетами, т.к. взяты с PyPI. Тулза dh-virtualenv [33] позволяет объединить одно с другим, и грубо говоря, автоматизированно собирать deb-ки из текущего развернутого virtualenv-а. Ставится она кстати через обычный apt-get. Внутри проекта, помимо setup.py и requirements.txt создается директория debian, в которой описываются характеристики и зависимости deb-пакета (rules, control и т.п.), а для создания пакета нагоняется консольная команда dpkg-buildpackage -us -uc. virtualenv на конечной qa/prod машине ставить не надо, т.к. он автоматически скачивается и упаковывается утилитой при создании пакета.
Lightning Talks этого дня лично мне запомнился одним очень интересным докладом про то, почему не стоит злоупотреблять getattr().
Пример кода:
import random
class A(object):
def get_prop(self):
return getattr(self, 'prop', None)
class B(A):
@property
def prop(self):
return random.chioce(['test prop1', 'test prop2', 'test prop3'])
print(B().get_prop())
Данный код будет выводить всегда None, т.к. исключение (из-за неправильного имени метода, т.е. random.chioce) будет игнорироваться внутри getattr.
Доклад “Everything You Always Wanted to Know About Memory in Python But Were Afraid to Ask” [34] лично мне, как человеку, сильно далекому от C/C++, и привыкшему мыслить более приземленными материями, было очень интересно послушать. Какие-то вещи я уже знал, какие-то вещи лишний раз освежил в памяти. Не буду останавливаться на деталях, скажу так — особенно интересно было послушать про существующие тулы, которые имеют реальное практическое применение (objgraph [35], профилировщик памяти guppy [36] и т.п.), и про то, что в Python можно заюзать раличные либы, реализующие низкоуровневый malloc(), и какой профит будет от этих замен. В общем, лично я рекомендую всем посмотреть этот доклад [34]. Так же в этот же день проходил ещё один крутой доклад на схожую тему — «Fun with cPython memory allocator» [37]. К сожалению, я на него не ходил, но судя по отзывам моих коллег — доклад весьма стоящий. Многие наверное сталкивались с проблемой, когда создаешь в Python список из большого количества строк строк, потом удаляешь его, а память не уменьшается. Вот про эту проблему рассказывается в докладе — как это, из-за чего и как с этим бороться.
Далее был весьма неоднозначный доклад «Advanced Database Programming with Python» [38]. Тем, кто в своей практике мало работал с базами данных — рекомендую послушать. Узнаете такие вещи, как уровни изоляции транзакций, например, и чем они отличаются друг от друга, а так же про python-ячью специфику работы с базами данных (согласно PEP 249 [39] autocommit=0 де факто и commit-ы надо не забывать писать вручную) и про какие-то базовые вещи по оптимизации запросов. Доклад неоднозначный, потому что автор делает акцент на множестве весьма редких оптимизаций типо, как например генерить ID вставляемой записи в Python-е, а не полагаться на auto_increment/sequences БД. Это-то конечно хорошо, вот только опыт показывает, что наслушавшись таких докладов, некоторые программисты начинают преждевременно оптимизировать все и вся, и это в 99% случаев приводит к весьма плачевным последствиям.
И последним было выступление от Бенуа Шесно, создателя web сервера gunicorn [40]. Рассматривалось 100500 существующих вариантов реализации мультизадачности в python, и новый 100501-ый вариант — библиотечка offset [41], привносящая в python функционал кроутин языка Go. Во время выступления я немного покопался во внутренностях данной библиотеки — судя по всему в основе данной либы лежит боле низкоуровневая реализация кроутин основанная на библиотеке fibers [42]. Сама же offset [41] привносит в язык более высокоуровневые обертки. Т.е. грубо говоря, позволяет писать программы на python сродни тому, как они бы выглядели бы в Go. В своем докладе автор как раз приводит примеры схожести кода реализации некой абстрактной задачи, написанного на Go и написанного на Python, но с использованием offset [41]. В общем, всем тем, кому недостаточно существующего функционала тредов, tornado/twisted, asyncio, gevent и модуля multiprocessing — данная библиотека может показаться весьма интересной. Слушать же сам доклад особого смысла не имеет — лучше сразу лезть в код на github и пробовать.
Заключительные Lightning Talks в этот день мне запомнились докладом про HSTS [43]. Очень полезная штука надо сказать, о которой мало кто знает. Фактически это HTTP response заголовок, который указывает браузеру всегда принудительно использовать HTTPS-соединение для данного хостнейма. Т.е. в дальнейшем если пользователь вбивает в браузере some-url.com [44], то браузер сам автоматически подставит https. Полезно и из соображений безопасности и и из соображений сокращения числа редиректов с HTTP на HTTPS, возвращаемых с сервера.
На конференции было огроменное количество стендов от компаний, так или иначе связанных с Python (Google, Amazon, DjangoCMS, JetBrains, Atlassian и пр). К ним ко всем можно было подходить и общаться на разного рода интересующие вопросы. Мы довольно много общались с ребятами из Google (правда это было не на самой конференции, а на after party от Google). Из интересного — Python у них используется преимущественно во внутренних продуктах, ну разве что кроме Youtube-а. Так же они нам по секрету сказали, что разработчики Google не очень-то любят BigTable, и уже сейчас в лабораториях Google готовится к выпуску новая революционная БД (кодовое название Spanner [45]), позволяющая делать распределенные транзакции на кластере, и при этом обладающая всеми плюсами NoSQL. По слухам, вроде как даже Open Source (в чем, конечно, есть большие-большие сомнения).
Так же общались с представителями DjangoCMS [46] (тут ничего интересного, банальная незатейливая CMS на Django, можно установить на свой сервер, а можно использовать SaaS решение) и c представителями Amazon. Касательно последних, задал им вопрос, затронутый на конференции highload 2012го года, по поводу того, что пропускная способность инстансов довольно разная и непропорциональна типу инстанса (см. презентацию [47] — 25ый слайд), но получил в ответ «ну это специфика виртуализации такая, мы не можем сказать почему, обратитесь в поддержку». Кстати, думаю многим будет интересно, ребята из Amazon раздавали анкеты с вопросами на Python-тематику. Уже сейчас не вспомню, то ли они призы разыгрывали, то ли хантили таким образом. В общем, вопросики весьма специфичные, из разряда «эти самые вопросы, которые никогда не встречаются на практике, но их любят задавать на собеседованиях в больших конторах»:
1. Which is called first when creating an object:
a. __create__
b. __new__
c. __init__
d. __del__
2. What is printed by the last statement in:
def foo(x, l=[]):
l+=2*x
print l
foo('a')
foo('bc')
a. ['a','b','c']
b. ['a','bc']
c. ['a','a','b','c','b','c']
d. ['a','a','bc','bc']
3. What does the last statement print?
class A(str):
pass
a=A('a')
d={'a':42}
d[a]=42
print type(d.keys()[0])
a. str
b. A
c. dict
d. int
4. Which of the following will these 2 statements return on Python vesrion 2?
5 * 10 is 50
100 * 100 is 10000
a. True, True
b. True, False
c. False, True
d. False, False
В целом, впечатления от конференции весьма положительные. Основная ставка организаторов делалась на общения в кулуарах. На самом деле, это первая конференция на моей памяти, где доклады прямо сразу же выкладываются на YouTube. И хотя уровень большинства докладов я бы оценил как средний, тем не менее прозвучало довольно много интересных вещей, которые так или иначе можно применить в реальных проектах.
Автор: StraNNikk
Источник [48]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/69227
Ссылки в тексте:
[1] посмотреть на YouTube: http://www.youtube.com/user/europython2014
[2] чему Python может поучиться у Haskell-а: https://www.youtube.com/watch?v=eVChXmNjV7o
[3] аннотации: http://legacy.python.org/dev/peps/pep-3107/
[4] mypy: http://www.mypy-lang.org/
[5] библиотечку под названием Architect: https://github.com/maxtepkeev/architect
[6] пакетный менеджер nix: https://www.youtube.com/watch?v=Eis-WqHda20
[7] NixOS: http://nixos.org/
[8] Dependency hell: http://archive09.linux.com/feature/155922
[9] доклад про потоковую обработку больших объемов данных с использованием Kafka и Storm: https://www.youtube.com/watch?v=uwiHZru2Wjc
[10] Storm: https://storm.incubator.apache.org/
[11] Kafka: http://kafka.apache.org/
[12] неплохой вводный доклад про Marconi: https://www.youtube.com/watch?v=d65TtqGp-9Q
[13] доклад про Logstash / Elasticsearch / Kibana: https://www.youtube.com/watch?v=J3ai0cDOAkY
[14] Logbook: http://www.pocoo.org/projects/logbook/
[15] написания мультиязыковой Sphinx-документации: https://www.youtube.com/watch?v=Nz8zutA55fI
[16] gettext: https://ru.wikipedia.org/wiki/Gettext
[17] sphinx-intl: https://pypi.python.org/pypi/sphinx-intl
[18] Transifex: https://www.transifex.com/
[19] слайды: https://speakerdeck.com/keimlink/writing-multi-language-documentation-using-sphinx-1
[20] доклад про gevent: https://www.youtube.com/watch?v=0wpYQr-_kqg
[21] gevent: http://www.gevent.org/
[22] web-микрофреймворк: http://nucleon.readthedocs.org/en/latest/index.html
[23] AMQP-библиотечка: http://pythonhosted.org/nucleon.amqp/
[24] «DevOps Risk Mitigation: Test Driven Infrastructure»: https://www.youtube.com/watch?v=L6TtXrLmdKA
[25] «Multiplatform binary packaging and distribution of your client apps»: https://www.youtube.com/watch?v=CoxAowBDDyE
[26] cythonize-им исходники: http://docs.cython.org/src/reference/compilation.html
[27] слайды: http://www.slideshare.net/hithwen/multiplatform-binary-packaging-of-your-python-client-apps
[28] эту статью: http://blog.biicode.com/bii-internals-compiling-your-python-application-with-cython/
[29] доклад от одного из разработчиков Disqus: https://www.youtube.com/watch?v=CXhljKhRVpI
[30] SOA: https://ru.wikipedia.org/wiki/%D0%A1%D0%B5%D1%80%D0%B2%D0%B8%D1%81-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%B0%D1%8F_%D0%B0%D1%80%D1%85%D0%B8%D1%82%D0%B5%D0%BA%D1%82%D1%83%D1%80%D0%B0
[31] Python Debugger Uncovered: https://www.youtube.com/watch?v=HfzdM7rsKbU
[32] доклад про tool-у dh-virtualenv: https://www.youtube.com/watch?v=d_jqe1O31X8
[33] dh-virtualenv: https://github.com/spotify/dh-virtualenv
[34] “Everything You Always Wanted to Know About Memory in Python But Were Afraid to Ask”: https://www.youtube.com/watch?v=hf4MKeP5oxg
[35] objgraph: http://mg.pov.lt/objgraph/
[36] guppy: https://pypi.python.org/pypi/guppy/
[37] «Fun with cPython memory allocator»: https://www.youtube.com/watch?v=l9Le_JOwgsM
[38] «Advanced Database Programming with Python»: https://www.youtube.com/watch?v=LyJ3evnz2Xw
[39] PEP 249: http://legacy.python.org/dev/peps/pep-0249/
[40] выступление от Бенуа Шесно, создателя web сервера gunicorn: https://www.youtube.com/watch?v=snIHnStehIo
[41] offset: https://github.com/benoitc/offset
[42] fibers: https://pypi.python.org/pypi/fibers/0.1.0
[43] HSTS: https://ru.wikipedia.org/wiki/HSTS
[44] some-url.com: http://some-url.com
[45] Spanner: http://www.cubrid.org/blog/dev-platform/spanner-globally-distributed-database-by-google/
[46] DjangoCMS: https://www.django-cms.org
[47] презентацию: http://www.slideshare.net/profyclub_ru/partly-cloudy-aws-14831865
[48] Источник: http://habrahabr.ru/post/236119/
Нажмите здесь для печати.