536 lines
23 KiB
Markdown
536 lines
23 KiB
Markdown
<!-- Improved compatibility of К началу link: See: https://github.com/othneildrew/Best-README-Template/pull/73 -->
|
||
<a id="readme-top"></a>
|
||
<!--
|
||
*** Thanks for checking out the Best-README-Template. If you have a suggestion
|
||
*** that would make this better, please fork the repo and create a pull request
|
||
*** or simply open an issue with the tag "enhancement".
|
||
*** Don't forget to give the project a star!
|
||
*** Thanks again! Now go create something AMAZING! :D
|
||
-->
|
||
|
||
|
||
<!-- PROJECT LOGO -->
|
||
<br />
|
||
<div align="center">
|
||
<!-- <a href="https://github.com/othneildrew/Best-README-Template"> -->
|
||
<img src="Logo-Futriix.png" height=100></img>
|
||
</a>
|
||
|
||
<h3 align="center">Futriix</h3>
|
||
|
||
<p align="center">
|
||
<b>Проект futriix это timeseries NOSQL субд без блокировок</b> <br>
|
||
<br />
|
||
<br />
|
||
<!-- <a href="">Сообщить об ошибке</a>
|
||
·
|
||
<!-- <a href="">Предложение новой функциональности</a> -->
|
||
</p>
|
||
</div>
|
||
|
||
## Краткая документация проекта Futriix
|
||
|
||
<!-- TABLE OF CONTENTS -->
|
||
<br>
|
||
<!-- <details> -->
|
||
<summary><b>Содержание</b></summary></br>
|
||
<ol>
|
||
<li>
|
||
<a href="#о-проекте">О проекте</a>
|
||
<li><a href="#лицензия">Лицензия</a></li>
|
||
<li><a href="#основные-термины">Основные термины</a></li>
|
||
<li><a href="#подготовка">Подготовка</a></li>
|
||
<li><a href="#компиляция">Компиляция</a></li>
|
||
<li><a href="#crud-команды-по-работе-с-временными-рядами">CRUD команды по работе с временными рядами</a></li>
|
||
<li><a href="#репликация">Репликация</a></li>
|
||
<li><a href="#резервное-копирование">Резервное копирование</a></li>
|
||
<li><a href="#http-api">HTTP API</a></li>
|
||
<li><a href="#lua-скрипты">Lua-скрипты</a></li>
|
||
<li><a href="#проблемы">Проблемы</a></li>
|
||
<li><a href="#дорожная-карта">Дорожная карта</a></li>
|
||
<li><a href="#вклад">Вклад</a></li>
|
||
<li><a href="#контакты">Контакты</a></li>
|
||
</ol>
|
||
<!-- </details> -->
|
||
|
||
<!-- ABOUT THE PROJECT -->
|
||
## О проекте
|
||
|
||
Futriix это time-series NOSQL субд без блокировок написанная на языке программирования Rust.
|
||
Поддерживает модель временных рядов (time series), в качестве основной модели.
|
||
Для расщирения базового функционала имеет встроенный lua-интепретатор.
|
||
При этом futriix является резидентной субд, т.е. хранящей свои данные в оперативной памяти, с их периодическим сохранением на внутренний носитель: HDD (жёсткий диск) или SSD-накопитель.
|
||
|
||
|
||
<!-- LICENSE -->
|
||
## Лицензия
|
||
|
||
Проект распространяется под 3-пунктной лицензией BSD. Подробнсти смотрите в файле `LICENSE.txt`.
|
||
|
||
## Основные термины
|
||
|
||
* **База Данных(БД)** -массив информация, хранящийся, например, на флешке, в файле, на кластере
|
||
* **Система Управления Базами Данных(СУБД)** - Это программа для внесения изменений в базу данных и поиска по ней
|
||
* **Временная метка (timestamp)**-Это метка времени, однозначно связывающая каждую запись в бд с конкретным моментом во времени. Если проводить аналогию с реляционными субд, то временнная метка это аналог термина **ключа** в реляционных субд.
|
||
* **Резидентная СУБД** - субд, хранящая все свои данные в оперативной памяти, с периодическим сохранением на HDD или SSD
|
||
* **Инстанс** - запущенный экземляр базы данных
|
||
* **Узел (хост,нода)** - физический сервер
|
||
* **Слайс(slice)** - аналог документа в любой документно-ориентированной субд
|
||
* **Репликасет** - группа актуальных данных,хранящиеся на нескольких узлах
|
||
* **Временные ряды (time series)** - это данные, последовательно собранные в регулярные промежутки времени, полученные из какого-либо устройства (цены на акции, данные температуры, объёмы продаж и.т.д.)
|
||
* **Кластер** - группа компьютеров, объединённых высокоскоростными каналами связи и представляющая с точки зрения пользователя единый аппаратный ресурс
|
||
* Команды, выполняемые с привилегиями суперпользователя (root), отмечены символом приглашения **«#»**
|
||
* Команды, выполняемые с правами обычного пользователя(user), отмечены символом приглашения **«$»**
|
||
* **FutBot** - интеллектуальный помощник в мессенджере Телеграмм, помогающий осущесвлять быстрый поиск по документации проекта
|
||
|
||
|
||
## Подготовка
|
||
|
||
**Для операционных систем семейства Debian** выполните следующие шаги:
|
||
* Устанавливаем язык программирования Rust
|
||
|
||
```sh
|
||
# apt update
|
||
# apt upgrade
|
||
# curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||
```
|
||
|
||
**Для операционных систем семейства Red Hat (Fedora, Aurora)** выполните следующие шаги:
|
||
* Устанавливаем язык программирования Rust
|
||
|
||
```sh
|
||
# dnf update
|
||
# curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||
```
|
||
|
||
**Для операционной системы Alpine** выполните следующие шаги:
|
||
* Устанавливаем язык программирования Rust
|
||
|
||
```sh
|
||
# apk update
|
||
# curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||
```
|
||
|
||
## Компиляция
|
||
|
||
1. Копируем репозиторий
|
||
```sh
|
||
$ git clone https://source.futriix.ru/gvsafronov/futriix
|
||
```
|
||
2. Переходим в каталог с исходном кодом src
|
||
```sh
|
||
$ cd futriix/
|
||
```
|
||
3. Компилируем Futriix с помощью пакетного менеджера `Cargo`
|
||
```sh
|
||
$ cargo build
|
||
```
|
||
4. Для запуска тестов запускаем команды:
|
||
```sh
|
||
$ cargo test --test integration # запуск только интеграционных тестов
|
||
$ cargo test --bench benches # запуск только бенчмарков
|
||
```
|
||
|
||
> [!WARNING]
|
||
> **Futriix также может быть скомпилирован для следующих операционных систем: `Linux`, `OSX`, `Open Indiana`, `FreeBSD`, но сборка для этих операционных систем не проводилась!!!**
|
||
|
||
<!-- USAGE EXAMPLES -->
|
||
## CRUD команды по работе с временными рядами
|
||
|
||
В данном разделе приведён пример основных команд субд Futriix
|
||
|
||
Запускаем клиент Futriix, перейдя в каталог с исходным кодом:
|
||
```sh
|
||
$ cd /target/realease && ./clif
|
||
```
|
||
|
||
Представьте себе, что вы работаете на метерологической станции, где ежедневно вам необходимо фиксировать показатели погоды: влажность, темпратуру воздуха (и.т.д.) давайте посмотрим, на данном примере, как мы могли бы добавить значение `температура (temperature)`в бд. Для этого, выполняем команду `insert`, следующим образом:
|
||
|
||
```sh
|
||
futriix:~> insert temperature 1672531200000 25.5
|
||
Insert successful
|
||
```
|
||
|
||
> [!TIP]
|
||
> **Поcле вставки данных в slice, сервер автоматически добавит временную метку, в нашем примере 1672531200000**
|
||
|
||
Как мы можем наблюдать ниже, сервером был получен ответ `successful`-это означает, что вставка данных (значение температуры) была внесена корректно.
|
||
|
||
```sh
|
||
futriix:~> insert humidity 1672531200000 {"value": 65, "unit": "%"}
|
||
Insert successful
|
||
|
||
```
|
||
|
||
Теперь давайте сделаем запрос на получение актуального значения с температурой (temperature) и влажностью (humidity) командой ниже `get`:
|
||
```sh
|
||
futriix:~> get temperature
|
||
[
|
||
[
|
||
1672531200000,
|
||
25.5
|
||
]
|
||
]
|
||
```
|
||
|
||
```sh
|
||
futriix:~> get humidity
|
||
[
|
||
[
|
||
1672531200000,
|
||
{
|
||
"unit": "%",
|
||
"value": 65
|
||
}
|
||
]
|
||
|
||
```
|
||
|
||
Получим диапазон в которых лежат средние значени температуры и влажности, указав оба эти значения (температуры и влажности), в качестве параметров к оператору `get`
|
||
```sh
|
||
futriix:~> get temperature 1672531200000 1672534800000
|
||
[
|
||
[
|
||
1672531200000,
|
||
25.5
|
||
]
|
||
]
|
||
]
|
||
|
||
|
||
```
|
||
Удалим оба значения
|
||
```sh
|
||
futriix:~> delete temperature 1672531200000 1672531200000
|
||
Delete successful
|
||
```
|
||
|
||
Посмотрим как работают транзакции (создание, откат, коммит)
|
||
```sh
|
||
futriix:~> begin
|
||
Transaction 1 started
|
||
|
||
futriix:tx1:~> insert pressure 1672531200000 1013
|
||
Insert successful
|
||
|
||
futriix:tx1:~> commit
|
||
Transaction 1 committed
|
||
```
|
||
|
||
**Выключение сервера через CLI**
|
||
|
||
Для того чтобы выключить сервер через CLI, используйте команду `shutdown` введя её в `clif`:
|
||
|
||
```sh
|
||
futriix:~> halt
|
||
Server shutdown initiated
|
||
```
|
||
|
||
<p align="right">(<a href="#readme-top">К началу</a>)</p>
|
||
|
||
## Репликация
|
||
|
||
1. Включите репликацию в конфигурационном файле `futriix.config.toml`, установив enabled = true в секции [replication] в файле конфигурации
|
||
`futriix.config.toml`
|
||
```sh
|
||
[replication]
|
||
enabled = false # Включена ли репликация
|
||
peer_nodes = [] # Список узлов для репликации (например ["192.168.1.2:8080"])
|
||
sync_interval = 1000 # Интервал синхронизации в мс
|
||
```
|
||
2. Откройте файл конфигурации `futriix.config.toml` в любом текстовом редакторе, например nano, если вы всё сделали правильно, он должен выглядеть так:
|
||
```sh
|
||
$ nano futriix/futriix.conf.toml
|
||
```
|
||
```sh
|
||
[server]
|
||
ip = "127.0.0.1" # IP-адрес сервера (0.0.0.0 для доступа из сети)
|
||
port = 8080 # Порт для TCP-сервера
|
||
log_path = "futriix.log" # Путь к лог-файлу
|
||
|
||
[client]
|
||
ip = "127.0.0.1" # IP для клиента (обычно localhost)
|
||
port = 8080 # Порт клиента (должен совпадать с серверным)
|
||
|
||
[replication]
|
||
enabled = false # Включена ли репликация
|
||
peer_nodes = [] # Список узлов для репликации (например ["192.168.1.2:8080"])
|
||
sync_interval = 1000 # Интервал синхронизации в мс
|
||
|
||
[http_api]
|
||
enabled = true # Включить HTTP API
|
||
port = 8081 # Порт для HTTP API (обычно на 1 больше основного)
|
||
|
||
```
|
||
4. Сохраните внесённые вами изменения, после чего репликация будет доступна в субд, выйдите из редактора, воспользовавшись командами ниже:
|
||
```sh
|
||
$ ctrl+O
|
||
$ ctrl+x
|
||
```
|
||
5. Также для включения репликации вы можете использовать команду в `futriix-cli`:
|
||
```sh
|
||
|
||
futriix:~> replication on
|
||
```
|
||
Сервер автоматически начнёт синхронизацию с указанными пирами (peer_nodes) с заданным интервалом (sync_interval).
|
||
|
||
После включения сервер будет периодически отправлять команды из истории (command_history) на все пиры для поддержания согласованности данных.
|
||
|
||
|
||
### Команды для управления репликацией
|
||
|
||
В проекте добавлены следующие команды для управления репликацией:
|
||
```sh
|
||
replication on — включить репликацию
|
||
replication off — выключить репликацию
|
||
replication status — получить статус репликации (включена/выключена, список пиров, время последней синхронизации)
|
||
replication add-peer <addr> — добавить пир для репликации (например, replication add-peer 127.0.0.1:8081)
|
||
replication remove-peer <addr> — удалить пир из списка репликации
|
||
```
|
||
|
||
|
||
## Резервное копирование
|
||
|
||
Для создания и восстановления из бекапа используются команды futload (восстановление из бэкапа) и futunload (создание бэкапа).
|
||
Вот примеры использования команд futload (восстановление из бэкапа) и futunload (создание бэкапа) в Futriix CLI:
|
||
|
||
futunload - Создание бэкапа
|
||
|
||
```sh
|
||
|
||
futunload <путь_к_файлу_бэкапа>
|
||
```
|
||
|
||
Пример 1: Создать бэкап в текущей директории
|
||
```sh
|
||
futunload ./backups/snapshot_2025.fut
|
||
|
||
Вывод при успехе:
|
||
text
|
||
|
||
Backup created successfully at ./backups/snapshot_2025.fut
|
||
```
|
||
|
||
Пример 2: Создать бэкап с абсолютным путём
|
||
|
||
```sh
|
||
futunload /var/backups/futriix/db_export.fut
|
||
```
|
||
|
||
2. futload - Восстановление из бэкапа
|
||
|
||
Формат команды:
|
||
bash
|
||
```sh
|
||
futload <путь_к_файлу_бэкапа>
|
||
```
|
||
|
||
Пример 1: Восстановить из локального файла
|
||
bash
|
||
```sh
|
||
futload ./backups/snapshot_2025.fut
|
||
|
||
Вывод при успехе:
|
||
text
|
||
|
||
Backup restored successfully from ./backups/snapshot_2024.fut
|
||
```
|
||
|
||
Пример 2: Восстановить из системного пути
|
||
```sh
|
||
futload /mnt/backups/prod_db.fut
|
||
|
||
```
|
||
|
||
<p align="right">(<a href="#readme-top">К началу</a>)</p>
|
||
|
||
|
||
## HTTP API
|
||
C помощью HTTP API можно быстро получить данные из субд по протоколу HTTPS, которые можно использовать в своём приложении, что называется "из коробки". Ниже приведены примеры для работы с HTTP API.
|
||
|
||
> [!WARNING]
|
||
> В данной реализации HTTP-API НЕ поддерживают аутентификацию и сложные операции (транзакции, репликация). Для использования сложых операций используйте TCP-клиент.
|
||
|
||
|
||
Добавление данных:
|
||
|
||
```sh
|
||
curl -X POST http://127.0.0.1:8081/api/insert \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"temperature": [1672531200000, 25.5],
|
||
"humidity": [1672531200000, {"value": 60, "unit": "%"}]
|
||
}'
|
||
```
|
||
|
||
**Ответ в случае успеха:**
|
||
|
||
```sh
|
||
{"status": "ok"}
|
||
```
|
||
|
||
Получение данных:
|
||
|
||
```sh
|
||
curl "http://127.0.0.1:8081/api/get/temperature/1672531200000/1672534800000"
|
||
```
|
||
|
||
**Ответ в случае успеха:**
|
||
|
||
```sh
|
||
[
|
||
[1672531200000, 25.5],
|
||
[1672531300000, 26.1]
|
||
]
|
||
```
|
||
|
||
Получение последнего значения:
|
||
|
||
```sh
|
||
curl "http://127.0.0.1:8081/api/latest/temperature"
|
||
```
|
||
|
||
**Ответ в случае успеха:**
|
||
|
||
```sh
|
||
[1672531300000, 26.1]
|
||
```
|
||
|
||
Удаление данных:
|
||
|
||
```sh
|
||
curl -X DELETE "http://127.0.0.1:8081/api/delete/temperature/1672531200000/1672531300000"
|
||
```
|
||
**Ответ в случае успеха:**
|
||
```sh
|
||
{"status": "ok"}
|
||
```
|
||
|
||
Пример Python-программы с использованием Http-API:
|
||
|
||
```sh
|
||
import requests
|
||
# Добавление данных
|
||
requests.post("http://127.0.0.1:8081/api/insert", json={
|
||
"cpu_load": [1672531200000, 0.75]
|
||
})
|
||
# Получение данных
|
||
response = requests.get("http://127.0.0.1:8081/api/latest/cpu_load")
|
||
print(response.json()) # [1672531200000, 0.75]
|
||
|
||
```
|
||
|
||
<p align="right">(<a href="#readme-top">К началу</a>)</p>
|
||
|
||
|
||
## Lua-скрипты
|
||
|
||
> [!CAUTION]
|
||
> **Поддержка работы lua в настоящий момент эксперементальная и может вызвать аварийное завершение сервера!!!**
|
||
|
||
1. Интерактивный режим работы, (выполнение скрипта в клиенте `futriix-cli`):
|
||
|
||
```sh
|
||
futriix:~> futexec
|
||
lua> return "Hello, " .. os.date("%Y-%m-%d")
|
||
```
|
||
|
||
2. Выполнение файлов скриптов (c помоью команды в клиенте `SysExec`):
|
||
|
||
```sh
|
||
futriix:~> sysexec my_script
|
||
|
||
````
|
||
|
||
3. Доступ к данным из сервера Lua на примера lua-скрипта для чтение и записи данных из субд
|
||
|
||
Скрипты имеют доступ к специальному API:
|
||
|
||
```sh
|
||
-- read.lua
|
||
-- Чтение данных
|
||
local value = futriix.get("my_key")
|
||
|
||
-- Запись данных
|
||
futriix.put("temp_key", {data = "test", ts = os.time()})
|
||
|
||
-- Пример сложной логики
|
||
for i = 1, 10 do
|
||
futriix.put("counter/"..i, i*2)
|
||
end
|
||
```
|
||
|
||
<p align="right">(<a href="#readme-top">К началу</a>)</p>
|
||
|
||
|
||
## Проблемы
|
||
|
||
В данном разделе описаны типовые проблемы, возникающие при эксплуатации субд Futrix.
|
||
|
||
1. **Описание проблемы:** После запуска futriix, в лог-файле `futriix.log` дата указывается без указания текущего года:
|
||
```sh
|
||
11:29:49 [INFO] Futriix Server started successfully
|
||
11:29:49 [INFO] Listening on: 127.0.0.1:8080
|
||
```
|
||
|
||
**Решение:**
|
||
```sh
|
||
На данный момент это выявленный программный баг, нужно ждать выпуска новой версии. :-))
|
||
```
|
||
|
||
<p align="right">(<a href="#readme-top">К началу</a>)</p>
|
||
|
||
<!-- ROADMAP -->
|
||
## Дорожная карта
|
||
|
||
- [x] Реализовать поддержку хранимых процедур
|
||
- [x] Реализовать поддержку многопоточности
|
||
- [x] Реализовать неблокирующие чтение/запись
|
||
- [x] Реализовать мульти-мастер асинхронную репликацию через файл конфигурации
|
||
- [x] Реализовать логирование
|
||
- [x] Реализовать команды сервера для управления репликацией
|
||
- [x] Реализовать поддержку первичных индексов
|
||
- [x] Реализовать поддержку протокола MessagePack
|
||
- [x] Реализовать поддержку транзакций
|
||
- [x] Добавить механизм сторонних модулей на языке lua, расширяющих базовый функционал сервера
|
||
- [x] Добавить макет интеллектуального помощника FutBot
|
||
- [x] Реализовать проверку запуска сервера при запуске клиента (если сервер НЕ запущен клиент не запускается)
|
||
- [x] Реализовать поддержку HTTP-restfull API
|
||
- [x] Исправить ошибки записи журнала логов (в журнал лога кроме текущего времени добавить текущий год)
|
||
- [ ] Реализовать утилиту тестирования сервера на количество запросов на чтение/запись
|
||
- [ ] Реализовать поддержку алгоритма Raft
|
||
- [ ] Реализовать поддержку SQL
|
||
- [ ] Реализовать поддержку вторичных индексов
|
||
- [ ] Реализовать полноценного интеллектуального помощника FutBot, задачами которого будут быстрый поиск ответов на вопросы, возникающие при эксплуатации субд Futrix.
|
||
|
||
См. [Открытые проблемы](https://source.futriix.ru/gvsafronov/futriixw/issues) полный список предлагаемых функций (и известных проблем).
|
||
|
||
<p align="right">(<a href="#readme-top">К началу</a>)</p>
|
||
|
||
<!-- CONTRIBUTING -->
|
||
|
||
|
||
|
||
<!-- CONTRIBUTING -->
|
||
## Вклад
|
||
|
||
Вклады — это то, что делает сообщество открытого исходного кода таким замечательным местом для обучения, вдохновения и творчества. Любой ваш вклад **очень ценится**.
|
||
|
||
Если у вас есть предложение, которое могло бы улучшить ситуацию, создайте форк репозитория и создайте запрос на включение. Также можно просто открыть задачу с тегом «улучшение».
|
||
|
||
|
||
1. Форкните проект
|
||
2. Создайте свою ветку функций (`git checkout -b Feature/AmazingFeature`)
|
||
3. Зафиксируйте свои изменения (git commit -m 'Add some AmazingFeature'`)
|
||
4. Отправьте в ветку (`git push main Feature/AmazingFeature`)
|
||
5. Откройте запрос на включение
|
||
|
||
<!-- CONTACT -->
|
||
## Контакты
|
||
|
||
Григорий Сафронов - [E-mail](gvsafronov@yandex.ru)
|
||
|
||
Ссылка на Интеллектуальный помощник - [FutBot](https://t.me/Futriix_bot)
|
||
|
||
<p align="right">(<a href="#readme-top">К началу</a>)</p>
|