Использование программного компонента#

Пример использования плагина безопасности DataGrid#

У плагина безопасности, входящего в поставку DataGrid, имеется открытый API.

Этот API представлен в виде java-класса SecurityDataManager. Данный класс читает и вносит изменения в distributed metastorage (распределенное хранилище метаданных). Это касается тех записей, которые относятся к пользователям и ролям. Именно на его основе строится администрирование пользователей и прав.

API работает следующим образом:

  1. Сущность IgniteClient подключается к кластеру с правами администратора безопасности.

  2. После подключения IgniteClient пользователь сможет выполнять различные действия, например, добавлять пользователей (addUser) или изменять пароль (changePassword).

Разработчик может подключить данный интерфейс к своему приложению, взяв из Nexus артефакт com.sbt.security.ignite:ignite-security-plugin:(ise-version), где ise-version — это версия DataGrid.

После этого, класс SecurityDataManager будет доступен для использования.

Механизм Read repair#

Внимание!

Экспериментальная функциональность.

Введение#

Read repair — это механизм проверки и восстановления согласованности данных между основной (primary) и резервными (backup) копиями партиции во время обычных операций чтения. В режиме Read repair DataGrid сравнивает значения определенного ключа (ключей) во всех копиях партиции.

Механизм Read repair применяется для восстановления согласованности данных в случае, если другие средства восстановления согласованности (восстановление из снепшота, восстановление из лога транзакции, восстановление из прикладной логики и т. д.) оказались неэффективны.

Примечание

При использовании механизма Read repair чтение производится со всех резервных копий данных, поэтому операции чтения становятся в ~2 раза более дорогостоящими. В связи с этим использовать механизм Read repair постоянно не рекомендуется.

По способу работы механизм напоминает утилиту idle_verify. Однако отличается тем, что idle_verify лишь обнаруживает несогласованность данных, а Read repair, используемый утилитой control.sh, обнаруживает каждый случай несогласованности данных, записывает его в общий лог либо в специальный файл consistency.log и исправляет несогласованность.

Ограничения#

Проверка согласованности не подходит для использования со следующими кешами:

  • кеши с backup factor = 0;

  • NEAR-кеши;

  • кеши, использующие стратегию read-through.

Отдельный лог-файл#

Отдельный лог-файл (например, consistency.log) содержит в себе информацию о каждом случае несогласованности (о каждом проблемном ключе).

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

Схема работы механизма#

Для включения механизма Read repair необходимо получить экземпляр кеша, в котором включена функция Read repair следующим образом:

IgniteCache<Object, Object> cache =
    ignite.cache("<cache-name>").withReadRepair(ReadRepairStrategy.<strategy>);

Object value = cache.get(<key>);

где:

  • <cache-name> — имя кеша;

  • <strategy> — стратегия восстановления;

  • <key> — ключ, по которому запрашиваются данные.

Стратегии восстановления согласованности#

В случае обнаружения нарушений согласованности значения по всей топологии будут заменены восстановленными значениями в соответствии с выбранной стратегией.

Стратегии восстановления согласованности описаны в документе «Руководство по системному администрированию», раздел «Сценарии администрирования», подраздел «Стратегии проверки и восстановления согласованности данных».

События#

При обнаружении несогласованности данных в любой из копий партиции Platform V Data Grid генерирует событие нарушения согласованности EVT_CONSISTENCY_VIOLATION при условии, что генерация событий включена в конфигурации (подробнее о событии см. официальную документацию Apache Ignite или документ «Справочник Java API DataGrid»).

Такие события можно прослушивать и получать уведомления о проблемах согласованности (подробнее о работе с событиями см. официальную документацию Apache Ignite).

Read repair для транзакционных кешей#

Проверка и устранение несогласованности данных для транзакционных кешей происходит:

  • автоматически: для транзакций в оптимистическом режиме (TransactionConcurrency.OPTIMISTIC) ИЛИ транзакций с уровнем изоляции READ_COMMITTED (TransactionIsolation.READ_COMMITTED);

  • в фазе фиксации (commit()): для транзакций в пессимистическом режиме (TransactionConcurrency.PESSIMISTIC) И с уровнем изоляции, отличным от READ_COMMITTED (TransactionIsolation.READ_COMMITTED).

Внимание

Механизм Read repair не гарантирует проверку всех копий партиции в случае, если значение уже закешировано в транзакции. Например, при использовании уровня изоляции, отличного от READ_COMMITTED, если значение уже прочитано, либо совершена операция записи, то будет получено закешированное значение.

Read repair для атомарных кешей#

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

Внимание

  • Из-за природы атомарного кеша могут наблюдаться ложноположительные результаты. Например, попытка проверить согласованность данных при загрузке кеша может привести к исключению о нарушении согласованности.

  • По умолчанию реализация совершает три попытки проверки заданного ключа. Количество попыток можно изменить с помощью свойства IgniteSystemProperties.IGNITE_NEAR_GET_MAX_REMAPS.

Промежуточное ПО для сервисов#

DataGrid позволяет пользователям применять собственную логику промежуточного ПО для своих сервисов и предоставляет следующую функциональность:

  1. Возможность скрытой передачи пользовательских неизменяемых параметров от прокси к сервису. Данная функциональность схожа с функциональностью заголовков HTTP-запросов.

  2. Возможность определения пользовательского перехватчика (interceptor) вызовов методов сервиса.

Контекст вызова сервиса#

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

Пользователь может создавать контекст и привязывать его к прокси сервиса. После этого, каждый вызов метода прокси будет скрыто передавать параметры контекста сервису:

Java

    try (Ignite ignite = Ignition.start()) {
         ignite.services().deployClusterSingleton("EchoService", new EchoServiceImpl());
        // Создаем контекст.
        ServiceCallContext johnCtx = ServiceCallContext.builder().put("user", "John").build();
        ServiceCallContext maryCtx = ServiceCallContext.builder().put("user", "Mary").build();
        // Привязываем контекст к прокси.
        EchoService johnProxy = ignite.services().serviceProxy("EchoService", EchoService.class, false, johnCtx);
        EchoService maryProxy = ignite.services().serviceProxy("EchoService", EchoService.class, false, maryCtx);
        // Следующий вызов напечатает "Hello John!".
        System.out.println(johnProxy.hello());
        // Следующий вызов напечатает "Hello Mary!".
        System.out.println(maryProxy.hello());
    }

C#/.NET

var ignite = Ignition.Start();

    ignite.GetServices().DeployNodeSingleton("EchoService", new EchoService());

    // Создаем контекст.
    IServiceCallContext johnCtx = new ServiceCallContextBuilder().Set("user", "John").Build();
    IServiceCallContext maryCtx = new ServiceCallContextBuilder().Set("user", "Mary").Build();

    // Привязываем контекст к прокси.
    IEchoService johnProxy = ignite.GetServices().GetServiceProxy<IEchoService>("EchoService", false, johnCtx);
    IEchoService maryProxy = ignite.GetServices().GetServiceProxy<IEchoService>("EchoService", false, maryCtx);

    // Следующий вызов напечатает "Hello John!".
    Console.WriteLine(johnProxy.Hello());

    // Следующий вызов напечатает "Hello Mary!".
    Console.WriteLine(maryProxy.Hello());

Пользователь может прочитать контекст вызова (call context) с помощью метода currentCallContext класса ServiceContext:

  • Java

        @ServiceContextResource
        private ServiceContext ctx;
    
        /** {@inheritDoc} */
        @Override public String hello() {
            ServiceCallContext callCtx = ctx.currentCallContext();
    
            String proxyUser = callCtx != null ? callCtx.attribute("user") : null;
    
            return String.format("Hello %s!", (proxyUser == null || proxyUser.isEmpty() ? "anonymous" : proxyUser));
        }
    
  • C#/.NET

    public class EchoService : IEchoService
    {
        private IServiceContext _context;
    
        public void Init(IServiceContext context)
        {
            _context = context;
        }
    
        // ...
    
        public string Hello()
        {
            IServiceCallContext callCtx = _context.CurrentCallContext();
    
            String proxyUser = callCtx != null ? callCtx.GetAttribute("user") : null;
    
            return "Hello " + (proxyUser == null ? "anonymous" : proxyUser) + "!";
        }
    }
    

Примечание

Контекст вызова сервиса доступен только из текущего потока во время исполнения метода сервиса.

Перехватчик сервисов (Service Interceptor)#

Функционал Service Interceptor позволяет пользователям перехватывать вызовы методов любого сервиса, кроме методов, относящихся к жизненному циклу сервиса (init(), execute() и cancel()).

В классе конфигурации ServiceConfiguration вы можете задать один или несколько таких перехватчиков. Эти перехватчики развертываются вместе с сервисом и используют тот же загрузчик классов.

Каждый предыдущий перехватчик приводит в действие следующий перехватчик в цепи, используя делегированный вызов. Последний перехватчик в цепи вызывает метод сервиса. Таким образом, перехватчик, обозначенный первым в конфигурации, последним обрабатывает результат выполнения метода сервиса.

Внимание

Некорректная реализация перехватчика может привести к непредсказуемому поведению сервиса при его исполнении.

Пример создания перехватчика#

В данном разделе приводится пример создания перехватчика вызовов сервиса:

  • Java

        public class EchoServiceAccessInterceptor implements ServiceCallInterceptor {
            /** {@inheritDoc} */
            @Override public Object invoke(String mtd, Object[] args, ServiceContext ctx, Callable<Object> next) throws Exception {
                ServiceCallContext callCtx = ctx.currentCallContext();
    
                if (callCtx == null || callCtx.attribute("user") == null)
                    throw new SecurityException("Anonymous access is restricted.");
    
                return next.call();
            }
        }
    
  • C#/.NET

    public class EchoServiceAccessInterceptor : IServiceCallInterceptor {
        /** <inheritdoc /> */
        public object Invoke(string mtd, object[] args, IServiceContext ctx, Func<object> next)
        {
            IServiceCallContext callCtx = ctx.CurrentCallContext;
    
            if (callCtx == null || callCtx.GetAttribute("user") == null)
                throw new SecurityException("Anonymous access is restricted.");
    
            return next.Invoke();
        }
    }
    

Статистика производительности (Performance statistics)#

DataGrid включает в себя встроенный инструмент профилирования кластера.

Вы можете собирать статистику производительности с кластера и создавать отчеты о производительности.

Сбор статистики производительности#

Для сбора статистики производительности используются:

  1. Интерфейс JMX:

    Метод

    Описание

    start()

    Начать сбор статистики по кластеру

    stop()

    Остановить сбор статистики по кластеру

    rotate()

    Произвести ротацию файлов статистики в кластере

    started()

    true, если сбор статистики начат

  2. Утилита control.sh:

    Метод

    Описание

    start

    Начать сбор статистики по кластеру

    stop

    Остановить сбор статистики по кластеру

    rotate

    Произвести ротацию файлов статистики в кластере

    status

    Получить статус сбора статистики по кластеру

Каждый узел собирает статистику производительности в бинарном файле. Этот файл размещается в рабочей директории DataGrid по пути Platform-v-datagrid-work-directory/perf_stat. Для имени используется следующая маска: node-{nodeId}-{index}.prf.

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

Узлы используют циклический off-heap-буфер для временного хранения сериализованной статистики. Записывающий поток отправляет содержимое буфера в файл при достижении порога. Если буфер переполняется из-за медленного диска, некоторые показатели в статистике пропускаются. Для настройки обратитесь к разделу «Системные свойства» ниже.

Каждый процесс сбора статистики создает на узлах новый файл. Каждый следующий файл имеет такое имя, как у предыдущего, но с соответствующим индексом, например:

  • node-faedc6c9-3542-4610-ae10-4ff7e0600000.prf;

  • node-faedc6c9-3542-4610-ae10-4ff7e0600000-1.prf;

  • node-faedc6c9-3542-4610-ae10-4ff7e0600000-2.prf.

Создание отчета#

DataGrid предоставляет инструмент для генерации отчета из файлов статистики производительности. Инструмент является расширением для DataGrid и находится в каталоге utils под именем performance-statistics-ext.

Для создания отчета:

  1. Остановите сбор статистики, и поместите файлы со всех узлов в пустой каталог. Например:

    /path_to_files/
        ├── node-162c7147-fef8-4ea2-bd25-8653c41fc7fa.prf
        ├── node-7b8a7c5c-f3b7-46c3-90da-e66103c00001.prf
        └── node-faedc6c9-3542-4610-ae10-4ff7e0600000.prf
    
  2. Запустите скрипт из поставки:

    performance-statistics-tool/build-report.sh path_to_files
    

Отчет о производительности создается в новом каталоге по пути файлов статистики производительности:

path_to_files/report_yyyy-MM-dd_HH-mm-ss/

Для отображения отчета откройте в браузере страницу report_yyyy-MM-dd_HH-mm-ss/index.html.

Системные свойства#

Свойство

Тип

Значение по умолчанию

Описание

IGNITE_PERF_STAT_FILE_MAX_SIZE

Long

32 Гб

Максимальный размер файла статистики производительности в байтах. Сбор статистики производительности прекращается при превышении максимального размера файла

IGNITE_PERF_STAT_BUFFER_SIZE

Integer

32 Мб

Размер off-heap-буфера статистики производительности в байтах

IGNITE_PERF_STAT_FLUSH_SIZE

Integer

8 Мб

Минимальный размер пакета данных статистики производительности для отправления в файл в байтах

IGNITE_PERF_STAT_CACHED_STRINGS_THRESHOLD

Integer

1024

Порог закешированных строк статистики производительности. Кеширование строк прекращается при превышении порога

Настройки для аудита событий#

Для настройки аудита событий необходимо:

  1. Добавить RestProcessorPluginProvider в список плагинов.

  2. Включить события RestEventType.EVT_REST_REQ_SUCCEEDED и RestEventType.EVT_REST_REQ_FAILED в IgniteConfiguration. Пример:

    <bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration" primary="true">
        ...
        <property name="pluginProviders">
            <list>
                ...
                <ref bean="restProcPlugin"/>
            </list>
        </property>
    
        <property name="includeEventTypes" ref="eventTypes"/>
        ...
        </bean>
    
    <bean id="restProcPlugin" class="com.sbt.security.ignite.core.rest.RestProcessorPluginProvider">
            <property name="configuration">
                <bean id="restProcPluginConfiguration" class="com.sbt.security.ignite.core.rest.RestProcessorPluginConfiguration"/>
            </property>
    </bean>
    
    <util:list id="eventTypes" value-type="java.lang.Integer">
        ...
        <util:constant static-field="com.sbt.security.ignite.core.events.RestEventType.EVT_REST_REQ_SUCCEEDED"/>
        <util:constant static-field="com.sbt.security.ignite.core.events.RestEventType.EVT_REST_REQ_FAILED"/>
        ...
    </util:list>