Semántica temporal de Flink y explicación detallada de los ejemplos de Wartermark

1: Elicitación de la semántica del tiempo

Cuando hablamos de la semántica del tiempo, mencionamos un pequeño caso. En nuestra vida diaria, inevitablemente jugaremos juegos para matar el tiempo en el camino hacia y desde el trabajo en el metro. Suponiendo que cierto juego está configurado para pasar varios niveles en un minuto. Puntos de bonificación para algunos niveles, Zhang San ya había pasado 3 niveles 45 segundos antes del inicio del juego, pero después de 45 segundos el metro entró en el túnel de la montaña y no había señal, pero conectó 5 niveles. dentro de los 35 segundos del túnel. Después de 35 segundos del túnel, el metro sale del túnel y la red vuelve a la normalidad. En este momento, los datos en la caché se envían al servidor. Porque no hay señal en el túnel de montaña durante este período, la información conectada a las 5 puertas no es aceptada por el servidor a tiempo. Por lo tanto, la regla de dar n puntos si pasas n niveles dentro de 1 minuto establecida por el grupo del juego es un problema aquí. De acuerdo con las reglas del grupo del juego, aunque Zhang San borró el nivel durante el tiempo del túnel, I El servidor no tengo un registro de tu autorización, pero por un lado, para Zhang San, aunque no pasé 5 niveles en los 15 segundos restantes, al menos he pasado 5 niveles con la señal de tiempo antes, por lo que el juego El partido debe formular una regla muy completa, de lo contrario reducirá en gran medida la experiencia del usuario con el producto. Por lo tanto, el caso pequeño anterior conduce a la semántica de tiempo en nuestro Flink.

Inserte la descripción de la imagen aquí

1.1 Definición de semántica del tiempo

En el procesamiento de transmisiones, el tiempo es un concepto fundamental. Cómo estipular que los datos correspondientes ingresen en diferentes ventanas de acuerdo con la hora es el tema más importante. El procesamiento de transmisiones de Flink admite diferentes conceptos de tiempo, como se muestra a continuación Como se muestra en la figura:

Inserte la descripción de la imagen aquí

Hora del evento:

是事件创建的时间。它通常由事件中的时间戳描述,例如采集的日志数据中,每一条日志都会记录自己的生成时间,Flink通过时间戳分配器访问事件时间戳。

Tiempo de ingestión:

Ingestion Time是事件到达Flink Souce的时间。从Source到下游各个算子中间可能有很多计算环节,任何一个算子的处理速度快慢可能影响到下游算子的Processing Time。而Ingestion Time定义的是数据流最早进入Flink的时间,因此不会被算子处理速度影响。

Tiempo de procesamiento:

是每一个执行基于时间操作的算子的本地系统时间,与机器相关,默认的时间属性就是Processing Time。

1.2 Las ventajas y desventajas de la semántica de tres tiempos:

Hora del evento:

一个基于Event Time的Flink程序中必须定义Event Time,以及如何生成Watermark。我们可以使用元素中自带的时间,也可以在元素到达Flink后人为给Event Time赋值,使用Event Time的优势是结果的可预测性(可类比上述的玩游戏事件),缺点是缓存较大,增加了延迟,且调试和定位问题更复杂。

Nota: En el procesamiento de transmisión de Flink, la mayoría de las empresas usarán eventTime. Generalmente, solo cuando eventTime no esté disponible, se verán obligados a usar ProcessingTime o IngestionTime.

Tiempo de ingestión:

Ingestion Time通常是Event Time和Processing Time之间的一个折中方案。比起Event Time,Ingestion Time可以不需要设置复杂的Watermark,因此也不需要太多缓存,延迟较低。比起Processing Time,Ingestion Time的时间是Souce赋值的,一个事件在整个处理过程从头至尾都使用这个时间,而且后续算子不受前序算子处理速度的影响,计算结果相对准确一些,但计算成本稍高。

Tiempo de procesamiento:

Processing Time只依赖当前执行机器的系统时钟,不需要依赖Watermark,无需缓存。Processing Time是实现起来非常简单也是延迟最小的一种时间语义,但是我们一般都很少用到Processing Time此种时间语义。

1.3 Acerca de la introducción de EventTime:

La introducción de EventTime es muy simple, simplemente llame al método setStreamTimeCharacteristic después de crear el entorno.

val env = StreamExecutionEnvironment.getExecutionEnvironment
// 从调用时刻开始给env创建的每一个stream追加时间特征
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)

2: Marca de guerra

2.1 Marca de guerra derivada de condiciones no ideales:

Sabemos que el procesamiento de flujo tiene un proceso y un tiempo desde la generación del evento, hasta que fluye a través de la fuente y luego al operador. Aunque en la mayoría de los casos, los datos que fluyen al operador vienen en el orden de tiempo en que se genera el evento, pero Tampoco descarta la ocurrencia de desorden debido a la red, distribución, etc. El llamado desorden significa que el orden de los eventos recibidos por Flink no está estrictamente de acuerdo con el orden de la hora del evento del evento.

Inserte la descripción de la imagen aquí

Entonces hay un problema en este momento. Una vez que hay desorden, si solo determinamos el funcionamiento de la ventana en función de eventTime, no podemos saber si todos los datos están en su lugar, pero no podemos esperar indefinidamente. En este momento, debe Ser un mecanismo para asegurar un After time específico, la ventana debe activarse para realizar cálculos Este mecanismo especial es Watermark.

2.2 Descripción general de la marca de guerra:

1. La marca de agua es un mecanismo para medir el progreso del tiempo del evento.
2. La marca de agua se utiliza para manejar eventos fuera de orden, y el manejo correcto de eventos fuera de orden generalmente se realiza combinando el mecanismo de marca de agua con la ventana .
3. La marca de agua en el flujo de datos se utiliza para indicar que han llegado los datos cuya marca de tiempo es menor que la marca de agua, por lo que la ejecución de la ventana también es disparada por la marca de agua.
4. La marca de agua puede entenderse como un mecanismo de activación retardada. Podemos establecer el tiempo de retardo de la marca de agua t. Cada vez que el sistema verificará el máximo maxEventTime entre los datos que han llegado, y luego determinará que todos los datos cuyo eventTime sea menor que maxEventTime -t han llegado Si el tiempo de parada de una ventana es igual a maxEventTime-t, entonces esta ventana se activa para ejecutarse .

2.3 Características de Wartermark

Inserte la descripción de la imagen aquí

1. Una marca de agua es un registro de datos especial, que es esencialmente una marca de tiempo, y se transmite indiscriminadamente como datos comerciales. El propósito es medir el progreso del tiempo del evento.

2. La marca de agua debe aumentar de manera monótona para garantizar que el reloj de tiempo del evento de la tarea avance hacia adelante, no
hacia atrás.

3.La marca de agua está relacionada con la marca de tiempo de los datos

2.4 Marca de guerra gráfica

Inserte la descripción de la imagen aquí

Nota: Marca de agua es el "tiempo de cierre de la ventana" de la ventana anterior activada. Una vez que la puerta está cerrada, todos los datos dentro del rango de la ventana basados ​​en la hora actual se incluirán en la ventana.
Mientras no se alcance el nivel del agua, no importa cuánto avance el tiempo real, la ventana no se activará para cerrarse.

2.5 Introducción de Wartermark

Para la introducción de la marca de agua, la capa inferior de Flink nos ha ayudado a encapsular una gran cantidad de contenido. Solo necesitamos establecer la semántica de tiempo (establecida en EventTime), llamar al método assignTimestampsAndWatermarks y luego implementar la interfaz TimestampAssigner (también puede llamar asignarAscendingTimestamps, datos ascendentes directamente Extraiga la marca de tiempo, los datos secuenciales en el estado ideal usa este método, porque hay problemas como el retraso de la red en la vida real, por lo que este método rara vez se usa en general)

val env = StreamExecutionEnvironment.getExecutionEnvironment
    env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)//时间语义设置为EnevtTime,默认为ProcessingTime

dataStream.assignTimestampsAndWatermarks( new BoundedOutOfOrdernessTimestampExtractor[thermometer](Time.milliseconds(50)) {
    
    
  override def extractTimestamp(element: thermometer): Long = {
    
    
    element.timestamp * 1000L  //
  }
} )

Donde Time.milliseconds (50) es el tiempo de retraso T en el WaterMark anterior, aquí está el diagrama de herencia de la interfaz TimestampAssigner

Inserte la descripción de la imagen aquí

2.6 Prueba de ventana basada en semántica de tiempo

import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.assigners.{
    
    EventTimeSessionWindows, SlidingEventTimeWindows, TumblingEventTimeWindows}
import org.apache.flink.streaming.api.windowing.time.Time


case class thermometer(id : String ,time : Long,Temp : Double)
//温度计样例类

object Time_window {
    
    
  def main(args: Array[String]): Unit = {
    
    

    val env = StreamExecutionEnvironment.getExecutionEnvironment
    env.setParallelism(1)
    env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)//时间语义设置为EnevtTime,默认为ProcessingTime
    env.getConfig.setAutoWatermarkInterval(50)

    //从socket文本流中读取数据
    val inputStream = env.socketTextStream("hadoop102",7777)

    // 先转换成样例类类型
    val dataStream = inputStream
      .map( data => {
    
    
        val arr = data.split(",")
        thermometer(arr(0), arr(1).toLong, arr(2).toDouble)
      } )
     // .assignAscendingTimestamps(_.time * 1000L)    // 升序数据提取时间戳,理想状态下的顺序数据使用此种方法,此方法不需要定义
      //WaterMark,因为WaterMark直接采用的是数据进来时的时间戳

      .assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor[thermometer](Time.seconds(3)) {
    
    
        override def extractTimestamp(element: thermometer): Long = element.time.toLong * 1000L
      })

    val latetag = new OutputTag[(String, Double, Long)]("late")

    val res = dataStream
      .map(data => (data.id,data.Temp,data.time))
      .keyBy(_._1)   //按照id进行分组
//      .window(TumblingEventTimeWindows.of(Time.seconds(15)))  底层滚动窗口的实现
//      .window(SlidingEventTimeWindows.of(Time.seconds(15),Time.milliseconds(3))) //底层滑动窗口的实现
//      .window(EventTimeSessionWindows.withGap(Time.seconds(15)))  会话窗口
//      .countWindow(10)  滚动计数窗口
//      .countWindow(10,2) 滑动计数窗口
      .timeWindow(Time.seconds(10))  //使用Flink为我们封装好的滑动或者滚动窗口的实现方法
      .allowedLateness(Time.minutes(1)) //允许迟到1minute的数据
      .sideOutputLateData(latetag)

      .reduce((currdata,newdata)=>(currdata._1,currdata._2.min(newdata._2),newdata._3))  //每10s求出当前时间下各个温度计的最小值

    res.getSideOutput(latetag).print("late")
    res.print("result")


    env.execute("EventTime_Tumblingwindow test")

  }
}

Datos del termómetro utilizados en la prueba

1,1609745003,10.6
1,1609745004,8.2
1,1609745010,25.6
4,1609745003,24.7
5,1609745005,18.4
1,1609745013,7.2
1,1609745006,1.2
1,1609745014,35.4
1,1609745015,17.4
1,1609745023,22.9
1,1609745007,1.6
1,1609745100,7.0

Inserte la descripción de la imagen aquí

A partir de los datos de entrada actuales, se puede ver que el rango de la ventana es [0,10), y el WaterMark correspondiente cuando la marca de tiempo es 013 es exactamente 10. En este momento, se activan los datos en los segmentos 0-10 para procesar.

Inserte la descripción de la imagen aquí

De acuerdo con la ventana anterior, el rango de la ventana actual es [10, 20). Cuando la marca de tiempo es 023, se activa el cálculo de los datos 10-20 en el depósito. Para las ventanas 10-20, la temperatura más baja es 7.2 correspondiente a la marca de tiempo 013. Para las ventanas 0 a 10, en este momento, cuando ha salido el resultado de la operación de agregación anterior, vuelven a aparecer los datos de marca de tiempo de 006. Debido a que lo configuramos en el código, la allowedLateness(Time.minutes(1)) //允许迟到1minute的数据temperatura mínima actual de la ventana 0 a 10 se convierte en 1.2. La marca de tiempo se cambia correspondientemente a la última marca de tiempo de acuerdo con el código.

Inserte la descripción de la imagen aquí

Para las ventanas 0 a 10, aunque la marca de tiempo en la ventana anterior se inserta en este momento, debido a que la temperatura de 1.6 no es tan baja como el mínimo anterior de 1.2, la temperatura mínima sigue siendo 1.2 en este momento, pero la hora actual El sello ha cambiado a la última hora Poke 007.

Supongo que te gusta

Origin blog.csdn.net/weixin_44080445/article/details/112131990
Recomendado
Clasificación