1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/anur-kanashi

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

Kanashi 0.0.1-Альфа


Kanashi — это распределенная NoSQL база данных с памятью, основанная на Kotlin и поддерживающая транзакции. В точности говоря, она предназначена для углубленного изучения автором распределённых систем и не является конкурентом существующих зрелых баз данных. Kanashi использует Netty для связи и реализацию выборки через Raft, что можно рассматривать как встроенное грубое решение NameServer. Функции синхронизации журнала были адаптированы от Kafka. Кроме того, Kanashi поддерживает транзакции, но пока только уровень изоляции Repeatable Read.

В нестрогих тестах производительности было выявлено следующее:

  • Локальная запись журналов на сервере вместе с анализом журналов движком данных достигает около 300 000 операций в секунду (Intel(R) i7-8700 + SAMSUNG 860 EVO).
  • Вызов клиентом сервера на одном узле может достичь до 6 000 операций в секунду.
  • При вызове клиентом серверной группы (три машины) количество запросов составляет примерно 10 в секунду.Это не связано с низкой эффективностью координации между узлами, а скорее из-за использования модели pull для синхронизации журналов, где каждому действию требуется согласие более чем половины узлов для завершения записи, фиксации и уведомления о состоянии. Процесс начинается с синхронизации журналов, затем переходит к отчету о прогрессе, далее к групповой записи и заканчивается отметкой лидера о завершении записи. Для клиента этот процесс представляет собой линейную последовательность шагов.Однако для нескольких клиентов они могут работать параллельно и независимо друг от друга. Мы можем предположить, что при множестве клиентов общая производительность системы будет выше. Однако это также полностью демонстрирует недостаточность текущего подхода к обеспечению сильной консистентности данных и проблемы с дизайном клиента.

Дополнительно:

Проект Kanashi был создан на основе предыдущего проекта автора — фреймворка Hanabi, который был значительно улучшен.

Сейчас весь проект достаточно развит, так что его можно быстро преобразовать в другой тип фреймворков, таких как RPC фреймворк или распределённый планировщик задач.


1. Быстрый старт

1.1 Сервер

Настройте сервер, конфигурация которого находится в модуле kanashi-server в файле kanashi.properties:

#
# Установите имя сервера, будьте осторожны: имя сервера должно быть указано в client.addr
#
server.name=kanashi.1
#
# Конфигурация адреса состоит из client.addr.{serverName}={host}:{port}
#
client.addr.kanashi.1=127.0.0.1:11001
client.addr.kanashi.2=127.0.0.1:11002
client.addr.kanashi.3=127.0.0.1:11003

Вы можете использовать client.addr.{serverName}={host}:{port} для настройки информации о кластере, однако динамическое масштабирование узлов пока не поддерживается. server.name объявляет текущий узел как конкретный узел в сети. Однако это не обязательно должно быть указано в конфигурационном файле; его можно указать при запуске с помощью параметра server_name:kanashi.1.pic1-server

1.2 Клиентская часть

Клиентская часть пока очень проста и может быть запущена через импорт kanashi-client или непосредственно внутри kanashi-client. Для клиентской части требуется конфигурация в файле application.properties, расположенном в модуле kanashi-client. Конфигурация должна выглядеть следующим образом:

kanashi.host=127.0.0.1
kanashi.port=11001
kanashi.resend.backoff.ms=30

Используйте KanashiStrTemplate для отправки команд на сервер:


@Autowired
private KanashiStrTemplate kanashiStrTemplate;

@Test
public void test() {

    kanashiStrTemplate.delete("Anur");
    assert (kanashiStrTemplate.get("Anur") == null);

    kanashiStrTemplate.set("Anur", "1");
    assert (kanashiStrTemplate.get("Anur").equals("1"));

    kanashiStrTemplate.setIf("Anur", "2", "2");
    assert (kanashiStrTemplate.get("Anur").equals("1"));
}

Дополнительные примеры тестирования можно найти в файлах TestWithNonTrx, TestWithTrx, TestWritingAmountOfMsg.

Второй раздел: Описание проекта

Проект Kanashi состоит из шести основных модулей: модуль выбора лидерства, модуль журнала, модуль IOC, модуль данных, бизнес-модуль и конфигурационный модуль.

1.1 Модуль выбора лидерстваМодуль выбора лидерства является наиболее развитым модулем в рамках проекта и основан на алгоритме Raft. Ядром этого алгоритма являются несколько таймеров: таймер для перехода в состояние Candidate и инициализации нового цикла голосования, таймер для проведения голосования, таймер для отправки heartbeat-сообщений. Во время этапа выбора лидерства вся система становится недоступной до тех пор, пока новый лидер не будет выбран в новом цикле (Epoch, в проекте также называется Generation). После этого слушатель активирует событие, которое сообщает другим модулям о том, что новый лидер выбран.#### 1.2 Модуль журнала

Модуль журнала был адаптирован от Kafka и использует последовательную запись на диск для записи журналов. Одним журналом управляет объект LogItem. При записи на диск используется информация о смещении плюс объект LogItem. Набор журналов определённого размера (который можно указать в конфигурации) записывается в файл .log. Имя файла формируется на основе смещения первой записи в журнале.

Каждому файлу .log соответствует файл .index — индексный файл. Индексный файл использует разреженный индекс, который регистрирует относительное положение каждой записи в файле после записи определённого объёма данных. Когда кластер принимает решение о подтверждении определённого прогресса, все логи, старше этого прогресса, будут записаны на диск. Услуги, которые ещё не получили этот прогресс, могут синхронизироваться через запрос Fetch. Сообщение синхронизации будет отправлено в сеть непосредственно из логов на диске с использованием технологии нулевой копии.

1.3 Модуль IOC

Проект реализует простое внедрение:

/**
 * Created by Anur IjuoKaruKas on July 8, 2019
 *
 * Метаданные, связанные с выборами, хранятся здесь
 */
@NigateBean
public class ElectionMetaService {

    @NigateInject
    private final InetSocketAddressConfiguration inetSocketAddressConfiguration;

    @NigateInject
    private final LogService logService;
}
``````markdown
    @NigateInject
    private final NigateListenerService kanashiListenerService;

    private static final Logger logger = LoggerFactory.getLogger(ElectionMetaService.class);

    /**
     * После запуска загружаем сохраненный ранее прогресс GAO обратно в память
     */
    @NigatePostConstruct(dependsOn = "logService")
    public void init() {
        InitialGAO initialGAO = logService.getInitialGAO();
        generation = initialGAO.generation;
        offset = initialGAO.offset;
    }
}

С помощью аннотации @NigateBean мы объявляем экземпляр как bean, который можно внедрять в других beans с помощью аннотации @NigateInject. Также поддерживаются такие возможности, как PostConstruct, Listener и другие.

Хотя проект и небольшой, но он имеет все необходимые компоненты. Это основное отличие от проекта Hanabi. Хотя язык Kotlin позволяет легко реализовать паттерн Singleton, чтобы реализовать дополнительные функции, такие как слушатель событий или управление жизненным циклом, потребуется много усилий по поддержанию чистого кода.

1.4 Модуль данных и бизнес-модуль

Модуль данных был разработан недавно, его архитектурный дизайн удовлетворяет требования, модуль хорошо упакован и практически полностью декупирован от остальных модулей.

Модуль данных можно рассматривать как потребитель объектов журнала LogItem. В нем используются паттерны цепочки ответственности для выполнения операций чтения и записи. Для обеспечения изоляции данные разделены на три части: «неотправленные», «отправленные» и «часть LSM». ```Изначально было планирование полной реализации данных на уровне диска и построения дерева LSM. Однако эта задача требует значительных трудозатрат, поэтому работа над ней была приостановлена. Также требуется учет таких факторов, как распределение области, страницы и блока на диске. Кроме того, следует учитывать производительность, например, использование булевых фильтров для предотвращения бесполезных запросов. Сторона транзакций использует битовые карты для общего представления состояния транзакций, что также полезно для создания "снимка" всех транзакций базы данных.

Бизнес-модуль в основном представляет собой простое сочетание и вызов модулей движка данных:

StrApiTypeEnum.SELECT -> {
    engineDataQueryer.doQuery(engineExecutor, {
        if (it != null && !it.isDelete()) {
            engineExecutor.getEngineResult().setKanashiEntry(it);
        }
        engineExecutor.shotSuccess();
    }, false);
}

Интересной особенностью является управление блокировками транзакций:

fun acquire(trxId: Long, key: String, whatEverDo: () -> Unit) {
    // Создаем или получаем ранее зарегистрированную транзакцию и регистрируем владение этим ключом
    val trxHolder = trxHolderMap.compute(trxId) { _, th -> th ?: TrxHolder(trxId) }!!.also { it.holdKeys.add(key) };

    // Сначала встаем в очередь
    val waitQueue = lockKeeper.compute(key) { _, ll ->
        (ll ?: LinkedList()).also { if (!it.contains(trxId)) it.add(trxId) };
    }!!
```    когда (очередьОжидания.first()) {
        // Это означает, что ключ не заблокирован
        trxId -> {
            чтоКонечноДелаешь.invoke()
            logger.trace("Транзакция $trxId успешно приобрела или заново вошла в блокировку ключа $key и успешно выполнила операцию")
        }
    }```markdown
## Блокировка ключа

```kotlin
// This means that the key is locked
else -> {
    trxHolder.undoEvent.compute(key) { _, undoList ->
        (undoList ?: mutableListOf()).also { it.add(whatEverDo) }
    }
    logger.debug("Transaction $trxId cannot obtain a lock on key $key, will wait for notification from previous transaction and postpone operation execution")
}

Код написан в функциональном стиле, где выполняемые бизнес-действия выделены в отдельную функцию. Если блокировка была получена, то достаточно просто вызвать эту функцию; если нет, то она помещается в отображении для "ожидания уведомления", что позволяет избежать реального блокирования и снизить затраты на переключение потока из-за блокировки ключа.

### 1.5 Конфигурационный модуль

Код конфигурационного модуля был написан примерно год назад. В настоящее время многие настраиваемые места являются "магическими числами", записанными напрямую, реализация довольно простая, а приоритет совершенства невелик.
```### 3. Требования по исправлению или решению проблем — Кластерный режим менее стабилен в модуле данных по сравнению с одиночной конфигурацией, недостаточно протестирован
- Недостаток тестирования кластерного режима несколькими клиентами
- Отсутствие тестирования одиночного режима нескольким клиентам
- Жесткий дизайн соединения клиента с кластером и получения информации о нем
- Иногда возникают проблемы с чтением лог-файлов при неправильно настроенной грациозной остановке
- Необходим механизм принудительного завершения транзакций в случае превышения времени ожидания
- Возможна проблема конкурентного доступа к объекту `TrxHolder`, который хранит снимок транзакции; вероятность этого крайне мала и трудна для воспроизведения

### 4. ДругоеЕсли вас интересует проект или вы хотите вместе поработать над этими странными вещами, присоединяйтесь к группе, там в данный момент практически нет людей: [1035435027](https://vk.com/public1035435027)

![kanashi](https://images.gitee.com/uploads/images/2020/0405/161140_9dd61ee4_1460144.png)

Для обсуждения Java-технологий можно присоединиться к другой группе: [767271344](https://vk.com/public767271344)

![QR-код](https://images.gitee.com/uploads/images/2020/0405/161207_31fb2c55_1460144.png)

Кроме того, ищу работу = =, опыт работы 3 года — Java-backend, мое резюме:

[http://anur.ink/upload/2020/4/JAVA%E5%90%8E%E7%AB%AF-3%E5%B9%B4-%E7%BD%91%E7%BB%9F%E7%89%88-4ea872fb596f4553aa9f04cefcb65a84.pdf](http://anur.ink/upload/2020/4/JAVA%E5%90%8E%E7%AB%AF-3%E5%B9%B4-%E7%BD%91%E7%BB%9F%E7%89%88-4ea872fb596f4553aa9f04cefcb65a84.pdf)

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Описание недоступно Развернуть Свернуть
MIT
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/anur-kanashi.git
git@api.gitlife.ru:oschina-mirror/anur-kanashi.git
oschina-mirror
anur-kanashi
anur-kanashi
master