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

Остановлюсь на принципиальных отличиях от существующих решений.
Stateless
Пудж автоматически создаст базу данных test, включая вложенные директории, либо откроет. Нет необходимости хранить состояние таблицы и можно безопасно сохранять значения в многопоточных приложениях. Пудж потокобезопасен.
Typefree
В пудж можно записывать байты, строки, числа или структуры. Не беспокоясь о конвертации данных в их бинарное представление.
QuerySystem
Пудж предоставляет возможность извлекать ключи в определенном порядке, включая выборку с указанием лимита, отступом, сортировки и выборку по префиксу.
Приведенный выше код, является аналогом SQL запроса:
Следует учесть, что сортировка ключей — «ленивая». С другой стороны ключи хранятся в памяти и выполняется она довольно быстро.
Parallelism
Пудж, как и большинство современных баз данных использует модель неблокирующего чтения, однако запись в файл блокирует все операции. Но Вы можете создавать/открывать файлы «на лету», минимизируя количество блокировок. В пудже нет ошибки «database already opened». Пример использования в http роутере:
Engines
Несмотря на небольшой размер, пудж поддерживает два режима хранения данных. В памяти и на диске. По умолчанию пудж хранит данные (значения) только на диске. Но при желании можно включить режим хранения данных в памяти. В этом случае сбрасываться на диск они будут по запросу, либо при закрытии базы.
Status
Пудж используется как в домашних проектах, так и в продакшен, на графике ниже — количество запросов к http серверу на базе пудж, и количество запросов дольше 20 ms

В данном случае пудж включен в режиме полной синхронизации, и, в момент fsync — случаются значительные (более 20 ms) задержки. Но к счастью, их не так много в процентном соотношении.
На странице проекта можно найти больше ссылок с примерами интеграции пуджа в различные проекты.
Speed
В репозитории с benchmark'ами можно сравнить пудж с другими базами данных:
Пудж очень хорошо сбалансирован по соотношению между скоростью записи и скоростью чтения. Те он не является узкоспециализированной базой данных оптимизированной для чтения или записи. При высокой скорости чтения — сохраняется довольно высокая скорость записи. Которая впрочем может быть еще увеличена за счет распараллеливания записи в разные файлы (как это сделано в LSM Tree движках).
Ссылки на бд, использованные в тесте:
Просили сравнить с memcache и redis, но так как львиная доля времени тратится на сетевые интерфейсы при взаимодействии с данными бд, это не совсем честно. Хотя с другой стороны пудж выигрывает за счет многопоточности, даже несмотря на то, что пишет данные на диск.
Дальнейшее развитие

Остановлюсь на принципиальных отличиях от существующих решений.
Stateless
pudge.Set("../test/test", "Hello", "World")
Пудж автоматически создаст базу данных test, включая вложенные директории, либо откроет. Нет необходимости хранить состояние таблицы и можно безопасно сохранять значения в многопоточных приложениях. Пудж потокобезопасен.
Typefree
В пудж можно записывать байты, строки, числа или структуры. Не беспокоясь о конвертации данных в их бинарное представление.
type Point struct {
X int
Y int
}
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
Пудж, как и большинство современных баз данных использует модель неблокирующего чтения, однако запись в файл блокирует все операции. Но Вы можете создавать/открывать файлы «на лету», минимизируя количество блокировок. В пудже нет ошибки «database already opened». Пример использования в http роутере:
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.