Посмотрите исходный код flink, чтобы узнать состояние flink.

предисловие

Объясняя исходный код flink, давайте вместе войдем в мир flink.

Ниже приводится содержание текста этой статьи, а следующие случаи приведены
для справки.

  1. Посмотрите исходный код flink, чтобы узнать состояние flink.


состояние флинка

значительный

Apache Flink® — вычисления с отслеживанием состояния над потоками данных
Вычисления с отслеживанием состояния над потоками данных
https://flink.apache.org/

Зачем нужно государство?

● Отказоустойчивость
Пакетный расчет: нет, затем успех, затем пересчет.
Потоковые вычисления: механизм аварийного переключения
○ В большинстве сценариев это инкрементный расчет, и данные обрабатываются один за другим, и каждый расчет зависит от последнего результата расчета
○ Программная ошибка (машина, сеть, грязные данные) вызывает восстановление состояния из контрольная точка при перезапуске задания
● Отказоустойчивый механизм, точный отказоустойчивый механизм flink один раз. Непрерывно создавайте моментальные снимки распределенных потоков данных. Снимки легковесны и мало влияют на производительность. Состояние сохраняется в настраиваемой среде, на главном узле или в HDFS. В случае сбоя программы (машины, сети, программного обеспечения и т. д.) система перезапускает всех операторов и сбрасывается до последней успешной контрольной точки. Вход сбрасывается в соответствующую позицию моментального снимка состояния, чтобы гарантировать, что любая запись, обрабатываемая в перезапущенном параллельном потоке данных, не является частью состояния контрольной точки.
Чтобы отказоустойчивость работала, источник данных (очередь сообщений или брокер) должен иметь возможность воспроизводить поток данных. Например,
документ flink-kafka-connector: Облегченные асинхронные моментальные снимки для распределенных потоков данных https://arxiv.org/abs/1506.08603 описывает механизм создания моментальных снимков с помощью flink.
Статья основана на концептуальном алгоритме распределенного снимка для
контрольных точек и точек сохранения
: Точка сохраненияРезервное копирование в традиционную базу данных, CheckpointСпособы восстановления логов
● Flink отвечает за перераспределение состояния между параллельными инстансами
● водяной знак

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

● магазин элементов...

Что такое государство?

● Простое понимание:
данные потоковых вычислений мимолетны, а в реальных сценариях часто требуются предыдущие «данные», поэтому эти требуемые «данные» называются состоянием. Также называется статусом.

После того, как исходные данные поступают в пользовательский код, они выводятся в нисходящий поток.Если чтение и запись состояния задействованы в середине, эти состояния будут храниться в локальном бэкэнде состояния.
● Подробное объяснение:
состояние относится к промежуточному результату расчета или атрибуту метаданных узла расчета в процессе расчета потока.
Например:
○ Промежуточные результаты агрегации в процессе агрегации.
○ Смещение чтения записей в процессе потребления данных в Kafka.
○ Оператор включает любую форму состояния, и эти состояния должны быть включены в моментальный снимок.Существует множество форм состояния:
■ Определенное пользователем — состояние, непосредственно созданное или измененное с помощью функции преобразования, такой как map() или filter(). . Пользовательским состоянием может быть: простая переменная объекта Java в функции преобразования или состояние ключ/значение, связанное с функцией.
■ Состояние системы: это состояние относится к данным, кэшированным как часть вычислений оператора. Типичный пример: оконные буферы (window buffers), система собирает в него данные, соответствующие окну, до тех пор, пока окно не будет рассчитано и запущено.
Сводка: Моментальный снимок внутренних данных (вычислительных данных и атрибутов метаданных) задачи flink.

● Состояние обычно относится к состоянию конкретной задачи/оператора.
Контрольная точка представляет собой задание Flink, глобальный снимок состояния в определенный момент, который включает в себя состояние всех задач/операторов.
Механизм сохранения StateBackend (бэкэнд состояния), по умолчанию State будет сохраняться в памяти TaskManager, а CheckPoint будет храниться в памяти JobManager.
Место хранения State и CheckPoint зависит от конфигурации StateBackend. MemoryStateBackend на основе памяти, FsStateBackend на основе файловой системы, RocksDBState-Backend на основе носителя данных RockDB

определение состояния:

Согласно определению дескриптора состояния
объект StateTtlConfiguration передается дескриптору состояния для реализации очистки состояния.
● Определить ttl (срок жизни)
● Указать срок жизни
● Указать срок жизни...

государственная классификация:

● Принадлежит ли он определенному ключу
○ Состояние ключа: состояние сохранения keyedStream
○ Состояние оператора: нормальное состояние сохранения без ключа
● Управляется ли им flink
○ Необработанное состояние: управляется самим приложением
○ Состояние управления: управление flink
keyedState
здесь ключ, в котором мы находимся. Соответствующие поля в GroupBy/PartitioneBy в операторе SQL, значением ключа является массив байтов Row, состоящий из полей groupby/PartitionBy, каждый ключ имеет свое собственное состояние, а состояние между ключом и ключом невидимо ●
OperatorState
В реализации Source Connector внутри Flink OperatorState используется для записи смещения считанных исходных данных.

KeyedState Состояние оператора
Есть ли текущий обрабатываемый ключ (текущий ключ) никто Есть актуальный ключ
Находится ли объект хранения в куче Существует только одна реализация в куче Существует несколько реализаций on-heap и off-heap (RocksDB).
Нужно ли вручную объявлять снапшот (snapshot) и восстанавливать (restore) Ручная реализация Реализован самим бэкендом, прозрачен для пользователей
размер данных Обычно небольшой Обычно большой

Оператор делает снимок состояния барьера после того, как он получил все свои входные потоки и перед отправкой барьеров в свои выходные потоки. В этот момент данные перед барьером обновили состояние, и оно больше не будет зависеть от данных перед барьером. Поскольку моментальные снимки могут быть очень большими, внутреннюю систему хранения можно настраивать. По умолчанию хранится в памяти JobManager, но для производственной системы его необходимо настроить как надежную распределенную систему хранения (например, HDFS). После завершения сохранения состояния оператор подтвердит, что его контрольная точка завершена, и создаст барьер для последующего потока вывода.
  Снимок теперь содержит:
  1. Для параллельных источников входных данных: смещение положения в потоке данных при создании снимка
  2. Для оператора: указатель состояния, хранящийся в снимке
вставьте сюда описание изображения

создание состояния (запись):

● Flink оперирует кодом —> задачи одна за другой (в диспетчере задач) —> каждая задача содержит абстрактный класс AbstractInvokable —> основная функция задачи — вызвать AbstractInvokable.invoke() —> существует 5 реализаций этого абстрактного метод
вставьте сюда описание изображения
Streaming Все соответствующие реализации в обработке унаследованы от StreamTask —> абстрактный класс StreamTask содержит метод invoke() (около 150 строк кода) —> вызов интерфейса Runnable
в run()—>processInput(actionContext )–>inputProcessor.processInput(): метод завершает обработку входных данных пользователя (данные пользователя, водяной знак, данные контрольной точки) ----> streamOperator.processElement(record): streamOperator обрабатывает данные StreamOneInputProcessor—>streamOperator.processElement
вставьте сюда описание изображения
( запись);
вставьте сюда описание изображения
● StreamTask:
определяет полный жизненный цикл,

protected abstract void init() throws Exception;
private void run() throws Exception {
    
    };
protected void cleanup() throws Exception {
    
    };
protected void cancelTask() throws Exception {
    
    };

Пример: OneInputStreamTask (обработка ситуации ввода)
TaskManage---->запустить задачу----> Task->реализовать интерфейс Runnable run()---->dorun(): 320 строк кода, создать вызываемый объект (отражение -> получить класс -> получить конструктор -> создать экземпляр объекта)

private static AbstractInvokable loadAndInstantiateInvokable(
    ClassLoader classLoader, String className, Environment environment) throws Throwable {
    
    

    final Class<? extends AbstractInvokable> invokableClass;
    try {
    
    
        // 使用指定的classloader加载className对应的class,并转换为AbstractInvokable类型
        invokableClass =
            Class.forName(className, true, classLoader).asSubclass(AbstractInvokable.class);
    } catch (Throwable t) {
    
    
        throw new Exception("Could not load the task's invokable class.", t);
    }

    Constructor<? extends AbstractInvokable> statelessCtor;

    try {
    
    
        // 获取构造函数
        statelessCtor = invokableClass.getConstructor(Environment.class);
    } catch (NoSuchMethodException ee) {
    
    
        throw new FlinkException("Task misses proper constructor", ee);
    }

    // instantiate the class
    try {
    
    
        //noinspection ConstantConditions  --> cannot happen
        // 传入environment变量,创建出新的对象
        return statelessCtor.newInstance(environment);
    } catch (InvocationTargetException e) {
    
    
        // directly forward exceptions from the eager initialization
        throw e.getTargetException();
    } catch (Exception e) {
    
    
        throw new FlinkException("Could not instantiate the task's invokable class.", e);
    }
}

– вызвать ()
|
±—> Создать базовые утилиты (config и т. д.) и загрузить цепочку операторов
±—> operator.setup()
±—> конкретная задача init()
±—> initialize-operator-states() : initializeState();
±—> open-operators()
±—> run()
±—> close-operators()
±—> dispose-operators()
±—> общая очистка
±—> очистка для конкретной задачи()

● Модель многопоточности Flink StreamTask на основе MailBoxДавайте
сначала рассмотрим первоначальную мотивацию для этого преобразования/улучшения.В предыдущей модели многопоточности Flink будет несколько потенциальных потоков для одновременного доступа к ее внутреннему состоянию, таким как обработка событий и срабатывание контрольных точек, все они используют глобальную блокировку (блокировку контрольной точки) для обеспечения потокобезопасности Проблемы, вызванные этой схемой реализации, следующие: ○ Объект
блокировки будет передан в несколько классов, а читабельность кода относительно плохая
. ○ При использовании , если блокировка не получена, это может вызвать много проблем, что затрудняет обнаружение проблемы.Объект
блокировки также подвергается воздействию пользовательского API (см. SourceFunction#getCheckpointLock())
проектный документ MailBox:
вставьте сюда описание изображения

создать состояние

Передайте параметр абстрактного класса StateDescriptor -> 5 реализаций подкласса, вы можете видеть, что конечное состояние не ограничено типами состояний, operatorState и keyState

исходит из RichFunction, принадлежащего к базовому интерфейсу расширенных функций, и указывает RuntimeContext

public interface RichFunction extends Function {
    
    
    void open(Configuration parameters) throws Exception;
    void close() throws Exception;
    RuntimeContext getRuntimeContext();
    IterationRuntimeContext getIterationRuntimeContext();
    void setRuntimeContext(RuntimeContext t);
}

Интерфейс RuntimeContext —> абстрактный класс реализации AbstractRuntimeUDFContext —> класс реализации StreamingRuntimeContext
основан на StreamingRuntimeContext (другие классы реализации в конечном счете непротиворечивы), метод getState (ValueStateDescriptor stateProperties) врезается:

public <T> ValueState<T> getState(ValueStateDescriptor<T> stateProperties) {
    
    
      // 检查工作,判断是否为null,最终还是操作 keyedStateStore 这个属性,只是局部变量又拿了一次引用地址
      KeyedStateStore keyedStateStore = this.checkPreconditionsAndGetKeyedStateStore(stateProperties);
      //  对序列化器进行初始化
      stateProperties.initializeSerializerUnlessSet(this.getExecutionConfig());
      return keyedStateStore.getState(stateProperties);
    }
private KeyedStateStore checkPreconditionsAndGetKeyedStateStore(StateDescriptor<?, ?> stateDescriptor) {
    
    
      // 检查这个 stateDescriptor 不能为null,该参数是由最初一直传递至此  
      Preconditions.checkNotNull(stateDescriptor, "The state properties must not be null");
      // 该类自身的全局变量(属性、字段) keyedStateStore 不能为null
      Preconditions.checkNotNull(this.keyedStateStore, "Keyed state can only be used on a 'keyed stream', i.e., after a 'keyBy()' operation.");
        return this.keyedStateStore;
    }

Состояние с ключом можно использовать только в «потоке с ключом», т. е. после операции «keyBy()». Метод,
оцениваемый как null, часто упоминается внутри flink. StreamingRuntimeContext статически импортирует этот метод, поэтому его можно вызывать напрямую. Вы можете понять один раз:

public static <T> T checkNotNull(@Nullable T reference, @Nullable String errorMessage) {
    
    
        if (reference == null) {
    
    
            throw new NullPointerException(String.valueOf(errorMessage));
        } else {
    
    
            return reference;
        }
    }

На этом этапе следует отметить, что если свойство keyedStateStore самого StreamingRuntimeContext равно null, будет выдано исключение нулевого указателя, поэтому, как загрузить это свойство с отрицательным значением, функция этого свойства хорошо известна, и она связанные с хранением состояния.следующее исследование

Здесь есть ключевой момент. Конструктор этого класса принимает оператор AbstractStreamOperator<?>, а поле keyedStateStore инициализируется как operator.getKeyedStateStore(). Отсюда можно сделать вывод. Получение состояния и оператор (Operator , например карта, плоская карта) связана,

@VisibleForTesting
    public StreamingRuntimeContext(AbstractStreamOperator<?> operator, Environment env, Map<String, Accumulator<?, ?>> accumulators) {
    
    
        this(env, accumulators, operator.getMetricGroup(), operator.getOperatorID(), operator.getProcessingTimeService(), operator.getKeyedStateStore(), env.getExternalResourceInfoProvider());
    }

    public StreamingRuntimeContext(Environment env, Map<String, Accumulator<?, ?>> accumulators, MetricGroup operatorMetricGroup, OperatorID operatorID, ProcessingTimeService processingTimeService, @Nullable KeyedStateStore keyedStateStore, ExternalResourceInfoProvider externalResourceInfoProvider) {
    
    
        super(((Environment)Preconditions.checkNotNull(env)).getTaskInfo(), env.getUserCodeClassLoader(), env.getExecutionConfig(), accumulators, env.getDistributedCacheEntries(), operatorMetricGroup);
        this.taskEnvironment = env;
        this.streamConfig = new StreamConfig(env.getTaskConfiguration());
        this.operatorUniqueID = ((OperatorID)Preconditions.checkNotNull(operatorID)).toString();
        this.processingTimeService = processingTimeService;
        this.keyedStateStore = keyedStateStore;
        this.externalResourceInfoProvider = externalResourceInfoProvider;
    }


keyedStateStore эквивалентен operator.getKeyedStateStore(), и оператор создает AbstractStreamOperator с помощью оператора AbstractStreamOperator<?>

public final void initializeState(StreamTaskStateInitializer streamTaskStateManager) throws Exception {
    
    
        TypeSerializer<?> keySerializer = this.config.getStateKeySerializer(this.getUserCodeClassloader());
        StreamTask<?, ?> containingTask = (StreamTask)Preconditions.checkNotNull(this.getContainingTask());
        CloseableRegistry streamTaskCloseableRegistry = (CloseableRegistry)Preconditions.checkNotNull(containingTask.getCancelables());
        StreamOperatorStateContext context = streamTaskStateManager.streamOperatorStateContext(this.getOperatorID(), this.getClass().getSimpleName(), this.getProcessingTimeService(), this, keySerializer, streamTaskCloseableRegistry, this.metrics, this.config.getManagedMemoryFractionOperatorUseCaseOfSlot(ManagedMemoryUseCase.STATE_BACKEND, this.runtimeContext.getTaskManagerRuntimeInfo().getConfiguration(), this.runtimeContext.getUserCodeClassLoader()), this.isUsingCustomRawKeyedState());
        this.stateHandler = new StreamOperatorStateHandler(context, this.getExecutionConfig(), streamTaskCloseableRegistry);
        this.timeServiceManager = context.internalTimerServiceManager();
        this.stateHandler.initializeOperatorState(this);
 // 这里 setKeyedStateStore 就是给 StreamingRuntimeContext.keyedStateStore 修改值
  this.runtimeContext.setKeyedStateStore((KeyedStateStore)this.stateHandler.getKeyedStateStore().orElse((Object)null));
    }

keyedStateStore —> создается StreamOperatorStateHandler

public StreamOperatorStateHandler(StreamOperatorStateContext context, ExecutionConfig executionConfig, CloseableRegistry closeableRegistry) {
    
    
        this.context = context;
        this.operatorStateBackend = context.operatorStateBackend();
        this.keyedStateBackend = context.keyedStateBackend();
        this.closeableRegistry = closeableRegistry;
        if (this.keyedStateBackend != null) {
    
    
          // 创建了keyedStateStore
            this.keyedStateStore = new DefaultKeyedStateStore(this.keyedStateBackend, executionConfig);
        } else {
    
    
            this.keyedStateStore = null;
        }
    }

Резюме: То есть бэкэнд состояния не существует, то есть генерируется дефолт, и он первый раз пустой.
Вам может быть интересно узнать, когда кем был вызван InitializeState.
Это происходит из цепочки операторов. Flink объединит несколько операторов, соответствующих условиям, в цепочку операторов (OperatorChain). Затем при планировании задача фактически выполняет цепочку операторов. Когда существует несколько степеней параллелизма, каждая из нескольких задач выполняет
абстрактный родительский класс OperatorChain AbstractInvokable----> абстрактный подкласс StreamTask->invoke()->initializeState(); openAllOperators();
initializeState();

private void initializeState() throws Exception {
    
    
		StreamOperator<?>[] allOperators = operatorChain.getAllOperators();
		for (StreamOperator<?> operator : allOperators) {
    
    
			if (null != operator) {
    
    
				operator.initializeState();
			}
		}
	}

открытьВсеОператоры();

private void openAllOperators() throws Exception {
    
    
		for (StreamOperator<?> operator : operatorChain.getAllOperators()) {
    
    
			if (operator != null) {
    
    
				operator.open();
			}
		}
	}

stateProperties.initializeSerializerUnlessSet(getExecutionConfig());
Этот вызов функции действительно пришел в StateDescriptor. Я видел, что все состояния являются его подклассами.
Смысл аннотации к методу: инициализировать сериализатор, если он не был инициализирован ранее

//描述值类型的类型信息。只有在序列化器是惰性创建时才使用。
private TypeInformation<T> typeInfo;
//类型的序列化器。可能在构造函数中被急切地初始化,或者被惰性地初始化一次
public boolean isSerializerInitialized() {
    
    
		return serializerAtomicReference.get() != null;
	}
public void initializeSerializerUnlessSet(ExecutionConfig executionConfig) {
    
    
  // 先判断这个序列化器是否已经被创建,这个类代码比较简单,如下看看就好,
  // 如上看到调用默认构造器,则该对象的value字段为null,第一次代码到这里必定为null
		if (serializerAtomicReference.get() == null) {
    
    
      // 判断 typeInfo 是否为null,下面有代码剖析构造器这块
			checkState(typeInfo != null, "no serializer and no type info");
      // 尝试实例化和设置序列化器,这里是使用类型来创建序列化器,可以看到该处逻辑每执行一次就会创建一个序列化器
			TypeSerializer<T> serializer = typeInfo.createSerializer(executionConfig);
			// use cas to assure the singleton
      // 使用cas来保证单例,此处就是创建核心, compareAndSet 下面剖析
			if (!serializerAtomicReference.compareAndSet(null, serializer)) {
    
    
				LOG.debug("Someone else beat us at initializing the serializer.");
			}
		}
	}

состояние чистое

Зачем нужна государственная очистка?

● Своевременность состояния: действует в течение определенного периода времени, по прошествии определенного момента времени оно не имеет прикладной ценности
● Управление размером состояния перехода: управление постоянно растущим размером состояния

Как определить состояние очистки?

Flink1.6 представляет функцию State TTL. Разработчик настраивает время истечения срока действия и очищает его после определения тайм-аута (Time to Live).Объект StateTtlConfiguration
передается в дескриптор состояния для реализации очистки состояния.
Непрерывно очищайте исторические данные RocksDB и серверную часть состояния кучи (FSStateBackend и MemoryStateBackend), чтобы реализовать непрерывную очистку просроченного состояния
Пример кода

public class StateDemo {
    
    
    public static void main(String[] args) throws Exception {
    
    
        LocalStreamEnvironment env = StreamExecutionEnvironment.createLocalEnvironment();
        // this can be used in a streaming program like this (assuming we have a StreamExecutionEnvironment env)
        env.fromElements(Tuple2.of(1L, 3L), Tuple2.of(1L, 5L), Tuple2.of(1L, 10L), Tuple2.of(1L, 4L), Tuple2.of(1L, 2L))
                .keyBy(0)
                .flatMap(new MyFlatMapFunction())
                .print();

        // the printed output will be (1,4) and (1,5)
        env.execute();
    }
}

class MyFlatMapFunction extends RichFlatMapFunction<Tuple2<Long, Long>, Tuple2<Long, Long>> {
    
    

    private static final long serialVersionUID = 1808329479322205953L;
    /**
     * The ValueState handle. The first field is the count, the second field a running sum.
     */
    private transient ValueState<Tuple2<Long, Long>> sum;

    // 状态过期清除
    // flink 的状态清理是惰性策略,也就是我们访问的状态,可能已经过期了,但是还没有删除状态数据,我们可以配置
    // 是否返回过期状态的数据,不论是否返回过期数据,数据被访问后会立即清除过期状态。并且截止1.8.0 的版本
    // 状态的清除针对的是process time ,还不支持event time,可能在后期的版本中会支持。

    // flink的内部,状态ttl 功能是通过上次相关状态访问的附加时间戳和实际状态值来实现的,这样的方案会增加存储
    // 上的开销,但是会允许flink程序在查询数据,cp的时候访问数据的过期状态
    StateTtlConfig ttlConfig =
            StateTtlConfig.newBuilder(Time.days(1)) //它是生存时间值
                    .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
                    //状态可见性配置是否在读取访问时返回过期值
//            .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
                    .cleanupFullSnapshot() // 在快照的时候进行删除
                    .build();


    @Override
    public void flatMap(Tuple2<Long, Long> input, Collector<Tuple2<Long, Long>> out) throws Exception {
    
    

        // access the state value
        Tuple2<Long, Long> currentSum = sum.value();

        // update the count
        currentSum.f0 += 1;

        // add the second field of the input value
        currentSum.f1 += input.f1;

        // update the state
        sum.update(currentSum);

        // if the count reaches 2, emit the average and clear the state
        if (currentSum.f0 >= 2) {
    
    
            out.collect(new Tuple2<>(input.f0, currentSum.f1 / currentSum.f0));
            sum.clear();
        }
    }

    @Override
    public void open(Configuration config) {
    
    
        ValueStateDescriptor<Tuple2<Long, Long>> descriptor =
                new ValueStateDescriptor<>(
                        "average", // the state name
                        TypeInformation.of(new TypeHint<Tuple2<Long, Long>>() {
    
    
                        }), // type information
                        Tuple2.of(0L, 0L)); // default value of the state, if nothing was set

        //设置stage过期时间
        descriptor.enableTimeToLive(ttlConfig);
        sum = getRuntimeContext().getState(descriptor);
    }
}

основной код

StateTtlConfig ttlConfig =
            StateTtlConfig.newBuilder(Time.days(1)) //它是生存时间值
                    .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
                    //状态可见性配置是否在读取访问时返回过期值
                    .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
                    .setTtlTimeCharacteristic(StateTtlConfig.TtlTimeCharacteristic.ProcessingTime)
                    .cleanupFullSnapshot() // 在快照的时候进行删除
                    .build();

вполне 1,9

private StateTtlConfig(
		UpdateType updateType,
		StateVisibility stateVisibility,
		TtlTimeCharacteristic ttlTimeCharacteristic,
		Time ttl,
		CleanupStrategies cleanupStrategies) {
    
    
		this.updateType = checkNotNull(updateType);
		this.stateVisibility = checkNotNull(stateVisibility);
		this.ttlTimeCharacteristic = checkNotNull(ttlTimeCharacteristic);
		this.ttl = checkNotNull(ttl);
		this.cleanupStrategies = cleanupStrategies;
		checkArgument(ttl.toMilliseconds() > 0, "TTL is expected to be positive.");
	}

● .newBuilder()
: указывает время истечения срока действия. После установки отметка времени последнего доступа + TTL превышает текущее время, и срок действия отметки истекает.
Реализация:
https://ci.apache.org/projects/flink/flink- docs-master /api/java/org/apache/flink/runtime/state/ttl/class-use/TtlTimeProvider.html
● .setUpdateType() Вы можете видеть, что исходный код
setUpdateType (StateTtLConfig.UpdateType.OnCreateAndWrite)
указывает время обновление метки времени состояния, является объектом Enum.
○ Отключено, указывает, что временная метка не будет обновляться;
○ OnCreateAndWrite, указывает, что временная метка будет обновляться при каждом создании или записи состояния;
○ OnReadAndWrite, помимо обновления временной метки при создании и записи состояния, чтение также будет метка времени обновленного состояния.
● .setStateVisibility()
указывает, как поступать с истекшим, но не очищенным состоянием, а также является объектом Enum.
○ ReturnExpiredlfNotCleanedUp, даже если отметка времени этого состояния указывает на то, что оно истекло, оно будет возвращено вызывающей стороне, если оно не было фактически очищено; ○ NeverReturnExpired, по истечении
этого состояния оно никогда не будет возвращено вызывающей стороне Вызывающий объект вернет только пустое состояние, избегая помех, вызванных состоянием с истекшим сроком действия.
● .setTtlTimeCharacteristic(StateTtlConfig.TtlTimeCharacteristic.ProcessingTime)
TimeCharacteristic и TtlTimeCharacteristic: указывают режим времени, применимый к функции State TTL, которая по-прежнему является объектом Enum.
Первый был помечен как устаревший (заброшенный), и рекомендуется, чтобы новый код принимал новый параметр TtlTimeCharacteristic.
Начиная с Flink 1.8, в качестве режима времени поддерживается только ProcessingTime, а поддержка State TTL для режима EventTime все еще находится в стадии разработки. (См. 1.9 также поддерживает только ProcessingTime)
Концепция времени Flink
вставьте сюда описание изображения
○ EventTime: время создания события
○ Время обработки: локальное системное время, когда данные передаются каждому оператору операции, основанному на времени, по умолчанию
○ Ingestion Time: время, когда данные поступают на flink
.cleanupFullSnapshot() : Посмотрите на исходный код
Указывает стратегию очистки объектов с истекшим сроком действия В настоящее время существует три значения Enum.
○ FULL_STATE_SCAN_SNAPSHOT: соответствует классу EmptyCleanupStrategy, что означает, что просроченное состояние не будет активно очищаться.При выполнении полного снимка (Snapshot/Checkpoint) будет создан файл состояния меньшего размера, но локальное состояние не будет уменьшено . Только когда задание будет перезапущено и восстановлено из последней точки моментального снимка, локальное состояние действительно уменьшится, поэтому нехватка памяти все еще может быть не решена.
Чтобы решить проблему нехватки памяти, Flink также предоставляет значение перечисления для поэтапной очистки.Flink можно настроить на выполнение операции очистки каждый раз, когда считываются несколько записей, и вы можете указать, сколько недействительных записей следует очищать каждый раз: ○ INCREMENTAL_CLEANUP
: для Heap StateBackend
○ ROCKSDB_COMPACTION_FILTER (1.9 устарела) Для RocksDB StateBackend очистка состояния RocksDB реализуется путем вызова FlinkCompactionFilter, написанного на языке C++, через JNI.
Часто задаваемые вопросы:
● Доступны ли данные о прошлом статусе?
Очистка истечения срока действия, очистка состояния flink является инертной стратегией, то есть состояние, которое мы посещаем, могло быть просрочено, но данные состояния не были удалены.Мы можем настроить, возвращать ли данные в состоянии с истекшим сроком действия, независимо от того, истек ли срок действия данные возвращаются, доступ к данным осуществляется. Состояние с истекшим сроком действия очищается сразу после этого.
Внутри Flink функция TTL состояния реализована путем сохранения дополнительной метки времени последнего соответствующего доступа к состоянию вместе с фактическим значением состояния. Хотя этот подход увеличивает нагрузку на хранилище, он позволяет программам Flink получать доступ к просроченному состоянию данных при запросе данных, создании контрольных точек и восстановлении данных.
Стоит отметить:
а начиная с версии 1.8.0 очистка статуса идет на время обработки, а время события пока не поддерживается, пользователи могут только определить TTL статуса по времени обработки (Processing Time). Будущие версии Apache Flink планируют поддерживать время события (Event Time)
● Как избежать чтения устаревших данных?
При доступе к объекту состояния в операции чтения Flink проверит его метку времени и очистит состояние, если оно просрочено (в зависимости от настроенной видимости состояния, следует ли возвращать состояние с истекшим сроком действия). Из-за этой функции отложенного удаления устаревшие данные состояния, к которым больше никогда не будет доступа, навсегда займут место в хранилище, если только они не будут удалены сборщиком мусора.
Так как же удалить просроченное состояние без явной обработки логики приложения? Обычно мы можем настроить различные стратегии для удаления фона.
○ Полный моментальный снимок автоматически удаляет состояние с истекшим сроком действия
○ Инкрементная очистка серверной части состояния кучи
○ Фоновое уплотнение RocksDB может отфильтровывать состояние с истекшим сроком действия
○ Использовать таймер для удаления (таймеры)

Реализация хранилища состояний?

Как Flink сохраняет данные о состоянии, существует интерфейс StateBackend—>абстрактный класс AbstractStateBackend, который имеет 3 реализации
MemoryStateBackend, HeapStateBackend на основе памяти
используется в режиме отладки, не рекомендуется для режима производства
FsStateBackend на основе HDFS
Распределенное сохранение файлов, память эксплуатируется каждый раз при чтении и записи необходимо учитывать проблему OOM
● RocksDBStateBackend на основе
локальных файлов RocksDB + удаленное сохранение HDFS
По умолчанию используется StateBackendLoader, который загружает RocksDBStateBackend

Хранимая процедура состояния

два этапа

  1. Сначала хранить локально в RocksDB
  2. Цель асинхронной синхронизации с удаленной HDFS
    : не только устраняет ограничения HeapStateBackend (размер памяти, сбой и потеря машины и т. д.), но и снижает накладные расходы сетевого ввода-вывода чистого распределенного хранилища.

Подведем итог

Это все на сегодня.

Supongo que te gusta

Origin blog.csdn.net/qq_42859864/article/details/120656364
Recomendado
Clasificación