21
Шардинг - что это и как правильно его готовить. автор: Дмитрий Фурзенко, Sandstorm NV

Kranonit s16 (python). dmitry furzenko

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Kranonit s16 (python). dmitry furzenko

Шардинг - что это и как правильно его готовить.

автор: Дмитрий Фурзенко, Sandstorm NV

Page 2: Kranonit s16 (python). dmitry furzenko

О себе:● в сети известен под ником - Dimonji● python developer over 3+ year expirience● pythonic way в разработке● highload системы● Мои инструменты:

○ Pycharm or Emacs ○ Python○ Brain○ И очень много разных python библиотек :)

Page 3: Kranonit s16 (python). dmitry furzenko

Где работал/работаю:c 08.2011 по текущее время - Sandstorm NVс 05.2009 по 08.2011 ООО Любимое такси, разработчик программного обеспечения, системный администратор

Page 4: Kranonit s16 (python). dmitry furzenko

О чем будет доклад:● Теория построения шардинга● SQLAlchemy● gevent

Page 5: Kranonit s16 (python). dmitry furzenko

Ингредиенты для шардинга:● python 2.7● SQLAlchemy >= 0.7.9● MySQL or PostgreSQL● четкое понимание архитектуры приложения● немного магии

Page 6: Kranonit s16 (python). dmitry furzenko

Зачем нужен шардинг:● практически бесконечное горизонтальное

масштабирование production платформы● отказоустойчивость● более дешевый production

Page 7: Kranonit s16 (python). dmitry furzenko

Плюсы:● горизонтальное масштабирование● балансировка нагрузки на БД● более высокая отказоустойчивость● более низкий downtime

Page 8: Kranonit s16 (python). dmitry furzenko

Минусы:● выборка и обработка всех данных становиться

самым узким местом● требуется более тщательное проектирование

приложения● в некоторых моментах приходится пренебрегать т.н

нормальной формой БД

Page 9: Kranonit s16 (python). dmitry furzenko

Обобщенные принципы построения:● все данные которые будут расшардены должны

иметь общий ключ т.н сегмент● отдельная структура которая будет знать какой

сегмент какому шарду принадлежит● единый алгоритм распределения сегментов по

шардам

Page 10: Kranonit s16 (python). dmitry furzenko

SQLAlchemy● мощная орм, которая при минимуме усилий

позволяет абстрагировать разработчика от БД и работать на уровне объектов

● если алхимию неправильно использовать она может принести много головной боли разработчику

Page 11: Kranonit s16 (python). dmitry furzenko

Установка соединения с БД и pool соединений:● umysqldb● sqlalchemy.create_engine● sqlalchemy.orm.sessionmaker

Page 12: Kranonit s16 (python). dmitry furzenko

Пример организации соединения с одной БД

import umysqldbfrom sqlalchemy import create_enginefrom sqlalchemy.orm import sessionmaker

umysqldb.install_as_MySQLdb()SHARD_ENGINE = { 'engine': 'mysql', 'host': 'localhost', 'name': 'kranonit_shards', 'login': 'root', 'password': ''}_DSN = '%(engine)s://%(login)s:%(password)s@%(host)s/%(name)s?charset=utf8'

SHARD_CONNECTION = create_engine( _DSN % SHARD_ENGINE, echo=False, pool_recycle=3600, pool_size=5, max_overflow=0, isolation_level="READ COMMITTED")

SESSION = sessionmaker(bind=SHARD_CONNECTION, autocommit=True)S_SESSION = SESSION()

Page 13: Kranonit s16 (python). dmitry furzenko

Организация соединения с БД для шардовых БД:● pool соединений к шардовым базам● shard class

○ shard_chooser○ query_chooser○ id_chooser

Page 14: Kranonit s16 (python). dmitry furzenko

Пример организации соединения с шардовыми БД

CONNECTIONS = list()_DSN = '%(engine)s://%(login)s:%(password)s@%(host)s/%(name)s?charset=utf8'for shard in S_SESSION.query(Shard).all(): engine = create_engine( _DSN % {'engine': shard.engine, 'host': shard.host, 'name': shard.name, 'login': shard.login, 'password': shard.password}, echo=False, pool_recycle=3600, pool_size=shard.pool_size, max_overflow=shard.max_overflow, isolation_level=shard.isolation_level) CONNECTION[shard.id] = engine

createfunc = sessionmaker(class_=DeepShardedSession, autoflush=False)scoped = scoped_session(createfunc, scopefunc=getcurrent)scoped.configure(shards=CONNECTIONS)session = scoped()

Page 15: Kranonit s16 (python). dmitry furzenko

Логика распределения shard● uuid● балансировка● выбор емкости сегментов

○ 1 разряд uuid дает 16 записей на сегмент○ минимальный ключ для сегмента два разряда

uuid○ максимальноя количество записей в сегменте

Page 16: Kranonit s16 (python). dmitry furzenko

Пример модели для шардclass Shard(SEBase): __tablename__ = 'shards'

id = Column(Integer, primary_key=True) engine = Column(String(50), default='mysql') host = Column(String(255)) login = Column(String(100)) password = Column(String(100)) name = Column(String(100)) pool_size = Column(Integer(3), default=-1) max_overflow = Column(Integer(3), default=-1) isolation_level = Column(String(100), default='READ COMMITED') desc = Column(Text(255)) is_default = Column(Boolean, default=False)

__table_args__ = ( UniqueConstraint('host', 'name', name='_shard_host_name_uc'), {'mysql_engine': 'InnoDB', 'extend_existing': True, }, )

Page 17: Kranonit s16 (python). dmitry furzenko

Пример модели сегментовclass Segment(SEBase): __tablename__ = 'segments'

id = Column(String(5), primary_key=True) shard_id = Column(Integer, ForeignKey("shards.id")) shard = relationship( Shard, primaryjoin='Shard.id==Segment.shard_id', lazy='joined')

__table_args__ = ({ 'mysql_engine': 'InnoDB', 'extend_existing': True, })

Page 18: Kranonit s16 (python). dmitry furzenko

DeepShardedSession примерclass DeepShardedSession(ShardedSession): def __init__(self, query_cls=DeepShardedQuery, *args, **kwargs): self.__binds = {} super(DeepShardedSession, self).__init__( shard_chooser=self.shard_chooser, query_chooser=self.query_chooser, id_chooser=self.id_chooser, query_cls=query_cls, *args, **kwargs)

def shard_chooser(self, mapper, instance, clause=None, *args, **kwargs): “””Здесь описываем по каким критериям мы выбираем необходимый шард””” pass

def query_chooser(self, query, ident=None): """Здесь опираясь на условия запроса определяем на каких шардах его выполнять””” pass

Page 19: Kranonit s16 (python). dmitry furzenko

Почему одна БД плохо

Наша одна БД

Поток данных

Page 20: Kranonit s16 (python). dmitry furzenko

Почему шардинг хорошо

БД 1

БД 2

БД 3

БД 4

БД 5

БД n

Поток данных

Page 21: Kranonit s16 (python). dmitry furzenko

Немножко про geventGevent - green event, микропотоки в pythonПлюсы

● Псевдо многопоточность● Забываем про ужасы callback и deffered из Twisted● пишем код в обычном стиле и двумя строчками делаем его асинхронным

Минусы● сложно профилировать● не все библиотеки можно им пропатчить● требует определенных навыков в использовании

Применение● Практически везде где уместна работа с сетью, потоками и очередями