Хабрахабр

pudge встраиваемая база данных в 500 строк на golang

pudge — встраиваемая key/value база данных, написанная на стандартной библиотеке Go.

image

Остановлюсь на принципиальных отличиях от существующих решений.

Stateless

pudge.Set("../test/test", "Hello", "World")

Пудж автоматически создаст базу данных test, включая вложенные директории, либо откроет. Нет необходимости хранить состояние таблицы и можно безопасно сохранять значения в многопоточных приложениях. Пудж потокобезопасен.
Typefree

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

type Point struct for i := 100; i >= 0; i-- { p := &Point{X: i, Y: i} db.Set(i, p) } var point Point db.Get(8, &point) log.Println(point)

QuerySystem

Пудж предоставляет возможность извлекать ключи в определенном порядке, включая выборку с указанием лимита, отступом, сортировки и выборку по префиксу.

keys, _ := db.Keys(7, 2, 0, true)

Приведенный выше код, является аналогом SQL запроса:

select keys from db where key>7 order by keys asc limit 2 offset 0

Следует учесть, что сортировка ключей — «ленивая». С другой стороны ключи хранятся в памяти и выполняется она довольно быстро.

Parallelism

Но Вы можете создавать/открывать файлы «на лету», минимизируя количество блокировок. Пудж, как и большинство современных баз данных использует модель неблокирующего чтения, однако запись в файл блокирует все операции. Пример использования в http роутере: В пудже нет ошибки «database already opened».

func write(c *gin.Context) { var err error group := c.Param("group") counter := c.Param("counter") db, err := pudge.Open(group, cfg) if err != nil { renderError(c, err) return } _, err = db.Counter(counter, 1) if err != nil { renderError(c, err) return } c.String(http.StatusOK, "%s", "ok")
}

Engines

В памяти и на диске. Несмотря на небольшой размер, пудж поддерживает два режима хранения данных. Но при желании можно включить режим хранения данных в памяти. По умолчанию пудж хранит данные (значения) только на диске. В этом случае сбрасываться на диск они будут по запросу, либо при закрытии базы.

Status

Пудж используется как в домашних проектах, так и в продакшен, на графике ниже — количество запросов к http серверу на базе пудж, и количество запросов дольше 20 ms

Но к счастью, их не так много в процентном соотношении. В данном случае пудж включен в режиме полной синхронизации, и, в момент fsync — случаются значительные (более 20 ms) задержки.

На странице проекта можно найти больше ссылок с примерами интеграции пуджа в различные проекты.

Speed

В репозитории с benchmark'ами можно сравнить пудж с другими базами данных:

Test 1

Number of keys: 1000000
Minimum key size: 16, maximum key size: 64
Minimum value size: 128, maximum value size: 512
Concurrency: 2

pogreb

goleveldb

bolt

badgerdb

pudge

slowpoke

pudge(mem)

1M (Put+Get), seconds

187

38

126

34

23

23

2

1M Put, ops/sec

5336

34743

8054

33539

47298

46789

439581

1M Get, ops/sec

1782423

98406

499871

220597

499172

445783

1652069

FileSize,Mb

568

357

552

487

358

358

358

Пудж очень хорошо сбалансирован по соотношению между скоростью записи и скоростью чтения. Те он не является узкоспециализированной базой данных оптимизированной для чтения или записи. При высокой скорости чтения — сохраняется довольно высокая скорость записи. Которая впрочем может быть еще увеличена за счет распараллеливания записи в разные файлы (как это сделано в LSM Tree движках).

Ссылки на бд, использованные в тесте:

  • pogreb Embedded key-value store for read-heavy workloads written in Go
  • goleveldb LevelDB key/value database in Go.
  • bolt An embedded key/value database for Go.
  • badgerdb Fast key-value DB in Go
  • slowpoke Low-level key/value store in pure Go (based on pudge)
  • pudge Fast and simple key/value store written using Go's standard library

Просили сравнить с memcache и redis, но так как львиная доля времени тратится на сетевые интерфейсы при взаимодействии с данными бд, это не совсем честно. Хотя с другой стороны пудж выигрывает за счет многопоточности, даже несмотря на то, что пишет данные на диск.

Дальнейшее развитие

  • Транзакции. Было бы удобно объединять запросы на запись в пул, с автоматическим откатом в случае ошибки.
  • Возможность ограничения времени жизни ключа (как TTL в memcache/cassandra etc)
  • Отсутствие сервера. Удобно встраивать пудж в существующие микросервисы, но скорее всего появится отдельный сервер. В рамках отдельного проекта.
  • Мобильная версия. Для использования на Android, iOS и в виде плагина для Flutter.
Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть