Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Tarantool.org)

2,520 views

Published on

Оперативная память становится всё более дешёвой и производительной, что позволяет использовать её для хранения рабочего набора данных всё большего числа приложений. Хранение всех данных в оперативной памяти позволяет сделать их высоко доступными, а алгоритмы для работы с данными либо существенно упростить, либо ускорить, а иногда — и то, и другое.

Тезисы - http://www.highload.ru/2015/abstracts/1964.html

Published in: Engineering
  • Be the first to comment

  • Be the first to like this

Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Tarantool.org)

  1. 1. Алгоритмы и структуры данных для СУБД в оперативной памяти Константин Осипов kostja@tarantool.org http://try.tarantool.org
  2. 2. Содержание It's time for a complete rewrite!.. или почему в 2015 г. можно и нужно создавать новые СУБД Database people are logicians.. или почему инженерия ПО не менее важна чем красивые теории First time is the best time!.. смотрим на аллокаторы памяти Deep dive... специализированные структуры данных для оперативной памяти.
  3. 3. Архитектура СУБД
  4. 4. Постановка задачи - ACID ● ATOMICITY – транзакции работают по принципу “всё или ничего” - ошибка в середине приводит к откату всех действий транзакции ● CONSISTENCY – транзакции при модификации данных сохраняют их консистентность ● ISOLATION - выполнение параллельных транзакций имеет тот же эффект что и их последовательное применение ● DURABILTY – эффекты завершённых транзакций не теряются даже в случае программного сбоя или выхода из строя оборудования
  5. 5. ● Isolation — выполнение параллельных транзакций имеет тот же эффект что и их последовательное применение Isolation
  6. 6. ● Isolation — выполнение параллельных транзакций имеет тот же эффект что и их последовательное применение ● Consistency без isolation не достижим Isolation
  7. 7. ● Isolation — выполнение параллельных транзакций имеет тот же эффект что и их последовательное применение ● Consistency без isolation не достижим ● Пусть есть x, y, z – данные к которым осуществляется совместный доступ Isolation
  8. 8. ● Isolation — выполнение параллельных транзакций имеет тот же эффект что и их последовательное применение ● Consistency без isolation не достижим ● Пусть есть x, y, z – данные к которым осуществляется совместный доступ ● Расписание (schedule) — возможная история выполнения транзакций, конкретный порядок операций чтения и записи относительно друг друга E = r1[x] w1[x] w2[y] r2[z] Isolation
  9. 9. ● Если t1 транзакция использует X не допустить модификацию X в других транзакциях до завершения t1 ➔ Конкурентные транзакции работают с разными поднаборами данных ➔ Порядок модификаций одних и тех же данных фиксирован ● Блокировка (лок) — механизм обеспечения эксклюзивного доступа Isolation: классическое решение
  10. 10. ● Мы говорим, что история выполнения транзакций последовательна, если их действия в истории не пересекаются: E = r1[x] w1[y] commit1 w2[y] r2[z] commit2 ● Принцип two phase locking — локи захваченные транзакцией не должны освобождаться до commit ● Насколько это строгое требование? Предположим обратное: E = r1[x] r2[y] w2[x] w1[y] - не существует сериального выполнения t1 и t2 (их всего два — t1 t2 или t2 t1) с тем же эффектом Формализация: serial history
  11. 11. ● Таким образом, без 2PL история выполнения может оказаться несериализуемой ● Достаточно ли 2PL? Да: Two-Phase Locking Theorem: If all transactions in an execution are two-phase locked, then the execution is serializable. 2PL
  12. 12. ● Много пользователей = много потоков, требуется latching, т.е. разграничение доступа к ресурсам ● Внешнее хранение = два представления данных, в памяти и на диске Другие проблемы
  13. 13. Другие проблемы (2) page header modification log page trailer page directory compressed data BLOB pointers empty space page header page trailer row offset array row rowrow Row row row row rowrow trx id field 1 roll pointer field pointers field 2 field n
  14. 14. Stonebraker concept
  15. 15. Решение ● храним 100% данных в RAM ● транзакции выполняются строго последовательно в одном потоке ● получаем настоящий serial execution ● полное отсутствие блокировок ● Шардировать всё равно придётся, поэтому бьём на шарды сразу, с первой машины.
  16. 16. ● t1 записала X и завершилась ● выполняется успешно t2, которая читает X ● запись t1 в журнал привела к ошибке → нужно уметь делать откат при ошибке записи в журнал Работа с журналом
  17. 17. Аспекты инженерии
  18. 18. Latency vs. throughput
  19. 19. Concurrency – сойство систем, глобальное состояние которых изменяется чередующимся выполнением независимых или частично-независимых функций или компонент Parallelism – система конкурентна, но один или несколько блоков могут выполняться параллельно Concurrency vs. parallelism
  20. 20. With shared state: - locking ← not composable - wait-free algorithms – parallelism - hardware transactional memory Without shared state: - functional programming - actor model Подходы к concurrency
  21. 21. + портабельны, просты в использовании + низкие издержки - не интегрируются в poll() event loop - могут стать hot spot Locking
  22. 22. + ещё более низкие издержки - сложно реализовать и тестировать - не интегрируются в event loop - могут стать hot spot Wait-free algorithms
  23. 23. ● Дедлоки ● Конвоирование, хотспоты ● Лайвлоки ● Голодание ● Не универсальны – гранулярность статична, возможна инверсия приоритетов Locks are not composable!
  24. 24. Wait-free algorithms (2)
  25. 25. ● нет глобального состояния ● main = f(x) ● порядок выполнения не задаётся явно, зависит от данных ● функциональные зависимости просты для распараллеливания → composable - нет языков достаточно эффективных для системного программирования Functional programming
  26. 26. ● Actors – Посылают сообщения – Получают и обрабатывают сообщения – Создают actors ● нет глобального состояния ● unbounded non-determinism :( composable! Actor model
  27. 27. Intel Xeon E5 микроархитектура
  28. 28. Intel Xeon E5 чип
  29. 29. ● кооперативная многозадачность внутри потока ● обмен сообщениями между потоками и узлами → Erlang “на коленке” Выводы: actor model в Tarantool
  30. 30. Память, память, память
  31. 31. void *malloc(size_t size);  void free(void *); ● работает в любом потоке ● для любого размера (совсем любого) ● “средние по больнице” требования к фрагментации Классический менеджер памяти
  32. 32. ● не нужна синхронизация ● нужна поддержка квот ● нужна поддержка консистентных снимков памяти → специализированные аллокаторы памяти Аллокация в одном потоке
  33. 33. Аллокаторы Tarantool ● http://github.com/tarantool/small ● quota, slab_arena – аллоцирует данные выровненными 4МБ блоков, поддерживает квоты, multi-threaded ● slab_cache – buddy system для выровненных блоков от 4КБ до 4МБ ● mempool - позволяет аллоцировать и освободждать участки одинакового размера ● region_alloc – позволяет аллоцировать память, но не позволяет её освобождать :) ● small – колллекция pool allocators для разных типоразмеров ● matras – аллокатор для выровненных блоков, работающий в 32 битном адресном пространстве
  34. 34. slab_arena – quotas and VSS ● глобальна, thread-safe ● MAP_SHARED или MAP_PRIVATE ● поддержка квот, несколько арен в одной квоте ● size-aligned, preallocated prealloc slab 4M
  35. 35. slab_cache – buddy system ● thread local ● size-aligned
  36. 36. mempool – object pool ● thread local ● objects of the same size object size = 26 slab size = 2048, 76 objects per slab
  37. 37. small – slab allocator with MVCC ● collection of mempools for size classes void *small_alloc(small *, size_t size) void small_free(small *, void *, size_t size) object size = 24 object size = 32 object size = 40 object size = 48
  38. 38. ibuf, obuf, region ● Аллокаторые это контейнеры, а контейнеры это аллокаторы, различие только в наличии итерации по объектам ● Аллокаторы это буфера, а буфера это аллокаторы, различие лишь в возможности создания точки отката и восстанвлении на точку в прошлом
  39. 39. Структуры данных в RAM
  40. 40. Матрас Extent size: 16 kB Block size: 16 B Block id: 32 bit 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 1 id0 : high 11 bit id1 : middle 11 bit id2 : low 10 bit L0 extent: array of 2048 pointers to L1 extents Use id0 as index to find pointer to L1 extent L1 extents: arrays of 2048 pointers to L2 extents L2 extents: arrays of 1024 blocks Use id1 as index to find pointer to L2 extent Use id2 as index to the block 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1
  41. 41. Будущее: log-structured memory
  42. 42. The daily latency spike
  43. 43. Хэш-таблица Light Bucket: 16 bytes: 8 – value, 4 – hash, 4 – next bucket ID in chain Table: Buckets with ID: [0..M) Hash → Bucket ID: B(Hash) = Cover: C = M rounded up to the closest power of two; c = C / 2 Hash % C < M → Hash % C Hash % C ≥ M → Hash % C True bucket with ID holds a value with hash: B(hash) == ID Chain bucket with ID holds a value with hash: B(hash) != ID, but the another true bucket with ID = B(hash) starts a chain that contains this chain bucket 0x40 0x42 0x16 5 0xAB 0x44 value hash next 0 1 2 3 4 0x32 1 5 M = 6 C = 8, c = 4 0x40 % 8 = 0 0x16 % 8 = 6 0x16 % 4 = 2 0xAB % 8 = 3 0x44 % 8 = 4 0x32 % 8 = 2 0x40 0x32 2 0xAB 0x44 0 1 2 3 4 5 M = 7 C = 8, c = 4 0x40 % 8 = 0 0xAB % 8 = 3 0x44 % 8 = 4 0x42 % 8 = 2 6 0x16 5 0x16 % 8 = 6 0x42 0x32 % 8 = 20x42 % 8 = 2
  44. 44. Классические деревья: overhead
  45. 45. ● b-tree: compact and cache-oblivious ● b+-tree: cheap iteration ● b*-tree: more compact and more symmetric ● pointer compaction via matras ● MVCC via matras bps_tree
  46. 46. Inner nodes Leaf nodes ● K-ary (k-way) tree ● well balanced ● same size for leafs and inner nodes (512 B) ● non-root nodes are filled [2M/3..M] ● root may be filled [1..M] bps_tree
  47. 47. Leaf node Header Tuple[0] Tuple[1] Tuple[2] ... Up to 62 pointers to tuples, sorted by key definition Inner node Header MaxTuple[0] MaxTuple[1] ... Id[0] Id[1] Id[2] ... Matras IDs of subtrees MaxTuple[i - 1] < {All tuples in subtree i} ≤ MaxTuple[i + 1] Up to 42 subtrees with their maximal tuples (except last subtree) Subtrees are sorted by their maximal tuples Maximal tuple of maximal subtree is stored in upper node Maximal tuple of maximal subtree in root is stored in special place of tree Maximal tuple pointer in leaf node is copied exactly once somewhere in upper nodes of the tree, except of last tuple, that stored in special place bps_tree
  48. 48. Search / find insertion / deletion point Binary search (lower bound) in node 42 4 6318 80 i = 2 Root, inner node 20 5245 60 i = 1 Searching Inner node 23 3530 40 Leaf node42 43 45 ! About log(N) comparisons (N – number of tuples in tree) About log(N)/log(M) block scans (M – average number of tuples in node) bps_tree
  49. 49. 1) Find insertion point (path) 2) If leaf has space – insert into leaf; done (most common case) 3) If 2 closest siblings has space – rearrange and insert; done 4) Split the (full) node and 2 closest (full) siblings into 4 nodes and insert 5) Insert id of new node into parent – inner node; done In every case update MaxTuple in parents if it's changed 7040 5010 7040 5010 42 5040 4535 55 65 706020 3010 5042 4540 7060 65553520 3010 5040 4535 55 7565 7060 802515 2010 30 4235 4030 6050 55452515 2010 Root has no siblings; if full it splits into 2 nodes and new root is created 8070 7565 bps_tree: вставка
  50. 50. 1) Find deletion point (path) 2) Delete tuple from node 3) If not less than 2*M/3 tuples left – done 70 4050 10 7040 5010 42 4) If 2 closest siblings have more than 2*M/3 tuples left – rearrange; done 42 4540 7565 7060 802515 2010 30 6040 4530 8070 75652520 3010 4) Merge the node and 2 closest siblings into 2 nodes 5) Delete id of deleted node from parent – inner node; done In every case update MaxTuple in parents if it's changed 42 4540 65 706020 3010 7060 65454015 2010 Root is handled specially bps_tree: удаление
  51. 51. ● worst case about 12 bytes per tuple (4 bytes overhead) ● average case about 10 bytes per tuple (2 bytes overhead) ● worst case about 1.1 log(N) comparisons per search (AVL-tree about 1.45 log(N), RB-tree about 2 log(N) ● great cache hit ratio ● MVCC over matras bps_tree: итоги

×