Нереляционные базы данных и
как с этим жить опыт их использования на реальном проекте
2017, Кенжаев А.З.
Что такое "нереляционные базы даных"?
В чем отличие от реляционных?
Где их можно использовать и для чего?
Text
PostgreSQL.
Репликации и шардинг (хотя все равно все не слишком здорово), JSONB, крутая типизация, программы на стороне сервера и много чего еще
Clickhouse 🚀🚀🚀 (Yandex)
Столбцовая СУБД, крутое сжатие данных, обработка запроса параллельна на ядрах и распределена по серверам, хранение триллионов строк, обработка сотен миллионов строк в секунду и тд
Для чего:
Примеры: Berkeley DB, MemcacheDB, Redis, Riak, Amazon Dynamo, Tarantool
Для чего:
- большие данные
- распределенные базы данных
- масштабируемость
- сверхвысокая производительность
Примеры: Hadoop, Hypertable и Cassandra
Для чего:
- гибкая иерархическая структура данных
- необходимость репликации и шардинга
- производительность
Примеры: CouchDB, MongoDB
Для чего:
- сложные связанные структуры данных, графы
- например, для социальных сетей
Примеры: Neo4j, OrientDB
- Service Bus (Шина сервиса), очереди, события
- Secondary Storage (Дополнительное хранилище)
- Горячие данные
- Логи, счетчики, метрики, журналы
- и многое другое
Гарантированность выполнения
Отказоустойчивость
Масштабируемость горизонтально
Модульность
Необходимо разработать сервис-планировщик (Scheduler), который умеет хранить и выполнять задачи (таски) по заданному для каждой периоду времени, а также, соответственно, отдавать информацию таске, о статусе ее выполнения и уметь делать с информацией о задачах всякие штуки
export default {
taskSchema: {
_id: String,
request: Object,
schedule: String,
status: String,
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now },
},
};
/**
* Index of available task statuses
* @type {Object}
*/
export default {
running: 'running',
stopped: 'stopped',
done: 'done',
deleted: 'deleted',
outdated: 'outdated',
};
Схема:
ENUM статусов задачи:
0 5 * * * node ~/script.js -request {"method": "GET", url: "http://google.com"}
Отказоустойчивость
Масштабируемость горизонтально
Высокая производительность
Сервис обслуживает десятки (а в будущем сотни) тысяч камер, на которые отправляет запросы.
Найти блокеры и bottlenecks и устранить
Исходя из указанных предпосылок, вполне можно выбрать:
2. Мы должны гарантировать выполнение задач, и иметь возможность горизонтально масштабироваться
Наше приложение можно разбить на следующие сервисы:
- Relay Service. Предоставляет REST-API (endpoint) для работы с нашим сервисом.
- Scheduler Service. Отвечает за непосредственно планирование выполнения задач.
- Request Performer. Умеет отправлять HTTP-запросы
- Watcher. Следит за тем, чтобы все задачи действительно выполнялись.
Сервисная шина спешит на помощь.
- Все сервисы общаются только через нее. Это дает нам независимость сервисов друг от друга
- У каждого сервиса есть свой канал. Если мы хотим что-то сказать сервису, то нам достаточно "послать сообщение" в этот канал.
- Каждый сервис предоставляет из себя кластер из воркеров. Это дает
горизонтальную масштабируемость - расширяем кластер, добавляем новый воркер
отказоустойчивость. если кто-то упал, остальные продолжают работать и забирать сообщения
производительность. кто-то сильно занят - работу сделают другие
В свою очередь, шина должна быть
По сути, шина становится самой критичной точкой отказа и "боттлнеком" сервиса (не считая БД).
И очень бы хотелось спокойно спать по ночам :)
В качестве шины будем использовать еще одно NoSQL решение:
const waitForNewTask = () => redis
.brpop([redisChannel.newTasks, workerId], 0)
.then(([, message]) => {
handleTask(message);
waitForNewTask();
});
Ожидание задач от шины
export function send(command) {
if (getConnectionsTotal() < connectionsLimit) {
sendRequest(command);
} else {
redisPusher.lpush(
redisChannel.workerRequests,
JSON.stringify(command)
);
}
}
Отправка события в шину