Flink零基础学习笔记:基础概念

Posted 2022努力学习每一天

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flink零基础学习笔记:基础概念相关的知识,希望对你有一定的参考价值。

一、Apache Flink的定义、架构和原理

Apache Flink是一个分布式大数据处理引擎,可以对有限数据流无限数据流进行有状态无状态的计算,能够部署在各种集群环境,对各种规模大小的数据以内存速度进行快速计算

接下来我们介绍一下这些关键词的意义。

处理无界和有界数据

任何数据都能形成一种事件流。信用卡交易、传感器测量、机器日志、网站或移动应用程序上的用户交互记录,所有这些数据都形成一种流。

数据可以被定义为无界或者有界流来处理。

  1. 无界流 定义流的开始,但是没有定义流的结束。它们会无休止地产生数据。无界流的数据必须持续处理,即数据被摄取后需要立刻处理。我们不能等到所有数据都到达再处理,因为输入是无限的,在任何时候输入都不会完成。处理无界数据通常要求以特定的顺序摄取事件,例如事件的发生顺序,以便能够推断结果的完整性。
  2. 有界流 定义流的开始,也定义流的结束。有界流可以在摄取所有数据之后进行计算。有界流的所有数据可以被排序,所以并不需要有序摄取。有界流处理通常被称为批处理

部署到任意地方

Apache Flink是一个分布式系统,它需要计算资源来执行应用程序。Flink集成了所有常见的集群资源管理器,例如Hadoop YARN、Apache Mesos和Kubernetes,但同时也可以作为独立集群运行。

Flink能够在上述每个资源管理器中很好地工作,这是通过资源管理器特定(resource-manager-specific)的部署模式实现的。Flink可以采用与当前资源管理器相适应的方式进行交互。

部署Flink程序时,Flink会根据应用程序配置的并行性自动标识所需的资源,并从资源管理器请求这些资源。在发生故障的情况下,Flink通过请求新的资源来替换发生故障的容器,这种自动故障恢复机制确保了Flink应用程序的高可用性。提交或控制应用程序的所有通信都是通过REST调用进行的,这可以简化Flink与各种环境中的集成。

REST(Representational State Transfer),即表述性状态转移。它要求每个资源都有一个唯一的标识符URI,通过HTTP协议提供一组操作来访问和操作资源。提交或控制Flink应用程序的所有通信都是通过REST调用进行的,这使得Flink与各种环境中的集成变得更加容易。例如,你可以通过REST调用从脚本或其他应用程序启动Flink应用程序,或者通过REST API监视和控制正在运行的应用程序。

总之,Flink的自动资源管理和自动故障恢复机制以及REST接口提供了一种高效、灵活和易于集成的方式来部署和管理Flink应用程序。

运行任意规模应用

Flink旨在任意规模上运行有状态流的应用。因此,应用程序被并行化为可能数千个任务,这些任务分布在集群中并发执行。从而应用程序能够充分利用集群中的CPU、内存、磁盘和网络IO。而且Flink很容易维护非常大的应用程序状态。而且Flink很容易维护非常大的应用程序状态。其异步和增量的检查点算法对处理延迟产生最小的影响,同时保证精确的一次状态的一致性。这使得Flink可以轻松处理大规模数据集,并且可以快速恢复到应用程序发生故障之前的状态。Flink 是一个高度可扩展且具有强大状态管理功能的流式计算框架,可以在各种规模的数据集上高效地运行。

  • 每天处理数万亿事件
  • 应用维护几TB大小的状态
  • 应用在数千个内核上运行

利用内存性能

有状态的Flink程序针对本地状态访问进行了优化,以提高处理延迟并保证状态一致性。任务的状态始终保留在内存中,以便快速访问和计算。如果状态大小超过可用内存,则Flink会将其保存在能高效访问的磁盘数据结构中,这样可以最大限度减少访问磁盘的次数,从而提高处理性能。任务通过访问本地(通常在内存中)状态来进行所有的计算,从而产生非常低的处理延迟。Flink通过定期和异步地对本地状态进行持久化存储来保证故障场景下精确的一次的状态一致性。

 

 

 

小甲鱼零基础汇编语言学习笔记第五章之[BX]和loop指令

     这一章主要介绍什么是[BX]以及loop(循环)指令怎么使用,loop和[BX]又怎么样相结合,段前缀又是什么鬼,以及如何使用段前缀。
 
1、[BX]的概念
     [BX]和[0]类似,[0]表示内存单元的偏移地址是0。要完整描述一个内存单元,需要两种信息:内存单元的地址,内存单元的长度(类型)。[BX]同样也表示一个内存单元,它的偏移地址在bx中,比如指令:mov ax,[bx]。这里我们以一个程序为例:
技术分享
 1      assume cs:codesg
 2      codesg segment
 3      start:    mov ax,2000H
 4                  mov ds,ax
 5                  mov al,[0]
 6                  mov bl,[1]
 7                  mov cl,[2]
 8                  mov dl,[3]
 9                  mov ax,4C00H
10                  int 21H
11       codesg ends
12       end start
View Code
     进行编译,连接之后,使用debug来调试这个程序。对于编译器而言,[0]的中括号是不存在的,所以会出现把0放到al中,把1放到bl中。所以,我们要想偏移地址为某个数,所对应的内存单元传递到寄存器当中,就需要进行两步操作:
     mov bx,0
     mov ax,[bx]
     这样做的话,就可以实现将偏移地址为0对应的内存单元的值传递给寄存器了。
 
2、loop
     这是一个做循环操作的指令,指令格式:loop 标号。
     CPU执行loop指令时,要进行两个步骤的操作:
          (1)(cx)=(cx)-1(这里的cx放在一个括号里面,意思是cx的值)
          (2)判断cx是不是为零,不为零的话转到标号出执行程序。
     所以,loop和cx是有直接联系的,即cx的值影响着loop的执行结果。所以cx的值也就是指的是loop的循环次数,我们可以想到高级语言中,使用循环时(比如for循环),我们都会定义一个变量,来作为循环的条件,这个变量的值也就是循环的次数。
     现在我们来看用汇编来计算2^2结果的代码:
技术分享
1 assume cs:code
2 code segment
3        mov ax,2
4        add ax,ax
5       
6        mov ax,4c00h
7        int 21h
8 code ends
9 end
View Code
     计算2^3也是类似的,代码如下:   
技术分享
 1 assume cs:code
 2 code segment
 3        mov ax,2
 4        add ax,ax
 5        add ax,ax 
 6          
 7        mov ax,4c00h
 8        int 21h
 9 code ends
10 end
11    
View Code
     那么计算2^12,我们就要使用循环来做了,不然重复的代码太多,这个时候我们就要使用到loop指令了,代码如下:
技术分享
 1 assume cs:code
 2 code segment
 3        mov ax,2
 4        mov cx,11
 5 s:add ax,ax
 6        loop s
 7      
 8        mov ax,4c00h
 9        int 21h
10 code ends
11 end
View Code
     上面的代码中,s就是标号,这个标号可以是任何你自己定义的内容,实际上s标明了一个地址,这个地址处有一个指令:add ax,ax。cx我们定义的值为11,因为要算2^12,所以要循环11次。循环时,cx会减1,循环一次减一次,直到cx为0,停止循环。我们可以使用debug调试编译连接好的程序:
     技术分享
     从上面的内容,我们可以得到cx和loop指令互相配合的三个关键点:
     (1)、在cx中存放循环次数
     (2)、loop指令标号所标识的地址要在前面
     (3)、要循环执行的程序段,写在标号和loop指令之间。
 
3、loop和[bx]的联合使用
     我们先从几个问题入手:计算ffff:0~ffff:b单元中的数据的和,结果存储在dx中。
     (1)、运算后的结果是否会超出dx所能存储的值的范围?
          ffff:0~ffff:b内存单元中的数据是字节型数据,范围是0~256,12个这样的数据相加,结果是不会比65535更大的,因此dx中是可以存储下的。
     (2)、能够将ffff:0~ffff:b直接累加到dx当中呢?
          不行,因为ffff:0~ffff:b中的数据是8位的,不能直接加到16位寄存器dx中。
     (3)、能否将ffff:0~ffff:b中的数据累加到dl中,并设置(dh)=0,从而实现累加到dx中呢?
          不行,dl是一个8位寄存器,能容纳的数据的范围在0~255之间,ffff:0~ffff:b中的数据也是8位的,将12个8位的数据累加到一个8位寄存器中,可能会出现进位丢失的情况。
     (4)、那么到底应该怎样将这段内存单元中的数据的和存储到dx中呢?
          就是使用一个16位寄存器来做中介,将内存单元中的8位数据赋值到一个16位寄存器ax中,再将这个ax中的数据加到dx上,从而使得运算对象的类型能够的到匹配(ax,dx都是16进制)并且结果不会越界。
     因为这里要进行12次的相加,因此要使用到loop指令进行循环相加的操作,具体代码如下:
技术分享
 1 assume cs:codeseg
 2 codeseg segment
 3  
 4       mov ax,0ffffh
 5       mov ds,ax          ;初始化ds:bx 指向ffff:0内存单元
 6       mov bx,0
 7  
 8       mov dx,0            ;初始化累加寄存器dx
 9       mov cx,12          ;初始化循环计数寄存器cx
10  
11 s:  mov al,[bx]          
12      mov ah,0
13      add dx,ax     ;间接向dx中加上((ds)*16+(bx))单元中的数值
14      inc bx           ;ds:bx指向下一个单元
15      loop s
16  
17      mov ax,4c00h
18      int 21h
19  
20 codeseg ends  
21 end
View Code
 
4、Debug的G命令和P命令
     当我们对程序进行调试时,循环的次数很大时,我们不可能一次一次的执行t命令,因此要使用G命令或者P命令。G 循环结束的偏移地址,这样就可以一次执行完循环的内容。P,直接执行完循环的内容。
 
5、一段安全的空间
     当我们要直接向内存中写入内容时,这段内存空间不应该存放系统或者其它程序的数据或者代码,否则写入会导致操作系统发生错误,
DOS方式下,一般情况,0:200~0:2FF空间汇中没有存放系统或者其它程序的数据或者代码,以后我们写入内存就直接写到这段空间当中。
 
6、段前缀
     指令 mov ax,[bx]中,内存单元的偏移地址由bx给出,而段地址默认在ds中,我们可以在访问内存单元的指令中,显示的给出内存单元的段地址所在的段寄存器,比如,mov ax,ds:[bx],这里的段寄存器可以是ds,cs,es,ss,这些指令中的段寄存器在汇编语言中也被称为段前缀。
 
7、段前缀的使用
     首先我们考虑一个问题:将ffff:0~ffff:b中的数据复制到0:200~0:20b单元中。
     分析:
     (1)0:200~0:20b也就是0020:0~0020:b,它们描述的是同一个内存空间。
     (2)在循环中,源始单元 ffff:X 和目标单元 0200:X 的偏移地址X是变量,我们使用一个寄存器bx来存放
     代码如下:
技术分享
 1 assume cs:codeseg
 2 codeseg segment
 3  
 4       mov bx,0   ;偏移地址从0开始
 5       mov cx,12 ;循环次数为12次
 6  
 7 s:   mov ax,0ffffh  
 8       mov ds,ax ;ds的值为0ffffh
 9       mov dl,[bx] ;(dl)=((ds)*16+bx)将ffff:bx中的数据传入到dl中
10  
11       mov ax,0020h
12       mov ds,ax  ;ds的值为0020h
13       mov [bx],dl ;((ds)*16+bx)=(dl)将dl中的数据传入到0020:bx中
14  
15       inc bx ;bx自增1
16       loop s
17  
18       mov ax,4c00h
19       int 21h
20  
21 codeseg ends
22 end
View Code
     
  当然,我们上面的代码还有需要改进的地方,从上面的代码可以看到,我们重复设置了两次ds的值,这样做没有错,只是在循环的次数比较小的情况下,一旦循环的次数增到很大时,CPU就要进行很多次重复的操作,这样效率也就比较低了。因此,我们可以对代码进行相应的改进:
    
技术分享
 1 assume cs:codeseg
 2 codeseg segment
 3       mov ax,0ffffh
 4       mov ds,ax         ;(ds)=0ffffh
 5  
 6       mov ax,0020h
 7       mov es,ax          ;(es)=0020h
 8  
 9       mov bx,0   ;(bx)=0,这个时候,ds:bx指向ffff:0,es:bx指0020:0
10       mov cx,12   
11  
12 s:     
13       mov dl,[bx] ;(dl)=((ds)*16+(bx)),将ffff:bx中的数据传入到dl
14       mov es:[bx],dl ;((es)*16+(bx))=(dl),将dl中的数据传入0020:bx
15  
16       inc bx
17       loop s
18  
19       mov ax,4c00h
20       int 21h
21  
22 codeseg ends
23 end
View Code

 

以上是关于Flink零基础学习笔记:基础概念的主要内容,如果未能解决你的问题,请参考以下文章

学习笔记Flink—— Flink基础API及核心数据结构

学习笔记Flink—— Flink基础API及核心数据结构

Flink 系统性学习笔记系列

每日学Java系列-Java零基础学习笔记Java标识符|关键字|变量

尚硅谷_Java零基础教程(多线程)-- 学习笔记

尚硅谷_Java零基础教程(泛型generics)-- 学习笔记